--- a/.hgtags Tue Jul 02 17:09:04 2013 +0200
+++ b/.hgtags Mon Jan 13 13:47:47 2014 +0100
@@ -30,11 +30,7 @@
c9c492787a8aa1b7916e22eb6498cba1c8fa316c cubicweb-debian-version-3_2_0-1
634c251dd032894850080c4e5aeb0a4e09f888c0 cubicweb-version-3_2_1
e784f8847a124a93e5b385d7a92a2772c050fe82 cubicweb-debian-version-3_2_1-1
-6539ce84f04357ef65ccee0896a30997b16a4ece cubicweb-version-3_2_2
-92d1a15f08f7c5fa87643ffb4273d12cb3f41c63 cubicweb-debian-version-3_2_2-1
-6539ce84f04357ef65ccee0896a30997b16a4ece cubicweb-version-3_2_2
9b21e068fef73c37bcb4e53d006a7bde485f390b cubicweb-version-3_2_2
-92d1a15f08f7c5fa87643ffb4273d12cb3f41c63 cubicweb-debian-version-3_2_2-1
0e07514264aa1b0b671226f41725ea4c066c210a cubicweb-debian-version-3_2_2-1
f60bb84b86cf371f1f25197e00c778b469297721 cubicweb-version-3_2_3
4003d24974f15f17bd03b7efd6a5047cad4e4c41 cubicweb-debian-version-3_2_3-1
@@ -43,10 +39,8 @@
a356da3e725bfcb59d8b48a89d04be05ea261fd3 3.3.1
e3aeb6e6c3bb5c18e8dcf61bae9d654beda6c036 cubicweb-version-3_3_2
bef5e74e53f9de8220451dca4b5863a24a0216fb cubicweb-debian-version-3_3_2-1
-1cf9e44e2f1f4415253b8892a0adfbd3b69e84fd cubicweb-version-3_3_3
+47b5236774a0cf3b1cfe75f6d4bd2ec989644ace cubicweb-version-3_3_3
81973c897c9e78e5e52643e03628654916473196 cubicweb-debian-version-3_3_3-1
-1cf9e44e2f1f4415253b8892a0adfbd3b69e84fd cubicweb-version-3_3_3
-47b5236774a0cf3b1cfe75f6d4bd2ec989644ace cubicweb-version-3_3_3
2ba27ce8ecd9828693ec53c517e1c8810cbbe33e cubicweb-debian-version-3_3_3-2
d46363eac5d71bc1570d69337955154dfcd8fcc8 cubicweb-version-3.3.4
7dc22caa7640bf70fcae55afb6d2326829dacced cubicweb-debian-version-3.3.4-1
@@ -82,11 +76,7 @@
37d025b2aa7735dae4a861059014c560b45b19e6 cubicweb-debian-version-3.5.4-1
1eca47d59fd932fe23f643ca239cf2408e5b1856 cubicweb-version-3.5.5
aad818d9d9b6fdb2ffea56c0a9af718c0b69899d cubicweb-debian-version-3.5.5-1
-b79f361839a7251b35eb8378fbc0773de7c8a815 cubicweb-version-3.5.6
-e6225e8e36c6506c774e0a76acc301d8ae1c1028 cubicweb-debian-version-3.5.6-1
-b79f361839a7251b35eb8378fbc0773de7c8a815 cubicweb-version-3.5.6
4e619e97b3fd70769a0f454963193c10cb87f9d4 cubicweb-version-3.5.6
-e6225e8e36c6506c774e0a76acc301d8ae1c1028 cubicweb-debian-version-3.5.6-1
5f7c939301a1b915e17eec61c05e8e9ab8bdc182 cubicweb-debian-version-3.5.6-1
0fc300eb4746e01f2755b9eefd986d58d8366ccf cubicweb-version-3.5.7
7a96c0544c138a0c5f452e5b2428ce6e2b7cb378 cubicweb-debian-version-3.5.7-1
@@ -98,8 +88,6 @@
4920121d41f28c8075a4f00461911677396fc566 cubicweb-debian-version-3.5.11-1
98af3d02b83e7635207781289cc3445fb0829951 cubicweb-version-3.5.12
4281e1e2d76b9a37f38c0eeb1cbdcaa2fac6533c cubicweb-debian-version-3.5.12-1
-5f957e351b0a60d5c5fff60c560b04e666c3a8c6 cubicweb-version-3.6.0
-17e88f2485d1ea1fb8a3926a274637ce19e95d69 cubicweb-debian-version-3.6.0-1
450804da3ab2476b7ede0c1f956235b4c239734f cubicweb-version-3.6.0
d2ba93fcb8da95ceab08f48f8149a480215f149c cubicweb-debian-version-3.6.0-1
4ae30c9ca11b1edad67d25b76fce672171d02023 cubicweb-version-3.6.1
@@ -107,12 +95,12 @@
0a16f07112b90fb61d2e905855fece77e5a7e39c cubicweb-debian-version-3.6.1-2
bfebe3d14d5390492925fc294dfdafad890a7104 cubicweb-version-3.6.2
f3b4bb9121a0e7ee5961310ff79e61c890948a77 cubicweb-debian-version-3.6.2-1
+9c342fa4f1b73e06917d7dc675949baff442108b cubicweb-version-3.6.3
+f9fce56d6a0c2bc6c4b497b66039a8bbbbdc8074 cubicweb-debian-version-3.6.3-1
270aba1e6fa21dac6b070e7815e6d1291f9c87cd cubicweb-version-3.7.0
0c9ff7e496ce344b7e6bf5c9dd2847daf9034e5e cubicweb-debian-version-3.7.0-1
6b0832bbd1daf27c2ce445af5b5222e1e522fb90 cubicweb-version-3.7.1
9194740f070e64da5a89f6a9a31050a8401ebf0c cubicweb-debian-version-3.7.1-1
-9c342fa4f1b73e06917d7dc675949baff442108b cubicweb-version-3.6.3
-f9fce56d6a0c2bc6c4b497b66039a8bbbbdc8074 cubicweb-debian-version-3.6.3-1
d010f749c21d55cd85c5feb442b9cf816282953c cubicweb-version-3.7.2
8fda29a6c2191ba3cc59242c17b28b34127c75fa cubicweb-debian-version-3.7.2-1
768beb8e15f15e079f8ee6cfc35125e12b19e140 cubicweb-version-3.7.3
@@ -135,10 +123,11 @@
5d05b08adeab1ea301e49ed8537e35ede6db92f6 cubicweb-debian-version-3.8.5-1
1a24c62aefc5e57f61be3d04affd415288e81904 cubicweb-version-3.8.6
607a90073911b6bb941a49b5ec0b0d2a9cd479af cubicweb-debian-version-3.8.6-1
+a1a334d934390043a4293a4ee42bdceb1343246e cubicweb-version-3.8.7
+1cccf88d6dfe42986e1091de4c364b7b5814c54f cubicweb-debian-version-3.8.7-1
+48f468f33704e401a8e7907e258bf1ac61eb8407 cubicweb-version-3.9.x
d9936c39d478b6701a4adef17bc28888ffa011c6 cubicweb-version-3.9.0
eda4940ffef8b7d36127e68de63a52388374a489 cubicweb-debian-version-3.9.0-1
-a1a334d934390043a4293a4ee42bdceb1343246e cubicweb-version-3.8.7
-1cccf88d6dfe42986e1091de4c364b7b5814c54f cubicweb-debian-version-3.8.7-1
4d75f743ed49dd7baf8bde7b0e475244933fa08e cubicweb-version-3.9.1
9bd75af3dca36d7be5d25fc5ab1b89b34c811456 cubicweb-debian-version-3.9.1-1
e51796b9caf389c224c6f66dcb8aa75bf1b82eff cubicweb-version-3.9.2
@@ -155,6 +144,11 @@
1c01f9dffd64d507863c9f8f68e3585b7aa24374 cubicweb-debian-version-3.9.7-1
eed788018b595d46a55805bd8d2054c401812b2b cubicweb-version-3.9.8
e4dba8ae963701a36be94ae58c790bc97ba029bb cubicweb-debian-version-3.9.8-1
+df0b2de62cec10c84a2fff5233db05852cbffe93 cubicweb-version-3.9.9
+1ba51b00fc44faa0d6d57448000aaa1fd5c6ab57 cubicweb-debian-version-3.9.9-1
+b7db1f59355832a409d2032e19c84cfffdb3b265 cubicweb-debian-version-3.9.9-2
+09c98763ae9d43616d047c1b25d82b4e41a4362f cubicweb-debian-version-3.9.9-3
+a62f24e1497e953fbaed5894f6064a64f7ac0be3 cubicweb-version-3.10.x
0793fe84651be36f8de9b4faba3781436dc07be0 cubicweb-version-3.10.0
9ef1347f8d99e7daad290738ef93aa894a2c03ce cubicweb-debian-version-3.10.0-1
6c6859a676732c845af69f92e74d4aafae12f83a cubicweb-version-3.10.1
@@ -163,15 +157,7 @@
4a87c8af6f3ffe59c6048ebbdc1b6b204d0b9c7f cubicweb-debian-version-3.10.2-1
8eb58d00a0cedcf7b275b1c7f43b08e2165f655c cubicweb-version-3.10.3
303b150ebb7a92b2904efd52b446457999cab370 cubicweb-debian-version-3.10.3-1
-3829498510a754b1b8a40582cb8dcbca9145fc9d cubicweb-version-3.10.4
-49f1226f2fab6d9ff17eb27d5a66732a4e5b5add cubicweb-debian-version-3.10.4-1
-df0b2de62cec10c84a2fff5233db05852cbffe93 cubicweb-version-3.9.9
-1ba51b00fc44faa0d6d57448000aaa1fd5c6ab57 cubicweb-debian-version-3.9.9-1
-b7db1f59355832a409d2032e19c84cfffdb3b265 cubicweb-debian-version-3.9.9-2
-09c98763ae9d43616d047c1b25d82b4e41a4362f cubicweb-debian-version-3.9.9-3
-3829498510a754b1b8a40582cb8dcbca9145fc9d cubicweb-version-3.10.4
d73733479a3af453f06b849ed88d120784ce9224 cubicweb-version-3.10.4
-49f1226f2fab6d9ff17eb27d5a66732a4e5b5add cubicweb-debian-version-3.10.4-1
7b41930e1d32fea3989a85f6ea7281983300adb1 cubicweb-debian-version-3.10.4-1
159d0dbe07d9eb1c6ace4c5e160d1ec6e6762086 cubicweb-version-3.10.5
e2e7410e994777589aec218d31eef9ff8d893f92 cubicweb-debian-version-3.10.5-1
@@ -181,21 +167,20 @@
bf5d9a1415e3c9abe6b68ba3b24a8ad741f9de3c cubicweb-debian-version-3.10.7-1
e581a86a68f089946a98c966ebca7aee58a5718f cubicweb-version-3.10.8
132b525de25bc75ed6389c45aee77e847cb3a437 cubicweb-debian-version-3.10.8-1
-48f468f33704e401a8e7907e258bf1ac61eb8407 cubicweb-version-3.9.x
37432cede4fe55b97fc2e9be0a2dd20e8837a848 cubicweb-version-3.11.0
8daabda9f571863e8754f8ab722744c417ba3abf cubicweb-debian-version-3.11.0-1
d0410eb4d8bbf657d7f32b0c681db09b1f8119a0 cubicweb-version-3.11.1
77318f1ec4aae3523d455e884daf3708c3c79af7 cubicweb-debian-version-3.11.1-1
56ae3cd5f8553678a2b1d4121b61241598d0ca68 cubicweb-version-3.11.2
954b5b51cd9278eb45d66be1967064d01ab08453 cubicweb-debian-version-3.11.2-1
+b7a124f9aed2c7c9c86c6349ddd9f0a07023f0ca cubicweb-version-3.11.3
+b3c6702761a18a41fdbb7bc1083f92aefce07765 cubicweb-debian-version-3.11.3-1
fd502219eb76f4bfd239d838a498a1d1e8204baf cubicweb-version-3.12.0
92b56939b7c77bbf443b893c495a20f19bc30702 cubicweb-debian-version-3.12.0-1
59701627adba73ee97529f6ea0e250a0f3748e32 cubicweb-version-3.12.1
07e2c9c7df2617c5ecfa84cb819b3ee8ef91d1f2 cubicweb-debian-version-3.12.1-1
5a9b6bc5653807500c30a7eb0e95b90fd714fec3 cubicweb-version-3.12.2
6d418fb3ffed273562aae411efe323d5138b592a cubicweb-debian-version-3.12.2-1
-b7a124f9aed2c7c9c86c6349ddd9f0a07023f0ca cubicweb-version-3.11.3
-b3c6702761a18a41fdbb7bc1083f92aefce07765 cubicweb-debian-version-3.11.3-1
e712bc6f1f71684f032bfcb9bb151a066c707dec cubicweb-version-3.12.3
ba8fe4f2e408c3fdf6c297cd42c2577dcac50e71 cubicweb-debian-version-3.12.3-1
5cd0dbc26882f60e3f11ec55e7f058d94505e7ed cubicweb-version-3.12.4
@@ -204,14 +189,16 @@
6dfe78a0797ccc34962510f8c2a57f63d65ce41e cubicweb-debian-version-3.12.5-1
a18dac758150fe9c1f9e4958d898717c32a8f679 cubicweb-version-3.12.6
105767487c7075dbcce36474f1af0485985cbf2c cubicweb-debian-version-3.12.6-1
-b661ef475260ca7d9ea5c36ba2cc86e95e5b17d3 cubicweb-version-3.13.0
-a96137858f571711678954477da6f7f435870cea cubicweb-debian-version-3.13.0-1
628fe57ce746c1dac87fb1b078b2026057df894e cubicweb-version-3.12.7
a07517985136bbbfa6610c428a1b42cd04cd530b cubicweb-debian-version-3.12.7-1
50122a47ce4fb2ecbf3cf20ed2777f4276c93609 cubicweb-version-3.12.8
cf49ed55685a810d8d73585330ad1a57cc76260d cubicweb-debian-version-3.12.8-1
cb2990aaa63cbfe593bcf3afdbb9071e4c76815a cubicweb-version-3.12.9
92464e39134c70e4ddbe6cd78a6e3338a3b88b05 cubicweb-debian-version-3.12.9-1
+074c848a3712a77737d9a1bfbb618c75f5c0cbfa cubicweb-version-3.12.10
+9dfd21fa0a8b9f121a08866ad3e2ebd1dd06790d cubicweb-debian-version-3.12.10-1
+b661ef475260ca7d9ea5c36ba2cc86e95e5b17d3 cubicweb-version-3.13.0
+a96137858f571711678954477da6f7f435870cea cubicweb-debian-version-3.13.0-1
7d84317ef185a10c5eb78e6086f2297d2f4bd1e3 cubicweb-version-3.13.1
cc0578049cbe8b1d40009728e36c17e45da1fc6b cubicweb-debian-version-3.13.1-1
f9227b9d61835f03163b8133a96da35db37a0c8d cubicweb-version-3.13.2
@@ -220,11 +207,8 @@
fb48c55cb80234bc0164c9bcc0e2cfc428836e5f cubicweb-debian-version-3.13.3-1
223ecf0620b6c87d997f8011aca0d9f0ee4750af cubicweb-version-3.13.4
52f26475d764129c5559b2d80fd57e6ea1bdd6ba cubicweb-debian-version-3.13.4-1
-a62f24e1497e953fbaed5894f6064a64f7ac0be3 cubicweb-version-3.10.x
20d9c550c57eb6f9adcb0cfab1c11b6b8793afb6 cubicweb-version-3.13.5
2e9dd7d945557c210d3b79153c65f6885e755315 cubicweb-debian-version-3.13.5-1
-074c848a3712a77737d9a1bfbb618c75f5c0cbfa cubicweb-version-3.12.10
-9dfd21fa0a8b9f121a08866ad3e2ebd1dd06790d cubicweb-debian-version-3.12.10-1
17c007ad845abbac82e12146abab32a634657574 cubicweb-version-3.13.6
8a8949ca5351d48c5cf795ccdff06c1d4aab2ce0 cubicweb-debian-version-3.13.6-1
68e8c81fa96d6bcd21cc17bc9832d388ce05a9eb cubicweb-version-3.13.7
@@ -233,10 +217,10 @@
43f83f5d0a4d57a06e9a4990bc957fcfa691eec3 cubicweb-debian-version-3.13.8-1
07afe32945aa275052747f78ef1f55858aaf6fa9 cubicweb-version-3.13.9
0a3cb5e60d57a7a9851371b4ae487094ec2bf614 cubicweb-debian-version-3.13.9-1
+2ad4e5173c73a43804c265207bcabb8940bd42f4 cubicweb-version-3.13.10
+2eab9a5a6bf8e3b0cf706bee8cdf697759c0a33a cubicweb-debian-version-3.13.10-1
5c4390eb10c3fe76a81e6fccec109d7097dc1a8d cubicweb-version-3.14.0
0bfe22fceb383b46d62b437bf5dd0141a714afb8 cubicweb-debian-version-3.14.0-1
-2ad4e5173c73a43804c265207bcabb8940bd42f4 cubicweb-version-3.13.10
-2eab9a5a6bf8e3b0cf706bee8cdf697759c0a33a cubicweb-debian-version-3.13.10-1
793d2d327b3ebf0b82b2735cf3ccb86467d1c08a cubicweb-version-3.14.1
6928210da4fc25d086b5b8d5ff2029da41aade2e cubicweb-debian-version-3.14.1-1
049a3819f03dc79d803be054cc3bfe8425313f63 cubicweb-version-3.14.2
@@ -250,8 +234,6 @@
55fc796ed5d5f31245ae60bd148c9e42657a1af6 cubicweb-debian-version-3.14.5-1
db021578232b885dc5e55dfca045332ce01e7f35 cubicweb-version-3.14.6
75364c0994907764715bd5011f6a59d934dbeb7d cubicweb-debian-version-3.14.6-1
-0642b2d03acaa5e065cae7590e82b388a280ca22 cubicweb-version-3.15.0
-925db25a3250c5090cf640fc2b02bde5818b9798 cubicweb-debian-version-3.15.0-1
3ba3ee5b3a89a54d1dc12ed41d5c12232eda1952 cubicweb-version-3.14.7
20ee573bd2379a00f29ff27bb88a8a3344d4cdfe cubicweb-debian-version-3.14.7-1
15fe07ff687238f8cc09d8e563a72981484085b3 cubicweb-version-3.14.8
@@ -260,6 +242,8 @@
68c762adf2d5a2c338910ef1091df554370586f0 cubicweb-debian-version-3.14.9-1
0ff798f80138ca8f50a59f42284380ce8f6232e8 cubicweb-version-3.14.10
197bcd087c87cd3de9f21f5bf40bd6203c074f1f cubicweb-debian-version-3.14.10-1
+0642b2d03acaa5e065cae7590e82b388a280ca22 cubicweb-version-3.15.0
+925db25a3250c5090cf640fc2b02bde5818b9798 cubicweb-debian-version-3.15.0-1
783a5df54dc742e63c8a720b1582ff08366733bd cubicweb-version-3.15.1
fe5e60862b64f1beed2ccdf3a9c96502dfcd811b cubicweb-debian-version-3.15.1-1
2afc157ea9b2b92eccb0f2d704094e22ce8b5a05 cubicweb-version-3.15.2
@@ -291,19 +275,51 @@
ee860c51f56bd65c4f6ea363462c02700d1dab5a cubicweb-version-3.16.3
ee860c51f56bd65c4f6ea363462c02700d1dab5a cubicweb-debian-version-3.16.3-1
ee860c51f56bd65c4f6ea363462c02700d1dab5a cubicweb-centos-version-3.16.3-1
-cc1a0aad580cf93d26959f97d8d6638e786c1082 cubicweb-version-3.17.0
-22be40c492e9034483bfec379ca11462ea97825b cubicweb-debian-version-3.17.0-1
-09a0c7ea6c3cb97bbbeed3795b3c3715ceb9566b cubicweb-debian-version-3.17.0-2
041804bc48e91e440a5b573ceb0df5bf22863b80 cubicweb-version-3.16.4
041804bc48e91e440a5b573ceb0df5bf22863b80 cubicweb-debian-version-3.16.4-1
041804bc48e91e440a5b573ceb0df5bf22863b80 cubicweb-centos-version-3.16.4-1
810a05fba1a46ab893b6cadac109097a047f8355 cubicweb-version-3.16.5
810a05fba1a46ab893b6cadac109097a047f8355 cubicweb-debiann-version-3.16.5-1
810a05fba1a46ab893b6cadac109097a047f8355 cubicweb-centos-version-3.16.5-1
-f98d1c46ed9fd5db5262cf5be1c8e159c90efc8b cubicweb-version-3.17.1
+b4ccaf13081d2798c0414d002e743cb0bf6d81f8 cubicweb-version-3.16.6
+b4ccaf13081d2798c0414d002e743cb0bf6d81f8 cubicweb-centos-version-3.16.6-1
+b4ccaf13081d2798c0414d002e743cb0bf6d81f8 cubicweb-debian-version-3.16.6-1
+cc1a0aad580cf93d26959f97d8d6638e786c1082 cubicweb-version-3.17.0
+22be40c492e9034483bfec379ca11462ea97825b cubicweb-debian-version-3.17.0-1
+09a0c7ea6c3cb97bbbeed3795b3c3715ceb9566b cubicweb-debian-version-3.17.0-2
f98d1c46ed9fd5db5262cf5be1c8e159c90efc8b cubicweb-version-3.17.1
-73f2ad404716cd211b735e67ee16875f1fff7374 cubicweb-debian-version-3.17.1-1
f98d1c46ed9fd5db5262cf5be1c8e159c90efc8b cubicweb-debian-version-3.17.1-1
f98d1c46ed9fd5db5262cf5be1c8e159c90efc8b cubicweb-centos-version-3.17.1-1
+965f894b63cb7c4456acd82257709f563bde848f cubicweb-centos-version-3.17.1-2
195e519fe97c8d1a5ab5ccb21bf7c88e5801b657 cubicweb-version-3.17.2
195e519fe97c8d1a5ab5ccb21bf7c88e5801b657 cubicweb-debian-version-3.17.2-1
+32b4d5314fd90fe050c931886190f9a372686148 cubicweb-version-3.17.3
+32b4d5314fd90fe050c931886190f9a372686148 cubicweb-debian-version-3.17.3-1
+32b4d5314fd90fe050c931886190f9a372686148 cubicweb-centos-version-3.17.3-1
+c7ba8e5d2e45e3d1289c1403df40d7dcb5e62acb cubicweb-version-3.17.4
+c7ba8e5d2e45e3d1289c1403df40d7dcb5e62acb cubicweb-debian-version-3.17.4-1
+c7ba8e5d2e45e3d1289c1403df40d7dcb5e62acb cubicweb-centos-version-3.17.4-1
+15dd5b37998b8ef5e8fab1ea0491e6bd8e9f3355 cubicweb-centos-version-3.17.5-1
+15dd5b37998b8ef5e8fab1ea0491e6bd8e9f3355 cubicweb-version-3.17.5
+15dd5b37998b8ef5e8fab1ea0491e6bd8e9f3355 cubicweb-debian-version-3.17.5-1
+5b9fedf67a2912a80fe315a477df9e3ab104c734 cubicweb-centos-version-3.17.6-1
+5b9fedf67a2912a80fe315a477df9e3ab104c734 cubicweb-version-3.17.6
+5b9fedf67a2912a80fe315a477df9e3ab104c734 cubicweb-debian-version-3.17.6-1
+483181543899a762d068cfdc3ae751b54adc3f14 cubicweb-centos-version-3.17.7-1
+483181543899a762d068cfdc3ae751b54adc3f14 cubicweb-version-3.17.7
+483181543899a762d068cfdc3ae751b54adc3f14 cubicweb-debian-version-3.17.7-1
+909eb8b584c437b3d2580beff1325c3d5b5dcfb5 cubicweb-centos-version-3.17.8-1
+909eb8b584c437b3d2580beff1325c3d5b5dcfb5 cubicweb-version-3.17.8
+909eb8b584c437b3d2580beff1325c3d5b5dcfb5 cubicweb-debian-version-3.17.8-1
+5668d210e49c910180ff27712b6ae9ce8286e06c cubicweb-version-3.17.9
+5668d210e49c910180ff27712b6ae9ce8286e06c cubicweb-debian-version-3.17.9-1
+fe0e1863a13772836f40f743cc6fe4865f288ed3 cubicweb-centos-version-3.17.10-1
+fe0e1863a13772836f40f743cc6fe4865f288ed3 cubicweb-version-3.17.10
+fe0e1863a13772836f40f743cc6fe4865f288ed3 cubicweb-debian-version-3.17.10-1
+7f67db7c848ec20152daf489d9e11f0fc8402e9b cubicweb-centos-version-3.17.11-1
+7f67db7c848ec20152daf489d9e11f0fc8402e9b cubicweb-version-3.17.11
+7f67db7c848ec20152daf489d9e11f0fc8402e9b cubicweb-debian-version-3.17.11-1
+b02e2912cad5d80395e488c55b548495e8320198 cubicweb-debian-version-3.17.11-2
+db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-version-3.18.0
+db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-debian-version-3.18.0-1
+db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-centos-version-3.18.0-1
--- a/README Tue Jul 02 17:09:04 2013 +0200
+++ b/README Mon Jan 13 13:47:47 2014 +0100
@@ -34,4 +34,4 @@
Look in the doc/ subdirectory or read http://docs.cubicweb.org/
-
+It includes the Entypo pictograms by Daniel Bruce — www.entypo.com
--- a/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -22,6 +22,8 @@
# ignore the pygments UserWarnings
import warnings
+import cPickle
+import zlib
warnings.filterwarnings('ignore', category=UserWarning,
message='.*was already imported',
module='.*pygments')
@@ -120,6 +122,26 @@
binary.seek(0)
return binary
+ def __eq__(self, other):
+ if not isinstance(other, Binary):
+ return False
+ return self.getvalue(), other.getvalue()
+
+
+ # Binary helpers to store/fetch python objects
+
+ @classmethod
+ def zpickle(cls, obj):
+ """ return a Binary containing a gzipped pickle of obj """
+ retval = cls()
+ retval.write(zlib.compress(cPickle.dumps(obj, protocol=2)))
+ return retval
+
+ def unzpickle(self):
+ """ decompress and loads the stream before returning it """
+ return cPickle.loads(zlib.decompress(self.getvalue()))
+
+
def str_or_binary(value):
if isinstance(value, Binary):
return value
@@ -127,7 +149,6 @@
BASE_CONVERTERS['Password'] = str_or_binary
-
# use this dictionary to rename entity types while keeping bw compat
ETYPE_NAME_MAP = {}
--- a/__pkginfo__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/__pkginfo__.py Mon Jan 13 13:47:47 2014 +0100
@@ -22,7 +22,7 @@
modname = distname = "cubicweb"
-numversion = (3, 17, 2)
+numversion = (3, 18, 0)
version = '.'.join(str(num) for num in numversion)
description = "a repository of entities / relations for knowledge management"
@@ -40,10 +40,10 @@
]
__depends__ = {
- 'logilab-common': '>= 0.59.0',
+ 'logilab-common': '>= 0.60.0',
'logilab-mtconverter': '>= 0.8.0',
'rql': '>= 0.31.2',
- 'yams': '>= 0.37.0',
+ 'yams': '>= 0.39.0',
#gettext # for xgettext, msgcat, etc...
# web dependancies
'simplejson': '>= 2.0.9',
@@ -51,8 +51,7 @@
'Twisted': '',
# XXX graphviz
# server dependencies
- 'logilab-database': '>= 1.10',
- 'pysqlite': '>= 2.5.5', # XXX install pysqlite2
+ 'logilab-database': '>= 1.11',
'passlib': '',
}
--- a/_exceptions.py Tue Jul 02 17:09:04 2013 +0200
+++ b/_exceptions.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -19,6 +19,10 @@
__docformat__ = "restructuredtext en"
+from warnings import warn
+
+from logilab.common.decorators import cachedproperty
+
from yams import ValidationError as ValidationError
# abstract exceptions #########################################################
@@ -61,7 +65,7 @@
"""
class AuthenticationError(ConnectionError):
- """raised when when an attempt to establish a connection failed do to wrong
+ """raised when an attempt to establish a connection failed due to wrong
connection information (login / password or other authentication token)
"""
@@ -81,6 +85,26 @@
class UniqueTogetherError(RepositoryError):
"""raised when a unique_together constraint caused an IntegrityError"""
+ def __init__(self, session, **kwargs):
+ self.session = session
+ assert 'rtypes' in kwargs or 'cstrname' in kwargs
+ self.kwargs = kwargs
+
+ @cachedproperty
+ def rtypes(self):
+ if 'rtypes' in self.kwargs:
+ return self.kwargs['rtypes']
+ cstrname = unicode(self.kwargs['cstrname'])
+ cstr = self.session.find('CWUniqueTogetherConstraint', name=cstrname).one()
+ return sorted(rtype.name for rtype in cstr.relations)
+
+ @cachedproperty
+ def args(self):
+ warn('[3.18] UniqueTogetherError.args is deprecated, just use '
+ 'the .rtypes accessor.',
+ DeprecationWarning)
+ # the first argument, etype, is never used and was never garanteed anyway
+ return None, self.rtypes
# security exceptions #########################################################
@@ -134,6 +158,15 @@
a non final entity
"""
+class MultipleResultsError(CubicWebRuntimeError):
+ """raised when ResultSet.one() is called on a resultset with multiple rows
+ of multiple columns.
+ """
+
+class NoResultError(CubicWebRuntimeError):
+ """raised when no result is found but at least one is expected.
+ """
+
class UndoTransactionException(QueryError):
"""Raised when undoing a transaction could not be performed completely.
--- a/cubicweb.spec Tue Jul 02 17:09:04 2013 +0200
+++ b/cubicweb.spec Mon Jan 13 13:47:47 2014 +0100
@@ -7,7 +7,7 @@
%endif
Name: cubicweb
-Version: 3.17.2
+Version: 3.18.0
Release: logilab.1%{?dist}
Summary: CubicWeb is a semantic web application framework
Source0: http://download.logilab.org/pub/cubicweb/cubicweb-%{version}.tar.gz
@@ -20,11 +20,11 @@
BuildArch: noarch
Requires: %{python}
-Requires: %{python}-logilab-common >= 0.59.0
+Requires: %{python}-logilab-common >= 0.60.0
Requires: %{python}-logilab-mtconverter >= 0.8.0
Requires: %{python}-rql >= 0.31.2
-Requires: %{python}-yams >= 0.37.0
-Requires: %{python}-logilab-database >= 1.10.0
+Requires: %{python}-yams >= 0.39.0
+Requires: %{python}-logilab-database >= 1.11.0
Requires: %{python}-passlib
Requires: %{python}-lxml
Requires: %{python}-twisted-web
@@ -46,11 +46,13 @@
%install
NO_SETUPTOOLS=1 %{__python} setup.py --quiet install --no-compile --prefix=%{_prefix} --root="$RPM_BUILD_ROOT"
+mkdir -p $RPM_BUILD_ROOT/var/log/cubicweb
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-, root, root)
+%dir /var/log/cubicweb
/*
--- a/cwconfig.py Tue Jul 02 17:09:04 2013 +0200
+++ b/cwconfig.py Mon Jan 13 13:47:47 2014 +0100
@@ -53,8 +53,7 @@
If you are not administrator of you machine or if you need to play with some
specific version of |cubicweb| you can use `virtualenv`_ a tool to create
-isolated Python environments. Since version 3.9 |cubicweb| is **`virtualenv`
-friendly** and won't write any file outside the virtualenv directory.
+isolated Python environments.
- instances are stored in :file:`<VIRTUAL_ENV>/etc/cubicweb.d`
- temporary files (such as pid file) in :file:`<VIRTUAL_ENV>/var/run/cubicweb`
@@ -206,7 +205,7 @@
"""return a list of installed configurations in a directory
according to \*-ctl files
"""
- return [name for name in ('repository', 'twisted', 'all-in-one')
+ return [name for name in ('repository', 'all-in-one')
if exists(join(directory, '%s.conf' % name))]
def guess_configuration(directory):
@@ -328,7 +327,7 @@
# the format below can be useful to debug multi thread issues:
# log_format = '%(asctime)s - [%(threadName)s] (%(name)s) %(levelname)s: %(message)s'
# nor remove appobjects based on unused interface [???]
- cleanup_interface_sobjects = True
+ cleanup_unused_appobjects = True
if (CWDEV and _forced_mode != 'system'):
mode = 'user'
@@ -499,21 +498,11 @@
try:
gendeps = getattr(pkginfo, key.replace('_cubes', ''))
except AttributeError:
- # bw compat
- if hasattr(pkginfo, oldkey):
- warn('[3.8] cube %s: %s is deprecated, use %s dict'
- % (cube, oldkey, key), DeprecationWarning)
- deps = getattr(pkginfo, oldkey)
- else:
- deps = {}
+ deps = {}
else:
deps = dict( (x[len('cubicweb-'):], v)
for x, v in gendeps.iteritems()
if x.startswith('cubicweb-'))
- if not isinstance(deps, dict):
- deps = dict((key, None) for key in deps)
- warn('[3.8] cube %s should define %s as a dict' % (cube, key),
- DeprecationWarning)
for depcube in deps:
try:
newname = CW_MIGRATION_MAP[depcube]
@@ -940,10 +929,9 @@
' "cubicweb-ctl list")' % appid)
return home
- MODES = ('common', 'repository', 'Any', 'web')
+ MODES = ('common', 'repository', 'Any')
MCOMPAT = {'all-in-one': MODES,
- 'repository': ('common', 'repository', 'Any'),
- 'twisted' : ('common', 'web'),}
+ 'repository': ('common', 'repository', 'Any')}
@classmethod
def accept_mode(cls, mode):
#assert mode in cls.MODES, mode
@@ -1189,11 +1177,13 @@
sourcedirs.append(self.i18n_lib_dir())
return i18n.compile_i18n_catalogs(sourcedirs, i18ndir, langs)
- def sendmails(self, msgs):
+ def sendmails(self, msgs, fromaddr=None):
"""msgs: list of 2-uple (message object, recipients). Return False
if connection to the smtp server failed, else True.
"""
server, port = self['smtp-host'], self['smtp-port']
+ if fromaddr is None:
+ fromaddr = '%s <%s>' % (self['sender-name'], self['sender-addr'])
SMTP_LOCK.acquire()
try:
try:
@@ -1202,10 +1192,9 @@
self.exception("can't connect to smtp server %s:%s (%s)",
server, port, ex)
return False
- heloaddr = '%s <%s>' % (self['sender-name'], self['sender-addr'])
for msg, recipients in msgs:
try:
- smtp.sendmail(heloaddr, recipients, msg.as_string())
+ smtp.sendmail(fromaddr, recipients, msg.as_string())
except Exception as ex:
self.exception("error sending mail to %s (%s)",
recipients, ex)
--- a/cwctl.py Tue Jul 02 17:09:04 2013 +0200
+++ b/cwctl.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -48,13 +48,9 @@
from cubicweb.toolsutils import Command, rm, create_dir, underline_title
from cubicweb.__pkginfo__ import version
-if support_args(CommandLine, 'check_duplicated_command'):
- # don't check duplicated commands, it occurs when reloading site_cubicweb
- CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.',
- version=version, check_duplicated_command=False)
-else:
- CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.',
- version=version)
+# don't check duplicated commands, it occurs when reloading site_cubicweb
+CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.',
+ version=version, check_duplicated_command=False)
def wait_process_end(pid, maxtry=10, waittime=1):
"""wait for a process to actually die"""
@@ -266,12 +262,7 @@
if tinfo:
descr = getattr(tinfo, 'description', '')
if not descr:
- descr = getattr(tinfo, 'short_desc', '')
- if descr:
- warn('[3.8] short_desc is deprecated, update %s'
- ' pkginfo' % cube, DeprecationWarning)
- else:
- descr = tinfo.__doc__
+ descr = tinfo.__doc__
if descr:
print ' '+ ' \n'.join(descr.splitlines())
modes = detect_available_modes(cwcfg.cube_dir(cube))
@@ -357,7 +348,7 @@
}),
('config',
{'short': 'c', 'type' : 'choice', 'metavar': '<install type>',
- 'choices': ('all-in-one', 'repository', 'twisted'),
+ 'choices': ('all-in-one', 'repository'),
'default': 'all-in-one',
'help': 'installation type, telling which part of an instance '
'should be installed. You can list available configurations using the'
@@ -751,6 +742,7 @@
print '\n' + underline_title('Upgrading the instance %s' % appid)
from logilab.common.changelog import Version
config = cwcfg.config_for(appid)
+ instance_running = exists(config['pid-file'])
config.repairing = True # notice we're not starting the server
config.verbosity = self.config.verbosity
set_sources_mode = getattr(config, 'set_sources_mode', None)
@@ -760,6 +752,7 @@
mih = config.migration_handler()
repo = mih.repo_connect()
vcconf = repo.get_versions()
+ helper = self.config_helper(config, required=False)
if self.config.force_cube_version:
for cube, version in self.config.force_cube_version.iteritems():
vcconf[cube] = Version(version)
@@ -782,7 +775,7 @@
if cubicwebversion > applcubicwebversion:
toupgrade.append(('cubicweb', applcubicwebversion, cubicwebversion))
# only stop once we're sure we have something to do
- if not (CWDEV or self.config.nostartstop):
+ if instance_running and not (CWDEV or self.config.nostartstop):
StopInstanceCommand(self.logger).stop_instance(appid)
# run cubicweb/componants migration scripts
if self.config.fs_only or toupgrade:
@@ -798,8 +791,10 @@
if not self.i18nupgrade(config):
return
print
+ if helper:
+ helper.postupgrade(repo)
print '-> instance migrated.'
- if not (CWDEV or self.config.nostartstop):
+ if instance_running and not (CWDEV or self.config.nostartstop):
# restart instance through fork to get a proper environment, avoid
# uicfg pb (and probably gettext catalogs, to check...)
forkcmd = '%s start %s' % (sys.argv[0], appid)
@@ -1038,9 +1033,56 @@
raise ConfigurationError('unknown configuration key "%s" for mode %s' % (key, appcfg.name))
appcfg.save()
+
+# WSGI #########
+
+def wsgichoices():
+ try:
+ from werkzeug import serving
+ except ImportError:
+ return ('stdlib',)
+ return ('stdlib', 'werkzeug')
+
+class WSGIDebugStartHandler(InstanceCommand):
+ """Start an interactive wsgi server """
+ name = 'wsgi'
+ actionverb = 'started'
+ arguments = '<instance>'
+ options = (
+ ('method',
+ {'short': 'm',
+ 'type': 'choice',
+ 'metavar': '<method>',
+ 'default': 'stdlib',
+ 'choices': wsgichoices(),
+ 'help': 'wsgi utility/method'}),
+ ('loglevel',
+ {'short': 'l',
+ 'type' : 'choice',
+ 'metavar': '<log level>',
+ 'default': 'debug',
+ 'choices': ('debug', 'info', 'warning', 'error'),
+ 'help': 'debug if -D is set, error otherwise',
+ }),
+ )
+
+ def wsgi_instance(self, appid):
+ config = cwcfg.config_for(appid, debugmode=1)
+ init_cmdline_log_threshold(config, self['loglevel'])
+ assert config.name == 'all-in-one'
+ meth = self['method']
+ if meth == 'stdlib':
+ from cubicweb.wsgi import server
+ else:
+ from cubicweb.wsgi import wz as server
+ return server.run(config)
+
+
+
for cmdcls in (ListCommand,
CreateInstanceCommand, DeleteInstanceCommand,
StartInstanceCommand, StopInstanceCommand, RestartInstanceCommand,
+ WSGIDebugStartHandler,
ReloadConfigurationCommand, StatusCommand,
UpgradeInstanceCommand,
ListVersionsInstanceCommand,
@@ -1051,6 +1093,8 @@
):
CWCTL.register(cmdcls)
+
+
def run(args):
"""command line tool"""
import os
--- a/cwvreg.py Tue Jul 02 17:09:04 2013 +0200
+++ b/cwvreg.py Mon Jan 13 13:47:47 2014 +0100
@@ -211,8 +211,7 @@
from cubicweb import (CW_SOFTWARE_ROOT, ETYPE_NAME_MAP, CW_EVENT_MANAGER,
onevent, Binary, UnknownProperty, UnknownEid)
-from cubicweb.predicates import (implements, appobject_selectable,
- _reset_is_instance_cache)
+from cubicweb.predicates import appobject_selectable, _reset_is_instance_cache
@onevent('before-registry-reload')
@@ -230,15 +229,6 @@
sys.modules.pop('cubicweb.web.uicfg', None)
sys.modules.pop('cubicweb.web.uihelper', None)
-def use_interfaces(obj):
- """return interfaces required by the given object by searching for
- `implements` predicate
- """
- impl = obj.__select__.search_selector(implements)
- if impl:
- return sorted(impl.expected_ifaces)
- return ()
-
def require_appobject(obj):
"""return appobjects required by the given object by searching for
`appobject_selectable` predicate
@@ -568,7 +558,6 @@
def reset(self):
CW_EVENT_MANAGER.emit('before-registry-reset', self)
super(CWRegistryStore, self).reset()
- self._needs_iface = {}
self._needs_appobject = {}
# two special registries, propertydefs which care all the property
# definitions, and propertyvals which contains values for those
@@ -626,6 +615,15 @@
self.register_objects(path)
CW_EVENT_MANAGER.emit('after-registry-reload')
+ def load_file(self, filepath, modname):
+ # override to allow some instrumentation (eg localperms)
+ modpath = modname.split('.')
+ try:
+ self.currently_loading_cube = modpath[modpath.index('cubes') + 1]
+ except ValueError:
+ self.currently_loading_cube = 'cubicweb'
+ return super(CWRegistryStore, self).load_file(filepath, modname)
+
def _set_schema(self, schema):
"""set instance'schema"""
self.schema = schema
@@ -641,20 +639,6 @@
for obj in objects:
obj.schema = schema
- @deprecated('[3.9] use .register instead')
- def register_if_interface_found(self, obj, ifaces, **kwargs):
- """register `obj` but remove it if no entity class implements one of
- the given `ifaces` interfaces at the end of the registration process.
-
- Extra keyword arguments are given to the
- :meth:`~cubicweb.cwvreg.CWRegistryStore.register` function.
- """
- self.register(obj, **kwargs)
- if not isinstance(ifaces, (tuple, list)):
- self._needs_iface[obj] = (ifaces,)
- else:
- self._needs_iface[obj] = ifaces
-
def register(self, obj, *args, **kwargs):
"""register `obj` application object into `registryname` or
`obj.__registry__` if not specified, with identifier `oid` or
@@ -665,15 +649,6 @@
"""
obj = related_appobject(obj)
super(CWRegistryStore, self).register(obj, *args, **kwargs)
- # XXX bw compat
- ifaces = use_interfaces(obj)
- if ifaces:
- if not obj.__name__.endswith('Adapter') and \
- any(iface for iface in ifaces if not isinstance(iface, basestring)):
- warn('[3.9] %s: interfaces in implements selector are '
- 'deprecated in favor of adapters / adaptable '
- 'selector' % obj.__name__, DeprecationWarning)
- self._needs_iface[obj] = ifaces
depends_on = require_appobject(obj)
if depends_on is not None:
self._needs_appobject[obj] = depends_on
@@ -687,41 +662,14 @@
def initialization_completed(self):
"""cw specific code once vreg initialization is completed:
- * remove objects requiring a missing interface, unless
- config.cleanup_interface_sobjects is false
+ * remove objects requiring a missing appobject, unless
+ config.cleanup_unused_appobjects is false
* init rtags
"""
# we may want to keep interface dependent objects (e.g.for i18n
# catalog generation)
- if self.config.cleanup_interface_sobjects:
- # XXX deprecated with cw 3.9: remove appobjects that don't support
- # any available interface
- implemented_interfaces = set()
- if 'Any' in self.get('etypes', ()):
- for etype in self.schema.entities():
- if etype.final:
- continue
- cls = self['etypes'].etype_class(etype)
- if cls.__implements__:
- warn('[3.9] %s: using __implements__/interfaces are '
- 'deprecated in favor of adapters' % cls.__name__,
- DeprecationWarning)
- for iface in cls.__implements__:
- implemented_interfaces.update(iface.__mro__)
- implemented_interfaces.update(cls.__mro__)
- for obj, ifaces in self._needs_iface.items():
- ifaces = frozenset(isinstance(iface, basestring)
- and iface in self.schema
- and self['etypes'].etype_class(iface)
- or iface
- for iface in ifaces)
- if not ('Any' in ifaces or ifaces & implemented_interfaces):
- reg = self[obj_registries(obj)[0]]
- self.debug('unregister %s (no implemented '
- 'interface among %s)', reg.objid(obj), ifaces)
- self.unregister(obj)
- # since 3.9: remove appobjects which depending on other, unexistant
- # appobjects
+ if self.config.cleanup_unused_appobjects:
+ # remove appobjects which depend on other, unexistant appobjects
for obj, (regname, regids) in self._needs_appobject.items():
try:
registry = self[regname]
@@ -740,8 +688,8 @@
if 'uicfg' in self: # 'uicfg' is not loaded in a pure repository mode
for rtags in self['uicfg'].itervalues():
for rtag in rtags:
- # don't check rtags if we don't want to cleanup_interface_sobjects
- rtag.init(self.schema, check=self.config.cleanup_interface_sobjects)
+ # don't check rtags if we don't want to cleanup_unused_appobjects
+ rtag.init(self.schema, check=self.config.cleanup_unused_appobjects)
# rql parsing utilities ####################################################
--- a/dataimport.py Tue Jul 02 17:09:04 2013 +0200
+++ b/dataimport.py Mon Jan 13 13:47:47 2014 +0100
@@ -105,8 +105,8 @@
return i+1
def ucsvreader_pb(stream_or_path, encoding='utf-8', separator=',', quote='"',
- skipfirst=False, withpb=True):
- """same as ucsvreader but a progress bar is displayed as we iter on rows"""
+ skipfirst=False, withpb=True, skip_empty=True):
+ """same as :func:`ucsvreader` but a progress bar is displayed as we iter on rows"""
if isinstance(stream_or_path, basestring):
if not osp.exists(stream_or_path):
raise Exception("file doesn't exists: %s" % stream_or_path)
@@ -118,23 +118,30 @@
rowcount -= 1
if withpb:
pb = shellutils.ProgressBar(rowcount, 50)
- for urow in ucsvreader(stream, encoding, separator, quote, skipfirst):
+ for urow in ucsvreader(stream, encoding, separator, quote,
+ skipfirst=skipfirst, skip_empty=skip_empty):
yield urow
if withpb:
pb.update()
print ' %s rows imported' % rowcount
def ucsvreader(stream, encoding='utf-8', separator=',', quote='"',
- skipfirst=False, ignore_errors=False):
+ skipfirst=False, ignore_errors=False, skip_empty=True):
"""A csv reader that accepts files with any encoding and outputs unicode
strings
+
+ if skip_empty (the default), lines without any values specified (only
+ separators) will be skipped. This is useful for Excel exports which may be
+ full of such lines.
"""
it = iter(csv.reader(stream, delimiter=separator, quotechar=quote))
if not ignore_errors:
if skipfirst:
it.next()
for row in it:
- yield [item.decode(encoding) for item in row]
+ decoded = [item.decode(encoding) for item in row]
+ if not skip_empty or any(decoded):
+ yield [item.decode(encoding) for item in row]
else:
# Skip first line
try:
@@ -151,7 +158,10 @@
# Error in CSV, ignore line and continue
except csv.Error:
continue
- yield [item.decode(encoding) for item in row]
+ decoded = [item.decode(encoding) for item in row]
+ if not skip_empty or any(decoded):
+ yield decoded
+
def callfunc_every(func, number, iterable):
"""yield items of `iterable` one by one and call function `func`
@@ -792,6 +802,9 @@
assert not rtype.startswith('reverse_')
self.add_relation(self.session, eid_from, rtype, eid_to,
self.rschema(rtype).inlined)
+ if self.rschema[rtype].symmetric:
+ self.add_relation(self.session, eid_to, rtype, eid_from,
+ self.rschema(rtype).inlined)
self._nb_inserted_relations += 1
@property
@@ -918,6 +931,9 @@
# XXX Could subjtype be inferred ?
self.source.add_relation(self.session, subj_eid, rtype, obj_eid,
self.rschema(rtype).inlined, **kwargs)
+ if self.rschema[rtype].symmetric:
+ self.source.add_relation(self.session, obj_eid, rtype, subj_eid,
+ self.rschema(rtype).inlined, **kwargs)
def drop_indexes(self, etype):
"""Drop indexes for a given entity type"""
--- a/dbapi.py Tue Jul 02 17:09:04 2013 +0200
+++ b/dbapi.py Mon Jan 13 13:47:47 2014 +0100
@@ -179,7 +179,7 @@
puri = urlparse(database)
method = puri.scheme.lower()
if method == 'inmemory':
- config = cwconfig.instance_configuration(puri.path)
+ config = cwconfig.instance_configuration(puri.netloc)
else:
config = cwconfig.CubicWebNoAppConfiguration()
repo = get_repository(database, config=config)
@@ -226,7 +226,7 @@
raises an AuthenticationError if anonymous usage is not allowed
"""
anoninfo = vreg.config.anonymous_user()
- if anoninfo is None: # no anonymous user
+ if anoninfo[0] is None: # no anonymous user
raise AuthenticationError('anonymous access is not authorized')
anon_login, anon_password = anoninfo
# use vreg's repository cache
@@ -365,25 +365,6 @@
"""return the definition of sources used by the repository."""
return self.cnx.source_defs()
- @deprecated('[3.8] use direct access to req.session.data dictionary')
- def session_data(self):
- """return a dictionary containing session data"""
- return self.session.data
-
- @deprecated('[3.8] use direct access to req.session.data dictionary')
- def get_session_data(self, key, default=None, pop=False):
- if pop:
- return self.session.data.pop(key, default)
- return self.session.data.get(key, default)
-
- @deprecated('[3.8] use direct access to req.session.data dictionary')
- def set_session_data(self, key, value):
- self.session.data[key] = value
-
- @deprecated('[3.8] use direct access to req.session.data dictionary')
- def del_session_data(self, key):
- self.session.data.pop(key, None)
-
# these are overridden by set_log_methods below
# only defining here to prevent pylint from complaining
info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
@@ -419,7 +400,7 @@
def _txid(self):
return self.connection._txid(self)
- def execute(self, rql, args=None, eid_key=None, build_descr=True):
+ def execute(self, rql, args=None, build_descr=True):
"""execute a rql query, return resulting rows and their description in
a :class:`~cubicweb.rset.ResultSet` object
@@ -450,10 +431,6 @@
execute('Any X WHERE X eid %(x)s', {'x': 123})
"""
- if eid_key is not None:
- warn('[3.8] eid_key is deprecated, you can safely remove this argument',
- DeprecationWarning, stacklevel=2)
- # XXX use named argument for build_descr in case repo is < 3.8
rset = self._repo.execute(self._sessid, rql, args,
build_descr=build_descr, **self._txid())
rset.req = self.req
--- a/debian.hardy/compat Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-5
--- a/debian.hardy/rules Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-#!/usr/bin/make -f
-# Sample debian/rules that uses debhelper.
-# GNU copyright 1997 to 1999 by Joey Hess.
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-PY_VERSION:=$(shell pyversions -d)
-
-build: build-stamp
-build-stamp:
- dh_testdir
- # XXX doesn't work if logilab-doctools, logilab-xml are not in build depends
- # and I can't get pbuilder find them in its chroot :(
- # cd doc && make
- # FIXME cleanup and use sphinx-build as build-depends ?
- NO_SETUPTOOLS=1 python setup.py build
- touch build-stamp
-
-clean:
- dh_testdir
- dh_testroot
- rm -f build-stamp configure-stamp
- rm -rf build
- #rm -rf debian/cubicweb-*/
- find . -name "*.pyc" -delete
- rm -f $(basename $(wildcard debian/*.in))
- dh_clean
-
-install: build $(basename $(wildcard debian/*.in))
- dh_testdir
- dh_testroot
- dh_clean
- dh_installdirs
-
- NO_SETUPTOOLS=1 python setup.py -q install --no-compile --prefix=debian/tmp/usr
-
- # Put all the python library and data in cubicweb-common
- # and scripts in cubicweb-server
- dh_install -vi
- # cwctl in the cubicweb-ctl package
- rm -f debian/cubicweb-common/usr/share/pyshared/cubicweb/cwctl.py
-
-
- # Remove unittests directory (should be available in cubicweb-dev only)
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/server/test
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/hooks/test
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/sobjects/test
- rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/site-packages/cubicweb/web/test
- rm -rf debian/cubicweb-twisted/usr/lib/${PY_VERSION}/site-packages/cubicweb/etwist/test
- rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/ext/test
- rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/entities/test
-
- # cubes directory must be managed as a valid python module
- touch debian/cubicweb-common/usr/share/cubicweb/cubes/__init__.py
-
-%: %.in
- sed "s/PY_VERSION/${PY_VERSION}/g" < $< > $@
-
-# Build architecture-independent files here.
-binary-indep: build install
- dh_testdir
- dh_testroot -i
- dh_pycentral -i
- dh_installinit -i -n --name cubicweb -u"defaults 99"
- dh_installlogrotate -i
- dh_installdocs -i -A README
- dh_installman -i
- dh_installchangelogs -i
- dh_link -i
- dh_compress -i -X.py -X.ini -X.xml
- dh_fixperms -i
- dh_installdeb -i
- dh_gencontrol -i
- dh_md5sums -i
- dh_builddeb -i
-
-binary-arch:
-
-binary: binary-indep
-.PHONY: build clean binary binary-indep binary-arch
-
--- a/debian/changelog Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/changelog Mon Jan 13 13:47:47 2014 +0100
@@ -1,3 +1,70 @@
+cubicweb (3.18.0-1) unstable; urgency=low
+
+ * new upstream release.
+
+ -- Julien Cristau <julien.cristau@logilab.fr> Fri, 10 Jan 2014 17:14:18 +0100
+
+cubicweb (3.17.11-2) unstable; urgency=low
+
+ * Override lintian false-positive about debian/rules.tmpl in the cube
+ skeleton.
+
+ -- Julien Cristau <julien.cristau@logilab.fr> Wed, 11 Dec 2013 15:56:39 +0100
+
+cubicweb (3.17.11-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Aurelien Campeas <aurelien.campeas@logilab.fr> Fri, 06 Dec 2013 15:55:48 +0100
+
+cubicweb (3.17.10-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Julien Cristau <julien.cristau@logilab.fr> Wed, 23 Oct 2013 17:23:45 +0200
+
+cubicweb (3.17.9-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Julien Cristau <julien.cristau@logilab.fr> Tue, 08 Oct 2013 17:57:04 +0200
+
+cubicweb (3.17.8-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- David Douard <david.douard@logilab.fr> Thu, 03 Oct 2013 15:12:32 +0200
+
+cubicweb (3.17.7-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- David Douard <david.douard@logilab.fr> Thu, 26 Sep 2013 15:13:39 +0200
+
+cubicweb (3.17.6-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- David Douard <david.douard@logilab.fr> Tue, 06 Aug 2013 11:49:04 +0200
+
+cubicweb (3.17.5-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- David Douard <david.douard@logilab.fr> Wed, 31 Jul 2013 16:58:19 +0200
+
+cubicweb (3.17.4-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- David Douard <david.douard@logilab.fr> Fri, 26 Jul 2013 09:44:19 +0200
+
+cubicweb (3.17.3-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- David Douard <david.douard@logilab.fr> Tue, 09 Jul 2013 15:10:16 +0200
+
cubicweb (3.17.2-1) unstable; urgency=low
* new upstream release
@@ -22,6 +89,12 @@
-- Pierre-Yves David <pierre-yves.david@logilab.fr> Mon, 29 Apr 2013 11:20:56 +0200
+cubicweb (3.16.6-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Florent Cayré <florent.cayre@logilab.fr> Sat, 13 Jul 2013 05:10:23 +0200
+
cubicweb (3.16.5-1) unstable; urgency=low
* new upstream release
--- a/debian/control Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/control Mon Jan 13 13:47:47 2014 +0100
@@ -10,13 +10,12 @@
Build-Depends:
debhelper (>= 7),
python (>= 2.6),
- python-central (>= 0.5),
python-sphinx,
python-logilab-common,
- python-unittest2,
+ python-unittest2 | python (>= 2.7),
python-logilab-mtconverter,
python-rql,
- python-yams (>= 0.37),
+ python-yams (>= 0.39),
python-lxml,
Standards-Version: 3.9.1
Homepage: http://www.cubicweb.org
@@ -24,7 +23,6 @@
Package: cubicweb
Architecture: all
-XB-Python-Version: ${python:Versions}
Depends:
${misc:Depends},
${python:Depends},
@@ -45,7 +43,6 @@
Package: cubicweb-server
Architecture: all
-XB-Python-Version: ${python:Versions}
Conflicts: cubicweb-multisources
Replaces: cubicweb-multisources
Provides: cubicweb-multisources
@@ -54,7 +51,7 @@
${python:Depends},
cubicweb-common (= ${source:Version}),
cubicweb-ctl (= ${source:Version}),
- python-logilab-database (>= 1.10.0),
+ python-logilab-database (>= 1.11.0),
cubicweb-postgresql-support
| cubicweb-mysql-support
| python-pysqlite2,
@@ -101,7 +98,6 @@
Package: cubicweb-twisted
Architecture: all
-XB-Python-Version: ${python:Versions}
Provides: cubicweb-web-frontend
Depends:
${misc:Depends},
@@ -123,7 +119,6 @@
Package: cubicweb-web
Architecture: all
-XB-Python-Version: ${python:Versions}
Depends:
${misc:Depends},
${python:Depends},
@@ -136,6 +131,8 @@
python-fyzz,
python-imaging,
python-rdflib
+Breaks:
+ cubicweb-inlinedit (<< 1.1.1),
Description: web interface library for the CubicWeb framework
CubicWeb is a semantic web application framework.
.
@@ -148,15 +145,14 @@
Package: cubicweb-common
Architecture: all
-XB-Python-Version: ${python:Versions}
Depends:
${misc:Depends},
${python:Depends},
graphviz,
gettext,
python-logilab-mtconverter (>= 0.8.0),
- python-logilab-common (>= 0.59.0),
- python-yams (>= 0.37.0),
+ python-logilab-common (>= 0.60.0),
+ python-yams (>= 0.39.0),
python-rql (>= 0.31.2),
python-lxml
Recommends:
@@ -164,6 +160,10 @@
python-crypto
Conflicts: cubicweb-core
Replaces: cubicweb-core
+Breaks:
+ cubicweb-comment (<< 1.9.1),
+ cubicweb-person (<< 1.8.0),
+ cubicweb-geocoding (<< 0.2.0),
Description: common library for the CubicWeb framework
CubicWeb is a semantic web application framework.
.
@@ -173,7 +173,6 @@
Package: cubicweb-ctl
Architecture: all
-XB-Python-Version: ${python:Versions}
Depends:
${misc:Depends},
${python:Depends},
@@ -188,7 +187,6 @@
Package: cubicweb-dev
Architecture: all
-XB-Python-Version: ${python:Versions}
Depends:
${misc:Depends},
${python:Depends},
--- a/debian/copyright Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/copyright Mon Jan 13 13:47:47 2014 +0100
@@ -8,7 +8,7 @@
Copyright:
- Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE).
+ Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
http://www.logilab.fr/ -- mailto:contact@logilab.fr
License:
@@ -29,3 +29,18 @@
On Debian systems, the complete text of the GNU Lesser General Public License
may be found in '/usr/share/common-licenses/LGPL-2.1'.
+
+Entypo pictograms:
+
+Author:
+
+ Daniel Bruce <info@entypo.com> (www.entypo.com)
+
+Licence:
+
+ Entypo pictograms are licensed under CC BY-SA 3.0 and the font
+ under SIL Open Font License.
+
+ The rights to each pictogram in the social extension are either
+ trademarked or copyrighted by the respective company.
+
--- a/debian/cubicweb-common.install.in Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-common.install.in Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/entities/ usr/lib/PY_VERSION/site-packages/cubicweb
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/ext/ usr/lib/PY_VERSION/site-packages/cubicweb
-debian/tmp/usr/share/cubicweb/cubes/ usr/share/cubicweb/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/*.py usr/share/pyshared/cubicweb
+usr/lib/PY_VERSION/*-packages/cubicweb/entities/
+usr/lib/PY_VERSION/*-packages/cubicweb/ext/
+usr/share/cubicweb/cubes/
+usr/lib/PY_VERSION/*-packages/cubicweb/*.py
--- a/debian/cubicweb-ctl.dirs Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-ctl.dirs Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,3 @@
-usr/lib/python2.4/site-packages/cubicweb/
etc/init.d
etc/cubicweb.d
etc/bash_completion.d
--- a/debian/cubicweb-ctl.install.in Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-ctl.install.in Mon Jan 13 13:47:47 2014 +0100
@@ -1,3 +1,3 @@
-debian/tmp/usr/bin/cubicweb-ctl usr/bin/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/cwctl.py usr/lib/PY_VERSION/site-packages/cubicweb
-debian/cubicweb-ctl.bash_completion etc/bash_completion.d/cubicweb-ctl
+usr/bin/cubicweb-ctl usr/bin/
+usr/lib/PY_VERSION/*-packages/cubicweb/cwctl.py
+../cubicweb-ctl.bash_completion etc/bash_completion.d/cubicweb-ctl
--- a/debian/cubicweb-dev.install.in Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-dev.install.in Mon Jan 13 13:47:47 2014 +0100
@@ -1,10 +1,10 @@
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/devtools/ usr/lib/PY_VERSION/site-packages/cubicweb/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/skeleton/ usr/lib/PY_VERSION/site-packages/cubicweb/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/test usr/lib/PY_VERSION/site-packages/cubicweb/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/entities/test usr/lib/PY_VERSION/site-packages/cubicweb/entities/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/ext/test usr/lib/PY_VERSION/site-packages/cubicweb/ext/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/server/test usr/lib/PY_VERSION/site-packages/cubicweb/server/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/test usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/hooks/test usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/web/test usr/lib/PY_VERSION/site-packages/cubicweb/web/
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/etwist/test usr/lib/PY_VERSION/site-packages/cubicweb/etwist/
+usr/lib/PY_VERSION/*-packages/cubicweb/devtools/
+usr/lib/PY_VERSION/*-packages/cubicweb/skeleton/
+usr/lib/PY_VERSION/*-packages/cubicweb/test
+usr/lib/PY_VERSION/*-packages/cubicweb/entities/test
+usr/lib/PY_VERSION/*-packages/cubicweb/ext/test
+usr/lib/PY_VERSION/*-packages/cubicweb/server/test
+usr/lib/PY_VERSION/*-packages/cubicweb/sobjects/test
+usr/lib/PY_VERSION/*-packages/cubicweb/hooks/test
+usr/lib/PY_VERSION/*-packages/cubicweb/web/test
+usr/lib/PY_VERSION/*-packages/cubicweb/etwist/test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/cubicweb-dev.lintian-overrides Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,1 @@
+missing-dep-for-interpreter make => make | build-essential | dpkg-dev (usr/share/pyshared/cubicweb/skeleton/debian/rules.tmpl)
--- a/debian/cubicweb-documentation.install.in Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-documentation.install.in Mon Jan 13 13:47:47 2014 +0100
@@ -1,3 +1,3 @@
-doc/book usr/share/doc/cubicweb-documentation
-doc/html usr/share/doc/cubicweb-documentation
-debian/cubicweb-doc usr/share/doc-base/cubicweb-doc
+../../doc/book usr/share/doc/cubicweb-documentation
+../../doc/html usr/share/doc/cubicweb-documentation
+../../debian/cubicweb-doc usr/share/doc-base/cubicweb-doc
--- a/debian/cubicweb-server.install.in Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-server.install.in Mon Jan 13 13:47:47 2014 +0100
@@ -1,5 +1,5 @@
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/server/ usr/lib/PY_VERSION/site-packages/cubicweb
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/hooks/ usr/lib/PY_VERSION/site-packages/cubicweb
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/sobjects/ usr/lib/PY_VERSION/site-packages/cubicweb
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/schemas/ usr/lib/PY_VERSION/site-packages/cubicweb
-debian/tmp/usr/share/cubicweb/migration/ usr/share/cubicweb/
+usr/lib/PY_VERSION/*-packages/cubicweb/server/
+usr/lib/PY_VERSION/*-packages/cubicweb/hooks/
+usr/lib/PY_VERSION/*-packages/cubicweb/sobjects/
+usr/lib/PY_VERSION/*-packages/cubicweb/schemas/
+usr/share/cubicweb/migration/
--- a/debian/cubicweb-twisted.install.in Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-twisted.install.in Mon Jan 13 13:47:47 2014 +0100
@@ -1,1 +1,1 @@
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/etwist/ usr/lib/PY_VERSION/site-packages/cubicweb/
+usr/lib/PY_VERSION/*-packages/cubicweb/etwist/
--- a/debian/cubicweb-web.install.in Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/cubicweb-web.install.in Mon Jan 13 13:47:47 2014 +0100
@@ -1,3 +1,3 @@
-debian/tmp/usr/lib/PY_VERSION/site-packages/cubicweb/web usr/lib/PY_VERSION/site-packages/cubicweb
-debian/tmp/usr/share/cubicweb/cubes/shared/data usr/share/cubicweb/cubes/shared
-debian/tmp/usr/share/cubicweb/cubes/shared/wdoc usr/share/cubicweb/cubes/shared
+usr/lib/PY_VERSION/*-packages/cubicweb/web
+usr/share/cubicweb/cubes/shared/data
+usr/share/cubicweb/cubes/shared/wdoc
--- a/debian/rules Tue Jul 02 17:09:04 2013 +0200
+++ b/debian/rules Mon Jan 13 13:47:47 2014 +0100
@@ -18,17 +18,11 @@
# distributions and we don't want to block a new release of Cubicweb
# because of documentation issues.
-PYTHONPATH=$${PYTHONPATH:+$${PYTHONPATH}:}$(CURDIR)/debian/pythonpath $(MAKE) -C doc/book/en all
- # squeeze has a broken combination of jquery and sphinx, fix it up so search works(ish)
- if grep -q jQuery\\.className doc/html/_static/doctools.js && grep -q "jQuery JavaScript Library v1\.4\." doc/html/_static/jquery.js; then \
- echo 'Patching doctools.js for jQuery 1.4 compat'; \
- sed -i 's/jQuery\.className.has(node\.parentNode, className)/jQuery(node.parentNode).hasClass(className)/' doc/html/_static/doctools.js; \
- fi
rm -rf debian/pythonpath
touch build-stamp
clean:
dh_testdir
- dh_testroot
rm -f build-stamp configure-stamp
rm -rf build
#rm -rf debian/cubicweb-*/
@@ -42,27 +36,26 @@
dh_clean
dh_installdirs
- #python setup.py install_lib --no-compile --install-dir=debian/cubicweb-common/usr/lib/python2.4/site-packages/
NO_SETUPTOOLS=1 python setup.py -q install --no-compile --prefix=debian/tmp/usr
# Put all the python library and data in cubicweb-common
# and scripts in cubicweb-server
- dh_install -vi
+ dh_install -vi --sourcedir=debian/tmp
# cwctl in the cubicweb-ctl package
- rm -f debian/cubicweb-common/usr/share/pyshared/cubicweb/cwctl.py
+ rm -f debian/cubicweb-common/usr/lib/python*/*/cubicweb/cwctl.py
# wdoc in the cubicweb-web package
rm -rf debian/cubicweb-common/usr/share/cubicweb/cubes/shared/wdoc
rm -rf debian/cubicweb-common/usr/share/cubicweb/cubes/shared/data
dh_lintian
# Remove unittests directory (should be available in cubicweb-dev only)
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/server/test
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/hooks/test
- rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/site-packages/cubicweb/sobjects/test
- rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/site-packages/cubicweb/web/test
- rm -rf debian/cubicweb-twisted/usr/lib/${PY_VERSION}/site-packages/cubicweb/etwist/test
- rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/ext/test
- rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/site-packages/cubicweb/entities/test
+ rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/*-packages/cubicweb/server/test
+ rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/*-packages/cubicweb/hooks/test
+ rm -rf debian/cubicweb-server/usr/lib/${PY_VERSION}/*-packages/cubicweb/sobjects/test
+ rm -rf debian/cubicweb-web/usr/lib/${PY_VERSION}/*-packages/cubicweb/web/test
+ rm -rf debian/cubicweb-twisted/usr/lib/${PY_VERSION}/*-packages/cubicweb/etwist/test
+ rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/*-packages/cubicweb/ext/test
+ rm -rf debian/cubicweb-common/usr/lib/${PY_VERSION}/*-packages/cubicweb/entities/test
%: %.in
@@ -72,7 +65,7 @@
binary-indep: build install
dh_testdir
dh_testroot -i
- dh_pycentral -i
+ dh_python2 -i
dh_installinit -i -n --name cubicweb -u"defaults 99"
dh_installlogrotate -i
dh_installdocs -i -A README
--- a/devtools/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/devtools/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -26,6 +26,7 @@
import pickle
import glob
import warnings
+import tempfile
from hashlib import sha1 # pylint: disable=E0611
from datetime import timedelta
from os.path import (abspath, join, exists, split, isabs, isdir)
@@ -37,7 +38,7 @@
from cubicweb import ExecutionError, BadConnectionId
from cubicweb import schema, cwconfig
from cubicweb.server.serverconfig import ServerConfiguration
-from cubicweb.etwist.twconfig import TwistedConfiguration
+from cubicweb.etwist.twconfig import WebConfigurationBase
cwconfig.CubicWebConfiguration.cls_adjust_sys_path()
@@ -213,12 +214,12 @@
return BASE_URL
-class BaseApptestConfiguration(TestServerConfiguration, TwistedConfiguration):
+class BaseApptestConfiguration(TestServerConfiguration, WebConfigurationBase):
name = 'all-in-one' # so it search for all-in-one.conf, not repository.conf
options = cwconfig.merge_options(TestServerConfiguration.options
- + TwistedConfiguration.options)
- cubicweb_appobject_path = TestServerConfiguration.cubicweb_appobject_path | TwistedConfiguration.cubicweb_appobject_path
- cube_appobject_path = TestServerConfiguration.cube_appobject_path | TwistedConfiguration.cube_appobject_path
+ + WebConfigurationBase.options)
+ cubicweb_appobject_path = TestServerConfiguration.cubicweb_appobject_path | WebConfigurationBase.cubicweb_appobject_path
+ cube_appobject_path = TestServerConfiguration.cube_appobject_path | WebConfigurationBase.cube_appobject_path
def available_languages(self, *args):
return self.cw_languages()
@@ -287,8 +288,11 @@
The function create it if necessary"""
backupdir = join(self.config.apphome, 'database')
- if not isdir(backupdir):
+ try:
os.makedirs(backupdir)
+ except:
+ if not isdir(backupdir):
+ raise
return backupdir
def config_path(self, db_id):
@@ -324,8 +328,9 @@
# XXX we dump a dict of the config
# This is an experimental to help config dependant setup (like BFSS) to
# be propertly restored
- with open(config_path, 'wb') as conf_file:
+ with tempfile.NamedTemporaryFile(dir=os.path.dirname(config_path), delete=False) as conf_file:
conf_file.write(pickle.dumps(dict(self.config)))
+ os.rename(conf_file.name, config_path)
self.db_cache[self.db_cache_key(db_id)] = (backup_data, config_path)
def _backup_database(self, db_id):
--- a/devtools/devctl.py Tue Jul 02 17:09:04 2013 +0200
+++ b/devtools/devctl.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -46,7 +46,7 @@
a cube or for cubicweb (without a home)
"""
creating = True
- cleanup_interface_sobjects = False
+ cleanup_unused_appobjects = False
cubicweb_appobject_path = (ServerConfiguration.cubicweb_appobject_path
| WebConfiguration.cubicweb_appobject_path)
@@ -130,24 +130,31 @@
w('# singular and plural forms for each entity type\n')
w('\n')
vregdone = set()
+ afss = vreg['uicfg']['autoform_section']
+ aiams = vreg['uicfg']['actionbox_appearsin_addmenu']
if libconfig is not None:
+ # processing a cube, libconfig being a config with all its dependencies
+ # (cubicweb incl.)
from cubicweb.cwvreg import CWRegistryStore
libschema = libconfig.load_schema(remove_unused_rtypes=False)
- afs = vreg['uicfg'].select('autoform_section')
- appearsin_addmenu = vreg['uicfg'].select('actionbox_appearsin_addmenu')
cleanup_sys_modules(libconfig)
libvreg = CWRegistryStore(libconfig)
libvreg.set_schema(libschema) # trigger objects registration
- libafs = libvreg['uicfg'].select('autoform_section')
- libappearsin_addmenu = libvreg['uicfg'].select('actionbox_appearsin_addmenu')
+ libafss = libvreg['uicfg']['autoform_section']
+ libaiams = libvreg['uicfg']['actionbox_appearsin_addmenu']
# prefill vregdone set
list(_iter_vreg_objids(libvreg, vregdone))
+
+ def is_in_lib(rtags, eschema, rschema, role, tschema, predicate=bool):
+ return any(predicate(rtag.etype_get(eschema, rschema, role, tschema))
+ for rtag in rtags)
else:
+ # processing cubicweb itself
libschema = {}
- afs = vreg['uicfg'].select('autoform_section')
- appearsin_addmenu = vreg['uicfg'].select('actionbox_appearsin_addmenu')
for cstrtype in CONSTRAINTS:
add_msg(w, cstrtype)
+ libafss = libaiams = None
+ is_in_lib = lambda *args: False
done = set()
for eschema in sorted(schema.entities()):
if eschema.type in libschema:
@@ -169,32 +176,34 @@
if rschema.final:
continue
for tschema in targetschemas:
- fsections = afs.etype_get(eschema, rschema, role, tschema)
- if 'main_inlined' in fsections and \
- (libconfig is None or not
- 'main_inlined' in libafs.etype_get(
- eschema, rschema, role, tschema)):
- add_msg(w, 'add a %s' % tschema,
- 'inlined:%s.%s.%s' % (etype, rschema, role))
- add_msg(w, str(tschema),
- 'inlined:%s.%s.%s' % (etype, rschema, role))
- if appearsin_addmenu.etype_get(eschema, rschema, role, tschema):
- if libconfig is not None and libappearsin_addmenu.etype_get(
- eschema, rschema, role, tschema):
- if eschema in libschema and tschema in libschema:
- continue
- if role == 'subject':
- label = 'add %s %s %s %s' % (eschema, rschema,
- tschema, role)
- label2 = "creating %s (%s %%(linkto)s %s %s)" % (
- tschema, eschema, rschema, tschema)
- else:
- label = 'add %s %s %s %s' % (tschema, rschema,
- eschema, role)
- label2 = "creating %s (%s %s %s %%(linkto)s)" % (
- tschema, tschema, rschema, eschema)
- add_msg(w, label)
- add_msg(w, label2)
+
+ for afs in afss:
+ fsections = afs.etype_get(eschema, rschema, role, tschema)
+ if 'main_inlined' in fsections and not \
+ is_in_lib(libafss, eschema, rschema, role, tschema,
+ lambda x: 'main_inlined' in x):
+ add_msg(w, 'add a %s' % tschema,
+ 'inlined:%s.%s.%s' % (etype, rschema, role))
+ add_msg(w, str(tschema),
+ 'inlined:%s.%s.%s' % (etype, rschema, role))
+ break
+
+ for aiam in aiams:
+ if aiam.etype_get(eschema, rschema, role, tschema) and not \
+ is_in_lib(libaiams, eschema, rschema, role, tschema):
+ if role == 'subject':
+ label = 'add %s %s %s %s' % (eschema, rschema,
+ tschema, role)
+ label2 = "creating %s (%s %%(linkto)s %s %s)" % (
+ tschema, eschema, rschema, tschema)
+ else:
+ label = 'add %s %s %s %s' % (tschema, rschema,
+ eschema, role)
+ label2 = "creating %s (%s %s %s %%(linkto)s)" % (
+ tschema, tschema, rschema, eschema)
+ add_msg(w, label)
+ add_msg(w, label2)
+ break
# XXX also generate "creating ...' messages for actions in the
# addrelated submenu
w('# subject and object forms for each relation type\n')
--- a/devtools/fill.py Tue Jul 02 17:09:04 2013 +0200
+++ b/devtools/fill.py Mon Jan 13 13:47:47 2014 +0100
@@ -139,7 +139,7 @@
def generate_integer(self, entity, attrname, index):
"""generates a consistent value for 'attrname' if it's an integer"""
return self._constrained_generate(entity, attrname, 0, 1, index)
- generate_int = generate_integer
+ generate_int = generate_bigint = generate_integer
def generate_float(self, entity, attrname, index):
"""generates a consistent value for 'attrname' if it's a float"""
--- a/devtools/httptest.py Tue Jul 02 17:09:04 2013 +0200
+++ b/devtools/httptest.py Mon Jan 13 13:47:47 2014 +0100
@@ -20,6 +20,7 @@
"""
__docformat__ = "restructuredtext en"
+import random
import threading
import socket
import httplib
@@ -46,6 +47,8 @@
.. see:: :func:`test.test_support.bind_port`
"""
+ ports_scan = list(ports_scan)
+ random.shuffle(ports_scan) # lower the chance of race condition
for port in ports_scan:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/instrument.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,224 @@
+# copyright 2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr -- mailto:contact@logilab.fr
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+"""Instrumentation utilities"""
+
+import os
+
+try:
+ import pygraphviz
+except ImportError:
+ pygraphviz = None
+
+from cubicweb.cwvreg import CWRegistryStore
+from cubicweb.devtools.devctl import DevConfiguration
+
+
+ALL_COLORS = [
+ "00FF00", "0000FF", "FFFF00", "FF00FF", "00FFFF", "000000",
+ "800000", "008000", "000080", "808000", "800080", "008080", "808080",
+ "C00000", "00C000", "0000C0", "C0C000", "C000C0", "00C0C0", "C0C0C0",
+ "400000", "004000", "000040", "404000", "400040", "004040", "404040",
+ "200000", "002000", "000020", "202000", "200020", "002020", "202020",
+ "600000", "006000", "000060", "606000", "600060", "006060", "606060",
+ "A00000", "00A000", "0000A0", "A0A000", "A000A0", "00A0A0", "A0A0A0",
+ "E00000", "00E000", "0000E0", "E0E000", "E000E0", "00E0E0", "E0E0E0",
+ ]
+_COLORS = {}
+def get_color(key):
+ try:
+ return _COLORS[key]
+ except KeyError:
+ _COLORS[key] = '#'+ALL_COLORS[len(_COLORS) % len(ALL_COLORS)]
+ return _COLORS[key]
+
+def warn(msg, *args):
+ print 'WARNING: %s' % (msg % args)
+
+def info(msg):
+ print 'INFO: ' + msg
+
+
+class PropagationAnalyzer(object):
+ """Abstract propagation analyzer, providing utility function to extract
+ entities involved in propagation from a schema, as well as propagation
+ rules from hooks (provided they use intrumentalized sets, see
+ :class:`CubeTracerSet`).
+
+ Concrete classes should at least define `prop_rel` class attribute and
+ implements the `is_root` method.
+
+ See `localperms` or `nosylist` cubes for example usage (`ccplugin` module).
+ """
+ prop_rel = None # name of the propagation relation
+
+ def init(self, cube):
+ """Initialize analyze for the given cube, returning the (already loaded)
+ vregistry and a set of entities which we're interested in.
+ """
+ config = DevConfiguration(cube)
+ schema = config.load_schema()
+ vreg = CWRegistryStore(config)
+ vreg.set_schema(schema) # set_schema triggers objects registrations
+ eschemas = set(eschema for eschema in schema.entities()
+ if self.should_include(eschema))
+ return vreg, eschemas
+
+ def is_root(self, eschema):
+ """Return `True` if given entity schema is a root of the graph"""
+ raise NotImplementedError()
+
+ def should_include(self, eschema):
+ """Return `True` if given entity schema should be included by the graph.
+ """
+
+ if self.prop_rel in eschema.subjrels or self.is_root(eschema):
+ return True
+ return False
+
+ def prop_edges(self, s_rels, o_rels, eschemas):
+ """Return a set of edges where propagation has been detected.
+
+ Each edge is defined by a 4-uple (from node, to node, rtype, package)
+ where `rtype` is the relation type bringing from <from node> to <to
+ node> and `package` is the cube adding the rule to the propagation
+ control set (see see :class:`CubeTracerSet`).
+ """
+ schema = iter(eschemas).next().schema
+ prop_edges = set()
+ for rtype in s_rels:
+ found = False
+ for subj, obj in schema.rschema(rtype).rdefs:
+ if subj in eschemas and obj in eschemas:
+ found = True
+ prop_edges.add( (subj, obj, rtype, s_rels.value_cube[rtype]) )
+ if not found:
+ warn('no rdef match for %s', rtype)
+ for rtype in o_rels:
+ found = False
+ for subj, obj in schema.rschema(rtype).rdefs:
+ if subj in eschemas and obj in eschemas:
+ found = True
+ prop_edges.add( (obj, subj, rtype, o_rels.value_cube[rtype]) )
+ if not found:
+ warn('no rdef match for %s', rtype)
+ return prop_edges
+
+ def detect_problems(self, eschemas, edges):
+ """Given the set of analyzed entity schemas and edges between them,
+ return a set of entity schemas where a problem has been detected.
+ """
+ problematic = set()
+ for eschema in eschemas:
+ if self.has_problem(eschema, edges):
+ problematic.add(eschema)
+ not_problematic = set(eschemas).difference(problematic)
+ if not_problematic:
+ info('nothing problematic in: %s' %
+ ', '.join(e.type for e in not_problematic))
+ return problematic
+
+ def has_problem(self, eschema, edges):
+ """Return `True` if the given schema is considered problematic,
+ considering base propagation rules.
+ """
+ root = self.is_root(eschema)
+ has_prop_rel = self.prop_rel in eschema.subjrels
+ # root but no propagation relation
+ if root and not has_prop_rel:
+ warn('%s is root but miss %s', eschema, self.prop_rel)
+ return True
+ # propagated but without propagation relation / not propagated but
+ # with propagation relation
+ if not has_prop_rel and \
+ any(edge for edge in edges if edge[1] == eschema):
+ warn("%s miss %s but is reached by propagation",
+ eschema, self.prop_rel)
+ return True
+ elif has_prop_rel and not root:
+ rdef = eschema.rdef(self.prop_rel, takefirst=True)
+ edges = [edge for edge in edges if edge[1] == eschema]
+ if not edges:
+ warn("%s has %s but isn't reached by "
+ "propagation", eschema, self.prop_rel)
+ return True
+ # require_permission relation / propagation rule not added by
+ # the same cube
+ elif not any(edge for edge in edges if edge[-1] == rdef.package):
+ warn('%s has %s relation / propagation rule'
+ ' not added by the same cube (%s / %s)', eschema,
+ self.prop_rel, rdef.package, edges[0][-1])
+ return True
+ return False
+
+ def init_graph(self, eschemas, edges, problematic):
+ """Initialize and return graph, adding given nodes (entity schemas) and
+ edges between them.
+
+ Require pygraphviz installed.
+ """
+ if pygraphviz is None:
+ raise RuntimeError('pygraphviz is not installed')
+ graph = pygraphviz.AGraph(strict=False, directed=True)
+ for eschema in eschemas:
+ if eschema in problematic:
+ params = {'color': '#ff0000', 'fontcolor': '#ff0000'}
+ else:
+ params = {}#'color': get_color(eschema.package)}
+ graph.add_node(eschema.type, **params)
+ for subj, obj, rtype, package in edges:
+ graph.add_edge(str(subj), str(obj), label=rtype,
+ color=get_color(package))
+ return graph
+
+ def add_colors_legend(self, graph):
+ """Add a legend of used colors to the graph."""
+ for package, color in sorted(_COLORS.iteritems()):
+ graph.add_node(package, color=color, fontcolor=color, shape='record')
+
+
+class CubeTracerSet(object):
+ """Dumb set implementation whose purpose is to keep track of which cube is
+ being loaded when something is added to the set.
+
+ Results will be found in the `value_cube` attribute dictionary.
+
+ See `localperms` or `nosylist` cubes for example usage (`hooks` module).
+ """
+ def __init__(self, vreg, wrapped):
+ self.vreg = vreg
+ self.wrapped = wrapped
+ self.value_cube = {}
+
+ def add(self, value):
+ self.wrapped.add(value)
+ cube = self.vreg.currently_loading_cube
+ if value in self.value_cube:
+ warn('%s is propagated by cube %s and cube %s',
+ value, self.value_cube[value], cube)
+ else:
+ self.value_cube[value] = cube
+
+ def __iter__(self):
+ return iter(self.wrapped)
+
+ def __ior__(self, other):
+ for value in other:
+ self.add(value)
+ return self
+
+ def __ror__(self, other):
+ other |= self.wrapped
+ return other
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/cubes/i18ntestcube/__pkginfo__.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,18 @@
+# pylint: disable=W0622
+"""cubicweb i18n test cube application packaging information"""
+
+modname = 'i18ntestcube'
+distname = 'cubicweb-i18ntestcube'
+
+numversion = (0, 1, 0)
+version = '.'.join(str(num) for num in numversion)
+
+license = 'LGPL'
+author = 'LOGILAB S.A. (Paris, FRANCE)'
+author_email = 'contact@logilab.fr'
+description = 'forum'
+web = 'http://www.cubicweb.org/project/%s' % distname
+
+__depends__ = {'cubicweb': '>= 3.16.4',
+ }
+__recommends__ = {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/cubes/i18ntestcube/i18n/en.po.ref Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,170 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: cubicweb 3.16.5\n"
+"PO-Revision-Date: 2008-03-28 18:14+0100\n"
+"Last-Translator: Logilab Team <contact@logilab.fr>\n"
+"Language-Team: fr <contact@logilab.fr>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: cubicweb-devtools\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+# schema pot file, generated on 2013-07-12 16:18:12
+#
+# singular and plural forms for each entity type
+# subject and object forms for each relation type
+# (no object form for final or symmetric relation types)
+msgid "Forum"
+msgstr ""
+
+msgid "Forum_plural"
+msgstr ""
+
+msgid "This Forum"
+msgstr ""
+
+msgid "New Forum"
+msgstr ""
+
+msgctxt "inlined:Forum.in_forum.object"
+msgid "add a ForumThread"
+msgstr ""
+
+msgctxt "inlined:Forum.in_forum.object"
+msgid "ForumThread"
+msgstr ""
+
+msgid "add ForumThread in_forum Forum object"
+msgstr ""
+
+msgid "creating ForumThread (ForumThread in_forum Forum %(linkto)s)"
+msgstr ""
+
+msgid "ForumThread"
+msgstr ""
+
+msgid "ForumThread_plural"
+msgstr ""
+
+msgid "This ForumThread"
+msgstr ""
+
+msgid "New ForumThread"
+msgstr ""
+
+msgid "content"
+msgstr ""
+
+msgctxt "ForumThread"
+msgid "content"
+msgstr ""
+
+msgid "content_format"
+msgstr ""
+
+msgctxt "ForumThread"
+msgid "content_format"
+msgstr ""
+
+msgctxt "Forum"
+msgid "description"
+msgstr ""
+
+msgctxt "Forum"
+msgid "description_format"
+msgstr ""
+
+msgid "in_forum"
+msgstr ""
+
+msgctxt "ForumThread"
+msgid "in_forum"
+msgstr ""
+
+msgctxt "Forum"
+msgid "in_forum_object"
+msgstr ""
+
+msgid "in_forum_object"
+msgstr ""
+
+msgid "interested_in"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "interested_in"
+msgstr ""
+
+msgctxt "ForumThread"
+msgid "interested_in_object"
+msgstr ""
+
+msgctxt "Forum"
+msgid "interested_in_object"
+msgstr ""
+
+msgid "interested_in_object"
+msgstr ""
+
+msgid "nosy_list"
+msgstr ""
+
+msgctxt "ForumThread"
+msgid "nosy_list"
+msgstr ""
+
+msgctxt "Forum"
+msgid "nosy_list"
+msgstr ""
+
+msgctxt "CWUser"
+msgid "nosy_list_object"
+msgstr ""
+
+msgid "nosy_list_object"
+msgstr ""
+
+msgctxt "ForumThread"
+msgid "title"
+msgstr ""
+
+msgid "topic"
+msgstr ""
+
+msgctxt "Forum"
+msgid "topic"
+msgstr ""
+
+msgid "Topic"
+msgstr ""
+
+msgid "Description"
+msgstr ""
+
+msgid "Number of threads"
+msgstr ""
+
+msgid "Last activity"
+msgstr ""
+
+msgid ""
+"a long\n"
+"tranlated line\n"
+"hop."
+msgstr ""
+
+msgid "Subject"
+msgstr ""
+
+msgid "Created"
+msgstr ""
+
+msgid "Answers"
+msgstr ""
+
+msgid "Last answered"
+msgstr ""
+
+msgid "This forum does not have any thread yet."
+msgstr ""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/cubes/i18ntestcube/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# copyright 2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr -- mailto:contact@logilab.fr
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""cubicweb-forum schema"""
+
+from yams.buildobjs import (String, RichString, EntityType,
+ RelationDefinition, SubjectRelation)
+from yams.reader import context
+
+class Forum(EntityType):
+ topic = String(maxsize=50, required=True, unique=True)
+ description = RichString()
+
+class ForumThread(EntityType):
+ __permissions__ = {
+ 'read': ('managers', 'users'),
+ 'add': ('managers', 'users'),
+ 'update': ('managers', 'owners'),
+ 'delete': ('managers', 'owners')
+ }
+ title = String(required=True, fulltextindexed=True, maxsize=256)
+ content = RichString(required=True, fulltextindexed=True)
+ in_forum = SubjectRelation('Forum', cardinality='1*', inlined=True,
+ composite='object')
+class interested_in(RelationDefinition):
+ subject = 'CWUser'
+ object = ('ForumThread', 'Forum')
+
+class nosy_list(RelationDefinition):
+ subject = ('Forum', 'ForumThread')
+ object = 'CWUser'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/cubes/i18ntestcube/views.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,64 @@
+# copyright 2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr -- mailto:contact@logilab.fr
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""cubicweb-forum views/forms/actions/components for web ui"""
+
+from cubicweb import view
+from cubicweb.predicates import is_instance
+from cubicweb.web.views import primary, baseviews, uicfg
+from cubicweb.web.views.uicfg import autoform_section as afs
+
+class MyAFS(uicfg.AutoformSectionRelationTags):
+ __select__ = is_instance('ForumThread')
+
+_myafs = MyAFS()
+
+# XXX useless ASA logilab.common.registry is fixed
+_myafs.__module__ = "cubes.i18ntestcube.views"
+
+_myafs.tag_object_of(('*', 'in_forum', 'Forum'), 'main', 'inlined')
+
+afs.tag_object_of(('*', 'in_forum', 'Forum'), 'main', 'inlined')
+
+
+class ForumSameETypeListView(baseviews.SameETypeListView):
+ __select__ = baseviews.SameETypeListView.__select__ & is_instance('Forum')
+
+ def call(self, **kwargs):
+ _ = self._cw._
+ _('Topic'), _('Description')
+ _('Number of threads'), _('Last activity')
+ _('''a long
+tranlated line
+hop.''')
+
+
+class ForumLastActivity(view.EntityView):
+ __regid__ = 'forum_last_activity'
+ __select__ = view.EntityView.__select__ & is_instance('Forum')
+
+
+class ForumPrimaryView(primary.PrimaryView):
+ __select__ = primary.PrimaryView.__select__ & is_instance('Forum')
+
+ def render_entity_attributes(self, entity):
+ _ = self._cw._
+ _('Subject'), _('Created'), _('Answers'),
+ _('Last answered')
+ _('This forum does not have any thread yet.')
+
+class ForumThreadPrimaryView(primary.PrimaryView):
+ __select__ = primary.PrimaryView.__select__ & is_instance('ForumThread')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/unittest_i18n.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,79 @@
+# -*- coding: iso-8859-1 -*-
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""unit tests for i18n messages generator"""
+
+import os, os.path as osp
+import sys
+
+from logilab.common.testlib import TestCase, unittest_main
+
+from cubicweb.cwconfig import CubicWebNoAppConfiguration
+
+DATADIR = osp.join(osp.abspath(osp.dirname(__file__)), 'data')
+
+def load_po(fname):
+ """load a po file and return a set of encountered (msgid, msgctx)"""
+ msgs = set()
+ msgid = msgctxt = None
+ for line in open(fname):
+ if line.strip() in ('', '#'):
+ continue
+ if line.startswith('msgstr'):
+ assert not (msgid, msgctxt) in msgs
+ msgs.add( (msgid, msgctxt) )
+ msgid = msgctxt = None
+ elif line.startswith('msgid'):
+ msgid = line.split(' ', 1)[1][1:-1]
+ elif line.startswith('msgctx'):
+ msgctxt = line.split(' ', 1)[1][1: -1]
+ elif msgid is not None:
+ msgid += line[1:-1]
+ elif msgctxt is not None:
+ msgctxt += line[1:-1]
+ return msgs
+
+
+class cubePotGeneratorTC(TestCase):
+ """test case for i18n pot file generator"""
+
+ def setUp(self):
+ self._CUBES_PATH = CubicWebNoAppConfiguration.CUBES_PATH[:]
+ CubicWebNoAppConfiguration.CUBES_PATH.append(osp.join(DATADIR, 'cubes'))
+ CubicWebNoAppConfiguration.cls_adjust_sys_path()
+
+ def tearDown(self):
+ CubicWebNoAppConfiguration.CUBES_PATH[:] = self._CUBES_PATH
+
+ def test_i18ncube(self):
+ # MUST import here to make, since the import statement fire
+ # the cube paths setup (and then must occur after the setUp)
+ from cubicweb.devtools.devctl import update_cube_catalogs
+ cube = osp.join(DATADIR, 'cubes', 'i18ntestcube')
+ msgs = load_po(osp.join(cube, 'i18n', 'en.po.ref'))
+ update_cube_catalogs(cube)
+ newmsgs = load_po(osp.join(cube, 'i18n', 'en.po'))
+ self.assertEqual(msgs, newmsgs)
+
+if __name__ == '__main__':
+ # XXX dirty hack to make this test runnable using python (works
+ # fine with pytest, but not with python directly if this hack is
+ # not present)
+ # XXX to remove ASA logilab.common is fixed
+ sys.path.append('')
+ unittest_main()
--- a/devtools/test/unittest_testlib.py Tue Jul 02 17:09:04 2013 +0200
+++ b/devtools/test/unittest_testlib.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -20,7 +20,9 @@
from cStringIO import StringIO
from unittest import TextTestRunner
+
from logilab.common.testlib import TestSuite, TestCase, unittest_main
+from logilab.common.registry import yes
from cubicweb.devtools import htmlparser
from cubicweb.devtools.testlib import CubicWebTC
@@ -172,8 +174,23 @@
self.assertTrue(rdef.permissions['add'])
self.assertTrue(rdef.permissions['read'], ())
+ def test_temporary_appobjects_registered(self):
+ class AnAppobject(object):
+ __registries__ = ('hip',)
+ __regid__ = 'hop'
+ __select__ = yes()
+ registered = None
+ @classmethod
+ def __registered__(cls, reg):
+ cls.registered = reg
+
+ with self.temporary_appobjects(AnAppobject):
+ self.assertEqual(self.vreg['hip'], AnAppobject.registered)
+ self.assertIn(AnAppobject, self.vreg['hip']['hop'])
+ self.assertNotIn(AnAppobject, self.vreg['hip']['hop'])
+
+
class RepoAccessTC(CubicWebTC):
-
def test_repo_connection(self):
acc = self.new_access('admin')
with acc.repo_cnx() as cnx:
--- a/devtools/testlib.py Tue Jul 02 17:09:04 2013 +0200
+++ b/devtools/testlib.py Mon Jan 13 13:47:47 2014 +0100
@@ -90,7 +90,7 @@
MAILBOX = []
-class Email:
+class Email(object):
"""you'll get instances of Email into MAILBOX during tests that trigger
some notification.
@@ -99,7 +99,8 @@
* `recipients` is a list of email address which are the recipients of this
message
"""
- def __init__(self, recipients, msg):
+ def __init__(self, fromaddr, recipients, msg):
+ self.fromaddr = fromaddr
self.recipients = recipients
self.msg = msg
@@ -126,8 +127,8 @@
pass
def close(self):
pass
- def sendmail(self, helo_addr, recipients, msg):
- MAILBOX.append(Email(recipients, msg))
+ def sendmail(self, fromaddr, recipients, msg):
+ MAILBOX.append(Email(fromaddr, recipients, msg))
cwconfig.SMTP = MockSMTP
@@ -391,13 +392,10 @@
@nocoverage
@deprecated('[4.0] explicitly use RepoAccess object in test instead')
- def execute(self, rql, args=None, eidkey=None, req=None):
+ def execute(self, rql, args=None, req=None):
"""executes <rql>, builds a resultset, and returns a couple (rset, req)
where req is a FakeRequest
"""
- if eidkey is not None:
- warn('[3.8] eidkey is deprecated, you can safely remove this argument',
- DeprecationWarning, stacklevel=2)
req = req or self.request(rql=rql)
return req.execute(unicode(rql), args)
@@ -432,10 +430,7 @@
# server side db api #######################################################
@deprecated('[4.0] explicitly use RepoAccess object in test instead')
- def sexecute(self, rql, args=None, eid_key=None):
- if eid_key is not None:
- warn('[3.8] eid_key is deprecated, you can safely remove this argument',
- DeprecationWarning, stacklevel=2)
+ def sexecute(self, rql, args=None):
self.session.set_cnxset()
return self.session.execute(rql, args)
@@ -620,6 +615,10 @@
self.vreg._loadedmods.setdefault(self.__module__, {})
for obj in appobjects:
self.vreg.register(obj)
+ registered = getattr(obj, '__registered__', None)
+ if registered:
+ for registry in obj.__registries__:
+ registered(self.vreg[registry])
try:
yield
finally:
@@ -1128,15 +1127,6 @@
self.assertEqual(len(MAILBOX), nb_msgs)
return messages
- # deprecated ###############################################################
-
- @deprecated('[3.8] use self.execute(...).get_entity(0, 0)')
- def entity(self, rql, args=None, eidkey=None, req=None):
- if eidkey is not None:
- warn('[3.8] eidkey is deprecated, you can safely remove this argument',
- DeprecationWarning, stacklevel=2)
- return self.execute(rql, args, req=req).get_entity(0, 0)
-
# auto-populating test classes and utilities ###################################
--- a/doc/3.15.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/3.15.rst Mon Jan 13 13:47:47 2014 +0100
@@ -13,7 +13,7 @@
used for entity cache invalidation.
* Improved WSGI support. While there is still some caveats, most of the code
- which as twisted only is now generic and allows related functionalities to work
+ which was twisted only is now generic and allows related functionalities to work
with a WSGI front-end.
* Full undo/transaction support : undo of modification has eventually been
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/3.18.rst Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,101 @@
+What's new in CubicWeb 3.18?
+============================
+
+The migration script does not handle sqlite nor mysql instances.
+
+
+New functionalities
+--------------------
+
+* add a security debugging tool
+ (see `#2920304 <http://www.cubicweb.org/2920304>`_)
+
+* introduce an `add` permission on attributes, to be interpreted at
+ entity creation time only and allow the implementation of complex
+ `update` rules that don't block entity creation (before that the
+ `update` attribute permission was interpreted at entity creation and
+ update time)
+
+* the primary view display controller (uicfg) now has a
+ `set_fields_order` method similar to the one available for forms
+
+* new method `ResultSet.one(col=0)` to retrive a single entity and enforce the
+ result has only one row (see `#3352314 https://www.cubicweb.org/ticket/3352314`_)
+
+* new method `RequestSessionBase.find` to look for entities
+ (see `#3361290 https://www.cubicweb.org/ticket/3361290`_)
+
+* the embedded jQuery copy has been updated to version 1.10.2, and jQuery UI to
+ version 1.10.3.
+
+* initial support for wsgi for the debug mode, available through the new
+ ``wsgi`` cubicweb-ctl command, which can use either python's builtin
+ wsgi server or the werkzeug module if present.
+
+* a ``rql-table`` directive is now available in ReST fields
+
+* cubicweb-ctl upgrade can now generate the static data resource directory
+ directly, without a manual call to gen-static-datadir.
+
+API changes
+-----------
+
+* not really an API change, but the entity permission checks are now
+ systematically deferred to an operation, instead of a) trying in a
+ hook and b) if it failed, retrying later in an operation
+
+* The default value storage for attributes is no longer String, but
+ Bytes. This opens the road to storing arbitrary python objects, e.g.
+ numpy arrays, and fixes a bug where default values whose truth value
+ was False were not properly migrated.
+
+* `symmetric` relations are no more handled by an rql rewrite but are
+ now handled with hooks (from the `activeintegrity` category); this
+ may have some consequences for applications that do low-level database
+ manipulations or at times disable (some) hooks.
+
+* `unique together` constraints (multi-columns unicity constraints)
+ get a `name` attribute that maps the CubicWeb contraint entities to
+ corresponding backend index.
+
+* BreadCrumbEntityVComponent's open_breadcrumbs method now includes
+ the first breadcrumbs separator
+
+* entities can be compared for equality and hashed
+
+* the ``on_fire_transition`` predicate accepts a sequence of possible
+ transition names
+
+* the GROUP_CONCAT rql aggregate function no longer repeats duplicate
+ values, on the sqlite and postgresql backends
+
+Deprecation
+---------------------
+
+* ``pyrorql`` sources have been deprecated. Multisource will be fully dropped
+ in the next version. If you are still using pyrorql, switch to ``datafeed``
+ **NOW**!
+
+* the old multi-source system
+
+* `find_one_entity` and `find_entities` in favor of `find`
+ (see `#3361290 https://www.cubicweb.org/ticket/3361290`_)
+
+* the `TmpFileViewMixin` and `TmpPngView` classes (see `#3400448
+ https://www.cubicweb.org/ticket/3400448`_)
+
+Deprecated Code Drops
+----------------------
+
+* ``ldapuser`` have been dropped; use ``ldapfeed`` now
+ (see `#2936496 <http://www.cubicweb.org/2936496>`_)
+
+* action ``GotRhythm`` was removed, make sure you do not
+ import it in your cubes (even to unregister it)
+ (see `#3093362 <http://www.cubicweb.org/3093362>`_)
+
+* all 3.8 backward compat is gone
+
+* all 3.9 backward compat (including the javascript side) is gone
+
+* the ``twisted`` (web-only) instance type has been removed
--- a/doc/book/en/admin/config.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/admin/config.rst Mon Jan 13 13:47:47 2014 +0100
@@ -57,19 +57,28 @@
PostgreSQL
~~~~~~~~~~
-For installation, please refer to the `PostgreSQL project online documentation`_.
-
-.. _`PostgreSQL project online documentation`: http://www.postgresql.org/
+Many Linux distributions ship with the appropriate PostgreSQL packages.
+Basically, you need to install the following packages:
-You need to install the three following packages: `postgresql-8.X`,
-`postgresql-client-8.X`, and `postgresql-plpython-8.X`. If you run postgres
-version prior to 8.3, you'll also need the `postgresql-contrib-8.X` package for
-full-text search extension.
+* `postgresql` and `postgresql-client`, which will pull the respective
+ versioned packages (e.g. `postgresql-9.1` and `postgresql-client-9.1`) and,
+ optionally,
+* a `postgresql-plpython-X.Y` package with a version corresponding to that of
+ the aforementioned packages (e.g. `postgresql-plpython-9.1`).
+
+If you run postgres version prior to 8.3, you'll also need the
+`postgresql-contrib-8.X` package for full-text search extension.
If you run postgres on another host than the |cubicweb| repository, you should
install the `postgresql-client` package on the |cubicweb| host, and others on the
database host.
+For extra details concerning installation, please refer to the `PostgreSQL
+project online documentation`_.
+
+.. _`PostgreSQL project online documentation`: http://www.postgresql.org/docs
+
+
Database cluster
++++++++++++++++
--- a/doc/book/en/admin/setup.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/admin/setup.rst Mon Jan 13 13:47:47 2014 +0100
@@ -121,35 +121,50 @@
`Virtualenv` install
--------------------
-Since version 3.9, |cubicweb| can be safely installed, used and contained inside
-a `virtualenv`_. You can use either :ref:`pip <PipInstallation>` or
-:ref:`easy_install <EasyInstallInstallation>` to install |cubicweb| inside an
-activated virtual environment.
+|cubicweb| can be safely installed, used and contained inside a
+`virtualenv`_. You can use either :ref:`pip <PipInstallation>` or
+:ref:`easy_install <EasyInstallInstallation>` to install |cubicweb|
+inside an activated virtual environment.
.. _PipInstallation:
`pip` install
-------------
-pip_ is a python utility that helps downloading, building, installing, and
-managing python packages and their dependencies. It is fully compatible with
-`virtualenv`_ and installs the packages from sources published on the
-`The Python Package Index`_.
+`pip <http://pip.openplans.org/>`_ is a python tool that helps downloading,
+building, installing, and managing Python packages and their dependencies. It
+is fully compatible with `virtualenv`_ and installs the packages from sources
+published on the `The Python Package Index`_.
-.. _`pip`: http://pip.openplans.org/
.. _`virtualenv`: http://virtualenv.openplans.org/
A working compilation chain is needed to build the modules that include C
-extensions. If you definitively wont, installing `Lxml <http://lxml.de/>`_,
+extensions. If you really do not want to compile anything, installing `Lxml <http://lxml.de/>`_,
`Twisted Web <http://twistedmatrix.com/trac/wiki/Downloads/>`_ and `libgecode
<http://www.gecode.org/>`_ will help.
-To install |cubicweb| and its dependencies, just run::
+For Debian, these minimal dependencies can be obtained by doing::
+
+ apt-get install gcc python-pip python-dev python-lxml
+
+or, if you prefer to get as much as possible from pip::
+
+ apt-get install gcc python-pip python-dev libxslt1-dev libxml2-dev
+
+For Windows, you can install pre-built packages (possible `source
+<http://www.lfd.uci.edu/~gohlke/pythonlibs/>`_). For a minimal setup, install
+`pip <http://www.lfd.uci.edu/~gohlke/pythonlibs/#pip>`_, `setuptools
+<http://www.lfd.uci.edu/~gohlke/pythonlibs/#setuptools>`_, `libxml-python
+<http://www.lfd.uci.edu/~gohlke/pythonlibs/#libxml-python>`_, `lxml
+<http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml>`_ and `twisted
+<http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted>`_ from this source making
+sure to choose the correct architecture and version of Python.
+
+Finally, install |cubicweb| and its dependencies, by running::
pip install cubicweb
-There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
-list of available cubes on
+Many other :ref:`cubes <AvailableCubes>` are available. A list is available at
`PyPI <http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb&submit=search>`_
or at the `CubicWeb.org forge`_.
--- a/doc/book/en/annexes/rql/language.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/annexes/rql/language.rst Mon Jan 13 13:47:47 2014 +0100
@@ -81,7 +81,7 @@
are expressed as explained below:
* string should be between double or single quotes. If the value contains a
- quote, it should be preceded by a backslash '\'
+ quote, it should be preceded by a backslash '\\'
* floats separator is dot '.'
@@ -747,7 +747,7 @@
.. sourcecode:: sql
- INSERT Person X: X name 'foo', X friend Y WHERE name 'nice'
+ INSERT Person X: X name 'foo', X friend Y WHERE Y name 'nice'
.. _RQLSetQuery:
--- a/doc/book/en/devrepo/datamodel/definition.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/datamodel/definition.rst Mon Jan 13 13:47:47 2014 +0100
@@ -226,13 +226,13 @@
* `SizeConstraint`: allows to specify a minimum and/or maximum size on
string (generic case of `maxsize`)
-* `BoundConstraint`: allows to specify a minimum and/or maximum value
+* `BoundaryConstraint`: allows to specify a minimum and/or maximum value
on numeric types and date
.. sourcecode:: python
- from yams.constraints import BoundConstraint, TODAY
- BoundConstraint('<=', TODAY())
+ from yams.constraints import BoundaryConstraint, TODAY
+ BoundaryConstraint('<=', TODAY())
* `IntervalBoundConstraint`: allows to specify an interval with
included values
@@ -330,7 +330,8 @@
For a relation, the possible actions are `read`, `add`, and `delete`.
-For an attribute, the possible actions are `read`, and `update`.
+For an attribute, the possible actions are `read`, `add` and `update`,
+and they are a refinement of an entity type permission.
For each access type, a tuple indicates the name of the authorized groups and/or
one or multiple RQL expressions to satisfy to grant access. The access is
@@ -364,7 +365,8 @@
.. sourcecode:: python
__permissions__ = {'read': ('managers', 'users', 'guests',),
- 'update': ('managers', ERQLExpression('U has_update_permission X')),}
+ 'add': ('managers', ERQLExpression('U has_add_permission X'),
+ 'update': ('managers', ERQLExpression('U has_update_permission X')),}
The standard user groups
````````````````````````
@@ -476,13 +478,8 @@
Here are the current rules:
-1. permission to add/update entity and its attributes are checked:
-
- - on commit if the entity has been added
-
- - in an 'after_update_entity' hook if the entity has been updated. If it fails
- at this time, it will be retried on commit (hence you get the permission if
- you have it just after the modification or *at* commit time)
+1. permission to add/update entity and its attributes are checked on
+ commit
2. permission to delete an entity is checked in 'before_delete_entity' hook
--- a/doc/book/en/devrepo/devcore/dbapi.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/devcore/dbapi.rst Mon Jan 13 13:47:47 2014 +0100
@@ -29,6 +29,11 @@
Also, a rollback is automatically done if an error occurs during commit.
+.. note::
+
+ A :exc:`ValidationError` has a `entity` attribute. In CubicWeb,
+ this atttribute is set to the entity's eid (not a reference to the
+ entity itself).
Executing RQL queries from a view or a hook
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- a/doc/book/en/devrepo/entityclasses/adapters.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/entityclasses/adapters.rst Mon Jan 13 13:47:47 2014 +0100
@@ -10,13 +10,7 @@
.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
.. _`adapter`: http://en.wikipedia.org/wiki/Adapter_pattern
-In |cubicweb| adapters provide logical functionalities to entity types. They
-are introduced in version `3.9`. Before that one had to implement Interfaces in
-entity classes to achieve a similar goal. However, the problem with this
-approach is that is clutters the entity class's namespace, exposing name
-collision risks with schema attributes/relations or even methods names
-(different interfaces may define the same method with not necessarily the same
-behaviour expected).
+In |cubicweb| adapters provide logical functionalities to entity types.
Definition of an adapter is quite trivial. An excerpt from cubicweb
itself (found in :mod:`cubicweb.entities.adapters`):
--- a/doc/book/en/devrepo/entityclasses/application-logic.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/entityclasses/application-logic.rst Mon Jan 13 13:47:47 2014 +0100
@@ -2,7 +2,7 @@
----------------------------------------
The previous chapters detailed the classes and methods available to
-the developper at the so-called `ORM`_ level. However they say little
+the developer at the so-called `ORM`_ level. However they say little
about the common patterns of usage of these objects.
.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping
@@ -13,22 +13,22 @@
Hooks and Operations provide support for the implementation of rules
such as computed attributes, coherency invariants, etc (they play the
-same role as database triggers, but in a way that is independant of
+same role as database triggers, but in a way that is independent of
the actual data sources).
So a lot of an application's business rules will be written in Hooks
(or Operations).
On the web side, views also typically operate using entity
-objects. Obvious entity methods for use in views are the dublin code
-method like dc_title, etc. For separation of concerns reasons, one
+objects. Obvious entity methods for use in views are the Dublin Core
+methods like ``dc_title``. For separation of concerns reasons, one
should ensure no ui logic pervades the entities level, and also no
business logic should creep into the views.
In the duration of a transaction, entities objects can be instantiated
many times, in views and hooks, even for the same database entity. For
instance, in a classic CubicWeb deployment setup, the repository and
-the web frontend are separated process communicating over the
+the web front-end are separated process communicating over the
wire. There is no way state can be shared between these processes
(there is a specific API for that). Hence, it is not possible to use
entity objects as messengers between these components of an
@@ -38,24 +38,24 @@
object was built.
Setting an attribute or relation value can be done in the context of a
-Hook/Operation, using the obj.cw_set(x=42) notation or a plain
-RQL SET expression.
+Hook/Operation, using the ``obj.cw_set(x=42)`` notation or a plain
+RQL ``SET`` expression.
In views, it would be preferable to encapsulate the necessary logic in
a method of an adapter for the concerned entity class(es). But of
-course, this advice is also reasonnable for Hooks/Operations, though
+course, this advice is also reasonable for Hooks/Operations, though
the separation of concerns here is less stringent than in the case of
views.
This leads to the practical role of objects adapters: it's where an
-important part of the application logic lie (the other part being
+important part of the application logic lies (the other part being
located in the Hook/Operations).
Anatomy of an entity class
--------------------------
We can look now at a real life example coming from the `tracker`_
-cube. Let us begin to study the entities/project.py content.
+cube. Let us begin to study the ``entities/project.py`` content.
.. sourcecode:: python
@@ -77,10 +77,10 @@
The fact that the `Project` entity type implements an ``ITree``
interface is materialized by the ``ProjectAdapter`` class (inheriting
-the pre-defined ``ITreeAdapter`` whose __regid__ is of course
+the pre-defined ``ITreeAdapter`` whose ``__regid__`` is of course
``ITree``), which will be selected on `Project` entity types because
of its selector. On this adapter, we redefine the ``tree_relation``
-attribute of the ITreeAdapter class.
+attribute of the ``ITreeAdapter`` class.
This is typically used in views concerned with the representation of
tree-like structures (CubicWeb provides several such views).
@@ -95,16 +95,16 @@
about the transitive closure of the child relation). This is a further
argument to implement it at entity class level.
-`fetch_attrs` configures which attributes should be prefetched when using ORM
-methods retrieving entity of this type. In a same manner, the `cw_fetch_order` is
+``fetch_attrs`` configures which attributes should be pre-fetched when using ORM
+methods retrieving entity of this type. In a same manner, the ``cw_fetch_order`` is
a class method allowing to control sort order. More on this in :ref:`FetchAttrs`.
-We can observe the big TICKET_DEFAULT_STATE_RESTR is a pure
+We can observe the big ``TICKET_DEFAULT_STATE_RESTR`` is a pure
application domain piece of data. There is, of course, no limitation
to the amount of class attributes of this kind.
The ``dc_title`` method provides a (unicode string) value likely to be
-consummed by views, but note that here we do not care about output
+consumed by views, but note that here we do not care about output
encodings. We care about providing data in the most universal format
possible, because the data could be used by a web view (which would be
responsible of ensuring XHTML compliance), or a console or file
@@ -113,8 +113,8 @@
.. note::
- The dublin code `dc_xxx` methods are not moved to an adapter as they
- are extremely prevalent in cubicweb and assorted cubes and should be
+ The Dublin Core `dc_xxx` methods are not moved to an adapter as they
+ are extremely prevalent in CubicWeb and assorted cubes and should be
available for all entity types.
Let us now dig into more substantial pieces of code, continuing the
@@ -159,8 +159,8 @@
* entity code is concerned with the application domain
-* it is NOT concerned with database coherency (this is the realm of
- Hooks/Operations); in other words, it assumes a coherent world
+* it is NOT concerned with database consistency (this is the realm of
+ Hooks/Operations); in other words, it assumes a consistent world
* it is NOT (directly) concerned with end-user interfaces
--- a/doc/book/en/devrepo/migration.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/migration.rst Mon Jan 13 13:47:47 2014 +0100
@@ -46,7 +46,7 @@
Again in the directory `migration`, the file `depends.map` allows to indicate
that for the migration to a particular model version, you always have to first
migrate to a particular *CubicWeb* version. This file can contain comments (lines
-starting by `#`) and a dependancy is listed as follows: ::
+starting with `#`) and a dependency is listed as follows: ::
<model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
@@ -170,9 +170,9 @@
* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
query, either to interrogate or update. A result set object is returned.
-* `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given
- type. The attribute and relation values are specified using the named and
- positionned parameters.
+* `add_entity(etype, *args, **kwargs)`, adds a new entity of the given type.
+ The attribute and relation values are specified as named positional
+ arguments.
Workflow creation
-----------------
--- a/doc/book/en/devrepo/repo/hooks.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/repo/hooks.rst Mon Jan 13 13:47:47 2014 +0100
@@ -237,7 +237,7 @@
interface. Hence its constructor is different from the default Exception
constructor. It accepts, positionally:
-* an entity eid,
+* an entity eid (**not the entity itself**),
* a dict whose keys represent attribute (or relation) names and values
an end-user facing message (hence properly translated) relating the
--- a/doc/book/en/devrepo/repo/sessions.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/repo/sessions.rst Mon Jan 13 13:47:47 2014 +0100
@@ -59,7 +59,7 @@
other credentials elements (calling `authentication_information`),
giving the request object each time
- * the default retriever (oddly named `LoginPasswordRetreiver`)
+ * the default retriever (named `LoginPasswordRetriever`)
will in turn defer login and password fetching to the request
object (which, depending on the authentication mode (`cookie`
or `http`), will do the appropriate things and return a login
--- a/doc/book/en/devrepo/testing.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/testing.rst Mon Jan 13 13:47:47 2014 +0100
@@ -18,12 +18,7 @@
convenience methods to help test all of this.
In the realm of views, automatic tests check that views are valid
-XHTML. See :ref:`automatic_views_tests` for details. Since 3.9, bases
-for web functional testing using `windmill
-<http://www.getwindmill.com/>`_ are set. See test cases in
-cubicweb/web/test/windmill and python wrapper in
-cubicweb/web/test_windmill/ if you want to use this in your own cube.
-
+XHTML. See :ref:`automatic_views_tests` for details.
Most unit tests need a live database to work against. This is achieved
by CubicWeb using automatically sqlite (bundled with Python, see
--- a/doc/book/en/devrepo/vreg.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devrepo/vreg.rst Mon Jan 13 13:47:47 2014 +0100
@@ -81,7 +81,6 @@
.. autoclass:: cubicweb.predicates.has_mimetype
.. autoclass:: cubicweb.predicates.is_in_state
.. autofunction:: cubicweb.predicates.on_fire_transition
-.. autoclass:: cubicweb.predicates.implements
Logged user predicates
--- a/doc/book/en/devweb/request.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devweb/request.rst Mon Jan 13 13:47:47 2014 +0100
@@ -30,11 +30,7 @@
* `Session data handling`
- * `session_data()`, returns a dictionary containing all the session data
- * `get_session_data(key, default=None)`, returns a value associated to the given
- key or the value `default` if the key is not defined
- * `set_session_data(key, value)`, assign a value to a key
- * `del_session_data(key)`, suppress the value associated to a key
+ * `session.data` is the dictionnary of the session data; it can be manipulated like an ordinary Python dictionnary
* `Edition` (utilities for edition control):
--- a/doc/book/en/devweb/views/wdoc.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/devweb/views/wdoc.rst Mon Jan 13 13:47:47 2014 +0100
@@ -8,10 +8,8 @@
Help views
----------
.. autoclass:: cubicweb.web.views.wdoc.InlineHelpView
-.. autoclass:: cubicweb.web.views.wdoc.ChangeLogView
Actions
-------
.. autoclass:: cubicweb.web.views.wdoc.HelpAction
-.. autoclass:: cubicweb.web.views.wdoc.ChangeLogAction
.. autoclass:: cubicweb.web.views.wdoc.AboutAction
--- a/doc/book/en/tutorials/advanced/part02_security.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/tutorials/advanced/part02_security.rst Mon Jan 13 13:47:47 2014 +0100
@@ -259,26 +259,26 @@
# relations where the "parent" entity is the object
O_RELS = set(('filed_under', 'comments',))
- class AddEntitySecurityPropagationHook(hook.PropagateSubjectRelationHook):
+ class AddEntitySecurityPropagationHook(hook.PropagateRelationHook):
"""propagate permissions when new entity are added"""
__regid__ = 'sytweb.addentity_security_propagation'
- __select__ = (hook.PropagateSubjectRelationHook.__select__
+ __select__ = (hook.PropagateRelationHook.__select__
& hook.match_rtype_sets(S_RELS, O_RELS))
main_rtype = 'may_be_read_by'
subject_relations = S_RELS
object_relations = O_RELS
- class AddPermissionSecurityPropagationHook(hook.PropagateSubjectRelationAddHook):
+ class AddPermissionSecurityPropagationHook(hook.PropagateRelationAddHook):
"""propagate permissions when new entity are added"""
__regid__ = 'sytweb.addperm_security_propagation'
- __select__ = (hook.PropagateSubjectRelationAddHook.__select__
+ __select__ = (hook.PropagateRelationAddHook.__select__
& hook.match_rtype('may_be_read_by',))
subject_relations = S_RELS
object_relations = O_RELS
- class DelPermissionSecurityPropagationHook(hook.PropagateSubjectRelationDelHook):
+ class DelPermissionSecurityPropagationHook(hook.PropagateRelationDelHook):
__regid__ = 'sytweb.delperm_security_propagation'
- __select__ = (hook.PropagateSubjectRelationDelHook.__select__
+ __select__ = (hook.PropagateRelationDelHook.__select__
& hook.match_rtype('may_be_read_by',))
subject_relations = S_RELS
object_relations = O_RELS
--- a/doc/book/en/tutorials/advanced/part04_ui-base.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/tutorials/advanced/part04_ui-base.rst Mon Jan 13 13:47:47 2014 +0100
@@ -194,8 +194,6 @@
.. Note::
- * Adapters have been introduced in CubicWeb 3.9 / cubicweb-folder 1.8.
-
* As seen earlier, we want to **replace** the folder's `ITree` adapter by our
implementation, hence the custom `registration_callback` method.
@@ -241,12 +239,6 @@
ascendant/descendant ordering and a strict comparison with current file's name
(the "X" variable representing the current file).
-.. Note::
-
- * Former `implements` selector should be replaced by one of `is_instance` /
- `adaptable` selector with CubicWeb >= 3.9. In our case, `is_instance` to
- tell our adapter is able to adapt `File` entities.
-
Notice that this query supposes we wont have two files of the same name in the
same folder, else things may go wrong. Fixing this is out of the scope of this
blog. And as I would like to have at some point a smarter, context sensitive
@@ -358,7 +350,7 @@
You'll have to answer some questions, as we've seen in `an earlier post`_.
Now that everything is tested, I can transfer the new code to the production
-server, `apt-get upgrade` cubicweb 3.9 and its dependencies, and eventually
+server, `apt-get upgrade` cubicweb and its dependencies, and eventually
upgrade the production instance.
--- a/doc/book/en/tutorials/advanced/part05_ui-advanced.rst Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/book/en/tutorials/advanced/part05_ui-advanced.rst Mon Jan 13 13:47:47 2014 +0100
@@ -1,8 +1,6 @@
Building my photos web site with |cubicweb| part V: let's make it even more user friendly
=========================================================================================
-We'll now see how to benefit from features introduced in 3.9 and 3.10 releases of CubicWeb
-
.. _uiprops:
Step 1: tired of the default look?
@@ -29,9 +27,9 @@
LOGO = data('logo.jpg')
-The uiprops machinery has been introduced in `CubicWeb 3.9`_. It is used to define
-some static file resources, such as the logo, default Javascript / CSS files, as
-well as CSS properties (we'll see that later).
+The uiprops machinery is used to define some static file resources,
+such as the logo, default Javascript / CSS files, as well as CSS
+properties (we'll see that later).
.. Note::
This file is imported specifically by |cubicweb|, with a predefined name space,
@@ -373,5 +371,4 @@
.. _`CubicWeb 3.10`: http://www.cubicweb.org/blogentry/1330518
-.. _`CubicWeb 3.9`: http://www.cubicweb.org/blogentry/1179899
.. _`here`: http://webdesign.about.com/od/css3/f/blfaqbgsize.htm
--- a/doc/tools/pyjsrest.py Tue Jul 02 17:09:04 2013 +0200
+++ b/doc/tools/pyjsrest.py Mon Jan 13 13:47:47 2014 +0100
@@ -136,7 +136,6 @@
'cubicweb.preferences',
'cubicweb.edition',
'cubicweb.reledit',
- 'cubicweb.rhythm',
'cubicweb.timeline-ext',
]
--- a/entities/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entities/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -33,6 +33,11 @@
__regid__ = 'Any'
__implements__ = ()
+ @classproperty
+ def cw_etype(cls):
+ """entity type as a string"""
+ return cls.__regid__
+
@classmethod
def cw_create_url(cls, req, **kwargs):
""" return the url of the entity creation form for this entity type"""
@@ -58,11 +63,6 @@
# meta data api ###########################################################
- @classproperty
- def cw_etype(self):
- """entity Etype as a string"""
- return self.__regid__
-
def dc_title(self):
"""return a suitable *unicode* title for this entity"""
for rschema, attrschema in self.e_schema.attribute_definitions():
--- a/entities/adapters.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entities/adapters.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2010-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2010-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -28,9 +28,7 @@
from logilab.common.decorators import cached
from cubicweb import ValidationError, view
-from cubicweb.predicates import (implements, is_instance, relation_possible,
- match_exception)
-from cubicweb.interfaces import IDownloadable, ITree
+from cubicweb.predicates import is_instance, relation_possible, match_exception
class IEmailableAdapter(view.EntityAdapter):
@@ -67,11 +65,9 @@
class INotifiableAdapter(view.EntityAdapter):
- __needs_bw_compat__ = True
__regid__ = 'INotifiable'
__select__ = is_instance('Any')
- @view.implements_adapter_compat('INotifiableAdapter')
def notification_references(self, view):
"""used to control References field of email send on notification
for this entity. `view` is the notification view.
@@ -167,27 +163,25 @@
class IDownloadableAdapter(view.EntityAdapter):
"""interface for downloadable entities"""
- __needs_bw_compat__ = True
__regid__ = 'IDownloadable'
- __select__ = implements(IDownloadable, warn=False) # XXX for bw compat, else should be abstract
+ __abstract__ = True
- @view.implements_adapter_compat('IDownloadable')
def download_url(self, **kwargs): # XXX not really part of this interface
"""return an url to download entity's content"""
raise NotImplementedError
- @view.implements_adapter_compat('IDownloadable')
+
def download_content_type(self):
"""return MIME type of the downloadable content"""
raise NotImplementedError
- @view.implements_adapter_compat('IDownloadable')
+
def download_encoding(self):
"""return encoding of the downloadable content"""
raise NotImplementedError
- @view.implements_adapter_compat('IDownloadable')
+
def download_file_name(self):
"""return file name of the downloadable content"""
raise NotImplementedError
- @view.implements_adapter_compat('IDownloadable')
+
def download_data(self):
"""return actual data of the downloadable content"""
raise NotImplementedError
@@ -219,27 +213,16 @@
.. automethod: children_rql
.. automethod: path
"""
- __needs_bw_compat__ = True
__regid__ = 'ITree'
- __select__ = implements(ITree, warn=False) # XXX for bw compat, else should be abstract
+ __abstract__ = True
child_role = 'subject'
parent_role = 'object'
- @property
- def tree_relation(self):
- warn('[3.9] tree_attribute is deprecated, define tree_relation on a custom '
- 'ITree for %s instead' % (self.entity.__class__),
- DeprecationWarning)
- return self.entity.tree_attribute
-
- # XXX should be removed from the public interface
- @view.implements_adapter_compat('ITree')
def children_rql(self):
"""Returns RQL to get the children of the entity."""
return self.entity.cw_related_rql(self.tree_relation, self.parent_role)
- @view.implements_adapter_compat('ITree')
def different_type_children(self, entities=True):
"""Return children entities of different type as this entity.
@@ -253,7 +236,6 @@
return [e for e in res if e.e_schema != eschema]
return res.filtered_rset(lambda x: x.e_schema != eschema, self.entity.cw_col)
- @view.implements_adapter_compat('ITree')
def same_type_children(self, entities=True):
"""Return children entities of the same type as this entity.
@@ -267,23 +249,19 @@
return [e for e in res if e.e_schema == eschema]
return res.filtered_rset(lambda x: x.e_schema is eschema, self.entity.cw_col)
- @view.implements_adapter_compat('ITree')
def is_leaf(self):
"""Returns True if the entity does not have any children."""
return len(self.children()) == 0
- @view.implements_adapter_compat('ITree')
def is_root(self):
"""Returns true if the entity is root of the tree (e.g. has no parent).
"""
return self.parent() is None
- @view.implements_adapter_compat('ITree')
def root(self):
"""Return the root entity of the tree."""
return self._cw.entity_from_eid(self.path()[0])
- @view.implements_adapter_compat('ITree')
def parent(self):
"""Returns the parent entity if any, else None (e.g. if we are on the
root).
@@ -294,7 +272,6 @@
except (KeyError, IndexError):
return None
- @view.implements_adapter_compat('ITree')
def children(self, entities=True, sametype=False):
"""Return children entities.
@@ -307,7 +284,6 @@
return self.entity.related(self.tree_relation, self.parent_role,
entities=entities)
- @view.implements_adapter_compat('ITree')
def iterparents(self, strict=True):
"""Return an iterator on the parents of the entity."""
def _uptoroot(self):
@@ -322,7 +298,6 @@
return chain([self.entity], _uptoroot(self))
return _uptoroot(self)
- @view.implements_adapter_compat('ITree')
def iterchildren(self, _done=None):
"""Return an iterator over the item's children."""
if _done is None:
@@ -334,7 +309,6 @@
yield child
_done.add(child.eid)
- @view.implements_adapter_compat('ITree')
def prefixiter(self, _done=None):
"""Return an iterator over the item's descendants in a prefixed order."""
if _done is None:
@@ -347,7 +321,6 @@
for entity in child.cw_adapt_to('ITree').prefixiter(_done):
yield entity
- @view.implements_adapter_compat('ITree')
@cached
def path(self):
"""Returns the list of eids from the root object to this object."""
@@ -379,6 +352,7 @@
class IUserFriendlyError(view.EntityAdapter):
__regid__ = 'IUserFriendlyError'
__abstract__ = True
+
def __init__(self, *args, **kwargs):
self.exc = kwargs.pop('exc')
super(IUserFriendlyError, self).__init__(*args, **kwargs)
@@ -386,11 +360,16 @@
class IUserFriendlyUniqueTogether(IUserFriendlyError):
__select__ = match_exception(UniqueTogetherError)
+
def raise_user_exception(self):
- etype, rtypes = self.exc.args
- msg = self._cw._('violates unique_together constraints (%s)') % (
- ', '.join([self._cw._(rtype) for rtype in rtypes]))
- raise ValidationError(self.entity.eid, dict((col, msg) for col in rtypes))
+ _ = self._cw._
+ rtypes = self.exc.rtypes
+ rtypes_msg = {}
+ for rtype in rtypes:
+ rtypes_msg[rtype] = _('%s is part of violated unicity constraint') % rtype
+ globalmsg = _('some relations violate a unicity constraint')
+ rtypes_msg['unicity constraint'] = globalmsg
+ raise ValidationError(self.entity.eid, rtypes_msg)
# deprecated ###################################################################
--- a/entities/lib.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entities/lib.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -15,14 +15,15 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""entity classes for optional library entities
+"""entity classes for optional library entities"""
-"""
__docformat__ = "restructuredtext en"
from urlparse import urlsplit, urlunsplit
from datetime import datetime
+from logilab.mtconverter import xml_escape
+
from cubicweb import UnknownProperty
from cubicweb.entity import _marker
from cubicweb.entities import AnyEntity, fetch_config
@@ -81,7 +82,10 @@
format='text/html'):
"""overriden to return displayable address when necessary"""
if attr == 'address':
- return self.display_address()
+ address = self.display_address()
+ if format == 'text/html':
+ address = xml_escape(address)
+ return address
return super(EmailAddress, self).printable_value(attr, value, attrtype, format)
--- a/entities/test/unittest_base.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entities/test/unittest_base.py Mon Jan 13 13:47:47 2014 +0100
@@ -25,7 +25,6 @@
from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.interfaces import IMileStone, ICalendarable
from cubicweb.entities import AnyEntity
@@ -82,12 +81,19 @@
self.assertEqual(email.display_address(), 'maarten.ter.huurne@philips.com')
self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne@philips.com')
self.vreg.config.global_set_option('mangle-emails', True)
- self.assertEqual(email.display_address(), 'maarten.ter.huurne at philips dot com')
- self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne at philips dot com')
- email = self.execute('INSERT EmailAddress X: X address "syt"').get_entity(0, 0)
- self.assertEqual(email.display_address(), 'syt')
- self.assertEqual(email.printable_value('address'), 'syt')
+ try:
+ self.assertEqual(email.display_address(), 'maarten.ter.huurne at philips dot com')
+ self.assertEqual(email.printable_value('address'), 'maarten.ter.huurne at philips dot com')
+ email = self.execute('INSERT EmailAddress X: X address "syt"').get_entity(0, 0)
+ self.assertEqual(email.display_address(), 'syt')
+ self.assertEqual(email.printable_value('address'), 'syt')
+ finally:
+ self.vreg.config.global_set_option('mangle-emails', False)
+ def test_printable_value_escape(self):
+ email = self.execute('INSERT EmailAddress X: X address "maarten&ter@philips.com"').get_entity(0, 0)
+ self.assertEqual(email.printable_value('address'), 'maarten&ter@philips.com')
+ self.assertEqual(email.printable_value('address', format='text/plain'), 'maarten&ter@philips.com')
class CWUserTC(BaseEntityTC):
@@ -127,27 +133,6 @@
self.request().create_entity('CWGroup', name=u'logilab', reverse_in_group=e)
-class InterfaceTC(CubicWebTC):
-
- def test_nonregr_subclasses_and_mixins_interfaces(self):
- from cubicweb.entities.wfobjs import WorkflowableMixIn
- WorkflowableMixIn.__implements__ = (ICalendarable,)
- CWUser = self.vreg['etypes'].etype_class('CWUser')
- class MyUser(CWUser):
- __implements__ = (IMileStone,)
- self.vreg._loadedmods[__name__] = {}
- self.vreg.register(MyUser)
- self.vreg['etypes'].initialization_completed()
- MyUser_ = self.vreg['etypes'].etype_class('CWUser')
- # a copy is done systematically
- self.assertTrue(issubclass(MyUser_, MyUser))
- self.assertTrue(implements(MyUser_, IMileStone))
- self.assertTrue(implements(MyUser_, ICalendarable))
- # original class should not have beed modified, only the copy
- self.assertTrue(implements(MyUser, IMileStone))
- self.assertFalse(implements(MyUser, ICalendarable))
-
-
class SpecializedEntityClassesTC(CubicWebTC):
def select_eclass(self, etype):
--- a/entities/test/unittest_wfobjs.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entities/test/unittest_wfobjs.py Mon Jan 13 13:47:47 2014 +0100
@@ -75,7 +75,7 @@
wf.add_transition(u'baz', (bar,), foo)
with self.assertRaises(ValidationError) as cm:
self.commit()
- self.assertEqual(cm.exception.errors, {'name-subject': 'workflow already have a transition of that name'})
+ self.assertEqual(cm.exception.errors, {'name-subject': 'workflow already has a transition of that name'})
# no pb if not in the same workflow
wf2 = add_wf(self, 'Company')
foo = wf.add_state(u'foo', initial=True)
@@ -88,7 +88,7 @@
biz.cw_set(name=u'baz')
with self.assertRaises(ValidationError) as cm:
self.commit()
- self.assertEqual(cm.exception.errors, {'name-subject': 'workflow already have a transition of that name'})
+ self.assertEqual(cm.exception.errors, {'name-subject': 'workflow already has a transition of that name'})
class WorkflowTC(CubicWebTC):
--- a/entities/wfobjs.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entities/wfobjs.py Mon Jan 13 13:47:47 2014 +0100
@@ -32,7 +32,6 @@
from cubicweb.entities import AnyEntity, fetch_config
from cubicweb.view import EntityAdapter
from cubicweb.predicates import relation_possible
-from cubicweb.mixins import MI_REL_TRIGGERS
class WorkflowException(Exception): pass
@@ -379,65 +378,8 @@
return self.by_transition and self.by_transition[0] or None
-class WorkflowableMixIn(object):
- """base mixin providing workflow helper methods for workflowable entities.
- This mixin will be automatically set on class supporting the 'in_state'
- relation (which implies supporting 'wf_info_for' as well)
- """
- @property
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').main_workflow")
- def main_workflow(self):
- return self.cw_adapt_to('IWorkflowable').main_workflow
- @property
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').current_workflow")
- def current_workflow(self):
- return self.cw_adapt_to('IWorkflowable').current_workflow
- @property
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').current_state")
- def current_state(self):
- return self.cw_adapt_to('IWorkflowable').current_state
- @property
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').state")
- def state(self):
- return self.cw_adapt_to('IWorkflowable').state
- @property
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').printable_state")
- def printable_state(self):
- return self.cw_adapt_to('IWorkflowable').printable_state
- @property
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').workflow_history")
- def workflow_history(self):
- return self.cw_adapt_to('IWorkflowable').workflow_history
-
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').cwetype_workflow()")
- def cwetype_workflow(self):
- return self.cw_adapt_to('IWorkflowable').main_workflow()
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').latest_trinfo()")
- def latest_trinfo(self):
- return self.cw_adapt_to('IWorkflowable').latest_trinfo()
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').possible_transitions()")
- def possible_transitions(self, type='normal'):
- return self.cw_adapt_to('IWorkflowable').possible_transitions(type)
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').fire_transition()")
- def fire_transition(self, tr, comment=None, commentformat=None):
- return self.cw_adapt_to('IWorkflowable').fire_transition(tr, comment, commentformat)
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').change_state()")
- def change_state(self, statename, comment=None, commentformat=None, tr=None):
- return self.cw_adapt_to('IWorkflowable').change_state(statename, comment, commentformat, tr)
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').subworkflow_input_trinfo()")
- def subworkflow_input_trinfo(self):
- return self.cw_adapt_to('IWorkflowable').subworkflow_input_trinfo()
- @deprecated("[3.9] use entity.cw_adapt_to('IWorkflowable').subworkflow_input_transition()")
- def subworkflow_input_transition(self):
- return self.cw_adapt_to('IWorkflowable').subworkflow_input_transition()
-
-
-MI_REL_TRIGGERS[('in_state', 'subject')] = WorkflowableMixIn
-
-
-
-class IWorkflowableAdapter(WorkflowableMixIn, EntityAdapter):
+class IWorkflowableAdapter(EntityAdapter):
"""base adapter providing workflow helper methods for workflowable entities.
"""
__regid__ = 'IWorkflowable'
--- a/entity.py Tue Jul 02 17:09:04 2013 +0200
+++ b/entity.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -42,7 +42,6 @@
from cubicweb.rqlrewrite import RQLRewriter
from cubicweb.uilib import soup2xhtml
-from cubicweb.mixins import MI_REL_TRIGGERS
from cubicweb.mttransforms import ENGINE
_marker = object()
@@ -194,31 +193,11 @@
setattr(cls, rschema.type, Attribute(rschema.type))
mixins = []
for rschema, _, role in eschema.relation_definitions():
- if (rschema, role) in MI_REL_TRIGGERS:
- mixin = MI_REL_TRIGGERS[(rschema, role)]
- if not (issubclass(cls, mixin) or mixin in mixins): # already mixed ?
- mixins.append(mixin)
- for iface in getattr(mixin, '__implements__', ()):
- if not interface.implements(cls, iface):
- interface.extend(cls, iface)
if role == 'subject':
attr = rschema.type
else:
attr = 'reverse_%s' % rschema.type
setattr(cls, attr, Relation(rschema, role))
- if mixins:
- # see etype class instantation in cwvreg.ETypeRegistry.etype_class method:
- # due to class dumping, cls is the generated top level class with actual
- # user class as (only) parent. Since we want to be able to override mixins
- # method from this user class, we have to take care to insert mixins after that
- # class
- #
- # note that we don't plug mixins as user class parent since it causes pb
- # with some cases of entity classes inheritance.
- mixins.insert(0, cls.__bases__[0])
- mixins += cls.__bases__[1:]
- cls.__bases__ = tuple(mixins)
- cls.info('plugged %s mixins on %s', mixins, cls)
fetch_attrs = ('modification_date',)
@@ -308,7 +287,10 @@
select._varmaker = rqlvar_maker(defined=select.defined_vars,
aliases=select.aliases, index=26)
if settype:
- select.add_type_restriction(mainvar, cls.__regid__)
+ rel = select.add_type_restriction(mainvar, cls.__regid__)
+ # should use 'is_instance_of' instead of 'is' so we retrieve
+ # subclasses instances as well
+ rel.r_type = 'is_instance_of'
if fetchattrs is None:
fetchattrs = cls.fetch_attrs
cls._fetch_restrictions(mainvar, select, fetchattrs, user, ordermethod)
@@ -558,7 +540,14 @@
raise NotImplementedError('comparison not implemented for %s' % self.__class__)
def __eq__(self, other):
- raise NotImplementedError('comparison not implemented for %s' % self.__class__)
+ if isinstance(self.eid, (int, long)):
+ return self.eid == other.eid
+ return self is other
+
+ def __hash__(self):
+ if isinstance(self.eid, (int, long)):
+ return self.eid
+ return super(Entity, self).__hash__()
def _cw_update_attr_cache(self, attrcache):
# if context is a repository session, don't consider dont-cache-attrs as
@@ -983,7 +972,7 @@
return value
def related(self, rtype, role='subject', limit=None, entities=False, # XXX .cw_related
- safe=False):
+ safe=False, targettypes=None):
"""returns a resultset of related entities
:param rtype:
@@ -997,10 +986,13 @@
:param safe:
if True, an empty rset/list of entities will be returned in case of
:exc:`Unauthorized`, else (the default), the exception is propagated
+ :param targettypes:
+ a tuple of target entity types to restrict the query
"""
rtype = str(rtype)
- if limit is None:
- # we cannot do much wrt cache on limited queries
+ # Caching restricted/limited results is best avoided.
+ cacheable = limit is None and targettypes is None
+ if cacheable:
cache_key = '%s_%s' % (rtype, role)
if cache_key in self._cw_related_cache:
return self._cw_related_cache[cache_key][entities]
@@ -1008,7 +1000,7 @@
if entities:
return []
return self._cw.empty_rset()
- rql = self.cw_related_rql(rtype, role, limit=limit)
+ rql = self.cw_related_rql(rtype, role, limit=limit, targettypes=targettypes)
try:
rset = self._cw.execute(rql, {'x': self.eid})
except Unauthorized:
@@ -1016,9 +1008,9 @@
raise
rset = self._cw.empty_rset()
if entities:
- if limit is None:
+ if cacheable:
self.cw_set_relation_cache(rtype, role, rset)
- return self.related(rtype, role, limit, entities)
+ return self.related(rtype, role, entities=entities)
return list(rset.entities())
else:
return rset
@@ -1181,8 +1173,7 @@
if v in select.defined_vars and v in cstr.mainvars)
# rewrite constraint by constraint since we want a AND between
# expressions.
- rewriter.rewrite(select, [(varmap, (cstr,))], select.solutions,
- args, existant)
+ rewriter.rewrite(select, [(varmap, (cstr,))], args, existant)
# insert security RQL expressions granting the permission to 'add' the
# relation into the rql syntax tree, if necessary
rqlexprs = rdef.get_rqlexprs('add')
@@ -1194,8 +1185,7 @@
varmap = dict((v, v) for v in (searchedvar.name, evar.name)
if v in select.defined_vars)
# rewrite all expressions at once since we want a OR between them.
- rewriter.rewrite(select, [(varmap, rqlexprs)], select.solutions,
- args, existant)
+ rewriter.rewrite(select, [(varmap, rqlexprs)], args, existant)
# ensure we have an order defined
if not select.orderby:
select.add_sort_var(select.defined_vars[searchedvar.name])
@@ -1281,8 +1271,8 @@
>>> c = rql('Any X WHERE X is Company').get_entity(0, 0)
>>> p = rql('Any X WHERE X is Person').get_entity(0, 0)
- >>> c.set(name=u'Logilab')
- >>> p.set(firstname=u'John', lastname=u'Doe', works_for=c)
+ >>> c.cw_set(name=u'Logilab')
+ >>> p.cw_set(firstname=u'John', lastname=u'Doe', works_for=c)
You can also set relations where the entity has 'object' role by
prefixing the relation name by 'reverse_'. Also, relation values may be
@@ -1323,7 +1313,8 @@
@deprecated('[3.16] use cw_set() instead of set_attributes()')
def set_attributes(self, **kwargs): # XXX cw_set_attributes
- self.cw_set(**kwargs)
+ if kwargs:
+ self.cw_set(**kwargs)
@deprecated('[3.16] use cw_set() instead of set_relations()')
def set_relations(self, **kwargs): # XXX cw_set_relations
@@ -1334,40 +1325,13 @@
(meaning that all relations of the given type from or to this object
should be deleted).
"""
- self.cw_set(**kwargs)
+ if kwargs:
+ self.cw_set(**kwargs)
@deprecated('[3.13] use entity.cw_clear_all_caches()')
def clear_all_caches(self):
return self.cw_clear_all_caches()
- @deprecated('[3.9] use entity.cw_attr_value(attr)')
- def get_value(self, name):
- return self.cw_attr_value(name)
-
- @deprecated('[3.9] use entity.cw_delete()')
- def delete(self, **kwargs):
- return self.cw_delete(**kwargs)
-
- @deprecated('[3.9] use entity.cw_attr_metadata(attr, metadata)')
- def attr_metadata(self, attr, metadata):
- return self.cw_attr_metadata(attr, metadata)
-
- @deprecated('[3.9] use entity.cw_has_perm(action)')
- def has_perm(self, action):
- return self.cw_has_perm(action)
-
- @deprecated('[3.9] use entity.cw_set_relation_cache(rtype, role, rset)')
- def set_related_cache(self, rtype, role, rset):
- self.cw_set_relation_cache(rtype, role, rset)
-
- @deprecated('[3.9] use entity.cw_clear_relation_cache(rtype, role)')
- def clear_related_cache(self, rtype=None, role=None):
- self.cw_clear_relation_cache(rtype, role)
-
- @deprecated('[3.9] use entity.cw_related_rql(rtype, [role, [targettypes]])')
- def related_rql(self, rtype, role='subject', targettypes=None):
- return self.cw_related_rql(rtype, role, targettypes)
-
@property
@deprecated('[3.10] use entity.cw_edited')
def edited_attributes(self):
--- a/etwist/request.py Tue Jul 02 17:09:04 2013 +0200
+++ b/etwist/request.py Mon Jan 13 13:47:47 2014 +0100
@@ -24,15 +24,21 @@
class CubicWebTwistedRequestAdapter(CubicWebRequestBase):
+ """ from twisted .req to cubicweb .form
+ req.files are put into .form[<filefield>]
+ """
def __init__(self, req, vreg, https):
self._twreq = req
super(CubicWebTwistedRequestAdapter, self).__init__(
vreg, https, req.args, headers=req.received_headers)
- for key, (name, stream) in req.files.iteritems():
- if name is None:
- self.form[key] = (name, stream)
- else:
- self.form[key] = (unicode(name, self.encoding), stream)
+ for key, name_stream_list in req.files.iteritems():
+ for name, stream in name_stream_list:
+ if name is not None:
+ name = unicode(name, self.encoding)
+ self.form.setdefault(key, []).append((name, stream))
+ # 3.16.4 backward compat
+ if len(self.form[key]) == 1:
+ self.form[key] = self.form[key][0]
self.content = self._twreq.content # stream
def http_method(self):
--- a/etwist/server.py Tue Jul 02 17:09:04 2013 +0200
+++ b/etwist/server.py Mon Jan 13 13:47:47 2014 +0100
@@ -244,7 +244,6 @@
self._do_process_multipart = True
self.process()
-
@monkeypatch(http.Request)
def process_multipart(self):
if not self._do_process_multipart:
@@ -254,16 +253,17 @@
keep_blank_values=1,
strict_parsing=1)
for key in form:
- value = form[key]
- if isinstance(value, list):
- self.args[key] = [v.value for v in value]
- elif value.filename:
- if value.done != -1: # -1 is transfer has been interrupted
- self.files[key] = (value.filename, value.file)
+ values = form[key]
+ if not isinstance(values, list):
+ values = [values]
+ for value in values:
+ if value.filename:
+ if value.done != -1: # -1 is transfer has been interrupted
+ self.files.setdefault(key, []).append((value.filename, value.file))
+ else:
+ self.files.setdefault(key, []).append((None, None))
else:
- self.files[key] = (None, None)
- else:
- self.args[key] = value.value
+ self.args.setdefault(key, []).append(value.value)
from logging import getLogger
from cubicweb import set_log_methods
--- a/etwist/twconfig.py Tue Jul 02 17:09:04 2013 +0200
+++ b/etwist/twconfig.py Mon Jan 13 13:47:47 2014 +0100
@@ -34,9 +34,8 @@
from cubicweb.web.webconfig import WebConfiguration
-class TwistedConfiguration(WebConfiguration):
+class WebConfigurationBase(WebConfiguration):
"""web instance (in a twisted web server) client of a RQL server"""
- name = 'twisted'
options = merge_options((
# ctl configuration
@@ -107,19 +106,17 @@
return 'http://%s:%s/' % (self['host'] or getfqdn(), self['port'] or 8080)
-CONFIGURATIONS.append(TwistedConfiguration)
-
try:
from cubicweb.server.serverconfig import ServerConfiguration
- class AllInOneConfiguration(TwistedConfiguration, ServerConfiguration):
+ class AllInOneConfiguration(WebConfigurationBase, ServerConfiguration):
"""repository and web instance in the same twisted process"""
name = 'all-in-one'
- options = merge_options(TwistedConfiguration.options
+ options = merge_options(WebConfigurationBase.options
+ ServerConfiguration.options)
- cubicweb_appobject_path = TwistedConfiguration.cubicweb_appobject_path | ServerConfiguration.cubicweb_appobject_path
- cube_appobject_path = TwistedConfiguration.cube_appobject_path | ServerConfiguration.cube_appobject_path
+ cubicweb_appobject_path = WebConfigurationBase.cubicweb_appobject_path | ServerConfiguration.cubicweb_appobject_path
+ cube_appobject_path = WebConfigurationBase.cube_appobject_path | ServerConfiguration.cube_appobject_path
def pyro_enabled(self):
"""tell if pyro is activated for the in memory repository"""
return self['pyro-server']
--- a/etwist/twctl.py Tue Jul 02 17:09:04 2013 +0200
+++ b/etwist/twctl.py Mon Jan 13 13:47:47 2014 +0100
@@ -22,7 +22,7 @@
from logilab.common.shellutils import rm
from cubicweb.toolsutils import CommandHandler
-from cubicweb.web.webctl import WebCreateHandler
+from cubicweb.web.webctl import WebCreateHandler, WebUpgradeHandler
# trigger configuration registration
import cubicweb.etwist.twconfig # pylint: disable=W0611
@@ -48,6 +48,9 @@
def poststop(self):
pass
+class TWUpgradeHandler(WebUpgradeHandler):
+ cfgname = 'twisted'
+
try:
from cubicweb.server import serverctl
@@ -73,5 +76,8 @@
cfgname = 'all-in-one'
subcommand = 'cubicweb-twisted'
+ class AllInOneUpgradeHandler(TWUpgradeHandler):
+ cfgname = 'all-in-one'
+
except ImportError:
pass
--- a/ext/rest.py Tue Jul 02 17:09:04 2013 +0200
+++ b/ext/rest.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -29,6 +29,8 @@
* `sourcecode` (if pygments is installed), source code colorization
+* `rql-table`, create a table from a RQL query
+
"""
__docformat__ = "restructuredtext en"
@@ -40,7 +42,7 @@
from docutils import statemachine, nodes, utils, io
from docutils.core import Publisher
-from docutils.parsers.rst import Parser, states, directives
+from docutils.parsers.rst import Parser, states, directives, Directive
from docutils.parsers.rst.roles import register_canonical_role, set_classes
from logilab.mtconverter import ESC_UCAR_TABLE, ESC_CAR_TABLE, xml_escape
@@ -251,6 +253,76 @@
winclude_directive.options = {'literal': directives.flag,
'encoding': directives.encoding}
+class RQLTableDirective(Directive):
+ """rql-table directive
+
+ Example:
+
+ .. rql-table::
+ :vid: mytable
+ :headers: , , progress
+ :colvids: 2=progress
+
+ Any X,U,X WHERE X is Project, X url U
+
+ All fields but the RQL string are optionnal. The ``:headers:`` option can
+ contain empty column names.
+ """
+
+ required_arguments = 0
+ optional_arguments = 0
+ has_content= True
+ final_argument_whitespace = True
+ option_spec = {'vid': directives.unchanged,
+ 'headers': directives.unchanged,
+ 'colvids': directives.unchanged}
+
+ def run(self):
+ errid = "rql-table directive"
+ self.assert_has_content()
+ if self.arguments:
+ raise self.warning('%s does not accept arguments' % errid)
+ rql = ' '.join([l.strip() for l in self.content])
+ _cw = self.state.document.settings.context._cw
+ _cw.ensure_ro_rql(rql)
+ try:
+ rset = _cw.execute(rql)
+ except Exception as exc:
+ raise self.error("fail to execute RQL query in %s: %r" %
+ (errid, exc))
+ if not rset:
+ raise self.warning("empty result set")
+ vid = self.options.get('vid', 'table')
+ try:
+ view = _cw.vreg['views'].select(vid, _cw, rset=rset)
+ except Exception as exc:
+ raise self.error("fail to select '%s' view in %s: %r" %
+ (vid, errid, exc))
+ headers = None
+ if 'headers' in self.options:
+ headers = [h.strip() for h in self.options['headers'].split(',')]
+ while headers.count(''):
+ headers[headers.index('')] = None
+ if len(headers) != len(rset[0]):
+ raise self.error("the number of 'headers' does not match the "
+ "number of columns in %s" % errid)
+ cellvids = None
+ if 'colvids' in self.options:
+ cellvids = {}
+ for f in self.options['colvids'].split(','):
+ try:
+ idx, vid = f.strip().split('=')
+ except ValueError:
+ raise self.error("malformatted 'colvids' option in %s" %
+ errid)
+ cellvids[int(idx.strip())] = vid.strip()
+ try:
+ content = view.render(headers=headers, cellvids=cellvids)
+ except Exception as exc:
+ raise self.error("Error rendering %s (%s)" % (errid, exc))
+ return [nodes.raw('', content, format='html')]
+
+
try:
from pygments import highlight
from pygments.lexers import get_lexer_by_name
@@ -385,3 +457,4 @@
directives.register_directive('winclude', winclude_directive)
if pygments_directive is not None:
directives.register_directive('sourcecode', pygments_directive)
+ directives.register_directive('rql-table', RQLTableDirective)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ext/test/data/views.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,24 @@
+# copyright 2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+
+from cubicweb.web.views import tableview
+
+class CustomRsetTableView(tableview.RsetTableView):
+ __regid__ = 'mytable'
+
--- a/ext/test/unittest_rest.py Tue Jul 02 17:09:04 2013 +0200
+++ b/ext/test/unittest_rest.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -82,5 +82,133 @@
out = rest_publish(context, ':bookmark:`%s`' % eid)
self.assertEqual(out, u'<p><h1>CWUser_plural</h1><div class="section"><a href="http://testing.fr/cubicweb/cwuser/admin" title="">admin</a></div><div class="section"><a href="http://testing.fr/cubicweb/cwuser/anon" title="">anon</a></div></p>\n')
+ def test_rqltable_nocontent(self):
+ context = self.context()
+ out = rest_publish(context, """.. rql-table::""")
+ self.assertIn("System Message: ERROR", out)
+ self.assertIn("Content block expected for the "rql-table" "
+ "directive; none found" , out)
+
+ def test_rqltable_norset(self):
+ context = self.context()
+ rql = "Any X WHERE X is CWUser, X firstname 'franky'"
+ out = rest_publish(
+ context, """\
+.. rql-table::
+
+ %(rql)s""" % {'rql': rql})
+ self.assertIn("System Message: WARNING", out)
+ self.assertIn("empty result set", out)
+
+ def test_rqltable_nooptions(self):
+ rql = """Any S,F,L WHERE X is CWUser, X surname S,
+ X firstname F, X login L"""
+ out = rest_publish(
+ self.context(), """\
+.. rql-table::
+
+ %(rql)s
+ """ % {'rql': rql})
+ req = self.request()
+ view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+ self.assertEqual(view.render(w=None)[49:], out[49:])
+
+ def test_rqltable_vid(self):
+ rql = """Any S,F,L WHERE X is CWUser, X surname S,
+ X firstname F, X login L"""
+ vid = 'mytable'
+ out = rest_publish(
+ self.context(), """\
+.. rql-table::
+ :vid: %(vid)s
+
+ %(rql)s
+ """ % {'rql': rql, 'vid': vid})
+ req = self.request()
+ view = self.vreg['views'].select(vid, req, rset=req.execute(rql))
+ self.assertEqual(view.render(w=None)[49:], out[49:])
+ self.assertIn(vid, out[:49])
+
+ def test_rqltable_badvid(self):
+ rql = """Any S,F,L WHERE X is CWUser, X surname S,
+ X firstname F, X login L"""
+ vid = 'mytabel'
+ out = rest_publish(
+ self.context(), """\
+.. rql-table::
+ :vid: %(vid)s
+
+ %(rql)s
+ """ % {'rql': rql, 'vid': vid})
+ self.assertIn("fail to select '%s' view" % vid, out)
+
+ def test_rqltable_headers(self):
+ rql = """Any S,F,L WHERE X is CWUser, X surname S,
+ X firstname F, X login L"""
+ headers = ["nom", "prenom", "identifiant"]
+ out = rest_publish(
+ self.context(), """\
+.. rql-table::
+ :headers: %(headers)s
+
+ %(rql)s
+ """ % {'rql': rql, 'headers': ', '.join(headers)})
+ req = self.request()
+ view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+ view.headers = headers
+ self.assertEqual(view.render(w=None)[49:], out[49:])
+
+ def test_rqltable_headers_missing(self):
+ rql = """Any S,F,L WHERE X is CWUser, X surname S,
+ X firstname F, X login L"""
+ headers = ["nom", "", "identifiant"]
+ out = rest_publish(
+ self.context(), """\
+.. rql-table::
+ :headers: %(headers)s
+
+ %(rql)s
+ """ % {'rql': rql, 'headers': ', '.join(headers)})
+ req = self.request()
+ view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+ view.headers = [headers[0], None, headers[2]]
+ self.assertEqual(view.render(w=None)[49:], out[49:])
+
+ def test_rqltable_headers_missing_edges(self):
+ rql = """Any S,F,L WHERE X is CWUser, X surname S,
+ X firstname F, X login L"""
+ headers = [" ", "prenom", ""]
+ out = rest_publish(
+ self.context(), """\
+.. rql-table::
+ :headers: %(headers)s
+
+ %(rql)s
+ """ % {'rql': rql, 'headers': ', '.join(headers)})
+ req = self.request()
+ view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+ view.headers = [None, headers[1], None]
+ self.assertEqual(view.render(w=None)[49:], out[49:])
+
+ def test_rqltable_colvids(self):
+ rql = """Any X,S,F,L WHERE X is CWUser, X surname S,
+ X firstname F, X login L"""
+ colvids = {0: "oneline"}
+ out = rest_publish(
+ self.context(), """\
+.. rql-table::
+ :colvids: %(colvids)s
+
+ %(rql)s
+ """ % {'rql': rql,
+ 'colvids': ', '.join(["%d=%s" % (k, v)
+ for k, v in colvids.iteritems()])
+ })
+ req = self.request()
+ view = self.vreg['views'].select('table', req, rset=req.execute(rql))
+ view.cellvids = colvids
+ self.assertEqual(view.render(w=None)[49:], out[49:])
+
+
if __name__ == '__main__':
unittest_main()
--- a/hooks/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -59,7 +59,9 @@
def update_feeds(repo):
# don't iter on repo.sources which doesn't include copy based
# sources (the one we're looking for)
- for source in repo.sources_by_eid.itervalues():
+ # take a list to avoid iterating on a dictionary which size may
+ # change
+ for source in list(repo.sources_by_eid.values()):
if (not source.copy_based_source
or not repo.config.source_enabled(source)
or not source.config['synchronize']):
--- a/hooks/integrity.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/integrity.py Mon Jan 13 13:47:47 2014 +0100
@@ -109,6 +109,30 @@
category = 'integrity'
+class EnsureSymmetricRelationsAdd(hook.Hook):
+ """ ensure X r Y => Y r X iff r is symmetric """
+ __regid__ = 'cw.add_ensure_symmetry'
+ category = 'activeintegrity'
+ events = ('after_add_relation',)
+ # __select__ is set in the registration callback
+
+ def __call__(self):
+ self._cw.repo.system_source.add_relation(self._cw, self.eidto,
+ self.rtype, self.eidfrom)
+
+
+class EnsureSymmetricRelationsDelete(hook.Hook):
+ """ ensure X r Y => Y r X iff r is symmetric """
+ __regid__ = 'cw.delete_ensure_symmetry'
+ category = 'activeintegrity'
+ events = ('after_delete_relation',)
+ # __select__ is set in the registration callback
+
+ def __call__(self):
+ self._cw.repo.system_source.delete_relation(self._cw, self.eidto,
+ self.rtype, self.eidfrom)
+
+
class CheckCardinalityHookBeforeDeleteRelation(IntegrityHook):
"""check cardinalities are satisfied"""
__regid__ = 'checkcard_before_delete_relation'
@@ -348,3 +372,11 @@
elif composite == 'object':
_DelayedDeleteSEntityOp.get_instance(self._cw).add_data(
(self.eidfrom, rtype))
+
+def registration_callback(vreg):
+ vreg.register_all(globals().values(), __name__)
+ symmetric_rtypes = [rschema.type for rschema in vreg.schema.relations()
+ if rschema.symmetric]
+ EnsureSymmetricRelationsAdd.__select__ = hook.Hook.__select__ & hook.match_rtype(*symmetric_rtypes)
+ EnsureSymmetricRelationsDelete.__select__ = hook.Hook.__select__ & hook.match_rtype(*symmetric_rtypes)
+
--- a/hooks/metadata.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/metadata.py Mon Jan 13 13:47:47 2014 +0100
@@ -149,7 +149,7 @@
# entity source handling #######################################################
-class ChangeEntityUpdateCaches(hook.Operation):
+class ChangeEntitySourceUpdateCaches(hook.Operation):
oldsource = newsource = entity = None # make pylint happy
def postcommit_event(self):
@@ -221,6 +221,6 @@
'mtime': datetime.now()}
self._cw.system_sql(syssource.sqlgen.insert('entities', attrs), attrs)
# register an operation to update repository/sources caches
- ChangeEntityUpdateCaches(self._cw, entity=entity,
- oldsource=oldsource.repo_source,
- newsource=syssource)
+ ChangeEntitySourceUpdateCaches(self._cw, entity=entity,
+ oldsource=oldsource.repo_source,
+ newsource=syssource)
--- a/hooks/notification.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/notification.py Mon Jan 13 13:47:47 2014 +0100
@@ -52,7 +52,7 @@
All others Operations end up adding data to this Operation.
The notification are done on ``postcommit_event`` to make sure to prevent
- sending notification about rollbacked data.
+ sending notification about rolled back data.
"""
containercls = list
--- a/hooks/security.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/security.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -20,14 +20,18 @@
"""
__docformat__ = "restructuredtext en"
+from warnings import warn
from logilab.common.registry import objectify_predicate
+from yams import buildobjs
+
from cubicweb import Unauthorized
from cubicweb.server import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS, hook
-def check_entity_attributes(session, entity, editedattrs=None, creation=False):
+
+def check_entity_attributes(session, entity, action, editedattrs=None):
eid = entity.eid
eschema = entity.e_schema
# ._cw_skip_security_attributes is there to bypass security for attributes
@@ -39,11 +43,26 @@
if attr in dontcheck:
continue
rdef = eschema.rdef(attr)
- if rdef.final: # non final relation are checked by other hooks
- # add/delete should be equivalent (XXX: unify them into 'update' ?)
- if creation and not rdef.permissions.get('update'):
+ if rdef.final: # non final relation are checked by standard hooks
+ perms = rdef.permissions.get(action)
+ # comparison below works because the default update perm is:
+ #
+ # ('managers', ERQLExpression(Any X WHERE U has_update_permission X,
+ # X eid %(x)s, U eid %(u)s))
+ #
+ # is deserialized in this order (groups first), and ERQLExpression
+ # implements comparison by rql expression.
+ if perms == buildobjs.DEFAULT_ATTRPERMS[action]:
+ # The default rule is to delegate to the entity
+ # rule. This is an historical artefact. Hence we take
+ # this object as a marker saying "no specific"
+ # permission rule for this attribute. Thus we just do
+ # nothing.
continue
- rdef.check_perm(session, 'update', eid=eid)
+ if perms == ():
+ # That means an immutable attribute.
+ raise Unauthorized(action, str(rdef))
+ rdef.check_perm(session, action, eid=eid)
class CheckEntityPermissionOp(hook.DataOperationMixIn, hook.LateOperation):
@@ -52,8 +71,7 @@
for eid, action, edited in self.get_data():
entity = session.entity_from_eid(eid)
entity.cw_check_perm(action)
- check_entity_attributes(session, entity, edited,
- creation=(action == 'add'))
+ check_entity_attributes(session, entity, action, edited)
class CheckRelationPermissionOp(hook.DataOperationMixIn, hook.LateOperation):
@@ -91,17 +109,11 @@
events = ('after_update_entity',)
def __call__(self):
- try:
- # check user has permission right now, if not retry at commit time
- self.entity.cw_check_perm('update')
- check_entity_attributes(self._cw, self.entity)
- except Unauthorized:
- self.entity._cw_clear_local_perm_cache('update')
- # save back editedattrs in case the entity is reedited later in the
- # same transaction, which will lead to cw_edited being
- # overwritten
- CheckEntityPermissionOp.get_instance(self._cw).add_data(
- (self.entity.eid, 'update', self.entity.cw_edited) )
+ # save back editedattrs in case the entity is reedited later in the
+ # same transaction, which will lead to cw_edited being
+ # overwritten
+ CheckEntityPermissionOp.get_instance(self._cw).add_data(
+ (self.entity.eid, 'update', self.entity.cw_edited) )
class BeforeDelEntitySecurityHook(SecurityHook):
--- a/hooks/syncschema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/syncschema.py Mon Jan 13 13:47:47 2014 +0100
@@ -28,7 +28,7 @@
from copy import copy
from yams.schema import BASE_TYPES, RelationSchema, RelationDefinitionSchema
-from yams import buildobjs as ybo, schema2sql as y2sql
+from yams import buildobjs as ybo, schema2sql as y2sql, convert_default_value
from logilab.common.decorators import clear_cache
@@ -39,21 +39,6 @@
from cubicweb.server import hook, schemaserial as ss
from cubicweb.server.sqlutils import SQL_PREFIX
-
-TYPE_CONVERTER = { # XXX
- 'Boolean': bool,
- 'Int': int,
- 'BigInt': int,
- 'Float': float,
- 'Password': str,
- 'String': unicode,
- 'Date' : unicode,
- 'Datetime' : unicode,
- 'Time' : unicode,
- 'TZDatetime' : unicode,
- 'TZTime' : unicode,
- }
-
# core entity and relation types which can't be removed
CORE_TYPES = BASE_TYPES | SCHEMA_TYPES | META_RTYPES | set(
('CWUser', 'CWGroup','login', 'upassword', 'name', 'in_group'))
@@ -116,7 +101,7 @@
if (specialization, rdefdef.object) in rschema.rdefs:
continue
sperdef = RelationDefinitionSchema(specialization, rschema,
- object, props)
+ object, None, values=props)
ss.execschemarql(session.execute, sperdef,
ss.rdef2rql(sperdef, cstrtypemap, groupmap))
@@ -437,11 +422,11 @@
def precommit_event(self):
session = self.session
entity = self.entity
- # entity.defaultval is a string or None, but we need a correctly typed
+ # entity.defaultval is a Binary or None, but we need a correctly typed
# value
default = entity.defaultval
if default is not None:
- default = TYPE_CONVERTER[entity.otype.name](default)
+ default = default.unzpickle()
props = {'default': default,
'indexed': entity.indexed,
'fulltextindexed': entity.fulltextindexed,
@@ -493,20 +478,11 @@
# attribute is still set to False, so we've to ensure it's False
rschema.final = True
insert_rdef_on_subclasses(session, eschema, rschema, rdefdef, props)
- # set default value, using sql for performance and to avoid
- # modification_date update
- if default:
- if rdefdef.object in ('Date', 'Datetime', 'TZDatetime'):
- # XXX may may want to use creation_date
- if default == 'TODAY':
- default = syssource.dbhelper.sql_current_date()
- elif default == 'NOW':
- default = syssource.dbhelper.sql_current_timestamp()
- session.system_sql('UPDATE %s SET %s=%s'
- % (table, column, default))
- else:
- session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column),
- {'default': default})
+ # update existing entities with the default value of newly added attribute
+ if default is not None:
+ default = convert_default_value(self.rdefdef, default)
+ session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column),
+ {'default': default})
def revertprecommit_event(self):
# revert changes on in memory schema
@@ -738,44 +714,38 @@
class CWUniqueTogetherConstraintAddOp(MemSchemaOperation):
entity = None # make pylint happy
+
def precommit_event(self):
session = self.session
prefix = SQL_PREFIX
- table = '%s%s' % (prefix, self.entity.constraint_of[0].name)
- cols = ['%s%s' % (prefix, r.name) for r in self.entity.relations]
- dbhelper= session.cnxset.source('system').dbhelper
- sqls = dbhelper.sqls_create_multicol_unique_index(table, cols)
+ entity = self.entity
+ table = '%s%s' % (prefix, entity.constraint_of[0].name)
+ cols = ['%s%s' % (prefix, r.name) for r in entity.relations]
+ dbhelper = session.cnxset.source('system').dbhelper
+ sqls = dbhelper.sqls_create_multicol_unique_index(table, cols, entity.name)
for sql in sqls:
session.system_sql(sql)
- # XXX revertprecommit_event
-
def postcommit_event(self):
- eschema = self.session.vreg.schema.schema_by_eid(self.entity.constraint_of[0].eid)
- attrs = [r.name for r in self.entity.relations]
+ entity = self.entity
+ eschema = self.session.vreg.schema.schema_by_eid(entity.constraint_of[0].eid)
+ attrs = [r.name for r in entity.relations]
eschema._unique_together.append(attrs)
class CWUniqueTogetherConstraintDelOp(MemSchemaOperation):
- entity = oldcstr = None # for pylint
- cols = [] # for pylint
+ entity = cstrname = None # for pylint
+ cols = () # for pylint
+
def precommit_event(self):
session = self.session
prefix = SQL_PREFIX
table = '%s%s' % (prefix, self.entity.type)
- dbhelper= session.cnxset.source('system').dbhelper
+ dbhelper = session.cnxset.source('system').dbhelper
cols = ['%s%s' % (prefix, c) for c in self.cols]
- sqls = dbhelper.sqls_drop_multicol_unique_index(table, cols)
+ sqls = dbhelper.sqls_drop_multicol_unique_index(table, cols, self.cstrname)
for sql in sqls:
- try:
- session.system_sql(sql)
- except Exception as exc: # should be ProgrammingError
- if sql.startswith('DROP'):
- self.error('execute of `%s` failed (cause: %s)', sql, exc)
- continue
- raise
-
- # XXX revertprecommit_event
+ session.system_sql(sql)
def postcommit_event(self):
eschema = self.session.vreg.schema.schema_by_eid(self.entity.eid)
@@ -1195,9 +1165,9 @@
schema = self._cw.vreg.schema
cstr = self._cw.entity_from_eid(self.eidfrom)
entity = schema.schema_by_eid(self.eidto)
- cols = [r.name for r in cstr.relations]
+ cols = tuple(r.name for r in cstr.relations)
CWUniqueTogetherConstraintDelOp(self._cw, entity=entity,
- oldcstr=cstr, cols=cols)
+ cstrname=cstr.name, cols=cols)
# permissions synchronization hooks ############################################
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hooks/test/data/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,25 @@
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+from yams.buildobjs import RelationDefinition
+
+class friend(RelationDefinition):
+ subject = ('CWUser', 'CWGroup')
+ object = ('CWUser', 'CWGroup')
+ symmetric = True
+
--- a/hooks/test/unittest_hooks.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/test/unittest_hooks.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -39,6 +39,37 @@
rset = self.execute('Any S WHERE X sender S, X eid %s' % eeid)
self.assertEqual(len(rset), 1)
+ def test_symmetric(self):
+ req = self.request()
+ u1 = self.create_user(req, u'1')
+ u2 = self.create_user(req, u'2')
+ u3 = self.create_user(req, u'3')
+ ga = req.create_entity('CWGroup', name=u'A')
+ gb = req.create_entity('CWGroup', name=u'B')
+ u1.cw_set(friend=u2)
+ u2.cw_set(friend=u3)
+ ga.cw_set(friend=gb)
+ ga.cw_set(friend=u1)
+ self.commit()
+ req = self.request()
+ for l1, l2 in ((u'1', u'2'),
+ (u'2', u'3')):
+ self.assertTrue(req.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s',
+ {'l1': l1, 'l2': l2}))
+ self.assertTrue(req.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s',
+ {'l1': l1, 'l2': l2}))
+ self.assertTrue(req.execute('Any GA,GB WHERE GA friend GB, GA name "A", GB name "B"'))
+ self.assertTrue(req.execute('Any GA,GB WHERE GB friend GA, GA name "A", GB name "B"'))
+ self.assertTrue(req.execute('Any GA,U1 WHERE GA friend U1, GA name "A", U1 login "1"'))
+ self.assertTrue(req.execute('Any GA,U1 WHERE U1 friend GA, GA name "A", U1 login "1"'))
+ self.assertFalse(req.execute('Any GA,U WHERE GA friend U, GA name "A", U login "2"'))
+ for l1, l2 in ((u'1', u'3'),
+ (u'3', u'1')):
+ self.assertFalse(req.execute('Any U1,U2 WHERE U1 friend U2, U1 login %(l1)s, U2 login %(l2)s',
+ {'l1': l1, 'l2': l2}))
+ self.assertFalse(req.execute('Any U1,U2 WHERE U2 friend U1, U1 login %(l1)s, U2 login %(l2)s',
+ {'l1': l1, 'l2': l2}))
+
def test_html_tidy_hook(self):
req = self.request()
entity = req.create_entity('Workflow', name=u'wf1',
--- a/hooks/test/unittest_integrity.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/test/unittest_integrity.py Mon Jan 13 13:47:47 2014 +0100
@@ -41,9 +41,6 @@
self.execute('SET X in_group Y WHERE X login "toto", Y name "guests"')
self.commit()
- def test_delete_required_relations_object(self):
- self.skipTest('no sample in the schema ! YAGNI ? Kermaat ?')
-
def test_static_vocabulary_check(self):
self.assertRaises(ValidationError,
self.execute,
--- a/hooks/test/unittest_syncschema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/hooks/test/unittest_syncschema.py Mon Jan 13 13:47:47 2014 +0100
@@ -19,7 +19,7 @@
from logilab.common.testlib import TestCase, unittest_main
-from cubicweb import ValidationError
+from cubicweb import ValidationError, Binary
from cubicweb.schema import META_RTYPES
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.server.sqlutils import SQL_PREFIX
@@ -73,9 +73,10 @@
self.commit()
self.assertTrue(schema.has_entity('Societe2'))
self.assertTrue(schema.has_relation('concerne2'))
- attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval "noname", '
+ attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, '
' X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F '
- 'WHERE RT name "name", E name "Societe2", F name "String"')[0][0]
+ 'WHERE RT name "name", E name "Societe2", F name "String"',
+ {'default': Binary.zpickle('noname')})[0][0]
self._set_attr_perms(attreid)
concerne2_rdef_eid = self.execute(
'INSERT CWRelation X: X cardinality "**", X relation_type RT, X from_entity E, X to_entity E '
@@ -289,8 +290,10 @@
def test_add_attribute_to_base_class(self):
- attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval "noname", X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F '
- 'WHERE RT name "messageid", E name "BaseTransition", F name "String"')[0][0]
+ attreid = self.execute('INSERT CWAttribute X: X cardinality "11", X defaultval %(default)s, '
+ 'X indexed TRUE, X relation_type RT, X from_entity E, X to_entity F '
+ 'WHERE RT name "messageid", E name "BaseTransition", F name "String"',
+ {'default': Binary.zpickle('noname')})[0][0]
assert self.execute('SET X read_permission Y WHERE X eid %(x)s, Y name "managers"',
{'x': attreid})
self.commit()
--- a/i18n/de.po Tue Jul 02 17:09:04 2013 +0200
+++ b/i18n/de.po Mon Jan 13 13:47:47 2014 +0100
@@ -114,8 +114,8 @@
msgstr "%s Fehlerbericht"
#, python-format
-msgid "%s not estimated"
-msgstr "%s unbekannt(e)"
+msgid "%s is part of violated unicity constraint"
+msgstr ""
#, python-format
msgid "%s relation should not be in mapped"
@@ -439,10 +439,6 @@
msgid "DEBUG"
msgstr ""
-#, python-format
-msgid "Data connection graph for %s"
-msgstr "Graf der Datenverbindungen für %s"
-
msgid "Date"
msgstr "Datum"
@@ -518,15 +514,9 @@
msgid "FormatConstraint"
msgstr "Format-Einschränkung"
-msgid "From:"
-msgstr "Von:"
-
msgid "Garbage collection information"
msgstr "Information zur Speicherbereinigung"
-msgid "Got rhythm?"
-msgstr "Hast Du Rhythmus ?"
-
msgid "Help"
msgstr "Hilfe"
@@ -695,9 +685,6 @@
msgid "RQLVocabularyConstraint"
msgstr "RQL Wortschatz-Einschränkung"
-msgid "Recipients:"
-msgstr "Adressaten:"
-
msgid "RegexpConstraint"
msgstr "regulärer Ausdruck Einschränkung"
@@ -759,9 +746,6 @@
msgid "SubWorkflowExitPoint_plural"
msgstr "subworkflow Endpunkte"
-msgid "Subject:"
-msgstr "Subjekt :"
-
msgid "Submit bug report"
msgstr "Fehlerbericht senden"
@@ -929,9 +913,6 @@
msgid "Web server"
msgstr "Web-Server"
-msgid "What's new?"
-msgstr "Was ist neu?"
-
msgid "Workflow"
msgstr "Workflow"
@@ -965,9 +946,6 @@
"\"Durchsuchen\" oberhalb eine neue Datei hochladen, oder den Datei-Inhalt "
"mit dem Widget unterhalb editieren."
-msgid "You can use any of the following substitutions in your text"
-msgstr "Sie können die folgenden Ersetzungen in Ihrem Text verwenden:"
-
msgid "You can't change this relation"
msgstr ""
@@ -1023,6 +1001,9 @@
msgid "abstract base class for transitions"
msgstr "abstrakte Basisklasse für Übergänge"
+msgid "action menu"
+msgstr ""
+
msgid "action(s) on this selection"
msgstr "Aktionen(en) bei dieser Auswahl"
@@ -1041,6 +1022,9 @@
msgid "add Bookmark bookmarked_by CWUser object"
msgstr "Lesezeichen"
+msgid "add CWAttribute add_permission RQLExpression subject"
+msgstr ""
+
msgid "add CWAttribute constrained_by CWConstraint subject"
msgstr "Einschränkung"
@@ -1149,6 +1133,10 @@
msgid "add_permission"
msgstr "kann hinzugefügt werden durch"
+msgctxt "CWAttribute"
+msgid "add_permission"
+msgstr ""
+
# subject and object forms for each relation type
# (no object form for final relation types)
msgctxt "CWEType"
@@ -1185,6 +1173,9 @@
"Die Relation %(rtype)s von %(frometype)s #%(eidfrom)s zu %(toetype)s #"
"%(eidto)s wurde hinzugefügt."
+msgid "additional type specific properties"
+msgstr ""
+
msgid "addrelated"
msgstr "hinzufügen"
@@ -1672,9 +1663,6 @@
"core relation indicating the types (including specialized types) of an entity"
msgstr ""
-msgid "cost"
-msgstr "Kosten"
-
msgid "could not connect to the SMTP server"
msgstr "Keine Verbindung mit dem SMTP-Server"
@@ -1727,6 +1715,10 @@
msgstr "Erstelle E-Mail-Adresse für Nutzer %(linkto)s"
msgid ""
+"creating RQLExpression (CWAttribute %(linkto)s add_permission RQLExpression)"
+msgstr ""
+
+msgid ""
"creating RQLExpression (CWAttribute %(linkto)s read_permission RQLExpression)"
msgstr "RQL-Ausdruck für Leseberechtigung für %(linkto)s"
@@ -2099,6 +2091,9 @@
msgid "default value"
msgstr "Standardwert"
+msgid "default value as gziped pickled python object"
+msgstr ""
+
msgid "default workflow for an entity type"
msgstr "Standard-Workflow eines Entitätstyps"
@@ -2373,18 +2368,9 @@
msgid "eid"
msgstr ""
-msgid "emails successfully sent"
-msgstr "E-Mails erfolgreich versandt."
-
-msgid "embed"
-msgstr "einbetten"
-
msgid "embedded html"
msgstr "HTML-Inhalt"
-msgid "embedding this url is forbidden"
-msgstr "Einbettung dieses URLs ist nicht erlaubt."
-
msgid "end_timestamp"
msgstr ""
@@ -2437,9 +2423,6 @@
msgid "error"
msgstr ""
-msgid "error while embedding page"
-msgstr "Fehler beim Einbetten der Seite"
-
msgid "error while publishing ReST text"
msgstr "Fehler beim Übersetzen von reST"
@@ -2449,9 +2432,6 @@
"Fehler beim Zugriff auf Quelle %s, möglicherweise sind die Daten "
"unvollständig."
-msgid "eta_date"
-msgstr "Enddatum"
-
msgid "exit state must be a subworkflow state"
msgstr "Exit-Zustand muss ein Subworkflow-Zustand sein."
@@ -2465,9 +2445,6 @@
msgid "exiting from subworkflow %s"
msgstr "verlasse Subworkflow %s"
-msgid "expected:"
-msgstr "erwartet:"
-
msgid "expression"
msgstr "Ausdruck"
@@ -2482,8 +2459,12 @@
msgid "exprtype"
msgstr "Typ des Ausdrucks"
-msgid "external page"
-msgstr "externe Seite"
+msgid "extra_props"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "extra_props"
+msgstr ""
msgid "facet-loading-msg"
msgstr ""
@@ -2901,10 +2882,6 @@
msgid "info"
msgstr "Information"
-#, python-format
-msgid "initial estimation %s"
-msgstr "Erste Schätzung %s"
-
msgid "initial state for this workflow"
msgstr "Anfangszustand für diesen Workflow"
@@ -3180,9 +3157,6 @@
msgid "message"
msgstr ""
-msgid "milestone"
-msgstr "Meilenstein"
-
#, python-format
msgid "missing parameters for entity %s"
msgstr "Fehlende Parameter für Entität %s"
@@ -3242,6 +3216,10 @@
msgid "name"
msgstr ""
+msgctxt "CWUniqueTogetherConstraint"
+msgid "name"
+msgstr ""
+
msgctxt "State"
msgid "name"
msgstr "Name"
@@ -3329,9 +3307,6 @@
msgid "no related entity"
msgstr "keine verknüpfte Entität"
-msgid "no related project"
-msgstr "kein verknüpftes Projekt"
-
msgid "no repository sessions found"
msgstr "keine Datenbank-Sitzung gefunden"
@@ -3531,15 +3506,6 @@
msgid "profile"
msgstr "Profil"
-msgid "progress"
-msgstr "Fortschritt"
-
-msgid "progress bar"
-msgstr "Fortschrittsbalken"
-
-msgid "project"
-msgstr "Projekt"
-
msgid "rdef-description"
msgstr "Beschreibung"
@@ -3808,9 +3774,6 @@
msgid "semantic description of this workflow"
msgstr "Semantische Beschreibung dieses Workflows"
-msgid "send email"
-msgstr "E-Mail senden"
-
msgid "september"
msgstr "September"
@@ -3839,9 +3802,6 @@
msgid "show filter form"
msgstr "Filter zeigen"
-msgid "sioc"
-msgstr "sioc"
-
msgid "site configuration"
msgstr "Konfiguration der Website"
@@ -3861,6 +3821,9 @@
"Eine oder mehrere frühere Transaktion(en) betreffen die Tntität. Machen Sie "
"sie zuerst rückgängig."
+msgid "some relations violate a unicity constraint"
+msgstr ""
+
msgid "sorry, the server is unable to handle this query"
msgstr "Der Server kann diese Anfrage leider nicht bearbeiten."
@@ -4056,9 +4019,6 @@
msgid "tablefilter"
msgstr "Tabellenfilter"
-msgid "task progression"
-msgstr "Fortschritt der Aufgabe"
-
msgid "text"
msgstr "Text"
@@ -4181,15 +4141,9 @@
msgid "to_state_object"
msgstr "Übergang zu diesem Zustand"
-msgid "todo_by"
-msgstr "zu erledigen bis"
-
msgid "toggle check boxes"
msgstr "Kontrollkästchen umkehren"
-msgid "toggle filter"
-msgstr "filter verbergen/zeigen"
-
msgid "tr_count"
msgstr ""
@@ -4480,6 +4434,14 @@
msgid "value %(KEY-value)s must be %(KEY-op)s %(KEY-boundary)s"
msgstr ""
+#, python-format
+msgid "value %(KEY-value)s must be <= %(KEY-boundary)s"
+msgstr ""
+
+#, python-format
+msgid "value %(KEY-value)s must be >= %(KEY-boundary)s"
+msgstr ""
+
msgid "value associated to this key is not editable manually"
msgstr ""
"Der mit diesem Schlüssele verbundene Wert kann n icht manuell geändert "
@@ -4523,10 +4485,6 @@
msgid "view_index"
msgstr "Index-Seite"
-#, python-format
-msgid "violates unique_together constraints (%s)"
-msgstr "Verletzung der unique_together-Einschränkung (%s)"
-
msgid "visible"
msgstr "sichtbar"
@@ -4536,6 +4494,9 @@
msgid "we are not yet ready to handle this query"
msgstr "Momentan können wir diese sparql-Anfrage noch nicht ausführen."
+msgid "web sessions without CNX"
+msgstr ""
+
msgid "wednesday"
msgstr "Mittwoch"
@@ -4566,11 +4527,11 @@
msgid "workflow"
msgstr "Workflow"
-msgid "workflow already have a state of that name"
-msgstr "Der Workflow hat bereits einen Zustand desselben Namens."
-
-msgid "workflow already have a transition of that name"
-msgstr "Der Workflow hat bereits einen Übergang desselben Namens."
+msgid "workflow already has a state of that name"
+msgstr ""
+
+msgid "workflow already has a transition of that name"
+msgstr ""
#, python-format
msgid "workflow changed to \"%s\""
@@ -4641,6 +4602,9 @@
#~ msgid "%(value)r doesn't match the %(regexp)r regular expression"
#~ msgstr "%(value)r entspricht nicht dem regulären Ausdruck %(regexp)r"
+#~ msgid "%s not estimated"
+#~ msgstr "%s unbekannt(e)"
+
#~ msgid ""
#~ "Can't restore relation %(rtype)s of entity %(eid)s, this relation does "
#~ "not exists anymore in the schema."
@@ -4648,11 +4612,98 @@
#~ "Kann die Relation %(rtype)s der Entität %(eid)s nicht wieder herstellen, "
#~ "diese Relation existiert nicht mehr in dem Schema."
+#~ msgid "Data connection graph for %s"
+#~ msgstr "Graf der Datenverbindungen für %s"
+
+#~ msgid "From:"
+#~ msgstr "Von:"
+
+#~ msgid "Got rhythm?"
+#~ msgstr "Hast Du Rhythmus ?"
+
+#~ msgid "Recipients:"
+#~ msgstr "Adressaten:"
+
+#~ msgid "Subject:"
+#~ msgstr "Subjekt :"
+
+#~ msgid "What's new?"
+#~ msgstr "Was ist neu?"
+
+#~ msgid "You can use any of the following substitutions in your text"
+#~ msgstr "Sie können die folgenden Ersetzungen in Ihrem Text verwenden:"
+
#~ msgid "can't change the %s attribute"
#~ msgstr "Kann das Attribut %s nicht ändern."
+#~ msgid "cost"
+#~ msgstr "Kosten"
+
+#~ msgid "emails successfully sent"
+#~ msgstr "E-Mails erfolgreich versandt."
+
+#~ msgid "embed"
+#~ msgstr "einbetten"
+
+#~ msgid "embedding this url is forbidden"
+#~ msgstr "Einbettung dieses URLs ist nicht erlaubt."
+
+#~ msgid "error while embedding page"
+#~ msgstr "Fehler beim Einbetten der Seite"
+
+#~ msgid "eta_date"
+#~ msgstr "Enddatum"
+
+#~ msgid "expected:"
+#~ msgstr "erwartet:"
+
+#~ msgid "external page"
+#~ msgstr "externe Seite"
+
#~ msgid "incorrect value (%(value)s) for type \"%(type)s\""
#~ msgstr "Wert %(value)s ungültig für den Typ \"%(type)s\""
+#~ msgid "initial estimation %s"
+#~ msgstr "Erste Schätzung %s"
+
#~ msgid "invalid value %(value)s, it must be one of %(choices)s"
#~ msgstr "Wert %(value)s ungültig, er muss zwischen %(choices)s"
+
+#~ msgid "milestone"
+#~ msgstr "Meilenstein"
+
+#~ msgid "no related project"
+#~ msgstr "kein verknüpftes Projekt"
+
+#~ msgid "progress"
+#~ msgstr "Fortschritt"
+
+#~ msgid "progress bar"
+#~ msgstr "Fortschrittsbalken"
+
+#~ msgid "project"
+#~ msgstr "Projekt"
+
+#~ msgid "send email"
+#~ msgstr "E-Mail senden"
+
+#~ msgid "sioc"
+#~ msgstr "sioc"
+
+#~ msgid "task progression"
+#~ msgstr "Fortschritt der Aufgabe"
+
+#~ msgid "todo_by"
+#~ msgstr "zu erledigen bis"
+
+#~ msgid "toggle filter"
+#~ msgstr "filter verbergen/zeigen"
+
+#~ msgid "violates unique_together constraints (%s)"
+#~ msgstr "Verletzung der unique_together-Einschränkung (%s)"
+
+#~ msgid "workflow already have a state of that name"
+#~ msgstr "Der Workflow hat bereits einen Zustand desselben Namens."
+
+#~ msgid "workflow already have a transition of that name"
+#~ msgstr "Der Workflow hat bereits einen Übergang desselben Namens."
--- a/i18n/en.po Tue Jul 02 17:09:04 2013 +0200
+++ b/i18n/en.po Mon Jan 13 13:47:47 2014 +0100
@@ -106,7 +106,7 @@
msgstr ""
#, python-format
-msgid "%s not estimated"
+msgid "%s is part of violated unicity constraint"
msgstr ""
#, python-format
@@ -417,10 +417,6 @@
msgid "DEBUG"
msgstr ""
-#, python-format
-msgid "Data connection graph for %s"
-msgstr ""
-
msgid "Date"
msgstr "Date"
@@ -496,15 +492,9 @@
msgid "FormatConstraint"
msgstr "format constraint"
-msgid "From:"
-msgstr ""
-
msgid "Garbage collection information"
msgstr ""
-msgid "Got rhythm?"
-msgstr ""
-
msgid "Help"
msgstr ""
@@ -671,9 +661,6 @@
msgid "RQLVocabularyConstraint"
msgstr "RQL vocabulary constraint"
-msgid "Recipients:"
-msgstr ""
-
msgid "RegexpConstraint"
msgstr "regular expression constrainte"
@@ -735,9 +722,6 @@
msgid "SubWorkflowExitPoint_plural"
msgstr "subworkflow exit-points"
-msgid "Subject:"
-msgstr ""
-
msgid "Submit bug report"
msgstr ""
@@ -905,9 +889,6 @@
msgid "Web server"
msgstr ""
-msgid "What's new?"
-msgstr ""
-
msgid "Workflow"
msgstr "Workflow"
@@ -934,9 +915,6 @@
"content online with the widget below."
msgstr ""
-msgid "You can use any of the following substitutions in your text"
-msgstr ""
-
msgid "You can't change this relation"
msgstr ""
@@ -985,6 +963,9 @@
msgid "abstract base class for transitions"
msgstr ""
+msgid "action menu"
+msgstr ""
+
msgid "action(s) on this selection"
msgstr ""
@@ -1003,6 +984,9 @@
msgid "add Bookmark bookmarked_by CWUser object"
msgstr "bookmark"
+msgid "add CWAttribute add_permission RQLExpression subject"
+msgstr "rql expression for add permission"
+
msgid "add CWAttribute constrained_by CWConstraint subject"
msgstr "constraint"
@@ -1111,6 +1095,10 @@
msgid "add_permission"
msgstr "can be added by"
+msgctxt "CWAttribute"
+msgid "add_permission"
+msgstr "add permission"
+
# subject and object forms for each relation type
# (no object form for final relation types)
msgctxt "CWEType"
@@ -1145,6 +1133,9 @@
"%(eidto)s"
msgstr ""
+msgid "additional type specific properties"
+msgstr ""
+
msgid "addrelated"
msgstr "add"
@@ -1627,9 +1618,6 @@
"core relation indicating the types (including specialized types) of an entity"
msgstr ""
-msgid "cost"
-msgstr ""
-
msgid "could not connect to the SMTP server"
msgstr ""
@@ -1682,6 +1670,10 @@
msgstr "creating email address for user %(linkto)s"
msgid ""
+"creating RQLExpression (CWAttribute %(linkto)s add_permission RQLExpression)"
+msgstr "RQL expression granting add permission on %(linkto)s"
+
+msgid ""
"creating RQLExpression (CWAttribute %(linkto)s read_permission RQLExpression)"
msgstr "RQL expression granting read permission on %(linkto)s"
@@ -2056,6 +2048,9 @@
msgid "default value"
msgstr ""
+msgid "default value as gziped pickled python object"
+msgstr ""
+
msgid "default workflow for an entity type"
msgstr ""
@@ -2322,18 +2317,9 @@
msgid "eid"
msgstr ""
-msgid "emails successfully sent"
-msgstr ""
-
-msgid "embed"
-msgstr ""
-
msgid "embedded html"
msgstr ""
-msgid "embedding this url is forbidden"
-msgstr ""
-
msgid "end_timestamp"
msgstr "end timestamp"
@@ -2386,9 +2372,6 @@
msgid "error"
msgstr ""
-msgid "error while embedding page"
-msgstr ""
-
msgid "error while publishing ReST text"
msgstr ""
@@ -2396,9 +2379,6 @@
msgid "error while querying source %s, some data may be missing"
msgstr ""
-msgid "eta_date"
-msgstr "ETA date"
-
msgid "exit state must be a subworkflow state"
msgstr ""
@@ -2412,9 +2392,6 @@
msgid "exiting from subworkflow %s"
msgstr ""
-msgid "expected:"
-msgstr ""
-
msgid "expression"
msgstr ""
@@ -2429,7 +2406,11 @@
msgid "exprtype"
msgstr "expression type"
-msgid "external page"
+msgid "extra_props"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "extra_props"
msgstr ""
msgid "facet-loading-msg"
@@ -2828,10 +2809,6 @@
msgid "info"
msgstr ""
-#, python-format
-msgid "initial estimation %s"
-msgstr ""
-
msgid "initial state for this workflow"
msgstr ""
@@ -3098,9 +3075,6 @@
msgid "message"
msgstr ""
-msgid "milestone"
-msgstr ""
-
#, python-format
msgid "missing parameters for entity %s"
msgstr ""
@@ -3160,6 +3134,10 @@
msgid "name"
msgstr "name"
+msgctxt "CWUniqueTogetherConstraint"
+msgid "name"
+msgstr ""
+
msgctxt "State"
msgid "name"
msgstr "name"
@@ -3245,9 +3223,6 @@
msgid "no related entity"
msgstr ""
-msgid "no related project"
-msgstr ""
-
msgid "no repository sessions found"
msgstr ""
@@ -3446,15 +3421,6 @@
msgid "profile"
msgstr ""
-msgid "progress"
-msgstr ""
-
-msgid "progress bar"
-msgstr ""
-
-msgid "project"
-msgstr ""
-
msgid "rdef-description"
msgstr "description"
@@ -3720,9 +3686,6 @@
msgid "semantic description of this workflow"
msgstr ""
-msgid "send email"
-msgstr ""
-
msgid "september"
msgstr ""
@@ -3748,9 +3711,6 @@
msgid "show filter form"
msgstr ""
-msgid "sioc"
-msgstr ""
-
msgid "site configuration"
msgstr ""
@@ -3766,6 +3726,9 @@
msgid "some later transaction(s) touch entity, undo them first"
msgstr ""
+msgid "some relations violate a unicity constraint"
+msgstr ""
+
msgid "sorry, the server is unable to handle this query"
msgstr ""
@@ -3957,9 +3920,6 @@
msgid "tablefilter"
msgstr "table filter"
-msgid "task progression"
-msgstr ""
-
msgid "text"
msgstr ""
@@ -4081,15 +4041,9 @@
msgid "to_state_object"
msgstr "transitions to this state"
-msgid "todo_by"
-msgstr "to do by"
-
msgid "toggle check boxes"
msgstr ""
-msgid "toggle filter"
-msgstr ""
-
msgid "tr_count"
msgstr "transition number"
@@ -4371,6 +4325,14 @@
msgid "value %(KEY-value)s must be %(KEY-op)s %(KEY-boundary)s"
msgstr ""
+#, python-format
+msgid "value %(KEY-value)s must be <= %(KEY-boundary)s"
+msgstr ""
+
+#, python-format
+msgid "value %(KEY-value)s must be >= %(KEY-boundary)s"
+msgstr ""
+
msgid "value associated to this key is not editable manually"
msgstr ""
@@ -4412,10 +4374,6 @@
msgid "view_index"
msgstr "index"
-#, python-format
-msgid "violates unique_together constraints (%s)"
-msgstr "violates unique_together constraints (%s)"
-
msgid "visible"
msgstr ""
@@ -4425,6 +4383,9 @@
msgid "we are not yet ready to handle this query"
msgstr ""
+msgid "web sessions without CNX"
+msgstr ""
+
msgid "wednesday"
msgstr ""
@@ -4453,10 +4414,10 @@
msgid "workflow"
msgstr ""
-msgid "workflow already have a state of that name"
-msgstr ""
-
-msgid "workflow already have a transition of that name"
+msgid "workflow already has a state of that name"
+msgstr ""
+
+msgid "workflow already has a transition of that name"
msgstr ""
#, python-format
@@ -4521,3 +4482,12 @@
#, python-format
msgid "you should un-inline relation %s which is supported and may be crossed "
msgstr ""
+
+#~ msgid "eta_date"
+#~ msgstr "ETA date"
+
+#~ msgid "todo_by"
+#~ msgstr "to do by"
+
+#~ msgid "violates unique_together constraints (%s)"
+#~ msgstr "violates unique_together constraints (%s)"
--- a/i18n/es.po Tue Jul 02 17:09:04 2013 +0200
+++ b/i18n/es.po Mon Jan 13 13:47:47 2014 +0100
@@ -115,8 +115,8 @@
msgstr "%s reporte de errores"
#, python-format
-msgid "%s not estimated"
-msgstr "%s no estimado(s)"
+msgid "%s is part of violated unicity constraint"
+msgstr ""
#, python-format
msgid "%s relation should not be in mapped"
@@ -439,10 +439,6 @@
msgid "DEBUG"
msgstr ""
-#, python-format
-msgid "Data connection graph for %s"
-msgstr "Gráfica de conexión de datos para %s"
-
msgid "Date"
msgstr "Fecha"
@@ -518,15 +514,9 @@
msgid "FormatConstraint"
msgstr "Restricción de Formato"
-msgid "From:"
-msgstr "De: "
-
msgid "Garbage collection information"
msgstr "Recolector de basura en memoria"
-msgid "Got rhythm?"
-msgstr "Tenemos Ritmo?"
-
msgid "Help"
msgstr "Ayuda"
@@ -693,9 +683,6 @@
msgid "RQLVocabularyConstraint"
msgstr "Restricción RQL de Vocabulario"
-msgid "Recipients:"
-msgstr "Destinatarios :"
-
msgid "RegexpConstraint"
msgstr "restricción expresión regular"
@@ -760,9 +747,6 @@
msgid "SubWorkflowExitPoint_plural"
msgstr "Salidas de sub-workflow"
-msgid "Subject:"
-msgstr "Sujeto:"
-
msgid "Submit bug report"
msgstr "Enviar un reporte de error (bug)"
@@ -932,9 +916,6 @@
msgid "Web server"
msgstr "Servidor web"
-msgid "What's new?"
-msgstr "Lo más reciente"
-
msgid "Workflow"
msgstr "Workflow"
@@ -968,11 +949,6 @@
"\"buscar\" en la parte superior, o editar el contenido del archivo en línea\n"
"en el campo siguiente."
-msgid "You can use any of the following substitutions in your text"
-msgstr ""
-"Puede realizar cualquiera de las siguientes sustituciones en el contenido de "
-"su email."
-
msgid "You can't change this relation"
msgstr ""
@@ -1033,6 +1009,9 @@
msgid "abstract base class for transitions"
msgstr "Clase de base abstracta para la transiciones"
+msgid "action menu"
+msgstr ""
+
msgid "action(s) on this selection"
msgstr "Acción(es) en esta selección"
@@ -1051,6 +1030,9 @@
msgid "add Bookmark bookmarked_by CWUser object"
msgstr "Agregar a los favoritos "
+msgid "add CWAttribute add_permission RQLExpression subject"
+msgstr ""
+
msgid "add CWAttribute constrained_by CWConstraint subject"
msgstr "Restricción"
@@ -1159,6 +1141,10 @@
msgid "add_permission"
msgstr "Autorización para agregar"
+msgctxt "CWAttribute"
+msgid "add_permission"
+msgstr ""
+
# subject and object forms for each relation type
# (no object form for final relation types)
msgctxt "CWEType"
@@ -1195,6 +1181,9 @@
"la relación %(rtype)s de %(frometype)s #%(eidfrom)s a %(toetype)s #%(eidto)s "
"ha sido agregada"
+msgid "additional type specific properties"
+msgstr ""
+
msgid "addrelated"
msgstr "Agregar"
@@ -1692,9 +1681,6 @@
"Relación sistema indicando los tipos (incluídos los tipos padres) de una "
"entidad"
-msgid "cost"
-msgstr "Costo"
-
msgid "could not connect to the SMTP server"
msgstr "Imposible de conectarse al servidor SMTP"
@@ -1747,6 +1733,10 @@
msgstr "Creación de una dirección electrónica para el usuario %(linkto)s"
msgid ""
+"creating RQLExpression (CWAttribute %(linkto)s add_permission RQLExpression)"
+msgstr ""
+
+msgid ""
"creating RQLExpression (CWAttribute %(linkto)s read_permission RQLExpression)"
msgstr "creación de una expresión RQL por el derecho de lectura de %(linkto)s"
@@ -2129,6 +2119,9 @@
msgid "default value"
msgstr "Valor por defecto"
+msgid "default value as gziped pickled python object"
+msgstr ""
+
msgid "default workflow for an entity type"
msgstr "Workflow por defecto para un tipo de entidad"
@@ -2412,18 +2405,9 @@
msgid "eid"
msgstr "eid"
-msgid "emails successfully sent"
-msgstr "Mensajes enviados con éxito"
-
-msgid "embed"
-msgstr "Incrustado"
-
msgid "embedded html"
msgstr "Html incrustado"
-msgid "embedding this url is forbidden"
-msgstr "La inclusión de este url esta prohibida"
-
msgid "end_timestamp"
msgstr ""
@@ -2478,9 +2462,6 @@
msgid "error"
msgstr "error"
-msgid "error while embedding page"
-msgstr "Error durante la inclusión de la página"
-
msgid "error while publishing ReST text"
msgstr ""
"Se ha producido un error durante la interpretación del texto en formato ReST"
@@ -2491,9 +2472,6 @@
"Un error ha ocurrido al interrogar %s, es posible que los \n"
"datos visibles se encuentren incompletos"
-msgid "eta_date"
-msgstr "Fecha de fin"
-
msgid "exit state must be a subworkflow state"
msgstr "El estado de salida debe de ser un estado del Sub-Workflow"
@@ -2507,9 +2485,6 @@
msgid "exiting from subworkflow %s"
msgstr "Salida del subworkflow %s"
-msgid "expected:"
-msgstr "Previsto :"
-
msgid "expression"
msgstr "Expresión"
@@ -2524,8 +2499,12 @@
msgid "exprtype"
msgstr "Tipo"
-msgid "external page"
-msgstr "Página externa"
+msgid "extra_props"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "extra_props"
+msgstr ""
msgid "facet-loading-msg"
msgstr ""
@@ -2942,10 +2921,6 @@
msgid "info"
msgstr "Información del Sistema"
-#, python-format
-msgid "initial estimation %s"
-msgstr "Estimación inicial %s"
-
msgid "initial state for this workflow"
msgstr "Estado inicial para este Workflow"
@@ -3221,9 +3196,6 @@
msgid "message"
msgstr ""
-msgid "milestone"
-msgstr "Milestone"
-
#, python-format
msgid "missing parameters for entity %s"
msgstr "Parámetros faltantes a la entidad %s"
@@ -3283,6 +3255,10 @@
msgid "name"
msgstr ""
+msgctxt "CWUniqueTogetherConstraint"
+msgid "name"
+msgstr ""
+
msgctxt "State"
msgid "name"
msgstr "nombre"
@@ -3370,9 +3346,6 @@
msgid "no related entity"
msgstr "No posee entidad asociada"
-msgid "no related project"
-msgstr "No tiene proyecto relacionado"
-
msgid "no repository sessions found"
msgstr "Ninguna sesión encontrada"
@@ -3572,15 +3545,6 @@
msgid "profile"
msgstr "perfil"
-msgid "progress"
-msgstr "Progreso"
-
-msgid "progress bar"
-msgstr "Barra de Progreso"
-
-msgid "project"
-msgstr "Proyecto"
-
msgid "rdef-description"
msgstr "Descripción"
@@ -3858,9 +3822,6 @@
msgid "semantic description of this workflow"
msgstr "Descripcion semántica de este Workflow"
-msgid "send email"
-msgstr "Enviar email"
-
msgid "september"
msgstr "Septiembre"
@@ -3890,9 +3851,6 @@
msgid "show filter form"
msgstr "Mostrar el Filtro"
-msgid "sioc"
-msgstr "SIOC"
-
msgid "site configuration"
msgstr "Configuración Sistema"
@@ -3909,6 +3867,9 @@
msgstr ""
"Las transacciones más recientes modificaron esta entidad, anúlelas primero"
+msgid "some relations violate a unicity constraint"
+msgstr ""
+
msgid "sorry, the server is unable to handle this query"
msgstr "Lo sentimos, el servidor no puede manejar esta consulta"
@@ -4106,9 +4067,6 @@
msgid "tablefilter"
msgstr "Tablero de Filtrado"
-msgid "task progression"
-msgstr "Progreso de la Acción"
-
msgid "text"
msgstr "Texto"
@@ -4231,15 +4189,9 @@
msgid "to_state_object"
msgstr "Transición hacia este Estado"
-msgid "todo_by"
-msgstr "Asignada a"
-
msgid "toggle check boxes"
msgstr "Cambiar valor"
-msgid "toggle filter"
-msgstr "esconder/mostrar el filtro"
-
msgid "tr_count"
msgstr "n° de transición"
@@ -4530,6 +4482,14 @@
msgid "value %(KEY-value)s must be %(KEY-op)s %(KEY-boundary)s"
msgstr ""
+#, python-format
+msgid "value %(KEY-value)s must be <= %(KEY-boundary)s"
+msgstr ""
+
+#, python-format
+msgid "value %(KEY-value)s must be >= %(KEY-boundary)s"
+msgstr ""
+
msgid "value associated to this key is not editable manually"
msgstr "El valor asociado a este elemento no es editable manualmente"
@@ -4571,10 +4531,6 @@
msgid "view_index"
msgstr "Inicio"
-#, python-format
-msgid "violates unique_together constraints (%s)"
-msgstr "viola el principio (o restricción) de singularidad (%s)"
-
msgid "visible"
msgstr "Visible"
@@ -4584,6 +4540,9 @@
msgid "we are not yet ready to handle this query"
msgstr "Aún no podemos manejar este tipo de consulta Sparql"
+msgid "web sessions without CNX"
+msgstr ""
+
msgid "wednesday"
msgstr "Miércoles"
@@ -4615,11 +4574,11 @@
msgid "workflow"
msgstr "Workflow"
-msgid "workflow already have a state of that name"
-msgstr "El Workflow ya tiene un Estado con ese nombre"
-
-msgid "workflow already have a transition of that name"
-msgstr "El Workflow ya tiene una transición con ese nombre"
+msgid "workflow already has a state of that name"
+msgstr ""
+
+msgid "workflow already has a transition of that name"
+msgstr ""
#, python-format
msgid "workflow changed to \"%s\""
@@ -4692,6 +4651,9 @@
#~ msgid "%(value)r doesn't match the %(regexp)r regular expression"
#~ msgstr "%(value)r no corresponde a la expresión regular %(regexp)r"
+#~ msgid "%s not estimated"
+#~ msgstr "%s no estimado(s)"
+
#~ msgid ""
#~ "Can't restore relation %(rtype)s of entity %(eid)s, this relation does "
#~ "not exists anymore in the schema."
@@ -4699,17 +4661,106 @@
#~ "No puede restaurar la relación %(rtype)s de la entidad %(eid)s, esta "
#~ "relación ya no existe en el esquema."
+#~ msgid "Data connection graph for %s"
+#~ msgstr "Gráfica de conexión de datos para %s"
+
+#~ msgid "From:"
+#~ msgstr "De: "
+
+#~ msgid "Got rhythm?"
+#~ msgstr "Tenemos Ritmo?"
+
+#~ msgid "Recipients:"
+#~ msgstr "Destinatarios :"
+
+#~ msgid "Subject:"
+#~ msgstr "Sujeto:"
+
+#~ msgid "What's new?"
+#~ msgstr "Lo más reciente"
+
+#~ msgid "You can use any of the following substitutions in your text"
+#~ msgstr ""
+#~ "Puede realizar cualquiera de las siguientes sustituciones en el contenido "
+#~ "de su email."
+
#~ msgid "can't change the %s attribute"
#~ msgstr "no puede modificar el atributo %s"
#~ msgid "can't change this relation"
#~ msgstr "no puede modificar esta relación"
+#~ msgid "cost"
+#~ msgstr "Costo"
+
+#~ msgid "emails successfully sent"
+#~ msgstr "Mensajes enviados con éxito"
+
+#~ msgid "embed"
+#~ msgstr "Incrustado"
+
+#~ msgid "embedding this url is forbidden"
+#~ msgstr "La inclusión de este url esta prohibida"
+
+#~ msgid "error while embedding page"
+#~ msgstr "Error durante la inclusión de la página"
+
+#~ msgid "eta_date"
+#~ msgstr "Fecha de fin"
+
+#~ msgid "expected:"
+#~ msgstr "Previsto :"
+
+#~ msgid "external page"
+#~ msgstr "Página externa"
+
#~ msgid "incorrect value (%(value)s) for type \"%(type)s\""
#~ msgstr "valor %(value)s incorrecto para el tipo \"%(type)s\""
+#~ msgid "initial estimation %s"
+#~ msgstr "Estimación inicial %s"
+
#~ msgid "invalid value %(value)s, it must be one of %(choices)s"
#~ msgstr "Valor %(value)s incorrecto, debe estar entre %(choices)s"
+#~ msgid "milestone"
+#~ msgstr "Milestone"
+
+#~ msgid "no related project"
+#~ msgstr "No tiene proyecto relacionado"
+
+#~ msgid "progress"
+#~ msgstr "Progreso"
+
+#~ msgid "progress bar"
+#~ msgstr "Barra de Progreso"
+
+#~ msgid "project"
+#~ msgstr "Proyecto"
+
+#~ msgid "send email"
+#~ msgstr "Enviar email"
+
+#~ msgid "sioc"
+#~ msgstr "SIOC"
+
+#~ msgid "task progression"
+#~ msgstr "Progreso de la Acción"
+
+#~ msgid "todo_by"
+#~ msgstr "Asignada a"
+
+#~ msgid "toggle filter"
+#~ msgstr "esconder/mostrar el filtro"
+
#~ msgid "unknown source type"
#~ msgstr "tipo de fuente desconocida"
+
+#~ msgid "violates unique_together constraints (%s)"
+#~ msgstr "viola el principio (o restricción) de singularidad (%s)"
+
+#~ msgid "workflow already have a state of that name"
+#~ msgstr "El Workflow ya tiene un Estado con ese nombre"
+
+#~ msgid "workflow already have a transition of that name"
+#~ msgstr "El Workflow ya tiene una transición con ese nombre"
--- a/i18n/fr.po Tue Jul 02 17:09:04 2013 +0200
+++ b/i18n/fr.po Mon Jan 13 13:47:47 2014 +0100
@@ -115,8 +115,8 @@
msgstr "%s rapport d'erreur"
#, python-format
-msgid "%s not estimated"
-msgstr "%s non estimé(s)"
+msgid "%s is part of violated unicity constraint"
+msgstr "%s appartient à une contrainte d'unicité transgressée"
#, python-format
msgid "%s relation should not be in mapped"
@@ -432,6 +432,8 @@
"Configuration of the system source goes to the 'sources' file, not in the "
"database"
msgstr ""
+"La configuration de la source système va dans le fichier 'sources' et non "
+"dans la base de données"
#, python-format
msgid "Created %(etype)s : %(entity)s"
@@ -440,10 +442,6 @@
msgid "DEBUG"
msgstr "DEBUG"
-#, python-format
-msgid "Data connection graph for %s"
-msgstr "Graphique de connection des données pour %s"
-
msgid "Date"
msgstr "Date"
@@ -519,15 +517,9 @@
msgid "FormatConstraint"
msgstr "contrainte de format"
-msgid "From:"
-msgstr "De :"
-
msgid "Garbage collection information"
msgstr "Information sur le ramasse-miette"
-msgid "Got rhythm?"
-msgstr "T'as le rythme ?"
-
msgid "Help"
msgstr "Aide"
@@ -694,9 +686,6 @@
msgid "RQLVocabularyConstraint"
msgstr "contrainte rql de vocabulaire"
-msgid "Recipients:"
-msgstr "Destinataires :"
-
msgid "RegexpConstraint"
msgstr "contrainte expression régulière"
@@ -761,9 +750,6 @@
msgid "SubWorkflowExitPoint_plural"
msgstr "Sorties de sous-workflow"
-msgid "Subject:"
-msgstr "Sujet :"
-
msgid "Submit bug report"
msgstr "Soumettre un rapport de bug"
@@ -935,9 +921,6 @@
msgid "Web server"
msgstr "Serveur web"
-msgid "What's new?"
-msgstr "Nouveautés"
-
msgid "Workflow"
msgstr "Workflow"
@@ -971,11 +954,6 @@
"\"parcourir\" ci-dessu, soit éditer le contenu du fichier en ligne\n"
"avec le champ ci-dessous."
-msgid "You can use any of the following substitutions in your text"
-msgstr ""
-"Vous pouvez utiliser n'importe quelle substitution parmi la liste suivante "
-"dans le contenu de votre courriel."
-
msgid "You can't change this relation"
msgstr "Vous ne pouvez pas modifier cette relation"
@@ -1036,6 +1014,9 @@
msgid "abstract base class for transitions"
msgstr "classe de base abstraite pour les transitions"
+msgid "action menu"
+msgstr "actions"
+
msgid "action(s) on this selection"
msgstr "action(s) sur cette sélection"
@@ -1054,6 +1035,9 @@
msgid "add Bookmark bookmarked_by CWUser object"
msgstr "signet"
+msgid "add CWAttribute add_permission RQLExpression subject"
+msgstr "définir une expression RQL d'ajout"
+
msgid "add CWAttribute constrained_by CWConstraint subject"
msgstr "contrainte"
@@ -1162,6 +1146,10 @@
msgid "add_permission"
msgstr "peut ajouter"
+msgctxt "CWAttribute"
+msgid "add_permission"
+msgstr "permission d'ajout"
+
# subject and object forms for each relation type
# (no object form for final relation types)
msgctxt "CWEType"
@@ -1198,6 +1186,9 @@
"la relation %(rtype)s de %(frometype)s #%(eidfrom)s vers %(toetype)s #"
"%(eidto)s a été ajoutée"
+msgid "additional type specific properties"
+msgstr "propriétés supplémentaires spécifiques au type"
+
msgid "addrelated"
msgstr "ajouter"
@@ -1704,9 +1695,6 @@
"relation système indiquant les types (y compris les types parents) d'une "
"entité"
-msgid "cost"
-msgstr "coût"
-
msgid "could not connect to the SMTP server"
msgstr "impossible de se connecter au serveur SMTP"
@@ -1759,6 +1747,10 @@
msgstr "création d'une adresse électronique pour l'utilisateur %(linkto)s"
msgid ""
+"creating RQLExpression (CWAttribute %(linkto)s add_permission RQLExpression)"
+msgstr "création d'une expression rql pour le droit d'ajout de %(linkto)s"
+
+msgid ""
"creating RQLExpression (CWAttribute %(linkto)s read_permission RQLExpression)"
msgstr "création d'une expression rql pour le droit de lecture de %(linkto)s"
@@ -2143,6 +2135,9 @@
msgid "default value"
msgstr "valeur par défaut"
+msgid "default value as gziped pickled python object"
+msgstr "valeur par défaut, sous forme d'objet python picklé zippé"
+
msgid "default workflow for an entity type"
msgstr "workflow par défaut pour un type d'entité"
@@ -2423,18 +2418,9 @@
msgid "eid"
msgstr "eid"
-msgid "emails successfully sent"
-msgstr "courriels envoyés avec succès"
-
-msgid "embed"
-msgstr "embarqué"
-
msgid "embedded html"
msgstr "HTML contenu"
-msgid "embedding this url is forbidden"
-msgstr "l'inclusion de cette url est interdite"
-
msgid "end_timestamp"
msgstr "horodate de fin"
@@ -2489,9 +2475,6 @@
msgid "error"
msgstr "erreur"
-msgid "error while embedding page"
-msgstr "erreur pendant l'inclusion de la page"
-
msgid "error while publishing ReST text"
msgstr ""
"une erreur s'est produite lors de l'interprétation du texte au format ReST"
@@ -2502,9 +2485,6 @@
"une erreur est survenue en interrogeant %s, il est possible que les\n"
"données affichées soient incomplètes"
-msgid "eta_date"
-msgstr "date de fin"
-
msgid "exit state must be a subworkflow state"
msgstr "l'état de sortie doit être un état du sous-workflow"
@@ -2518,9 +2498,6 @@
msgid "exiting from subworkflow %s"
msgstr "sortie du sous-workflow %s"
-msgid "expected:"
-msgstr "attendu :"
-
msgid "expression"
msgstr "expression"
@@ -2535,8 +2512,12 @@
msgid "exprtype"
msgstr "type"
-msgid "external page"
-msgstr "page externe"
+msgid "extra_props"
+msgstr ""
+
+msgctxt "CWAttribute"
+msgid "extra_props"
+msgstr "propriétés additionnelles"
msgid "facet-loading-msg"
msgstr "en cours de traitement, merci de patienter"
@@ -2951,10 +2932,6 @@
msgid "info"
msgstr "information"
-#, python-format
-msgid "initial estimation %s"
-msgstr "estimation initiale %s"
-
msgid "initial state for this workflow"
msgstr "état initial pour ce workflow"
@@ -3232,9 +3209,6 @@
msgid "message"
msgstr "message"
-msgid "milestone"
-msgstr "jalon"
-
#, python-format
msgid "missing parameters for entity %s"
msgstr "paramètres manquants pour l'entité %s"
@@ -3294,6 +3268,10 @@
msgid "name"
msgstr "nom"
+msgctxt "CWUniqueTogetherConstraint"
+msgid "name"
+msgstr "nom"
+
msgctxt "State"
msgid "name"
msgstr "nom"
@@ -3381,9 +3359,6 @@
msgid "no related entity"
msgstr "pas d'entité liée"
-msgid "no related project"
-msgstr "pas de projet rattaché"
-
msgid "no repository sessions found"
msgstr "aucune session trouvée"
@@ -3585,15 +3560,6 @@
msgid "profile"
msgstr "profil"
-msgid "progress"
-msgstr "avancement"
-
-msgid "progress bar"
-msgstr "barre d'avancement"
-
-msgid "project"
-msgstr "projet"
-
msgid "rdef-description"
msgstr "description"
@@ -3872,9 +3838,6 @@
msgid "semantic description of this workflow"
msgstr "description sémantique de ce workflow"
-msgid "send email"
-msgstr "envoyer un courriel"
-
msgid "september"
msgstr "septembre"
@@ -3903,9 +3866,6 @@
msgid "show filter form"
msgstr "afficher le filtre"
-msgid "sioc"
-msgstr "sioc"
-
msgid "site configuration"
msgstr "configuration du site"
@@ -3922,6 +3882,9 @@
msgstr ""
"des transactions plus récentes modifient cette entité, annulez les d'abord"
+msgid "some relations violate a unicity constraint"
+msgstr "certaines relations transgressent une contrainte d'unicité"
+
msgid "sorry, the server is unable to handle this query"
msgstr "désolé, le serveur ne peut traiter cette requête"
@@ -4121,9 +4084,6 @@
msgid "tablefilter"
msgstr "filtre de tableau"
-msgid "task progression"
-msgstr "avancement de la tâche"
-
msgid "text"
msgstr "text"
@@ -4246,15 +4206,9 @@
msgid "to_state_object"
msgstr "transition vers cet état"
-msgid "todo_by"
-msgstr "à faire par"
-
msgid "toggle check boxes"
msgstr "afficher/masquer les cases à cocher"
-msgid "toggle filter"
-msgstr "afficher/masquer le filtre"
-
msgid "tr_count"
msgstr "n° de transition"
@@ -4543,6 +4497,16 @@
msgid "value %(KEY-value)s must be %(KEY-op)s %(KEY-boundary)s"
msgstr "la valeur %(KEY-value)s n'est pas %(KEY-op)s %(KEY-boundary)s"
+#, python-format
+msgid "value %(KEY-value)s must be <= %(KEY-boundary)s"
+msgstr ""
+"la valeur %(KEY-value)s n'est pas inférieure ou égale à %(KEY-boundary)s"
+
+#, python-format
+msgid "value %(KEY-value)s must be >= %(KEY-boundary)s"
+msgstr ""
+"la valeur %(KEY-value)s n'est pas supérieure ou égale à %(KEY-boundary)s"
+
msgid "value associated to this key is not editable manually"
msgstr "la valeur associée à cette clé n'est pas éditable manuellement"
@@ -4588,10 +4552,6 @@
msgid "view_index"
msgstr "accueil"
-#, python-format
-msgid "violates unique_together constraints (%s)"
-msgstr "violation de contrainte unique_together (%s)"
-
msgid "visible"
msgstr "visible"
@@ -4602,6 +4562,9 @@
msgstr ""
"nous ne sommes pas capable de gérer ce type de requête sparql pour le moment"
+msgid "web sessions without CNX"
+msgstr "sessions web sans connexion associée"
+
msgid "wednesday"
msgstr "mercredi"
@@ -4633,10 +4596,10 @@
msgid "workflow"
msgstr "workflow"
-msgid "workflow already have a state of that name"
+msgid "workflow already has a state of that name"
msgstr "le workflow a déja un état du même nom"
-msgid "workflow already have a transition of that name"
+msgid "workflow already has a transition of that name"
msgstr "le workflow a déja une transition du même nom"
#, python-format
@@ -4703,27 +4666,3 @@
msgstr ""
"vous devriez enlevé la mise en ligne de la relation %s qui est supportée et "
"peut-être croisée"
-
-#~ msgid "Action"
-#~ msgstr "Action"
-
-#~ msgid "day"
-#~ msgstr "jour"
-
-#~ msgid "jump to selection"
-#~ msgstr "afficher cette sélection"
-
-#~ msgid "log out first"
-#~ msgstr "déconnecter vous d'abord"
-
-#~ msgid "month"
-#~ msgstr "mois"
-
-#~ msgid "today"
-#~ msgstr "aujourd'hui"
-
-#~ msgid "undo last change"
-#~ msgstr "annuler dernier changement"
-
-#~ msgid "week"
-#~ msgstr "semaine"
--- a/interfaces.py Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""Standard interfaces. Deprecated in favor of adapters.
-
-.. note::
-
- The `implements` selector used to match not only entity classes but also their
- interfaces. This will disappear in a future version. You should define an
- adapter for that interface and use `adaptable('MyIFace')` selector on appobjects
- that require that interface.
-
-"""
-__docformat__ = "restructuredtext en"
-
-from logilab.common.interface import Interface
-
-
-# XXX deprecates in favor of IProgressAdapter
-class IProgress(Interface):
- """something that has a cost, a state and a progression"""
-
- @property
- def cost(self):
- """the total cost"""
-
- @property
- def done(self):
- """what is already done"""
-
- @property
- def todo(self):
- """what remains to be done"""
-
- def progress_info(self):
- """returns a dictionary describing progress/estimated cost of the
- version.
-
- - mandatory keys are (''estimated', 'done', 'todo')
-
- - optional keys are ('notestimated', 'notestimatedcorrected',
- 'estimatedcorrected')
-
- 'noestimated' and 'notestimatedcorrected' should default to 0
- 'estimatedcorrected' should default to 'estimated'
- """
-
- def finished(self):
- """returns True if status is finished"""
-
- def in_progress(self):
- """returns True if status is not finished"""
-
- def progress(self):
- """returns the % progress of the task item"""
-
-# XXX deprecates in favor of IMileStoneAdapter
-class IMileStone(IProgress):
- """represents an ITask's item"""
-
- parent_type = None # specify main task's type
-
- def get_main_task(self):
- """returns the main ITask entity"""
-
- def initial_prevision_date(self):
- """returns the initial expected end of the milestone"""
-
- def eta_date(self):
- """returns expected date of completion based on what remains
- to be done
- """
-
- def completion_date(self):
- """returns date on which the subtask has been completed"""
-
- def contractors(self):
- """returns the list of persons supposed to work on this task"""
-
-# XXX deprecates in favor of IEmbedableAdapter
-class IEmbedable(Interface):
- """interface for embedable entities"""
-
- def embeded_url(self):
- """embed action interface"""
-
-# XXX deprecates in favor of ICalendarViewsAdapter
-class ICalendarViews(Interface):
- """calendar views interface"""
- def matching_dates(self, begin, end):
- """
- :param begin: day considered as begin of the range (`DateTime`)
- :param end: day considered as end of the range (`DateTime`)
-
- :return:
- a list of dates (`DateTime`) in the range [`begin`, `end`] on which
- this entity apply
- """
-
-# XXX deprecates in favor of ICalendarableAdapter
-class ICalendarable(Interface):
- """interface for items that do have a begin date 'start' and an end date 'stop'
- """
-
- @property
- def start(self):
- """return start date"""
-
- @property
- def stop(self):
- """return stop state"""
-
-# XXX deprecates in favor of ICalendarableAdapter
-class ITimetableViews(Interface):
- """timetable views interface"""
- def timetable_date(self):
- """XXX explain
-
- :return: date (`DateTime`)
- """
-
-# XXX deprecates in favor of IGeocodableAdapter
-class IGeocodable(Interface):
- """interface required by geocoding views such as gmap-view"""
-
- @property
- def latitude(self):
- """returns the latitude of the entity"""
-
- @property
- def longitude(self):
- """returns the longitude of the entity"""
-
- def marker_icon(self):
- """returns the icon that should be used as the marker"""
-
-
-# XXX deprecates in favor of IEmailableAdapter
-class IFeed(Interface):
- """interface for entities with rss flux"""
-
- def rss_feed_url(self):
- """"""
-
-# XXX deprecates in favor of IDownloadableAdapter
-class IDownloadable(Interface):
- """interface for downloadable entities"""
-
- def download_url(self): # XXX not really part of this interface
- """return an url to download entity's content"""
- def download_content_type(self):
- """return MIME type of the downloadable content"""
- def download_encoding(self):
- """return encoding of the downloadable content"""
- def download_file_name(self):
- """return file name of the downloadable content"""
- def download_data(self):
- """return actual data of the downloadable content"""
-
-# XXX deprecates in favor of IPrevNextAdapter
-class IPrevNext(Interface):
- """interface for entities which can be linked to a previous and/or next
- entity
- """
-
- def next_entity(self):
- """return the 'next' entity"""
- def previous_entity(self):
- """return the 'previous' entity"""
-
-# XXX deprecates in favor of IBreadCrumbsAdapter
-class IBreadCrumbs(Interface):
-
- def breadcrumbs(self, view, recurs=False):
- pass
-
-# XXX deprecates in favor of ITreeAdapter
-class ITree(Interface):
-
- def parent(self):
- """returns the parent entity"""
-
- def children(self):
- """returns the item's children"""
-
- def children_rql(self):
- """XXX returns RQL to get children"""
-
- def iterchildren(self):
- """iterates over the item's children"""
-
- def is_leaf(self):
- """returns true if this node as no child"""
-
- def is_root(self):
- """returns true if this node has no parent"""
-
- def root(self):
- """returns the root object"""
-
--- a/mail.py Tue Jul 02 17:09:04 2013 +0200
+++ b/mail.py Mon Jan 13 13:47:47 2014 +0100
@@ -90,7 +90,7 @@
email = u''
if uinfo.get('name'):
name = uinfo['name']
- elif config and config['sender-addr']:
+ elif config and config['sender-name']:
name = unicode(config['sender-name'])
else:
name = u''
--- a/migration.py Tue Jul 02 17:09:04 2013 +0200
+++ b/migration.py Mon Jan 13 13:47:47 2014 +0100
@@ -257,7 +257,7 @@
home_key = 'HOME'
if sys.platform == 'win32':
home_key = 'USERPROFILE'
- histfile = os.path.join(os.environ[home_key], ".eshellhist")
+ histfile = os.path.join(os.environ[home_key], ".cwshell_history")
try:
readline.read_history_file(histfile)
except IOError:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.17.11_Any.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,7 @@
+for table, column in [
+ ('transactions', 'tx_time'),
+ ('tx_entity_actions', 'tx_uuid'),
+ ('tx_relation_actions', 'tx_uuid')]:
+ session.cnxset.source('system').create_index(session, table, column)
+
+commit()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.18.0_Any.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,129 @@
+driver = config.sources()['system']['db-driver']
+if not (driver == 'postgres' or driver.startswith('sqlserver')):
+ import sys
+ print >>sys.stderr, 'This migration is not supported for backends other than sqlserver or postgres (yet).'
+ sys.exit(1)
+
+sync_schema_props_perms('defaultval')
+
+def convert_defaultval(cwattr, default):
+ from decimal import Decimal
+ import yams
+ from cubicweb import Binary
+ if default is None:
+ return
+ atype = cwattr.to_entity[0].name
+ if atype == 'Boolean':
+ # boolean attributes with default=False were stored as ''
+ assert default in ('True', 'False', ''), repr(default)
+ default = default == 'True'
+ elif atype in ('Int', 'BigInt'):
+ default = int(default)
+ elif atype == 'Float':
+ default = float(default)
+ elif atype == 'Decimal':
+ default = Decimal(default)
+ elif atype in ('Date', 'Datetime', 'TZDatetime', 'Time'):
+ try:
+ # handle NOW and TODAY, keep them stored as strings
+ yams.KEYWORD_MAP[atype][default.upper()]
+ default = default.upper()
+ except KeyError:
+ # otherwise get an actual date or datetime
+ default = yams.DATE_FACTORY_MAP[atype](default)
+ else:
+ assert atype == 'String', atype
+ default = unicode(default)
+ return Binary.zpickle(default)
+
+dbh = repo.system_source.dbhelper
+
+
+sql('ALTER TABLE cw_cwattribute ADD new_defaultval %s' % dbh.TYPE_MAPPING['Bytes'])
+
+for cwattr in rql('CWAttribute X').entities():
+ olddefault = cwattr.defaultval
+ if olddefault is not None:
+ req = "UPDATE cw_cwattribute SET new_defaultval = %(val)s WHERE cw_eid = %(eid)s"
+ args = {'val': dbh.binary_value(convert_defaultval(cwattr, olddefault).getvalue()), 'eid': cwattr.eid}
+ sql(req, args, ask_confirm=False)
+
+sql('ALTER TABLE cw_cwattribute DROP COLUMN cw_defaultval')
+if driver == 'postgres':
+ sql('ALTER TABLE cw_cwattribute RENAME COLUMN new_defaultval TO cw_defaultval')
+else: # sqlserver
+ sql("sp_rename 'cw_cwattribute.new_defaultval', 'cw_defaultval', 'COLUMN'")
+
+
+# Set object type to "Bytes" for CWAttribute's "defaultval" attribute
+rql('SET X to_entity B WHERE X is CWAttribute, X from_entity Y, Y name "CWAttribute", '
+ 'X relation_type Z, Z name "defaultval", B name "Bytes"')
+
+from yams import buildobjs as ybo
+schema.add_relation_def(ybo.RelationDefinition('CWAttribute', 'defaultval', 'Bytes'))
+schema.del_relation_def('CWAttribute', 'defaultval', 'String')
+
+commit()
+
+for rschema in schema.relations():
+ if rschema.symmetric:
+ subjects = set(repr(e.type) for e in rschema.subjects())
+ objects = set(repr(e.type) for e in rschema.objects())
+ assert subjects == objects
+ martians = set(str(eid) for eid, in sql('SELECT eid_to FROM %s_relation, entities WHERE eid_to = eid AND type NOT IN (%s)' %
+ (rschema.type, ','.join(subjects))))
+ martians |= set(str(eid) for eid, in sql('SELECT eid_from FROM %s_relation, entities WHERE eid_from = eid AND type NOT IN (%s)' %
+ (rschema.type, ','.join(subjects))))
+ if martians:
+ martians = ','.join(martians)
+ print 'deleting broken relations %s for eids %s' % (rschema.type, martians)
+ sql('DELETE FROM %s_relation WHERE eid_from IN (%s) OR eid_to IN (%s)' % (rschema.type, martians, martians))
+ with session.deny_all_hooks_but():
+ rql('SET X %(r)s Y WHERE Y %(r)s X, NOT X %(r)s Y' % {'r': rschema.type})
+ commit()
+
+
+# multi columns unique constraints regeneration
+from cubicweb.server import schemaserial
+
+# syncschema hooks would try to remove indices but
+# 1) we already do that below
+# 2) the hook expects the CWUniqueTogetherConstraint.name attribute that hasn't
+# yet been added
+with session.allow_all_hooks_but('syncschema'):
+ rql('DELETE CWUniqueTogetherConstraint C')
+commit()
+
+add_attribute('CWUniqueTogetherConstraint', 'name')
+
+# low-level wipe code for postgres & sqlserver, plain sql ...
+if driver == 'postgres':
+ for indexname, in sql('select indexname from pg_indexes'):
+ if indexname.startswith('unique_'):
+ print 'dropping index', indexname
+ sql('DROP INDEX %s' % indexname)
+ commit()
+elif driver.startswith('sqlserver'):
+ for viewname, in sql('select name from sys.views'):
+ if viewname.startswith('utv_'):
+ print 'dropping view (index should be cascade-deleted)', viewname
+ sql('DROP VIEW %s' % viewname)
+ commit()
+
+# recreate the constraints, hook will lead to low-level recreation
+for eschema in sorted(schema.entities()):
+ if eschema._unique_together:
+ rql_args = schemaserial.uniquetogether2rqls(eschema)
+ for rql, args in rql_args:
+ args['x'] = eschema.eid
+ session.execute(rql, args)
+ commit()
+
+
+add_relation_definition('CWAttribute', 'add_permission', 'CWGroup')
+add_relation_definition('CWAttribute', 'add_permission', 'RQLExpression')
+
+# all attributes perms have to be refreshed ...
+for rschema in schema.relations():
+ if relation.final:
+ sync_schema_props_perms(rschema.type, syncprops=False)
--- a/misc/migration/bootstrapmigration_repository.py Tue Jul 02 17:09:04 2013 +0200
+++ b/misc/migration/bootstrapmigration_repository.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -20,6 +20,7 @@
it should only include low level schema changes
"""
+from cubicweb import ConfigurationError
from cubicweb.server.session import hooks_control
from cubicweb.server import schemaserial as ss
@@ -37,19 +38,19 @@
if applcubicwebversion < (3, 17, 0) and cubicwebversion >= (3, 17, 0):
try:
add_cube('sioc', update_database=False)
- except ImportError:
+ except ConfigurationError:
if not confirm('In cubicweb 3.17 sioc views have been moved to the sioc '
'cube, which is not installed. Continue anyway?'):
raise
try:
add_cube('embed', update_database=False)
- except ImportError:
+ except ConfigurationError:
if not confirm('In cubicweb 3.17 embedding views have been moved to the embed '
'cube, which is not installed. Continue anyway?'):
raise
try:
add_cube('geocoding', update_database=False)
- except ImportError:
+ except ConfigurationError:
if not confirm('In cubicweb 3.17 geocoding views have been moved to the geocoding '
'cube, which is not installed. Continue anyway?'):
raise
@@ -72,7 +73,7 @@
from cubicweb import ExecutionError
try:
add_cube('localperms', update_database=False)
- except ImportError:
+ except ConfigurationError:
raise ExecutionError('In cubicweb 3.14, CWPermission and related stuff '
'has been moved to cube localperms. Install it first.')
--- a/misc/scripts/ldapuser2ldapfeed.py Tue Jul 02 17:09:04 2013 +0200
+++ b/misc/scripts/ldapuser2ldapfeed.py Mon Jan 13 13:47:47 2014 +0100
@@ -95,5 +95,5 @@
commit()
else:
rollback()
- print 'rollbacked'
+ print 'rolled back'
--- a/mixins.py Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,308 +0,0 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""mixins of entity/views organized somewhat in a graph or tree structure"""
-__docformat__ = "restructuredtext en"
-
-from itertools import chain
-
-from logilab.common.decorators import cached
-from logilab.common.deprecation import deprecated, class_deprecated
-
-from cubicweb.predicates import implements
-from cubicweb.interfaces import ITree
-
-
-class TreeMixIn(object):
- """base tree-mixin implementing the tree interface
-
- This mixin has to be inherited explicitly and configured using the
- tree_attribute, parent_target and children_target class attribute to
- benefit from this default implementation
- """
- __metaclass__ = class_deprecated
- __deprecation_warning__ = '[3.9] TreeMixIn is deprecated, use/override ITreeAdapter instead (%(cls)s)'
-
- tree_attribute = None
- # XXX misnamed
- parent_target = 'subject'
- children_target = 'object'
-
- def different_type_children(self, entities=True):
- """return children entities of different type as this entity.
-
- according to the `entities` parameter, return entity objects or the
- equivalent result set
- """
- res = self.related(self.tree_attribute, self.children_target,
- entities=entities)
- if entities:
- return [e for e in res if e.e_schema != self.e_schema]
- return res.filtered_rset(lambda x: x.e_schema != self.e_schema, self.cw_col)
-
- def same_type_children(self, entities=True):
- """return children entities of the same type as this entity.
-
- according to the `entities` parameter, return entity objects or the
- equivalent result set
- """
- res = self.related(self.tree_attribute, self.children_target,
- entities=entities)
- if entities:
- return [e for e in res if e.e_schema == self.e_schema]
- return res.filtered_rset(lambda x: x.e_schema is self.e_schema, self.cw_col)
-
- def iterchildren(self, _done=None):
- if _done is None:
- _done = set()
- for child in self.children():
- if child.eid in _done:
- self.error('loop in %s tree: %s', self.__regid__.lower(), child)
- continue
- yield child
- _done.add(child.eid)
-
- def prefixiter(self, _done=None):
- if _done is None:
- _done = set()
- if self.eid in _done:
- return
- _done.add(self.eid)
- yield self
- for child in self.same_type_children():
- for entity in child.prefixiter(_done):
- yield entity
-
- @cached
- def path(self):
- """returns the list of eids from the root object to this object"""
- path = []
- parent = self
- while parent:
- if parent.eid in path:
- self.error('loop in %s tree: %s', self.__regid__.lower(), parent)
- break
- path.append(parent.eid)
- try:
- # check we are not leaving the tree
- if (parent.tree_attribute != self.tree_attribute or
- parent.parent_target != self.parent_target):
- break
- parent = parent.parent()
- except AttributeError:
- break
-
- path.reverse()
- return path
-
- def iterparents(self, strict=True):
- def _uptoroot(self):
- curr = self
- while True:
- curr = curr.parent()
- if curr is None:
- break
- yield curr
- if not strict:
- return chain([self], _uptoroot(self))
- return _uptoroot(self)
-
- ## ITree interface ########################################################
- def parent(self):
- """return the parent entity if any, else None (e.g. if we are on the
- root
- """
- try:
- return self.related(self.tree_attribute, self.parent_target,
- entities=True)[0]
- except (KeyError, IndexError):
- return None
-
- def children(self, entities=True, sametype=False):
- """return children entities
-
- according to the `entities` parameter, return entity objects or the
- equivalent result set
- """
- if sametype:
- return self.same_type_children(entities)
- else:
- return self.related(self.tree_attribute, self.children_target,
- entities=entities)
-
- def children_rql(self):
- return self.cw_related_rql(self.tree_attribute, self.children_target)
-
- def is_leaf(self):
- return len(self.children()) == 0
-
- def is_root(self):
- return self.parent() is None
-
- def root(self):
- """return the root object"""
- return self._cw.entity_from_eid(self.path()[0])
-
-
-class EmailableMixIn(object):
- """base mixin providing the default get_email() method used by
- the massmailing view
-
- NOTE: The default implementation is based on the
- primary_email / use_email scheme
- """
- @deprecated("[3.9] use entity.cw_adapt_to('IEmailable').get_email()")
- def get_email(self):
- if getattr(self, 'primary_email', None):
- return self.primary_email[0].address
- if getattr(self, 'use_email', None):
- return self.use_email[0].address
- return None
-
-
-"""pluggable mixins system: plug classes registered in MI_REL_TRIGGERS on entity
-classes which have the relation described by the dict's key.
-
-NOTE: pluggable mixins can't override any method of the 'explicit' user classes tree
-(eg without plugged classes). This includes bases Entity and AnyEntity classes.
-"""
-MI_REL_TRIGGERS = {
- ('primary_email', 'subject'): EmailableMixIn,
- ('use_email', 'subject'): EmailableMixIn,
- }
-
-
-# XXX move to cubicweb.web.views.treeview once we delete usage from this file
-def _done_init(done, view, row, col):
- """handle an infinite recursion safety belt"""
- if done is None:
- done = set()
- entity = view.cw_rset.get_entity(row, col)
- if entity.eid in done:
- msg = entity._cw._('loop in %(rel)s relation (%(eid)s)') % {
- 'rel': entity.cw_adapt_to('ITree').tree_relation,
- 'eid': entity.eid
- }
- return None, msg
- done.add(entity.eid)
- return done, entity
-
-
-class TreeViewMixIn(object):
- """a recursive tree view"""
- __metaclass__ = class_deprecated
- __deprecation_warning__ = '[3.9] TreeViewMixIn is deprecated, use/override BaseTreeView instead (%(cls)s)'
-
- __regid__ = 'tree'
- __select__ = implements(ITree, warn=False)
- item_vid = 'treeitem'
-
- def call(self, done=None, **kwargs):
- if done is None:
- done = set()
- super(TreeViewMixIn, self).call(done=done, **kwargs)
-
- def cell_call(self, row, col=0, vid=None, done=None, maxlevel=None, **kwargs):
- assert maxlevel is None or maxlevel > 0
- done, entity = _done_init(done, self, row, col)
- if done is None:
- # entity is actually an error message
- self.w(u'<li class="badcontent">%s</li>' % entity)
- return
- self.open_item(entity)
- entity.view(vid or self.item_vid, w=self.w, **kwargs)
- if maxlevel is not None:
- maxlevel -= 1
- if maxlevel == 0:
- self.close_item(entity)
- return
- relatedrset = entity.children(entities=False)
- self.wview(self.__regid__, relatedrset, 'null', done=done,
- maxlevel=maxlevel, **kwargs)
- self.close_item(entity)
-
- def open_item(self, entity):
- self.w(u'<li class="%s">\n' % entity.cw_etype.lower())
- def close_item(self, entity):
- self.w(u'</li>\n')
-
-
-class TreePathMixIn(object):
- """a recursive path view"""
- __metaclass__ = class_deprecated
- __deprecation_warning__ = '[3.9] TreePathMixIn is deprecated, use/override TreePathView instead (%(cls)s)'
- __regid__ = 'path'
- item_vid = 'oneline'
- separator = u' > '
-
- def call(self, **kwargs):
- self.w(u'<div class="pathbar">')
- super(TreePathMixIn, self).call(**kwargs)
- self.w(u'</div>')
-
- def cell_call(self, row, col=0, vid=None, done=None, **kwargs):
- done, entity = _done_init(done, self, row, col)
- if done is None:
- # entity is actually an error message
- self.w(u'<span class="badcontent">%s</span>' % entity)
- return
- parent = entity.parent()
- if parent:
- parent.view(self.__regid__, w=self.w, done=done)
- self.w(self.separator)
- entity.view(vid or self.item_vid, w=self.w)
-
-
-class ProgressMixIn(object):
- """provide a default implementations for IProgress interface methods"""
- __metaclass__ = class_deprecated
- __deprecation_warning__ = '[3.9] ProgressMixIn is deprecated, use/override IProgressAdapter instead (%(cls)s)'
-
- @property
- def cost(self):
- return self.progress_info()['estimated']
-
- @property
- def revised_cost(self):
- return self.progress_info().get('estimatedcorrected', self.cost)
-
- @property
- def done(self):
- return self.progress_info()['done']
-
- @property
- def todo(self):
- return self.progress_info()['todo']
-
- @cached
- def progress_info(self):
- raise NotImplementedError()
-
- def finished(self):
- return not self.in_progress()
-
- def in_progress(self):
- raise NotImplementedError()
-
- def progress(self):
- try:
- return 100. * self.done / self.revised_cost
- except ZeroDivisionError:
- # total cost is 0 : if everything was estimated, task is completed
- if self.progress_info().get('notestimated'):
- return 0.
- return 100
--- a/predicates.py Tue Jul 02 17:09:04 2013 +0200
+++ b/predicates.py Mon Jan 13 13:47:47 2014 +0100
@@ -204,27 +204,6 @@
# remember, these imports are there for bw compat only
__BACKWARD_COMPAT_IMPORTS = (yes,)
-def score_interface(etypesreg, eclass, iface):
- """Return XXX if the give object (maybe an instance or class) implements
- the interface.
- """
- if getattr(iface, '__registry__', None) == 'etypes':
- # adjust score if the interface is an entity class
- parents, any = etypesreg.parent_classes(eclass.__regid__)
- if iface is eclass:
- return len(parents) + 4
- if iface is any: # Any
- return 1
- for index, basecls in enumerate(reversed(parents)):
- if iface is basecls:
- return index + 3
- return 0
- # XXX iface in implements deprecated in 3.9
- if implements_iface(eclass, iface):
- # implementing an interface takes precedence other special Any interface
- return 2
- return 0
-
# abstract predicates / mixin helpers ###########################################
@@ -745,53 +724,6 @@
return 1 # necessarily true if we're there
-class implements(EClassPredicate):
- """Return non-zero score for entity that are of the given type(s) or
- implements at least one of the given interface(s). If multiple arguments are
- given, matching one of them is enough.
-
- Entity types should be given as string, the corresponding class will be
- fetched from the entity types registry at selection time.
-
- See :class:`~cubicweb.predicates.EClassPredicate` documentation for entity
- class lookup / score rules according to the input context.
-
- .. note::
-
- when interface is an entity class, the score will reflect class
- proximity so the most specific object will be selected.
-
- .. note::
-
- deprecated in cubicweb >= 3.9, use either
- :class:`~cubicweb.predicates.is_instance` or
- :class:`~cubicweb.predicates.adaptable`.
- """
-
- def __init__(self, *expected_ifaces, **kwargs):
- emit_warn = kwargs.pop('warn', True)
- super(implements, self).__init__(**kwargs)
- self.expected_ifaces = expected_ifaces
- if emit_warn:
- warn('[3.9] implements predicate is deprecated, use either '
- 'is_instance or adaptable', DeprecationWarning, stacklevel=2)
-
- def __str__(self):
- return '%s(%s)' % (self.__class__.__name__,
- ','.join(str(s) for s in self.expected_ifaces))
-
- def score_class(self, eclass, req):
- score = 0
- etypesreg = req.vreg['etypes']
- for iface in self.expected_ifaces:
- if isinstance(iface, basestring):
- # entity type
- try:
- iface = etypesreg.etype_class(iface)
- except KeyError:
- continue # entity type not in the schema
- score += score_interface(etypesreg, eclass, iface)
- return score
def _reset_is_instance_cache(vreg):
vreg._is_instance_predicate_cache = {}
@@ -994,7 +926,11 @@
return 0 # relation not supported
if self.action:
if self.target_etype is not None:
- rschema = rschema.role_rdef(entity.e_schema, self.target_etype, self.role)
+ try:
+ rschema = rschema.role_rdef(entity.e_schema,
+ self.target_etype, self.role)
+ except KeyError:
+ return 0
if self.role == 'subject':
if not rschema.has_perm(entity._cw, self.action, fromeid=entity.eid):
return 0
@@ -1278,12 +1214,9 @@
','.join(str(s) for s in self.expected))
-def on_fire_transition(etype, tr_name, from_state_name=None):
+def on_fire_transition(etype, tr_names, from_state_name=None):
"""Return 1 when entity of the type `etype` is going through transition of
- the name `tr_name`.
-
- If `from_state_name` is specified, this predicate will also check the
- incoming state.
+ a name included in `tr_names`.
You should use this predicate on 'after_add_entity' hook, since it's actually
looking for addition of `TrInfo` entities. Hence in the hook, `self.entity`
@@ -1293,9 +1226,13 @@
See :class:`cubicweb.entities.wfobjs.TrInfo` for more information.
"""
+ if from_state_name is not None:
+ warn("on_fire_transition's from_state_name argument is unused", DeprecationWarning)
+ if isinstance(tr_names, basestring):
+ tr_names = set((tr_names,))
def match_etype_and_transition(trinfo):
# take care trinfo.transition is None when calling change_state
- return (trinfo.transition and trinfo.transition.name == tr_name
+ return (trinfo.transition and trinfo.transition.name in tr_names
# is_instance() first two arguments are 'cls' (unused, so giving
# None is fine) and the request/session
and is_instance(etype)(None, trinfo._cw, entity=trinfo.for_entity))
--- a/pylintext.py Tue Jul 02 17:09:04 2013 +0200
+++ b/pylintext.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,7 +1,7 @@
"""https://pastebin.logilab.fr/show/860/"""
-from logilab.astng import MANAGER, nodes, scoped_nodes
-from logilab.astng.builder import ASTNGBuilder
+from astroid import MANAGER, InferenceError, nodes, scoped_nodes
+from astroid.builder import AstroidBuilder
def turn_function_to_class(node):
"""turn a Function node into a Class node (in-place)"""
@@ -21,13 +21,16 @@
for node in assnodes:
if isinstance(node, scoped_nodes.Function) and node.decorators:
for decorator in node.decorators.nodes:
- for infered in decorator.infer():
- if infered.name in ('objectify_predicate', 'objectify_selector'):
- turn_function_to_class(node)
- break
- else:
+ try:
+ for infered in decorator.infer():
+ if infered.name in ('objectify_predicate', 'objectify_selector'):
+ turn_function_to_class(node)
+ break
+ else:
+ continue
+ break
+ except InferenceError:
continue
- break
# add yams base types into 'yams.buildobjs', astng doesn't grasp globals()
# magic in there
if module.name == 'yams.buildobjs':
@@ -36,7 +39,7 @@
module.locals[etype] = [scoped_nodes.Class(etype, None)]
# add data() to uiprops module
if module.name.split('.')[-1] == 'uiprops':
- fake = ASTNGBuilder(MANAGER).string_build('''
+ fake = AstroidBuilder(MANAGER).string_build('''
def data(string):
return u''
''')
@@ -44,5 +47,5 @@
def register(linter):
"""called when loaded by pylint --load-plugins, nothing to do here"""
- MANAGER.register_transformer(cubicweb_transform)
+ MANAGER.register_transform(nodes.Module, cubicweb_transform)
--- a/req.py Tue Jul 02 17:09:04 2013 +0200
+++ b/req.py Mon Jan 13 13:47:47 2014 +0100
@@ -29,7 +29,10 @@
from logilab.common.deprecation import deprecated
from logilab.common.date import ustrftime, strptime, todate, todatetime
-from cubicweb import Unauthorized, NoSelectableObject, uilib
+from rql.utils import rqlvar_maker
+
+from cubicweb import (Unauthorized, NoSelectableObject, NoResultError,
+ MultipleResultsError, uilib)
from cubicweb.rset import ResultSet
ONESECOND = timedelta(0, 1, 0)
@@ -169,16 +172,16 @@
cls = self.vreg['etypes'].etype_class(etype)
return cls.cw_instantiate(self.execute, **kwargs)
+ @deprecated('[3.18] use find(etype, **kwargs).entities()')
def find_entities(self, etype, **kwargs):
"""find entities of the given type and attribute values.
>>> users = find_entities('CWGroup', name=u'users')
>>> groups = find_entities('CWGroup')
"""
- parts = ['Any X WHERE X is %s' % etype]
- parts.extend('X %(attr)s %%(%(attr)s)s' % {'attr': attr} for attr in kwargs)
- return self.execute(', '.join(parts), kwargs).entities()
+ return self.find(etype, **kwargs).entities()
+ @deprecated('[3.18] use find(etype, **kwargs).one()')
def find_one_entity(self, etype, **kwargs):
"""find one entity of the given type and attribute values.
raise :exc:`FindEntityError` if can not return one and only one entity.
@@ -187,14 +190,43 @@
>>> groups = find_one_entity('CWGroup')
Exception()
"""
+ try:
+ return self.find(etype, **kwargs).one()
+ except (NoResultError, MultipleResultsError) as e:
+ raise FindEntityError("%s: (%s, %s)" % (str(e), etype, kwargs))
+
+ def find(self, etype, **kwargs):
+ """find entities of the given type and attribute values.
+
+ :returns: A :class:`ResultSet`
+
+ >>> users = find('CWGroup', name=u"users").one()
+ >>> groups = find('CWGroup').entities()
+ """
parts = ['Any X WHERE X is %s' % etype]
- parts.extend('X %(attr)s %%(%(attr)s)s' % {'attr': attr} for attr in kwargs)
+ varmaker = rqlvar_maker(defined='X')
+ eschema = self.vreg.schema[etype]
+ for attr, value in kwargs.items():
+ if isinstance(value, list) or isinstance(value, tuple):
+ raise NotImplementedError("List of values are not supported")
+ if hasattr(value, 'eid'):
+ kwargs[attr] = value.eid
+ if attr.startswith('reverse_'):
+ attr = attr[8:]
+ assert attr in eschema.objrels, \
+ '%s not in %s object relations' % (attr, eschema)
+ parts.append(
+ '%(varname)s %(attr)s X, '
+ '%(varname)s eid %%(reverse_%(attr)s)s'
+ % {'attr': attr, 'varname': varmaker.next()})
+ else:
+ assert attr in eschema.subjrels, \
+ '%s not in %s subject relations' % (attr, eschema)
+ parts.append('X %(attr)s %%(%(attr)s)s' % {'attr': attr})
+
rql = ', '.join(parts)
- rset = self.execute(rql, kwargs)
- if len(rset) != 1:
- raise FindEntityError('Found %i entitie(s) when 1 was expected (rql=%s ; %s)'
- % (len(rset), rql, repr(kwargs)))
- return rset.get_entity(0,0)
+
+ return self.execute(rql, kwargs)
def ensure_ro_rql(self, rql):
"""raise an exception if the given rql is not a select query"""
@@ -437,7 +469,7 @@
"""return the root url of the instance
"""
if secure:
- return self.vreg.config.get('https-url', self.vreg.config['base-url'])
+ return self.vreg.config.get('https-url') or self.vreg.config['base-url']
return self.vreg.config['base-url']
# abstract methods to override according to the web front-end #############
--- a/rqlrewrite.py Tue Jul 02 17:09:04 2013 +0200
+++ b/rqlrewrite.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -33,6 +33,13 @@
from cubicweb import Unauthorized
+def cleanup_solutions(rqlst, solutions):
+ for sol in solutions:
+ for vname in list(sol):
+ if not (vname in rqlst.defined_vars or vname in rqlst.aliases):
+ del sol[vname]
+
+
def add_types_restriction(schema, rqlst, newroot=None, solutions=None):
if newroot is None:
assert solutions is None
@@ -85,6 +92,7 @@
for etype in possibletypes:
node.append(n.Constant(etype, 'etype'))
else:
+ etype = iter(possibletypes).next()
node = n.Constant(etype, 'etype')
comp = mytyperel.children[1]
comp.replace(comp.children[0], node)
@@ -132,10 +140,69 @@
return newsolutions
+def _add_noinvariant(noinvariant, restricted, select, nbtrees):
+ # a variable can actually be invariant if it has not been restricted for
+ # security reason or if security assertion hasn't modified the possible
+ # solutions for the query
+ for vname in restricted:
+ try:
+ var = select.defined_vars[vname]
+ except KeyError:
+ # this is an alias
+ continue
+ if nbtrees != 1 or len(var.stinfo['possibletypes']) != 1:
+ noinvariant.add(var)
+
+
+def _expand_selection(terms, selected, aliases, select, newselect):
+ for term in terms:
+ for vref in term.iget_nodes(n.VariableRef):
+ if not vref.name in selected:
+ select.append_selected(vref)
+ colalias = newselect.get_variable(vref.name, len(aliases))
+ aliases.append(n.VariableRef(colalias))
+ selected.add(vref.name)
+
+def _has_multiple_cardinality(etypes, rdef, ttypes_func, cardindex):
+ """return True if relation definitions from entity types (`etypes`) to
+ target types returned by the `ttypes_func` function all have single (1 or ?)
+ cardinality.
+ """
+ for etype in etypes:
+ for ttype in ttypes_func(etype):
+ if rdef(etype, ttype).cardinality[cardindex] in '+*':
+ return True
+ return False
+
+def _compatible_relation(relations, stmt, sniprel):
+ """Search among given rql relation nodes if there is one 'compatible' with the
+ snippet relation, and return it if any, else None.
+
+ A relation is compatible if it:
+ * belongs to the currently processed statement,
+ * isn't negged (i.e. direct parent is a NOT node)
+ * isn't optional (outer join) or similarly as the snippet relation
+ """
+ for rel in relations:
+ # don't share if relation's scope is not the current statement
+ if rel.scope is not stmt:
+ continue
+ # don't share neged relation
+ if rel.neged(strict=True):
+ continue
+ # don't share optional relation, unless the snippet relation is
+ # similarly optional
+ if rel.optional and rel.optional != sniprel.optional:
+ continue
+ return rel
+ return None
+
+
def iter_relations(stinfo):
# this is a function so that test may return relation in a predictable order
return stinfo['relations'] - stinfo['rhsrelations']
+
class Unsupported(Exception):
"""raised when an rql expression can't be inserted in some rql query
because it create an unresolvable query (eg no solutions found)
@@ -164,13 +231,118 @@
if len(self.select.solutions) < len(self.solutions):
raise Unsupported()
- def rewrite(self, select, snippets, solutions, kwargs, existingvars=None):
+ def insert_local_checks(self, select, kwargs,
+ localchecks, restricted, noinvariant):
+ """
+ select: the rql syntax tree Select node
+ kwargs: query arguments
+
+ localchecks: {(('Var name', (rqlexpr1, rqlexpr2)),
+ ('Var name1', (rqlexpr1, rqlexpr23))): [solution]}
+
+ (see querier._check_permissions docstring for more information)
+
+ restricted: set of variable names to which an rql expression has to be
+ applied
+
+ noinvariant: set of variable names that can't be considered has
+ invariant due to security reason (will be filed by this method)
+ """
+ nbtrees = len(localchecks)
+ myunion = union = select.parent
+ # transform in subquery when len(localchecks)>1 and groups
+ if nbtrees > 1 and (select.orderby or select.groupby or
+ select.having or select.has_aggregat or
+ select.distinct or
+ select.limit or select.offset):
+ newselect = stmts.Select()
+ # only select variables in subqueries
+ origselection = select.selection
+ select.select_only_variables()
+ select.has_aggregat = False
+ # create subquery first so correct node are used on copy
+ # (eg ColumnAlias instead of Variable)
+ aliases = [n.VariableRef(newselect.get_variable(vref.name, i))
+ for i, vref in enumerate(select.selection)]
+ selected = set(vref.name for vref in aliases)
+ # now copy original selection and groups
+ for term in origselection:
+ newselect.append_selected(term.copy(newselect))
+ if select.orderby:
+ sortterms = []
+ for sortterm in select.orderby:
+ sortterms.append(sortterm.copy(newselect))
+ for fnode in sortterm.get_nodes(n.Function):
+ if fnode.name == 'FTIRANK':
+ # we've to fetch the has_text relation as well
+ var = fnode.children[0].variable
+ rel = iter(var.stinfo['ftirels']).next()
+ assert not rel.ored(), 'unsupported'
+ newselect.add_restriction(rel.copy(newselect))
+ # remove relation from the orig select and
+ # cleanup variable stinfo
+ rel.parent.remove(rel)
+ var.stinfo['ftirels'].remove(rel)
+ var.stinfo['relations'].remove(rel)
+ # XXX not properly re-annotated after security insertion?
+ newvar = newselect.get_variable(var.name)
+ newvar.stinfo.setdefault('ftirels', set()).add(rel)
+ newvar.stinfo.setdefault('relations', set()).add(rel)
+ newselect.set_orderby(sortterms)
+ _expand_selection(select.orderby, selected, aliases, select, newselect)
+ select.orderby = () # XXX dereference?
+ if select.groupby:
+ newselect.set_groupby([g.copy(newselect) for g in select.groupby])
+ _expand_selection(select.groupby, selected, aliases, select, newselect)
+ select.groupby = () # XXX dereference?
+ if select.having:
+ newselect.set_having([g.copy(newselect) for g in select.having])
+ _expand_selection(select.having, selected, aliases, select, newselect)
+ select.having = () # XXX dereference?
+ if select.limit:
+ newselect.limit = select.limit
+ select.limit = None
+ if select.offset:
+ newselect.offset = select.offset
+ select.offset = 0
+ myunion = stmts.Union()
+ newselect.set_with([n.SubQuery(aliases, myunion)], check=False)
+ newselect.distinct = select.distinct
+ solutions = [sol.copy() for sol in select.solutions]
+ cleanup_solutions(newselect, solutions)
+ newselect.set_possible_types(solutions)
+ # if some solutions doesn't need rewriting, insert original
+ # select as first union subquery
+ if () in localchecks:
+ myunion.append(select)
+ # we're done, replace original select by the new select with
+ # subqueries (more added in the loop below)
+ union.replace(select, newselect)
+ elif not () in localchecks:
+ union.remove(select)
+ for lcheckdef, lchecksolutions in localchecks.iteritems():
+ if not lcheckdef:
+ continue
+ myrqlst = select.copy(solutions=lchecksolutions)
+ myunion.append(myrqlst)
+ # in-place rewrite + annotation / simplification
+ lcheckdef = [({var: 'X'}, rqlexprs) for var, rqlexprs in lcheckdef]
+ self.rewrite(myrqlst, lcheckdef, kwargs)
+ _add_noinvariant(noinvariant, restricted, myrqlst, nbtrees)
+ if () in localchecks:
+ select.set_possible_types(localchecks[()])
+ add_types_restriction(self.schema, select)
+ _add_noinvariant(noinvariant, restricted, select, nbtrees)
+ self.annotate(union)
+
+ def rewrite(self, select, snippets, kwargs, existingvars=None):
"""
snippets: (varmap, list of rql expression)
with varmap a *tuple* (select var, snippet var)
"""
self.select = select
- self.solutions = solutions
+ # remove_solutions used below require a copy
+ self.solutions = solutions = select.solutions[:]
self.kwargs = kwargs
self.u_varname = None
self.removing_ambiguity = False
@@ -195,6 +367,7 @@
select, solutions, newsolutions))
if len(newsolutions) > len(solutions):
newsolutions = self.remove_ambiguities(snippets, newsolutions)
+ assert newsolutions
select.solutions = newsolutions
add_types_restriction(self.schema, select)
@@ -235,9 +408,14 @@
subselect.solutions, self.kwargs)
return
if varexistsmap is None:
- vi['rhs_rels'] = dict( (r.r_type, r) for r in sti['rhsrelations'])
- vi['lhs_rels'] = dict( (r.r_type, r) for r in sti['relations']
- if not r in sti['rhsrelations'])
+ # build an index for quick access to relations
+ vi['rhs_rels'] = {}
+ for rel in sti['rhsrelations']:
+ vi['rhs_rels'].setdefault(rel.r_type, []).append(rel)
+ vi['lhs_rels'] = {}
+ for rel in sti['relations']:
+ if not rel in sti['rhsrelations']:
+ vi['lhs_rels'].setdefault(rel.r_type, []).append(rel)
else:
vi['rhs_rels'] = vi['lhs_rels'] = {}
previous = None
@@ -464,7 +642,6 @@
exists = var.references()[0].scope
exists.add_constant_restriction(var, 'is', etype, 'etype')
# recompute solutions
- #select.annotated = False # avoid assertion error
self.compute_solutions()
# clean solutions according to initial solutions
return remove_solutions(self.solutions, self.select.solutions,
@@ -509,38 +686,34 @@
"""if the snippet relation can be skipped to use a relation from the
original query, return that relation node
"""
+ if sniprel.neged(strict=True):
+ return None # no way
rschema = self.schema.rschema(sniprel.r_type)
stmt = self.current_statement()
for vi in self.varinfos:
try:
if target == 'object':
- orel = vi['lhs_rels'][sniprel.r_type]
+ orels = vi['lhs_rels'][sniprel.r_type]
cardindex = 0
ttypes_func = rschema.objects
rdef = rschema.rdef
else: # target == 'subject':
- orel = vi['rhs_rels'][sniprel.r_type]
+ orels = vi['rhs_rels'][sniprel.r_type]
cardindex = 1
ttypes_func = rschema.subjects
rdef = lambda x, y: rschema.rdef(y, x)
except KeyError:
# may be raised by vi['xhs_rels'][sniprel.r_type]
- return None
- # don't share if relation's statement is not the current statement
- if orel.stmt is not stmt:
- return None
- # can't share neged relation or relations with different outer join
- if (orel.neged(strict=True) or sniprel.neged(strict=True)
- or (orel.optional and orel.optional != sniprel.optional)):
- return None
- # if cardinality is in '?1', we can ignore the snippet relation and use
- # variable from the original query
- for etype in vi['stinfo']['possibletypes']:
- for ttype in ttypes_func(etype):
- if rdef(etype, ttype).cardinality[cardindex] in '+*':
- return None
- break
- return orel
+ continue
+ # if cardinality isn't in '?1', we can't ignore the snippet relation
+ # and use variable from the original query
+ if _has_multiple_cardinality(vi['stinfo']['possibletypes'], rdef,
+ ttypes_func, cardindex):
+ continue
+ orel = _compatible_relation(orels, stmt, sniprel)
+ if orel is not None:
+ return orel
+ return None
def _use_orig_term(self, snippet_varname, term):
key = (self.current_expr, self.varmap, snippet_varname)
--- a/rset.py Tue Jul 02 17:09:04 2013 +0200
+++ b/rset.py Mon Jan 13 13:47:47 2014 +0100
@@ -23,7 +23,7 @@
from rql import nodes, stmts
-from cubicweb import NotAnEntity
+from cubicweb import NotAnEntity, NoResultError, MultipleResultsError
class ResultSet(object):
@@ -45,7 +45,7 @@
:param rql: the original RQL query string
"""
- def __init__(self, results, rql, args=None, description=(), rqlst=None):
+ def __init__(self, results, rql, args=None, description=None, rqlst=None):
self.rows = results
self.rowcount = results and len(results) or 0
# original query and arguments
@@ -53,7 +53,10 @@
self.args = args
# entity types for each cell (same shape as rows)
# maybe discarded if specified when the query has been executed
- self.description = description
+ if description is None:
+ self.description = []
+ else:
+ self.description = description
# parsed syntax tree
if rqlst is not None:
rqlst.schema = None # reset schema in case of pyro transfert
@@ -434,6 +437,25 @@
raise NotAnEntity(etype)
return self._build_entity(row, col)
+ def one(self, col=0):
+ """Retrieve exactly one entity from the query.
+
+ If the result set is empty, raises :exc:`NoResultError`.
+ If the result set has more than one row, raises
+ :exc:`MultipleResultsError`.
+
+ :type col: int
+ :param col: The column localising the entity in the unique row
+
+ :return: the partially initialized `Entity` instance
+ """
+ if len(self) == 1:
+ return self.get_entity(0, col)
+ elif len(self) == 0:
+ raise NoResultError("No row was found for one()")
+ else:
+ raise MultipleResultsError("Multiple rows were found for one()")
+
def _build_entity(self, row, col):
"""internal method to get a single entity, returns a partially
initialized Entity instance.
--- a/schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -21,11 +21,12 @@
_ = unicode
import re
-from os.path import join
+from os.path import join, basename
from logging import getLogger
from warnings import warn
-from logilab.common.decorators import cached, clear_cache, monkeypatch
+from logilab.common import tempattr
+from logilab.common.decorators import cached, clear_cache, monkeypatch, cachedproperty
from logilab.common.logging_ext import set_log_methods
from logilab.common.deprecation import deprecated, class_moved, moved
from logilab.common.textutils import splitstrip
@@ -44,6 +45,15 @@
import cubicweb
from cubicweb import ETYPE_NAME_MAP, ValidationError, Unauthorized
+try:
+ from cubicweb import server
+except ImportError:
+ # We need to lookup DEBUG from there,
+ # however a pure dbapi client may not have it.
+ class server(object): pass
+ server.DEBUG = False
+
+
PURE_VIRTUAL_RTYPES = set(('identity', 'has_text',))
VIRTUAL_RTYPES = set(('eid', 'identity', 'has_text',))
@@ -84,7 +94,7 @@
'WorkflowTransition', 'BaseTransition',
'SubWorkflowExitPoint'))
-INTERNAL_TYPES = set(('CWProperty', 'CWCache', 'ExternalUri',
+INTERNAL_TYPES = set(('CWProperty', 'CWCache', 'ExternalUri', 'CWDataImport',
'CWSource', 'CWSourceHostConfig', 'CWSourceSchemaConfig'))
@@ -94,6 +104,309 @@
ybo.ETYPE_PROPERTIES += ('eid',)
ybo.RTYPE_PROPERTIES += ('eid',)
+# Bases for manipulating RQL in schema #########################################
+
+def guess_rrqlexpr_mainvars(expression):
+ defined = set(split_expression(expression))
+ mainvars = set()
+ if 'S' in defined:
+ mainvars.add('S')
+ if 'O' in defined:
+ mainvars.add('O')
+ if 'U' in defined:
+ mainvars.add('U')
+ if not mainvars:
+ raise Exception('unable to guess selection variables')
+ return mainvars
+
+def split_expression(rqlstring):
+ for expr in rqlstring.split(','):
+ for noparen1 in expr.split('('):
+ for noparen2 in noparen1.split(')'):
+ for word in noparen2.split():
+ yield word
+
+def normalize_expression(rqlstring):
+ """normalize an rql expression to ease schema synchronization (avoid
+ suppressing and reinserting an expression if only a space has been
+ added/removed for instance)
+ """
+ return u', '.join(' '.join(expr.split()) for expr in rqlstring.split(','))
+
+
+class RQLExpression(object):
+ """Base class for RQL expression used in schema (constraints and
+ permissions)
+ """
+ # these are overridden by set_log_methods below
+ # only defining here to prevent pylint from complaining
+ info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
+ # to be defined in concrete classes
+ rqlst = None
+ predefined_variables = None
+
+ def __init__(self, expression, mainvars, eid):
+ """
+ :type mainvars: sequence of RQL variables' names. Can be provided as a
+ comma separated string.
+ :param mainvars: names of the variables being selected.
+
+ """
+ self.eid = eid # eid of the entity representing this rql expression
+ assert mainvars, 'bad mainvars %s' % mainvars
+ if isinstance(mainvars, basestring):
+ mainvars = set(splitstrip(mainvars))
+ elif not isinstance(mainvars, set):
+ mainvars = set(mainvars)
+ self.mainvars = mainvars
+ self.expression = normalize_expression(expression)
+ try:
+ self.full_rql = self.rqlst.as_string()
+ except RQLSyntaxError:
+ raise RQLSyntaxError(expression)
+ for mainvar in mainvars:
+ # if variable is predefined, an extra reference is inserted
+ # automatically (`VAR eid %(v)s`)
+ if mainvar in self.predefined_variables:
+ min_refs = 3
+ else:
+ min_refs = 2
+ if len(self.rqlst.defined_vars[mainvar].references()) < min_refs:
+ _LOGGER.warn('You did not use the %s variable in your RQL '
+ 'expression %s', mainvar, self)
+ # syntax tree used by read security (inserted in queries when necessary)
+ self.snippet_rqlst = parse(self.minimal_rql, print_errors=False).children[0]
+ # graph of links between variables, used by rql rewriter
+ self.vargraph = vargraph(self.rqlst)
+ # useful for some instrumentation, e.g. localperms permcheck command
+ self.package = ybo.PACKAGE
+
+ def __str__(self):
+ return self.full_rql
+ def __repr__(self):
+ return '%s(%s)' % (self.__class__.__name__, self.full_rql)
+
+ def __lt__(self, other):
+ if hasattr(other, 'expression'):
+ return self.expression < other.expression
+ return True
+
+ def __eq__(self, other):
+ if hasattr(other, 'expression'):
+ return self.expression == other.expression
+ return False
+
+ def __hash__(self):
+ return hash(self.expression)
+
+ def __deepcopy__(self, memo):
+ return self.__class__(self.expression, self.mainvars)
+ def __getstate__(self):
+ return (self.expression, self.mainvars)
+ def __setstate__(self, state):
+ self.__init__(*state)
+
+ @cachedproperty
+ def rqlst(self):
+ select = parse(self.minimal_rql, print_errors=False).children[0]
+ defined = set(split_expression(self.expression))
+ for varname in self.predefined_variables:
+ if varname in defined:
+ select.add_eid_restriction(select.get_variable(varname), varname.lower(), 'Substitute')
+ return select
+
+ # permission rql expression specific stuff #################################
+
+ @cached
+ def transform_has_permission(self):
+ found = None
+ rqlst = self.rqlst
+ for var in rqlst.defined_vars.itervalues():
+ for varref in var.references():
+ rel = varref.relation()
+ if rel is None:
+ continue
+ try:
+ prefix, action, suffix = rel.r_type.split('_')
+ except ValueError:
+ continue
+ if prefix != 'has' or suffix != 'permission' or \
+ not action in ('add', 'delete', 'update', 'read'):
+ continue
+ if found is None:
+ found = []
+ rqlst.save_state()
+ assert rel.children[0].name == 'U'
+ objvar = rel.children[1].children[0].variable
+ rqlst.remove_node(rel)
+ selected = [v.name for v in rqlst.get_selected_variables()]
+ if objvar.name not in selected:
+ colindex = len(selected)
+ rqlst.add_selected(objvar)
+ else:
+ colindex = selected.index(objvar.name)
+ found.append((action, colindex))
+ # remove U eid %(u)s if U is not used in any other relation
+ uvrefs = rqlst.defined_vars['U'].references()
+ if len(uvrefs) == 1:
+ rqlst.remove_node(uvrefs[0].relation())
+ if found is not None:
+ rql = rqlst.as_string()
+ if len(rqlst.selection) == 1 and isinstance(rqlst.where, nodes.Relation):
+ # only "Any X WHERE X eid %(x)s" remaining, no need to execute the rql
+ keyarg = rqlst.selection[0].name.lower()
+ else:
+ keyarg = None
+ rqlst.recover()
+ return rql, found, keyarg
+ return rqlst.as_string(), None, None
+
+ def _check(self, _cw, **kwargs):
+ """return True if the rql expression is matching the given relation
+ between fromeid and toeid
+
+ _cw may be a request or a server side transaction
+ """
+ creating = kwargs.get('creating')
+ if not creating and self.eid is not None:
+ key = (self.eid, tuple(sorted(kwargs.iteritems())))
+ try:
+ return _cw.local_perm_cache[key]
+ except KeyError:
+ pass
+ rql, has_perm_defs, keyarg = self.transform_has_permission()
+ # when creating an entity, expression related to X satisfied
+ if creating and 'X' in self.rqlst.defined_vars:
+ return True
+ if keyarg is None:
+ kwargs.setdefault('u', _cw.user.eid)
+ try:
+ rset = _cw.execute(rql, kwargs, build_descr=True)
+ except NotImplementedError:
+ self.critical('cant check rql expression, unsupported rql %s', rql)
+ if self.eid is not None:
+ _cw.local_perm_cache[key] = False
+ return False
+ except TypeResolverException as ex:
+ # some expression may not be resolvable with current kwargs
+ # (type conflict)
+ self.warning('%s: %s', rql, str(ex))
+ if self.eid is not None:
+ _cw.local_perm_cache[key] = False
+ return False
+ except Unauthorized as ex:
+ self.debug('unauthorized %s: %s', rql, str(ex))
+ if self.eid is not None:
+ _cw.local_perm_cache[key] = False
+ return False
+ else:
+ rset = _cw.eid_rset(kwargs[keyarg])
+ # if no special has_*_permission relation in the rql expression, just
+ # check the result set contains something
+ if has_perm_defs is None:
+ if rset:
+ if self.eid is not None:
+ _cw.local_perm_cache[key] = True
+ return True
+ elif rset:
+ # check every special has_*_permission relation is satisfied
+ get_eschema = _cw.vreg.schema.eschema
+ try:
+ for eaction, col in has_perm_defs:
+ for i in xrange(len(rset)):
+ eschema = get_eschema(rset.description[i][col])
+ eschema.check_perm(_cw, eaction, eid=rset[i][col])
+ if self.eid is not None:
+ _cw.local_perm_cache[key] = True
+ return True
+ except Unauthorized:
+ pass
+ if self.eid is not None:
+ _cw.local_perm_cache[key] = False
+ return False
+
+ @property
+ def minimal_rql(self):
+ return 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)),
+ self.expression)
+
+
+
+# rql expressions for use in permission definition #############################
+
+class ERQLExpression(RQLExpression):
+ predefined_variables = 'XU'
+
+ def __init__(self, expression, mainvars=None, eid=None):
+ RQLExpression.__init__(self, expression, mainvars or 'X', eid)
+
+ def check(self, _cw, eid=None, creating=False, **kwargs):
+ if 'X' in self.rqlst.defined_vars:
+ if eid is None:
+ if creating:
+ return self._check(_cw, creating=True, **kwargs)
+ return False
+ assert creating == False
+ return self._check(_cw, x=eid, **kwargs)
+ return self._check(_cw, **kwargs)
+
+
+def vargraph(rqlst):
+ """ builds an adjacency graph of variables from the rql syntax tree, e.g:
+ Any O,S WHERE T subworkflow_exit S, T subworkflow WF, O state_of WF
+ => {'WF': ['O', 'T'], 'S': ['T'], 'T': ['WF', 'S'], 'O': ['WF']}
+ """
+ vargraph = {}
+ for relation in rqlst.get_nodes(nodes.Relation):
+ try:
+ rhsvarname = relation.children[1].children[0].variable.name
+ lhsvarname = relation.children[0].name
+ except AttributeError:
+ pass
+ else:
+ vargraph.setdefault(lhsvarname, []).append(rhsvarname)
+ vargraph.setdefault(rhsvarname, []).append(lhsvarname)
+ #vargraph[(lhsvarname, rhsvarname)] = relation.r_type
+ return vargraph
+
+
+class GeneratedConstraint(object):
+ def __init__(self, rqlst, mainvars):
+ self.snippet_rqlst = rqlst
+ self.mainvars = mainvars
+ self.vargraph = vargraph(rqlst)
+
+
+class RRQLExpression(RQLExpression):
+ predefined_variables = 'SOU'
+
+ def __init__(self, expression, mainvars=None, eid=None):
+ if mainvars is None:
+ mainvars = guess_rrqlexpr_mainvars(expression)
+ RQLExpression.__init__(self, expression, mainvars, eid)
+
+ def check(self, _cw, fromeid=None, toeid=None):
+ kwargs = {}
+ if 'S' in self.rqlst.defined_vars:
+ if fromeid is None:
+ return False
+ kwargs['s'] = fromeid
+ if 'O' in self.rqlst.defined_vars:
+ if toeid is None:
+ return False
+ kwargs['o'] = toeid
+ return self._check(_cw, **kwargs)
+
+
+# In yams, default 'update' perm for attributes granted to managers and owners.
+# Within cw, we want to default to users who may edit the entity holding the
+# attribute.
+# These default permissions won't be checked by the security hooks:
+# since they delegate checking to the entity, we can skip actual checks.
+ybo.DEFAULT_ATTRPERMS['update'] = ('managers', ERQLExpression('U has_update_permission X'))
+ybo.DEFAULT_ATTRPERMS['add'] = ('managers', ERQLExpression('U has_add_permission X'))
+
+
PUB_SYSTEM_ENTITY_PERMS = {
'read': ('managers', 'users', 'guests',),
'add': ('managers',),
@@ -107,6 +420,7 @@
}
PUB_SYSTEM_ATTR_PERMS = {
'read': ('managers', 'users', 'guests',),
+ 'add': ('managers',),
'update': ('managers',),
}
RO_REL_PERMS = {
@@ -116,6 +430,7 @@
}
RO_ATTR_PERMS = {
'read': ('managers', 'users', 'guests',),
+ 'add': ybo.DEFAULT_ATTRPERMS['add'],
'update': (),
}
@@ -268,13 +583,25 @@
return False
PermissionMixIn.has_perm = has_perm
+
def check_perm(self, _cw, action, **kwargs):
# NB: _cw may be a server transaction or a request object.
#
# check user is in an allowed group, if so that's enough internal
# transactions should always stop there
+ DBG = False
+ if server.DEBUG & server.DBG_SEC:
+ if action in server._SECURITY_CAPS:
+ _self_str = str(self)
+ if server._SECURITY_ITEMS:
+ if any(item in _self_str for item in server._SECURITY_ITEMS):
+ DBG = True
+ else:
+ DBG = True
groups = self.get_groups(action)
if _cw.user.matching_groups(groups):
+ if DBG:
+ print 'check_perm: %r %r: user matches %s' % (action, _self_str, groups)
return
# if 'owners' in allowed groups, check if the user actually owns this
# object, if so that's enough
@@ -284,8 +611,15 @@
if 'owners' in groups and (
kwargs.get('creating')
or ('eid' in kwargs and _cw.user.owns(kwargs['eid']))):
+ if DBG:
+ print ('check_perm: %r %r: user is owner or creation time' %
+ (action, _self_str))
return
# else if there is some rql expressions, check them
+ if DBG:
+ print ('check_perm: %r %r %s' %
+ (action, _self_str, [(rqlexpr, kwargs, rqlexpr.check(_cw, **kwargs))
+ for rqlexpr in self.get_rqlexprs(action)]))
if any(rqlexpr.check(_cw, **kwargs)
for rqlexpr in self.get_rqlexprs(action)):
return
@@ -630,308 +964,6 @@
def schema_by_eid(self, eid):
return self._eid_index[eid]
-# Bases for manipulating RQL in schema #########################################
-
-def guess_rrqlexpr_mainvars(expression):
- defined = set(split_expression(expression))
- mainvars = set()
- if 'S' in defined:
- mainvars.add('S')
- if 'O' in defined:
- mainvars.add('O')
- if 'U' in defined:
- mainvars.add('U')
- if not mainvars:
- raise Exception('unable to guess selection variables')
- return mainvars
-
-def split_expression(rqlstring):
- for expr in rqlstring.split(','):
- for noparen1 in expr.split('('):
- for noparen2 in noparen1.split(')'):
- for word in noparen2.split():
- yield word
-
-def normalize_expression(rqlstring):
- """normalize an rql expression to ease schema synchronization (avoid
- suppressing and reinserting an expression if only a space has been
- added/removed for instance)
- """
- return u', '.join(' '.join(expr.split()) for expr in rqlstring.split(','))
-
-
-class RQLExpression(object):
- """Base class for RQL expression used in schema (constraints and
- permissions)
- """
- # these are overridden by set_log_methods below
- # only defining here to prevent pylint from complaining
- info = warning = error = critical = exception = debug = lambda msg,*a,**kw: None
- # to be defined in concrete classes
- full_rql = None
-
- def __init__(self, expression, mainvars, eid):
- """
- :type mainvars: sequence of RQL variables' names. Can be provided as a
- comma separated string.
- :param mainvars: names of the variables being selected.
-
- """
- self.eid = eid # eid of the entity representing this rql expression
- assert mainvars, 'bad mainvars %s' % mainvars
- if isinstance(mainvars, basestring):
- mainvars = set(splitstrip(mainvars))
- elif not isinstance(mainvars, set):
- mainvars = set(mainvars)
- self.mainvars = mainvars
- self.expression = normalize_expression(expression)
- try:
- self.rqlst = parse(self.full_rql, print_errors=False).children[0]
- except RQLSyntaxError:
- raise RQLSyntaxError(expression)
- for mainvar in mainvars:
- if len(self.rqlst.defined_vars[mainvar].references()) <= 2:
- _LOGGER.warn('You did not use the %s variable in your RQL '
- 'expression %s', mainvar, self)
- # syntax tree used by read security (inserted in queries when necessary)
- self.snippet_rqlst = parse(self.minimal_rql, print_errors=False).children[0]
-
- def __str__(self):
- return self.full_rql
- def __repr__(self):
- return '%s(%s)' % (self.__class__.__name__, self.full_rql)
-
- def __lt__(self, other):
- if hasattr(other, 'expression'):
- return self.expression < other.expression
- return True
-
- def __eq__(self, other):
- if hasattr(other, 'expression'):
- return self.expression == other.expression
- return False
-
- def __deepcopy__(self, memo):
- return self.__class__(self.expression, self.mainvars)
- def __getstate__(self):
- return (self.expression, self.mainvars)
- def __setstate__(self, state):
- self.__init__(*state)
-
- # permission rql expression specific stuff #################################
-
- @cached
- def transform_has_permission(self):
- found = None
- rqlst = self.rqlst
- for var in rqlst.defined_vars.itervalues():
- for varref in var.references():
- rel = varref.relation()
- if rel is None:
- continue
- try:
- prefix, action, suffix = rel.r_type.split('_')
- except ValueError:
- continue
- if prefix != 'has' or suffix != 'permission' or \
- not action in ('add', 'delete', 'update', 'read'):
- continue
- if found is None:
- found = []
- rqlst.save_state()
- assert rel.children[0].name == 'U'
- objvar = rel.children[1].children[0].variable
- rqlst.remove_node(rel)
- selected = [v.name for v in rqlst.get_selected_variables()]
- if objvar.name not in selected:
- colindex = len(selected)
- rqlst.add_selected(objvar)
- else:
- colindex = selected.index(objvar.name)
- found.append((action, colindex))
- # remove U eid %(u)s if U is not used in any other relation
- uvrefs = rqlst.defined_vars['U'].references()
- if len(uvrefs) == 1:
- rqlst.remove_node(uvrefs[0].relation())
- if found is not None:
- rql = rqlst.as_string()
- if len(rqlst.selection) == 1 and isinstance(rqlst.where, nodes.Relation):
- # only "Any X WHERE X eid %(x)s" remaining, no need to execute the rql
- keyarg = rqlst.selection[0].name.lower()
- else:
- keyarg = None
- rqlst.recover()
- return rql, found, keyarg
- return rqlst.as_string(), None, None
-
- def _check(self, _cw, **kwargs):
- """return True if the rql expression is matching the given relation
- between fromeid and toeid
-
- _cw may be a request or a server side transaction
- """
- creating = kwargs.get('creating')
- if not creating and self.eid is not None:
- key = (self.eid, tuple(sorted(kwargs.iteritems())))
- try:
- return _cw.local_perm_cache[key]
- except KeyError:
- pass
- rql, has_perm_defs, keyarg = self.transform_has_permission()
- # when creating an entity, expression related to X satisfied
- if creating and 'X' in self.rqlst.defined_vars:
- return True
- if keyarg is None:
- kwargs.setdefault('u', _cw.user.eid)
- try:
- rset = _cw.execute(rql, kwargs, build_descr=True)
- except NotImplementedError:
- self.critical('cant check rql expression, unsupported rql %s', rql)
- if self.eid is not None:
- _cw.local_perm_cache[key] = False
- return False
- except TypeResolverException as ex:
- # some expression may not be resolvable with current kwargs
- # (type conflict)
- self.warning('%s: %s', rql, str(ex))
- if self.eid is not None:
- _cw.local_perm_cache[key] = False
- return False
- except Unauthorized as ex:
- self.debug('unauthorized %s: %s', rql, str(ex))
- if self.eid is not None:
- _cw.local_perm_cache[key] = False
- return False
- else:
- rset = _cw.eid_rset(kwargs[keyarg])
- # if no special has_*_permission relation in the rql expression, just
- # check the result set contains something
- if has_perm_defs is None:
- if rset:
- if self.eid is not None:
- _cw.local_perm_cache[key] = True
- return True
- elif rset:
- # check every special has_*_permission relation is satisfied
- get_eschema = _cw.vreg.schema.eschema
- try:
- for eaction, col in has_perm_defs:
- for i in xrange(len(rset)):
- eschema = get_eschema(rset.description[i][col])
- eschema.check_perm(_cw, eaction, eid=rset[i][col])
- if self.eid is not None:
- _cw.local_perm_cache[key] = True
- return True
- except Unauthorized:
- pass
- if self.eid is not None:
- _cw.local_perm_cache[key] = False
- return False
-
- @property
- def minimal_rql(self):
- return 'Any %s WHERE %s' % (','.join(sorted(self.mainvars)),
- self.expression)
-
-# rql expressions for use in permission definition #############################
-
-class ERQLExpression(RQLExpression):
- def __init__(self, expression, mainvars=None, eid=None):
- RQLExpression.__init__(self, expression, mainvars or 'X', eid)
-
- @property
- def full_rql(self):
- rql = self.minimal_rql
- rqlst = getattr(self, 'rqlst', None) # may be not set yet
- if rqlst is not None:
- defined = rqlst.defined_vars
- else:
- defined = set(split_expression(self.expression))
- if 'X' in defined:
- rql += ', X eid %(x)s'
- if 'U' in defined:
- rql += ', U eid %(u)s'
- return rql
-
- def check(self, _cw, eid=None, creating=False, **kwargs):
- if 'X' in self.rqlst.defined_vars:
- if eid is None:
- if creating:
- return self._check(_cw, creating=True, **kwargs)
- return False
- assert creating == False
- return self._check(_cw, x=eid, **kwargs)
- return self._check(_cw, **kwargs)
-
-
-def vargraph(rqlst):
- """ builds an adjacency graph of variables from the rql syntax tree, e.g:
- Any O,S WHERE T subworkflow_exit S, T subworkflow WF, O state_of WF
- => {'WF': ['O', 'T'], 'S': ['T'], 'T': ['WF', 'S'], 'O': ['WF']}
- """
- vargraph = {}
- for relation in rqlst.get_nodes(nodes.Relation):
- try:
- rhsvarname = relation.children[1].children[0].variable.name
- lhsvarname = relation.children[0].name
- except AttributeError:
- pass
- else:
- vargraph.setdefault(lhsvarname, []).append(rhsvarname)
- vargraph.setdefault(rhsvarname, []).append(lhsvarname)
- #vargraph[(lhsvarname, rhsvarname)] = relation.r_type
- return vargraph
-
-
-class GeneratedConstraint(object):
- def __init__(self, rqlst, mainvars):
- self.snippet_rqlst = rqlst
- self.mainvars = mainvars
- self.vargraph = vargraph(rqlst)
-
-
-class RRQLExpression(RQLExpression):
- def __init__(self, expression, mainvars=None, eid=None):
- if mainvars is None:
- mainvars = guess_rrqlexpr_mainvars(expression)
- RQLExpression.__init__(self, expression, mainvars, eid)
- # graph of links between variable, used by rql rewriter
- self.vargraph = vargraph(self.rqlst)
-
- @property
- def full_rql(self):
- rql = self.minimal_rql
- rqlst = getattr(self, 'rqlst', None) # may be not set yet
- if rqlst is not None:
- defined = rqlst.defined_vars
- else:
- defined = set(split_expression(self.expression))
- if 'S' in defined:
- rql += ', S eid %(s)s'
- if 'O' in defined:
- rql += ', O eid %(o)s'
- if 'U' in defined:
- rql += ', U eid %(u)s'
- return rql
-
- def check(self, _cw, fromeid=None, toeid=None):
- kwargs = {}
- if 'S' in self.rqlst.defined_vars:
- if fromeid is None:
- return False
- kwargs['s'] = fromeid
- if 'O' in self.rqlst.defined_vars:
- if toeid is None:
- return False
- kwargs['o'] = toeid
- return self._check(_cw, **kwargs)
-
-
-# in yams, default 'update' perm for attributes granted to managers and owners.
-# Within cw, we want to default to users who may edit the entity holding the
-# attribute.
-ybo.DEFAULT_ATTRPERMS['update'] = (
- 'managers', ERQLExpression('U has_update_permission X'))
# additional cw specific constraints ###########################################
@@ -940,14 +972,11 @@
distinct_query = None
def serialize(self):
- # start with a comma for bw compat,see below
+ # start with a semicolon for bw compat, see below
return ';' + ','.join(sorted(self.mainvars)) + ';' + self.expression
@classmethod
def deserialize(cls, value):
- # XXX < 3.5.10 bw compat
- if not value.startswith(';'):
- return cls(value)
_, mainvars, expression = value.split(';', 2)
return cls(expression, mainvars)
@@ -1002,9 +1031,6 @@
self.msg or '')
def deserialize(cls, value):
- # XXX < 3.5.10 bw compat
- if not value.startswith(';'):
- return cls(value)
value, msg = value.split('\n', 1)
_, mainvars, expression = value.split(';', 2)
return cls(expression, mainvars, msg)
@@ -1071,7 +1097,7 @@
"""
# XXX turns mainvars into a required argument in __init__
distinct_query = True
-
+
def match_condition(self, session, eidfrom, eidto):
return len(self.exec_query(session, eidfrom, eidto)) <= 1
@@ -1148,7 +1174,8 @@
# bootstraping, ignore cubes
filepath = join(cubicweb.CW_SOFTWARE_ROOT, 'schemas', 'bootstrap.py')
self.info('loading %s', filepath)
- self.handle_file(filepath)
+ with tempattr(ybo, 'PACKAGE', 'cubicweb'): # though we don't care here
+ self.handle_file(filepath)
def unhandled_file(self, filepath):
"""called when a file without handler associated has been found"""
@@ -1188,11 +1215,12 @@
join(cubicweb.CW_SOFTWARE_ROOT, 'schemas', 'workflow.py'),
join(cubicweb.CW_SOFTWARE_ROOT, 'schemas', 'Bookmark.py')):
self.info('loading %s', filepath)
- self.handle_file(filepath)
+ with tempattr(ybo, 'PACKAGE', 'cubicweb'):
+ self.handle_file(filepath)
for cube in cubes:
for filepath in self.get_schema_files(cube):
- self.info('loading %s', filepath)
- self.handle_file(filepath)
+ with tempattr(ybo, 'PACKAGE', basename(cube)):
+ self.handle_file(filepath)
# these are overridden by set_log_methods below
# only defining here to prevent pylint from complaining
--- a/schemas/_regproc.postgres.sql Tue Jul 02 17:09:04 2013 +0200
+++ b/schemas/_regproc.postgres.sql Mon Jan 13 13:47:47 2014 +0100
@@ -10,10 +10,15 @@
SELECT array_to_string($1, ', ')
$$ LANGUAGE SQL;;
+
+CREATE FUNCTION cw_array_append_unique (anyarray, anyelement) RETURNS anyarray AS $$
+ SELECT array_append($1, (SELECT $2 WHERE $2 <> ALL($1)))
+$$ LANGUAGE SQL
+
DROP AGGREGATE IF EXISTS group_concat (anyelement) CASCADE;
CREATE AGGREGATE group_concat (
basetype = anyelement,
- sfunc = array_append,
+ sfunc = cw_array_append_unique,
stype = anyarray,
finalfunc = comma_join,
initcond = '{}'
--- a/schemas/bootstrap.py Tue Jul 02 17:09:04 2013 +0200
+++ b/schemas/bootstrap.py Mon Jan 13 13:47:47 2014 +0100
@@ -83,7 +83,7 @@
indexed = Boolean(description=_('create an index for quick search on this attribute'))
fulltextindexed = Boolean(description=_('index this attribute\'s value in the plain text index'))
internationalizable = Boolean(description=_('is this attribute\'s value translatable'))
- defaultval = String(maxsize=256)
+ defaultval = Bytes(description=_('default value as gziped pickled python object'))
extra_props = Bytes(description=_('additional type specific properties'))
description = RichString(internationalizable=True,
@@ -158,6 +158,7 @@
class CWUniqueTogetherConstraint(EntityType):
"""defines a sql-level multicolumn unique index"""
__permissions__ = PUB_SYSTEM_ENTITY_PERMS
+ name = String(required=True, unique=True, maxsize=64)
constraint_of = SubjectRelation('CWEType', cardinality='1*', composite='object',
inlined=True)
relations = SubjectRelation('CWRType', cardinality='+*',
@@ -235,7 +236,7 @@
"""groups allowed to add entities/relations of this type"""
__permissions__ = PUB_SYSTEM_REL_PERMS
name = 'add_permission'
- subject = ('CWEType', 'CWRelation')
+ subject = ('CWEType', 'CWRelation', 'CWAttribute')
object = 'CWGroup'
cardinality = '**'
@@ -268,7 +269,7 @@
"""rql expression allowing to add entities/relations of this type"""
__permissions__ = PUB_SYSTEM_REL_PERMS
name = 'add_permission'
- subject = ('CWEType', 'CWRelation')
+ subject = ('CWEType', 'CWRelation', 'CWAttribute')
object = 'RQLExpression'
cardinality = '*?'
composite = 'subject'
--- a/schemas/workflow.py Tue Jul 02 17:09:04 2013 +0200
+++ b/schemas/workflow.py Mon Jan 13 13:47:47 2014 +0100
@@ -89,14 +89,14 @@
name = String(required=True, indexed=True, internationalizable=True,
maxsize=256,
constraints=[RQLUniqueConstraint('S name N, S transition_of WF, Y transition_of WF, Y name N', 'Y',
- _('workflow already have a transition of that name'))])
+ _('workflow already has a transition of that name'))])
type = String(vocabulary=(_('normal'), _('auto')), default='normal')
description = RichString(description=_('semantic description of this transition'))
transition_of = SubjectRelation('Workflow', cardinality='1*', composite='object',
description=_('workflow to which this transition belongs'),
constraints=[RQLUniqueConstraint('S name N, Y transition_of O, Y name N', 'Y',
- _('workflow already have a transition of that name'))])
+ _('workflow already has a transition of that name'))])
class require_group(RelationDefinition):
--- a/server/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -26,6 +26,7 @@
import sys
from os.path import join, exists
from glob import glob
+from contextlib import contextmanager
from logilab.common.modutils import LazyObject
from logilab.common.textutils import splitstrip
@@ -78,14 +79,57 @@
DBG_HOOKS = 16
#: operations
DBG_OPS = 32
+#: security
+DBG_SEC = 64
#: more verbosity
-DBG_MORE = 64
+DBG_MORE = 128
#: all level enabled
-DBG_ALL = DBG_RQL + DBG_SQL + DBG_REPO + DBG_MS + DBG_HOOKS + DBG_OPS + DBG_MORE
+DBG_ALL = DBG_RQL + DBG_SQL + DBG_REPO + DBG_MS + DBG_HOOKS + DBG_OPS + DBG_SEC + DBG_MORE
+
+_SECURITY_ITEMS = []
+_SECURITY_CAPS = ['read', 'add', 'update', 'delete']
#: current debug mode
DEBUG = 0
+@contextmanager
+def tunesecurity(items=(), capabilities=()):
+ """Context manager to use in conjunction with DBG_SEC.
+
+ This allows some tuning of:
+ * the monitored capabilities ('read', 'add', ....)
+ * the object being checked by the security checkers
+
+ When no item is given, all of them will be watched.
+ By default all capabilities are monitored, unless specified.
+
+ Example use::
+
+ from cubicweb.server import debugged, DBG_SEC, tunesecurity
+ with debugged(DBG_SEC):
+ with tunesecurity(items=('Elephant', 'trumps'),
+ capabilities=('update', 'delete')):
+ babar.cw_set(trumps=celeste)
+ flore.cw_delete()
+
+ ==>
+
+ check_perm: 'update' 'relation Elephant.trumps.Elephant'
+ [(ERQLExpression(Any X WHERE U has_update_permission X, X eid %(x)s, U eid %(u)s),
+ {'eid': 2167}, True)]
+ check_perm: 'delete' 'Elephant'
+ [(ERQLExpression(Any X WHERE U has_delete_permission X, X eid %(x)s, U eid %(u)s),
+ {'eid': 2168}, True)]
+
+ """
+ olditems = _SECURITY_ITEMS[:]
+ _SECURITY_ITEMS.extend(list(items))
+ oldactions = _SECURITY_CAPS[:]
+ _SECURITY_CAPS[:] = capabilities
+ yield
+ _SECURITY_ITEMS[:] = olditems
+ _SECURITY_CAPS[:] = oldactions
+
def set_debug(debugmode):
"""change the repository debugging mode"""
global DEBUG
@@ -103,13 +147,13 @@
It can be used either as a context manager:
- >>> with debugged(server.DBG_RQL | server.DBG_REPO):
+ >>> with debugged('DBG_RQL | DBG_REPO'):
... # some code in which you want to debug repository activity,
... # seing information about RQL being executed an repository events.
or as a function decorator:
- >>> @debugged(server.DBG_RQL | server.DBG_REPO)
+ >>> @debugged('DBG_RQL | DBG_REPO')
... def some_function():
... # some code in which you want to debug repository activity,
... # seing information about RQL being executed an repository events
@@ -203,7 +247,11 @@
schemasql = sqlschema(schema, driver)
#skip_entities=[str(e) for e in schema.entities()
# if not repo.system_source.support_entity(str(e))])
- sqlexec(schemasql, execute, pbtitle=_title, delimiter=';;')
+ failed = sqlexec(schemasql, execute, pbtitle=_title, delimiter=';;')
+ if failed:
+ print 'The following SQL statements failed. You should check your schema.'
+ print failed
+ raise Exception('execution of the sql schema failed, you should check your schema')
sqlcursor.close()
sqlcnx.commit()
sqlcnx.close()
--- a/server/checkintegrity.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/checkintegrity.py Mon Jan 13 13:47:47 2014 +0100
@@ -57,6 +57,9 @@
pass
eids[eid] = False
return False
+ if etype not in session.vreg.schema:
+ eids[eid] = False
+ return False
sqlcursor.execute('SELECT * FROM %s%s WHERE %seid=%s' % (SQL_PREFIX, etype,
SQL_PREFIX, eid))
result = sqlcursor.fetchall()
@@ -179,12 +182,12 @@
"""check all entities registered in the repo system table"""
print 'Checking entities system table'
# system table but no source
- msg = ' Entity with eid %s exists in the system table but in no source (autofix will delete the entity)'
- cursor = session.system_sql('SELECT eid FROM entities;')
+ msg = ' Entity %s with eid %s exists in the system table but in no source (autofix will delete the entity)'
+ cursor = session.system_sql('SELECT eid,type FROM entities;')
for row in cursor.fetchall():
- eid = row[0]
+ eid, etype = row
if not has_eid(session, cursor, eid, eids):
- sys.stderr.write(msg % eid)
+ sys.stderr.write(msg % (etype, eid))
if fix:
session.system_sql('DELETE FROM entities WHERE eid=%s;' % eid)
notify_fixed(fix)
@@ -258,6 +261,12 @@
sys.stderr.write(msg % (rtype, target, eid))
notify_fixed(fix)
+def bad_inlined_msg(rtype, parent_eid, eid, fix):
+ msg = (' An inlined relation %s from %s to %s exists but the latter '
+ 'entity does not exist')
+ sys.stderr.write(msg % (rtype, parent_eid, eid))
+ notify_fixed(fix)
+
def check_relations(schema, session, eids, fix=1):
"""check that eids referenced by relations are registered in the repo system
@@ -271,13 +280,13 @@
for subjtype in rschema.subjects():
table = SQL_PREFIX + str(subjtype)
column = SQL_PREFIX + str(rschema)
- sql = 'SELECT %s FROM %s WHERE %s IS NOT NULL;' % (
+ sql = 'SELECT cw_eid,%s FROM %s WHERE %s IS NOT NULL;' % (
column, table, column)
cursor = session.system_sql(sql)
for row in cursor.fetchall():
- eid = row[0]
+ parent_eid, eid = row
if not has_eid(session, cursor, eid, eids):
- bad_related_msg(rschema, 'object', eid, fix)
+ bad_inlined_msg(rschema, parent_eid, eid, fix)
if fix:
sql = 'UPDATE %s SET %s=NULL WHERE %s=%s;' % (
table, column, column, eid)
@@ -366,6 +375,13 @@
eidcolumn = SQL_PREFIX + 'eid'
msg = ' %s with eid %s has no %s (autofix will set it to now)'
for etype, in cursor.fetchall():
+ if etype not in session.vreg.schema:
+ sys.stderr.write('entities table references unknown type %s\n' %
+ etype)
+ if fix:
+ session.system_sql("DELETE FROM entities WHERE type = %(type)s",
+ {'type': etype})
+ continue
table = SQL_PREFIX + etype
for rel, default in ( ('creation_date', datetime.now()),
('modification_date', datetime.now()), ):
--- a/server/edition.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/edition.py Mon Jan 13 13:47:47 2014 +0100
@@ -145,7 +145,7 @@
entity.e_schema.check(dict_protocol_catcher(entity),
creation=creation, relations=relations)
except ValidationError as ex:
- ex.entity = self.entity
+ ex.entity = self.entity.eid
raise
def clone(self):
--- a/server/hook.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/hook.py Mon Jan 13 13:47:47 2014 +0100
@@ -41,7 +41,7 @@
defined over data events.
Also, some :class:`~cubicweb.server.hook.Operation` may be registered by hooks,
-which will be fired when the transaction is commited or rollbacked.
+which will be fired when the transaction is commited or rolled back.
The purpose of data event hooks is usually to complement the data model as
defined in the schema, which is static by nature and only provide a restricted
@@ -169,7 +169,10 @@
* `after_add_relation`, `after_delete_relation`
-Take note that relations can be added or deleted, but not updated.
+Specific selectors are shipped for these kinds of events, see in particular
+:class:`~cubicweb.server.hook.match_rtype`.
+
+Also note that relations can be added or deleted, but not updated.
Non data events
~~~~~~~~~~~~~~~
@@ -439,11 +442,13 @@
class match_rtype(ExpectedValuePredicate):
- """accept if parameters specified as initializer arguments are specified
- in named arguments given to the predicate
+ """accept if the relation type is found in expected ones. Optional
+ named parameters `frometypes` and `toetypes` can be used to restrict
+ target subject and/or object entity types of the relation.
- :param \*expected: parameters (eg `basestring`) which are expected to be
- found in named arguments (kwargs)
+ :param \*expected: possible relation types
+ :param frometypes: candidate entity types as subject of relation
+ :param toetypes: candidate entity types as object of relation
"""
def __init__(self, *expected, **more):
self.expected = expected
@@ -673,16 +678,6 @@
{'x': self.eidfrom, 'p': self.eidto})
-PropagateSubjectRelationHook = class_renamed(
- 'PropagateSubjectRelationHook', PropagateRelationHook,
- '[3.9] PropagateSubjectRelationHook has been renamed to PropagateRelationHook')
-PropagateSubjectRelationAddHook = class_renamed(
- 'PropagateSubjectRelationAddHook', PropagateRelationAddHook,
- '[3.9] PropagateSubjectRelationAddHook has been renamed to PropagateRelationAddHook')
-PropagateSubjectRelationDelHook = class_renamed(
- 'PropagateSubjectRelationDelHook', PropagateRelationDelHook,
- '[3.9] PropagateSubjectRelationDelHook has been renamed to PropagateRelationDelHook')
-
# abstract classes for operation ###############################################
@@ -715,10 +710,10 @@
* `rollback`:
- the transaction has been either rollbacked either:
+ the transaction has been either rolled back either:
* intentionaly
- * a 'precommit' event failed, in which case all operations are rollbacked
+ * a 'precommit' event failed, in which case all operations are rolled back
once 'revertprecommit'' has been called
* `postcommit`:
@@ -780,7 +775,7 @@
"""
def rollback_event(self):
- """the observed connections set has been rollbacked
+ """the observed connections set has been rolled back
do nothing by default
"""
@@ -1044,7 +1039,7 @@
type/source cache eids of entities added in that transaction.
NOTE: querier's rqlst/solutions cache may have been polluted too with
- queries such as Any X WHERE X eid 32 if 32 has been rollbacked however
+ queries such as Any X WHERE X eid 32 if 32 has been rolled back however
generated queries are unpredictable and analysing all the cache probably
too expensive. Notice that there is no pb when using args to specify eids
instead of giving them into the rql string.
@@ -1052,7 +1047,7 @@
data_key = 'neweids'
def rollback_event(self):
- """the observed connections set has been rollbacked,
+ """the observed connections set has been rolled back,
remove inserted eid from repository type/source cache
"""
try:
@@ -1066,7 +1061,7 @@
"""
data_key = 'pendingeids'
def postcommit_event(self):
- """the observed connections set has been rollbacked,
+ """the observed connections set has been rolled back,
remove inserted eid from repository type/source cache
"""
try:
--- a/server/hooksmanager.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/hooksmanager.py Mon Jan 13 13:47:47 2014 +0100
@@ -17,11 +17,6 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
from logilab.common.deprecation import class_renamed, class_moved
from cubicweb.server import hook
+
SystemHook = class_renamed('SystemHook', hook.Hook)
-PropagateSubjectRelationHook = class_renamed('PropagateSubjectRelationHook',
- hook.PropagateSubjectRelationHook)
-PropagateSubjectRelationAddHook = class_renamed('PropagateSubjectRelationAddHook',
- hook.PropagateSubjectRelationAddHook)
-PropagateSubjectRelationDelHook = class_renamed('PropagateSubjectRelationDelHook',
- hook.PropagateSubjectRelationDelHook)
Hook = class_moved(hook.Hook)
--- a/server/migractions.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/migractions.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -44,7 +44,7 @@
from logilab.common.decorators import cached, clear_cache
from yams.constraints import SizeConstraint
-from yams.schema2sql import eschema2sql, rschema2sql
+from yams.schema2sql import eschema2sql, rschema2sql, unique_index_name
from yams.schema import RelationDefinitionSchema
from cubicweb import CW_SOFTWARE_ROOT, AuthenticationError, ExecutionError
@@ -83,8 +83,8 @@
repo.vreg.register(ClearGroupMap)
class ServerMigrationHelper(MigrationHelper):
- """specific migration helper for server side migration scripts,
- providind actions related to schema/data migration
+ """specific migration helper for server side migration scripts,
+ providing actions related to schema/data migration
"""
def __init__(self, config, schema, interactive=True,
@@ -559,26 +559,42 @@
self._synchronize_rdef_schema(subj, rschema, obj,
syncprops=syncprops, syncperms=syncperms)
if syncprops: # need to process __unique_together__ after rdefs were processed
- repo_unique_together = set([frozenset(ut)
- for ut in repoeschema._unique_together])
- unique_together = set([frozenset(ut)
- for ut in eschema._unique_together])
- for ut in repo_unique_together - unique_together:
- restrictions = []
- substs = {'x': repoeschema.eid}
- for i, col in enumerate(ut):
- restrictions.append('C relations T%(i)d, '
- 'T%(i)d name %%(T%(i)d)s' % {'i': i})
- substs['T%d'%i] = col
- self.rqlexec('DELETE CWUniqueTogetherConstraint C '
- 'WHERE C constraint_of E, '
- ' E eid %%(x)s,'
- ' %s' % ', '.join(restrictions),
- substs)
- for ut in unique_together - repo_unique_together:
- rql, substs = ss.uniquetogether2rql(eschema, ut)
- substs['x'] = repoeschema.eid
- self.rqlexec(rql, substs)
+ # mappings from constraint name to columns
+ # filesystem (fs) and repository (repo) wise
+ fs = {}
+ repo = {}
+ for cols in eschema._unique_together or ():
+ fs[unique_index_name(repoeschema, cols)] = sorted(cols)
+ schemaentity = self.session.entity_from_eid(repoeschema.eid)
+ for entity in schemaentity.related('constraint_of', 'object',
+ targettypes=('CWUniqueTogetherConstraint',)).entities():
+ repo[entity.name] = sorted(rel.name for rel in entity.relations)
+ added = set(fs) - set(repo)
+ removed = set(repo) - set(fs)
+
+ for name in removed:
+ self.rqlexec('DELETE CWUniqueTogetherConstraint C WHERE C name %(name)s',
+ {'name': name})
+
+ def possible_unique_constraint(cols):
+ for name in cols:
+ rschema = repoeschema.subjrels.get(name)
+ if rschema is None:
+ print 'dont add %s unique constraint on %s, missing %s' % (
+ ','.join(cols), eschema, name)
+ return False
+ if not (rschema.final or rschema.inlined):
+ print 'dont add %s unique constraint on %s, %s is neither final nor inlined' % (
+ ','.join(cols), eschema, name)
+ return False
+ return True
+
+ for name in added:
+ if possible_unique_constraint(fs[name]):
+ rql, substs = ss._uniquetogether2rql(eschema, fs[name])
+ substs['x'] = repoeschema.eid
+ substs['name'] = name
+ self.rqlexec(rql, substs)
def _synchronize_rdef_schema(self, subjtype, rtype, objtype,
syncperms=True, syncprops=True):
@@ -688,7 +704,10 @@
for rschema in newcubes_schema.relations():
existingschema = self.repo.schema.rschema(rschema.type)
for (fromtype, totype) in rschema.rdefs:
- if (fromtype, totype) in existingschema.rdefs:
+ # if rdef already exists or is infered from inheritance,
+ # don't add it
+ if (fromtype, totype) in existingschema.rdefs \
+ or rschema.rdefs[(fromtype, totype)].infered:
continue
# check we should actually add the relation definition
if not (fromtype in new or totype in new or rschema in new):
@@ -929,6 +948,10 @@
`newname` is a string giving the name of the renamed entity type
"""
schema = self.repo.schema
+ if oldname not in schema:
+ print 'warning: entity type %s is unknown, skip renaming' % oldname
+ return
+ # if merging two existing entity types
if newname in schema:
assert oldname in ETYPE_NAME_MAP, \
'%s should be mapped to %s in ETYPE_NAME_MAP' % (oldname,
@@ -1003,6 +1026,7 @@
# remove the old type: use rql to propagate deletion
self.rqlexec('DELETE CWEType ET WHERE ET name %(on)s', {'on': oldname},
ask_confirm=False)
+ # elif simply renaming an entity type
else:
self.rqlexec('SET ET name %(newname)s WHERE ET is CWEType, ET name %(on)s',
{'newname' : unicode(newname), 'on' : oldname},
@@ -1439,12 +1463,9 @@
# no result to fetch
return
- def rqlexec(self, rql, kwargs=None, cachekey=None, build_descr=True,
+ def rqlexec(self, rql, kwargs=None, build_descr=True,
ask_confirm=False):
"""rql action"""
- if cachekey is not None:
- warn('[3.8] cachekey is deprecated, you can safely remove this argument',
- DeprecationWarning, stacklevel=2)
if not isinstance(rql, (tuple, list)):
rql = ( (rql, kwargs), )
res = None
--- a/server/msplanner.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/msplanner.py Mon Jan 13 13:47:47 2014 +0100
@@ -92,6 +92,7 @@
from logilab.common.compat import any
from logilab.common.decorators import cached
+from logilab.common.deprecation import deprecated
from rql import BadRQLQuery
from rql.stmts import Union, Select
@@ -100,8 +101,7 @@
from cubicweb import server
from cubicweb.utils import make_uid
-from cubicweb.rqlrewrite import add_types_restriction
-from cubicweb.server.utils import cleanup_solutions
+from cubicweb.rqlrewrite import add_types_restriction, cleanup_solutions
from cubicweb.server.ssplanner import SSPlanner, OneFetchStep
from cubicweb.server.mssteps import *
@@ -1263,6 +1263,7 @@
inputmap.update(step.outputmap)
+@deprecated('[3.18] old multi-source system will go away in the next version')
class MSPlanner(SSPlanner):
"""MultiSourcesPlanner: build execution plan for rql queries
--- a/server/querier.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/querier.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -24,18 +24,15 @@
from logilab.common.compat import any
from rql import RQLSyntaxError, CoercionError
-from rql.stmts import Union, Select
-from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj
-from rql.nodes import (Relation, VariableRef, Constant, SubQuery, Function,
- Exists, Not)
+from rql.stmts import Union
+from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not
from yams import BASE_TYPES
-from cubicweb import ValidationError, Unauthorized, QueryError, UnknownEid
+from cubicweb import ValidationError, Unauthorized, UnknownEid
from cubicweb import Binary, server
from cubicweb.rset import ResultSet
from cubicweb.utils import QueryCache, RepeatList
-from cubicweb.server.utils import cleanup_solutions
from cubicweb.server.rqlannotation import SQLGenAnnotator, set_qdata
from cubicweb.server.ssplanner import READ_ONLY_RTYPES, add_types_restriction
from cubicweb.server.edition import EditedEntity
@@ -77,16 +74,18 @@
return session.describe(term.eval(args))[0]
def check_read_access(session, rqlst, solution, args):
- """check that the given user has credentials to access data read the
- query
+ """Check that the given user has credentials to access data read by the
+ query and return a dict defining necessary "local checks" (i.e. rql
+ expression in read permission defined in the schema) where no group grants
+ him the permission.
- return a dict defining necessary local checks (due to use of rql expression
- in the schema), keys are variable names and values associated rql expression
- for the associated variable with the given solution
+ Returned dictionary's keys are variable names and values the rql expressions
+ for this variable (with the given solution).
"""
# use `term_etype` since we've to deal with rewritten constants here,
# when used as an external source by another repository.
# XXX what about local read security w/ those rewritten constants...
+ DBG = (server.DEBUG & server.DBG_SEC) and 'read' in server._SECURITY_CAPS
schema = session.repo.schema
if rqlst.where is not None:
for rel in rqlst.where.iget_nodes(Relation):
@@ -104,8 +103,14 @@
term_etype(session, rel.children[1].children[0],
solution, args))
if not session.user.matching_groups(rdef.get_groups('read')):
+ if DBG:
+ print ('check_read_access: %s %s does not match %s' %
+ (rdef, session.user.groups, rdef.get_groups('read')))
# XXX rqlexpr not allowed
raise Unauthorized('read', rel.r_type)
+ if DBG:
+ print ('check_read_access: %s %s matches %s' %
+ (rdef, session.user.groups, rdef.get_groups('read')))
localchecks = {}
# iterate on defined_vars and not on solutions to ignore column aliases
for varname in rqlst.defined_vars:
@@ -117,6 +122,9 @@
if not erqlexprs:
ex = Unauthorized('read', solution[varname])
ex.var = varname
+ if DBG:
+ print ('check_read_access: %s %s %s %s' %
+ (varname, eschema, session.user.groups, eschema.get_groups('read')))
raise ex
# don't insert security on variable only referenced by 'NOT X relation Y' or
# 'NOT EXISTS(X relation Y)'
@@ -130,35 +138,6 @@
localchecks[varname] = erqlexprs
return localchecks
-def add_noinvariant(noinvariant, restricted, select, nbtrees):
- # a variable can actually be invariant if it has not been restricted for
- # security reason or if security assertion hasn't modified the possible
- # solutions for the query
- if nbtrees != 1:
- for vname in restricted:
- try:
- noinvariant.add(select.defined_vars[vname])
- except KeyError:
- # this is an alias
- continue
- else:
- for vname in restricted:
- try:
- var = select.defined_vars[vname]
- except KeyError:
- # this is an alias
- continue
- if len(var.stinfo['possibletypes']) != 1:
- noinvariant.add(var)
-
-def _expand_selection(terms, selected, aliases, select, newselect):
- for term in terms:
- for vref in term.iget_nodes(VariableRef):
- if not vref.name in selected:
- select.append_selected(vref)
- colalias = newselect.get_variable(vref.name, len(aliases))
- aliases.append(VariableRef(colalias))
- selected.add(vref.name)
# Plans #######################################################################
@@ -258,9 +237,8 @@
self.args = args
cached = True
else:
- noinvariant = set()
with self.session.security_enabled(read=False):
- self._insert_security(union, noinvariant)
+ noinvariant = self._insert_security(union)
if key is not None:
self.session.transaction_data[key] = (union, self.args)
else:
@@ -272,121 +250,39 @@
if union.has_text_query:
self.cache_key = None
- def _insert_security(self, union, noinvariant):
+ def _insert_security(self, union):
+ noinvariant = set()
for select in union.children[:]:
for subquery in select.with_:
- self._insert_security(subquery.query, noinvariant)
+ self._insert_security(subquery.query)
localchecks, restricted = self._check_permissions(select)
if any(localchecks):
- rewrite = self.session.rql_rewriter.rewrite
- nbtrees = len(localchecks)
- myunion = union
- # transform in subquery when len(localchecks)>1 and groups
- if nbtrees > 1 and (select.orderby or select.groupby or
- select.having or select.has_aggregat or
- select.distinct or
- select.limit or select.offset):
- newselect = Select()
- # only select variables in subqueries
- origselection = select.selection
- select.select_only_variables()
- select.has_aggregat = False
- # create subquery first so correct node are used on copy
- # (eg ColumnAlias instead of Variable)
- aliases = [VariableRef(newselect.get_variable(vref.name, i))
- for i, vref in enumerate(select.selection)]
- selected = set(vref.name for vref in aliases)
- # now copy original selection and groups
- for term in origselection:
- newselect.append_selected(term.copy(newselect))
- if select.orderby:
- sortterms = []
- for sortterm in select.orderby:
- sortterms.append(sortterm.copy(newselect))
- for fnode in sortterm.get_nodes(Function):
- if fnode.name == 'FTIRANK':
- # we've to fetch the has_text relation as well
- var = fnode.children[0].variable
- rel = iter(var.stinfo['ftirels']).next()
- assert not rel.ored(), 'unsupported'
- newselect.add_restriction(rel.copy(newselect))
- # remove relation from the orig select and
- # cleanup variable stinfo
- rel.parent.remove(rel)
- var.stinfo['ftirels'].remove(rel)
- var.stinfo['relations'].remove(rel)
- # XXX not properly re-annotated after security insertion?
- newvar = newselect.get_variable(var.name)
- newvar.stinfo.setdefault('ftirels', set()).add(rel)
- newvar.stinfo.setdefault('relations', set()).add(rel)
- newselect.set_orderby(sortterms)
- _expand_selection(select.orderby, selected, aliases, select, newselect)
- select.orderby = () # XXX dereference?
- if select.groupby:
- newselect.set_groupby([g.copy(newselect) for g in select.groupby])
- _expand_selection(select.groupby, selected, aliases, select, newselect)
- select.groupby = () # XXX dereference?
- if select.having:
- newselect.set_having([g.copy(newselect) for g in select.having])
- _expand_selection(select.having, selected, aliases, select, newselect)
- select.having = () # XXX dereference?
- if select.limit:
- newselect.limit = select.limit
- select.limit = None
- if select.offset:
- newselect.offset = select.offset
- select.offset = 0
- myunion = Union()
- newselect.set_with([SubQuery(aliases, myunion)], check=False)
- newselect.distinct = select.distinct
- solutions = [sol.copy() for sol in select.solutions]
- cleanup_solutions(newselect, solutions)
- newselect.set_possible_types(solutions)
- # if some solutions doesn't need rewriting, insert original
- # select as first union subquery
- if () in localchecks:
- myunion.append(select)
- # we're done, replace original select by the new select with
- # subqueries (more added in the loop below)
- union.replace(select, newselect)
- elif not () in localchecks:
- union.remove(select)
- for lcheckdef, lchecksolutions in localchecks.iteritems():
- if not lcheckdef:
- continue
- myrqlst = select.copy(solutions=lchecksolutions)
- myunion.append(myrqlst)
- # in-place rewrite + annotation / simplification
- lcheckdef = [({var: 'X'}, rqlexprs) for var, rqlexprs in lcheckdef]
- rewrite(myrqlst, lcheckdef, lchecksolutions, self.args)
- add_noinvariant(noinvariant, restricted, myrqlst, nbtrees)
- if () in localchecks:
- select.set_possible_types(localchecks[()])
- add_types_restriction(self.schema, select)
- add_noinvariant(noinvariant, restricted, select, nbtrees)
- self.rqlhelper.annotate(union)
+ self.session.rql_rewriter.insert_local_checks(
+ select, self.args, localchecks, restricted, noinvariant)
+ return noinvariant
def _check_permissions(self, rqlst):
- """return a dict defining "local checks", e.g. RQLExpression defined in
- the schema that should be inserted in the original query
-
- solutions where a variable has a type which the user can't definitly read
- are removed, else if the user may read it (eg if an rql expression is
- defined for the "read" permission of the related type), the local checks
- dict for the solution is updated
+ """Return a dict defining "local checks", i.e. RQLExpression defined in
+ the schema that should be inserted in the original query, together with
+ a set of variable names which requires some security to be inserted.
- return a dict with entries for each different local check necessary,
- with associated solutions as value. A local check is defined by a list
- of 2-uple, with variable name as first item and the necessary rql
- expression as second item for each variable which has to be checked.
- So solutions which don't require local checks will be associated to
- the empty tuple key.
+ Solutions where a variable has a type which the user can't definitly
+ read are removed, else if the user *may* read it (i.e. if an rql
+ expression is defined for the "read" permission of the related type),
+ the local checks dict is updated.
- note: rqlst should not have been simplified at this point
+ The local checks dict has entries for each different local check
+ necessary, with associated solutions as value, a local check being
+ defined by a list of 2-uple (variable name, rql expressions) for each
+ variable which has to be checked. Solutions which don't require local
+ checks will be associated to the empty tuple key.
+
+ Note rqlst should not have been simplified at this point.
"""
session = self.session
msgs = []
- neweids = session.transaction_data.get('neweids', ())
+ # dict(varname: eid), allowing to check rql expression for variables
+ # which have a known eid
varkwargs = {}
if not session.transaction_data.get('security-rqlst-cache'):
for var in rqlst.defined_vars.itervalues():
@@ -414,20 +310,27 @@
rqlexprs = localcheck.pop(varname)
except KeyError:
continue
- if eid in neweids:
+ # if entity has been added in the current transaction, the
+ # user can read it whatever rql expressions are associated
+ # to its type
+ if session.added_in_transaction(eid):
continue
for rqlexpr in rqlexprs:
if rqlexpr.check(session, eid):
break
else:
raise Unauthorized('No read acces on %r with eid %i.' % (var, eid))
+ # mark variables protected by an rql expression
restricted_vars.update(localcheck)
- localchecks.setdefault(tuple(localcheck.iteritems()), []).append(solution)
+ # turn local check into a dict key
+ localcheck = tuple(sorted(localcheck.iteritems()))
+ localchecks.setdefault(localcheck, []).append(solution)
# raise Unautorized exception if the user can't access to any solution
if not newsolutions:
raise Unauthorized('\n'.join(msgs))
+ # if there is some message, solutions have been modified and must be
+ # reconsidered by the syntax treee
if msgs:
- # (else solutions have not been modified)
rqlst.set_possible_types(newsolutions)
return localchecks, restricted_vars
@@ -728,7 +631,7 @@
if args:
# different SQL generated when some argument is None or not (IS
# NULL). This should be considered when computing sql cache key
- cachekey += tuple(sorted([k for k,v in args.iteritems()
+ cachekey += tuple(sorted([k for k, v in args.iteritems()
if v is None]))
# make an execution plan
plan = self.plan_factory(rqlst, args, session)
@@ -739,7 +642,7 @@
results = plan.execute()
except (Unauthorized, ValidationError):
# getting an Unauthorized/ValidationError exception means the
- # transaction must been rollbacked
+ # transaction must be rolled back
#
# notes:
# * we should not reset the connections set here, since we don't want the
--- a/server/repository.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/repository.py Mon Jan 13 13:47:47 2014 +0100
@@ -37,6 +37,7 @@
from datetime import datetime
from time import time, localtime, strftime
from contextlib import contextmanager
+from warnings import warn
from logilab.common.decorators import cached, clear_cache
from logilab.common.deprecation import deprecated
@@ -241,7 +242,7 @@
# load schema from the file system
if not config.creating:
self.warning("set fs instance'schema")
- self.set_schema(config.load_schema())
+ self.set_schema(config.load_schema(expand_cubes=True))
else:
# normal start: load the instance schema from the database
self.info('loading schema from the repository')
@@ -301,6 +302,8 @@
# initialized)
source.init(True, sourceent)
if not source.copy_based_source:
+ warn('[3.18] old multi-source system will go away in the next version',
+ DeprecationWarning)
self.sources.append(source)
self.querier.set_planner()
if add_to_cnxsets:
@@ -354,9 +357,8 @@
except Exception as ex:
import traceback
traceback.print_exc()
- raise Exception('Is the database initialised ? (cause: %s)' %
- (ex.args and ex.args[0].strip() or 'unknown')), \
- None, sys.exc_info()[-1]
+ raise (Exception('Is the database initialised ? (cause: %s)' % ex),
+ None, sys.exc_info()[-1])
return appschema
def _prepare_startup(self):
@@ -410,7 +412,7 @@
return self._cnxsets_pool.get(True, timeout=5)
except Queue.Empty:
raise Exception('no connections set available after 5 secs, probably either a '
- 'bug in code (too many uncommited/rollbacked '
+ 'bug in code (too many uncommited/rolled back '
'connections) or too much load on the server (in '
'which case you can try to set a bigger '
'connections pool size)')
@@ -755,16 +757,7 @@
# Zeroed to avoid useless overhead with pyro
rset._rqlst = None
return rset
- except (Unauthorized, RQLSyntaxError):
- raise
- except ValidationError as ex:
- # need ValidationError normalization here so error may pass
- # through pyro
- if hasattr(ex.entity, 'eid'):
- ex.entity = ex.entity.eid # error raised by yams
- args = list(ex.args)
- args[0] = ex.entity
- ex.args = tuple(args)
+ except (ValidationError, Unauthorized, RQLSyntaxError):
raise
except Exception:
# FIXME: check error to catch internal errors
@@ -839,7 +832,7 @@
"""close the session with the given id"""
session = self._get_session(sessionid, setcnxset=True, txid=txid,
checkshuttingdown=checkshuttingdown)
- # operation uncommited before close are rollbacked before hook is called
+ # operation uncommited before close are rolled back before hook is called
session.rollback(free_cnxset=False)
self.hm.call_hooks('session_close', session)
# commit session at this point in case write operation has been done
@@ -981,7 +974,7 @@
def _get_session(self, sessionid, setcnxset=False, txid=None,
checkshuttingdown=True):
- """return the user associated to the given session identifier"""
+ """return the session associated with the given session identifier"""
if checkshuttingdown and self.shutting_down:
raise ShuttingDown('Repository is shutting down')
try:
@@ -1408,11 +1401,9 @@
source.update_entity(session, entity)
edited.saved = True
except UniqueTogetherError as exc:
- etype, rtypes = exc.args
- problems = {}
- for col in rtypes:
- problems[col] = session._('violates unique_together constraints (%s)') % (','.join(rtypes))
- raise ValidationError(entity.eid, problems)
+ userhdlr = session.vreg['adapters'].select(
+ 'IUserFriendlyError', session, entity=entity, exc=exc)
+ userhdlr.raise_user_exception()
self.system_source.update_info(session, entity, need_fti_update)
if source.should_call_hooks:
if not only_inline_rels:
@@ -1566,10 +1557,6 @@
source.delete_relation(session, subject, rtype, object)
rschema = self.schema.rschema(rtype)
session.update_rel_cache_del(subject, rtype, object, rschema.symmetric)
- if rschema.symmetric:
- # on symmetric relation, we can't now in which sense it's
- # stored so try to delete both
- source.delete_relation(session, object, rtype, subject)
if source.should_call_hooks:
self.hm.call_hooks('after_delete_relation', session,
eidfrom=subject, rtype=rtype, eidto=object)
@@ -1623,7 +1610,7 @@
# client was not yet connected to the repo
return
if not session.closed:
- session.close()
+ self.close(session.id)
daemon.removeConnection = removeConnection
return daemon
@@ -1639,18 +1626,24 @@
@cached
def rel_type_sources(self, rtype):
+ warn('[3.18] old multi-source system will go away in the next version',
+ DeprecationWarning)
return tuple([source for source in self.sources
if source.support_relation(rtype)
or rtype in source.dont_cross_relations])
@cached
def can_cross_relation(self, rtype):
+ warn('[3.18] old multi-source system will go away in the next version',
+ DeprecationWarning)
return tuple([source for source in self.sources
if source.support_relation(rtype)
and rtype in source.cross_relations])
@cached
def is_multi_sources_relation(self, rtype):
+ warn('[3.18] old multi-source system will go away in the next version',
+ DeprecationWarning)
return any(source for source in self.sources
if not source is self.system_source
and source.support_relation(rtype))
--- a/server/rqlannotation.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/rqlannotation.py Mon Jan 13 13:47:47 2014 +0100
@@ -130,8 +130,6 @@
# can use N.ecrit_par as principal
if (stinfo['selected'] or len(stinfo['relations']) > 1):
break
- elif rschema.symmetric and stinfo['selected']:
- break
joins.add( (rel, role) )
else:
# if there is at least one ambigous relation and no other to
--- a/server/schemaserial.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/schemaserial.py Mon Jan 13 13:47:47 2014 +0100
@@ -25,9 +25,10 @@
from logilab.common.shellutils import ProgressBar
-from yams import BadSchemaDefinition, schema as schemamod, buildobjs as ybo
+from yams import (BadSchemaDefinition, schema as schemamod, buildobjs as ybo,
+ schema2sql as y2sql)
-from cubicweb import CW_SOFTWARE_ROOT, Binary
+from cubicweb import CW_SOFTWARE_ROOT, Binary, typed_eid
from cubicweb.schema import (KNOWN_RPROPERTIES, CONSTRAINTS, ETYPE_NAME_MAP,
VIRTUAL_RTYPES, PURE_VIRTUAL_RTYPES)
from cubicweb.server import sqlutils
@@ -77,8 +78,6 @@
def cstrtype_mapping(cursor):
"""cached constraint types mapping"""
map = dict(cursor.execute('Any T, X WHERE X is CWConstraintType, X name T'))
- if not 'BoundConstraint' in map:
- map['BoundConstraint'] = map['BoundaryConstraint']
return map
# schema / perms deserialization ##############################################
@@ -214,6 +213,11 @@
rdefeid, seid, reid, oeid, card, ord, desc, idx, ftidx, i18n, default = values
typeparams = extra_props.get(rdefeid)
typeparams = json.load(typeparams) if typeparams else {}
+ if default is not None:
+ if isinstance(default, Binary):
+ # while migrating from 3.17 to 3.18, we still have to
+ # handle String defaults
+ default = default.unzpickle()
_add_rdef(rdefeid, seid, reid, oeid,
cardinality=card, description=desc, order=ord,
indexed=idx, fulltextindexed=ftidx, internationalizable=i18n,
@@ -234,28 +238,24 @@
if rdefs is not None:
set_perms(rdefs, permsidx)
unique_togethers = {}
- try:
- rset = session.execute(
- 'Any X,E,R WHERE '
- 'X is CWUniqueTogetherConstraint, '
- 'X constraint_of E, X relations R', build_descr=False)
- except Exception:
- session.rollback() # first migration introducing CWUniqueTogetherConstraint cw 3.9.6
- else:
- for values in rset:
- uniquecstreid, eeid, releid = values
- eschema = schema.schema_by_eid(eeid)
- relations = unique_togethers.setdefault(uniquecstreid, (eschema, []))
- rel = ertidx[releid]
- if isinstance(rel, schemamod.RelationDefinitionSchema):
- # not yet migrated 3.9 database ('relations' target type changed
- # to CWRType in 3.10)
- rtype = rel.rtype.type
- else:
- rtype = str(rel)
- relations[1].append(rtype)
- for eschema, unique_together in unique_togethers.itervalues():
- eschema._unique_together.append(tuple(sorted(unique_together)))
+ rset = session.execute(
+ 'Any X,E,R WHERE '
+ 'X is CWUniqueTogetherConstraint, '
+ 'X constraint_of E, X relations R', build_descr=False)
+ for values in rset:
+ uniquecstreid, eeid, releid = values
+ eschema = schema.schema_by_eid(eeid)
+ relations = unique_togethers.setdefault(uniquecstreid, (eschema, []))
+ rel = ertidx[releid]
+ if isinstance(rel, schemamod.RelationDefinitionSchema):
+ # not yet migrated 3.9 database ('relations' target type changed
+ # to CWRType in 3.10)
+ rtype = rel.rtype.type
+ else:
+ rtype = str(rel)
+ relations[1].append(rtype)
+ for eschema, unique_together in unique_togethers.itervalues():
+ eschema._unique_together.append(tuple(sorted(unique_together)))
schema.infer_specialization_rules()
session.commit()
schema.reading_from_database = False
@@ -304,9 +304,6 @@
except KeyError:
return
for action, somethings in thispermsdict.iteritems():
- # XXX cw < 3.6.1 bw compat
- if isinstance(erschema, schemamod.RelationDefinitionSchema) and erschema.final and action == 'add':
- action = 'update'
erschema.permissions[action] = tuple(
isinstance(p, tuple) and erschema.rql_expression(*p) or p
for p in somethings)
@@ -344,13 +341,10 @@
cstrtypemap = {}
rql = 'INSERT CWConstraintType X: X name %(ct)s'
for cstrtype in CONSTRAINTS:
- if cstrtype == 'BoundConstraint':
- continue # XXX deprecated in yams 0.29 / cw 3.8.1
cstrtypemap[cstrtype] = execute(rql, {'ct': unicode(cstrtype)},
build_descr=False)[0][0]
if pb is not None:
pb.update()
- cstrtypemap['BoundConstraint'] = cstrtypemap['BoundaryConstraint']
# serialize relations
for rschema in schema.relations():
# skip virtual relations such as eid, has_text and identity
@@ -371,8 +365,8 @@
pb.update()
# serialize unique_together constraints
for eschema in eschemas:
- for unique_together in eschema._unique_together:
- execschemarql(execute, eschema, [uniquetogether2rql(eschema, unique_together)])
+ if eschema._unique_together:
+ execschemarql(execute, eschema, uniquetogether2rqls(eschema))
# serialize yams inheritance relationships
for rql, kwargs in specialize2rql(schema):
execute(rql, kwargs, build_descr=False)
@@ -431,7 +425,15 @@
values = {'x': eschema.eid, 'et': specialized_type.eid}
yield 'SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s', values
-def uniquetogether2rql(eschema, unique_together):
+def uniquetogether2rqls(eschema):
+ rql_args = []
+ for columns in eschema._unique_together:
+ rql, args = _uniquetogether2rql(eschema, columns)
+ args['name'] = y2sql.unique_index_name(eschema, columns)
+ rql_args.append((rql, args))
+ return rql_args
+
+def _uniquetogether2rql(eschema, unique_together):
relations = []
restrictions = []
substs = {}
@@ -443,10 +445,8 @@
restrictions.append('%(rtype)s name %%(%(rtype)s)s' % {'rtype': rtype})
relations = ', '.join(relations)
restrictions = ', '.join(restrictions)
- rql = ('INSERT CWUniqueTogetherConstraint C: '
- ' C constraint_of X, %s '
- 'WHERE '
- ' X eid %%(x)s, %s')
+ rql = ('INSERT CWUniqueTogetherConstraint C: C name %%(name)s, C constraint_of X, %s '
+ 'WHERE X eid %%(x)s, %s')
return rql % (relations, restrictions), substs
@@ -536,10 +536,7 @@
elif isinstance(value, str):
value = unicode(value)
if value is not None and prop == 'default':
- if value is False:
- value = u''
- if not isinstance(value, unicode):
- value = unicode(value)
+ value = Binary.zpickle(value)
values[amap.get(prop, prop)] = value
if extra:
values['extra_props'] = Binary(json.dumps(extra))
--- a/server/server.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/server.py Mon Jan 13 13:47:47 2014 +0100
@@ -48,7 +48,7 @@
def is_ready(self):
"""return true if the event is ready to be fired"""
now = self.timefunc()
- if self.absolute < now:
+ if self.absolute <= now:
return True
return False
@@ -109,7 +109,8 @@
self.daemon.handleRequests(req_timeout)
except select.error:
continue
- self.trigger_events()
+ finally:
+ self.trigger_events()
def quit(self):
"""stop the server"""
--- a/server/serverconfig.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/serverconfig.py Mon Jan 13 13:47:47 2014 +0100
@@ -361,7 +361,7 @@
self.init_cubes(self.expand_cubes(origcubes))
schema = CubicWebSchemaLoader().load(self, **kwargs)
if expand_cubes:
- # restaure original value
+ # restore original value
self._cubes = origcubes
return schema
--- a/server/serverctl.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/serverctl.py Mon Jan 13 13:47:47 2014 +0100
@@ -1065,6 +1065,25 @@
if val:
print key, ':', val
+
+
+def permissionshandler(relation, perms):
+ from yams.schema import RelationDefinitionSchema
+ from yams.buildobjs import DEFAULT_ATTRPERMS
+ from cubicweb.schema import (PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS,
+ PUB_SYSTEM_ATTR_PERMS, RO_REL_PERMS, RO_ATTR_PERMS)
+ defaultrelperms = (DEFAULT_ATTRPERMS, PUB_SYSTEM_REL_PERMS,
+ PUB_SYSTEM_ATTR_PERMS, RO_REL_PERMS, RO_ATTR_PERMS)
+ defaulteperms = (PUB_SYSTEM_ENTITY_PERMS,)
+ # canonicalize vs str/unicode
+ for p in ('read', 'add', 'update', 'delete'):
+ rule = perms.get(p)
+ if rule:
+ perms[p] = tuple(str(x) if isinstance(x, basestring) else x
+ for x in rule)
+ return perms, perms in defaultrelperms or perms in defaulteperms
+
+
class SchemaDiffCommand(Command):
"""Generate a diff between schema and fsschema description.
@@ -1085,7 +1104,7 @@
repo, cnx = repo_cnx(config)
session = repo._get_session(cnx.sessionid, setcnxset=True)
fsschema = config.load_schema(expand_cubes=True)
- schema_diff(repo.schema, fsschema, diff_tool)
+ schema_diff(fsschema, repo.schema, permissionshandler, diff_tool, ignore=('eid',))
for cmdclass in (CreateInstanceDBCommand, InitInstanceCommand,
--- a/server/session.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/session.py Mon Jan 13 13:47:47 2014 +0100
@@ -70,7 +70,7 @@
class transaction(object):
- """Ensure that the transaction is either commited or rollbacked at exit
+ """Ensure that the transaction is either commited or rolled back at exit
Context manager to enter a transaction for a session: when exiting the
`with` block on exception, call `session.rollback()`, else call
@@ -234,18 +234,17 @@
class CnxSetTracker(object):
"""Keep track of which connection use which cnxset.
- There should be one of this object per session plus one another for
- internal session.
+ There should be one of these objects per session (including internal sessions).
- Session object are responsible of creating their CnxSetTracker object.
+ Session objects are responsible for creating their CnxSetTracker object.
- Connection should use the :meth:`record` and :meth:`forget` to inform the
- tracker of cnxset they have acquired.
+ Connections should use the :meth:`record` and :meth:`forget` to inform the
+ tracker of cnxsets they have acquired.
.. automethod:: cubicweb.server.session.CnxSetTracker.record
.. automethod:: cubicweb.server.session.CnxSetTracker.forget
- Session use the :meth:`close` and :meth:`wait` method when closing.
+ Sessions use the :meth:`close` and :meth:`wait` methods when closing.
.. automethod:: cubicweb.server.session.CnxSetTracker.close
.. automethod:: cubicweb.server.session.CnxSetTracker.wait
@@ -260,18 +259,18 @@
self._record = {}
def __enter__(self):
- self._condition.__enter__()
+ return self._condition.__enter__()
def __exit__(self, *args):
- self._condition.__exit__(*args)
+ return self._condition.__exit__(*args)
def record(self, cnxid, cnxset):
- """Inform the tracker that a cnxid have acquired a cnxset
+ """Inform the tracker that a cnxid has acquired a cnxset
- This methode is to be used by Connection object.
+ This method is to be used by Connection objects.
This method fails when:
- - The cnxid already have a recorded cnxset.
+ - The cnxid already has a recorded cnxset.
- The tracker is not active anymore.
Notes about the caller:
@@ -279,7 +278,7 @@
(2) It must be prepared to release the cnxset if the
`cnxsettracker.forget` call fails.
(3) It should acquire the tracker lock until the very end of the operation.
- (4) However It take care to lock the CnxSetTracker object after having
+ (4) However it must only lock the CnxSetTracker object after having
retrieved the cnxset to prevent deadlock.
A typical usage look like::
@@ -294,13 +293,13 @@
repo._free_cnxset(cnxset) # (2)
raise
"""
- # dubious since the caller is suppose to have acquired it anyway.
+ # dubious since the caller is supposed to have acquired it anyway.
with self._condition:
if not self._active:
raise SessionClosedError('Closed')
old = self._record.get(cnxid)
if old is not None:
- raise ValueError('"%s" already have a cnx_set (%r)'
+ raise ValueError('connection "%s" already has a cnx_set (%r)'
% (cnxid, old))
self._record[cnxid] = cnxset
@@ -340,19 +339,19 @@
def close(self):
"""Marks the tracker as inactive.
- This methode is to be used by Session object.
+ This method is to be used by Session objects.
- Inactive tracker does not accept new record anymore.
+ An inactive tracker does not accept new records anymore.
"""
with self._condition:
self._active = False
def wait(self, timeout=10):
- """Wait for all recorded cnxset to be released
+ """Wait for all recorded cnxsets to be released
- This methode is to be used by Session object.
+ This method is to be used by Session objects.
- returns a tuple of connection id that remains open.
+ Returns a tuple of connection ids that remain open.
"""
with self._condition:
if self._active:
@@ -388,15 +387,15 @@
Holds all connection related data
- Database connections resource:
+ Database connection resources:
:attr:`running_dbapi_query`, boolean flag telling if the executing query
is coming from a dbapi connection or is a query from within the repository
:attr:`cnxset`, the connections set to use to execute queries on sources.
If the transaction is read only, the connection set may be freed between
- actual query. This allows multiple connection with a reasonable low
- connection set pool size. control mechanism is detailed below
+ actual queries. This allows multiple connections with a reasonably low
+ connection set pool size. Control mechanism is detailed below.
.. automethod:: cubicweb.server.session.Connection.set_cnxset
.. automethod:: cubicweb.server.session.Connection.free_cnxset
@@ -409,7 +408,7 @@
Internal transaction data:
- :attr:`data`,is a dictionary containing some shared data
+ :attr:`data` is a dictionary containing some shared data
cleared at the end of the transaction. Hooks and operations may put
arbitrary data in there, and this may also be used as a communication
channel between the client and the repository.
@@ -421,7 +420,7 @@
of None (not yet committing), 'precommit' (calling precommit event on
operations), 'postcommit' (calling postcommit event on operations),
'uncommitable' (some :exc:`ValidationError` or :exc:`Unauthorized` error
- has been raised during the transaction and so it must be rollbacked).
+ has been raised during the transaction and so it must be rolled back).
Hooks controls:
@@ -660,7 +659,7 @@
# Entity cache management #################################################
#
- # The connection entity cache as held in cnx.transaction_data it is removed at end the
+ # The connection entity cache as held in cnx.transaction_data is removed at the
# end of the connection (commit and rollback)
#
# XXX connection level caching may be a pb with multiple repository
@@ -833,9 +832,7 @@
entity._cw_related_cache['%s_%s' % (rtype, role)] = (
rset, tuple(entities))
- # Tracking of entity added of removed in the transaction ##################
- #
- # Those are function to allows cheap call from client in other process.
+ # Tracking of entities added of removed in the transaction ##################
@_open_only
def deleted_in_transaction(self, eid):
@@ -982,6 +979,7 @@
num = self.transaction_data.setdefault('tx_action_count', 0) + 1
self.transaction_data['tx_action_count'] = num
return num
+
# db-api like interface ###################################################
@_open_only
@@ -995,7 +993,7 @@
metas = self.repo.type_and_source_from_eid(eid, self)
if asdict:
return dict(zip(('type', 'source', 'extid', 'asource'), metas))
- # XXX :-1 for cw compat, use asdict=True for full information
+ # XXX :-1 for cw compat, use asdict=True for full information
return metas[:-1]
@_with_cnx_set
@@ -1211,6 +1209,7 @@
if getattr(result, '_cw', None) is not None:
result._cw = session
return result
+ meth_from_cnx.__doc__ = getattr(Connection, meth_name).__doc__
return meth_from_cnx
class Timestamp(object):
@@ -1229,14 +1228,13 @@
# RequestSessionBase at some point
"""Repository user session
- This tie all together:
+ This ties all together:
* session id,
* user,
* connections set,
* other session data.
- About session storage / transactions
- ------------------------------------
+ **About session storage / transactions**
Here is a description of internal session attributes. Besides :attr:`data`
and :attr:`transaction_data`, you should not have to use attributes
@@ -1280,8 +1278,8 @@
used by another session as long as no writing is done. This means we can
have multiple sessions with a reasonably low connections set pool size.
- .. automethod:: cubicweb.server.session.set_cnxset
- .. automethod:: cubicweb.server.session.free_cnxset
+ .. automethod:: cubicweb.server.session.Session.set_cnxset
+ .. automethod:: cubicweb.server.session.Session.free_cnxset
:attr:`mode`, string telling the connections set handling mode, may be one
of 'read' (connections set may be freed), 'write' (some write was done in
@@ -1296,7 +1294,7 @@
of None (not yet committing), 'precommit' (calling precommit event on
operations), 'postcommit' (calling postcommit event on operations),
'uncommitable' (some :exc:`ValidationError` or :exc:`Unauthorized` error
- has been raised during the transaction and so it must be rollbacked).
+ has been raised during the transaction and so it must be rolled back).
.. automethod:: cubicweb.server.session.Session.commit
.. automethod:: cubicweb.server.session.Session.rollback
@@ -1449,7 +1447,7 @@
call `session.commit()` on normal exit.
The `free_cnxset` will be given to rollback/commit methods to indicate
- wether the connections set should be freed or not.
+ whether the connections set should be freed or not.
"""
return transaction(self, free_cnxset)
@@ -1505,7 +1503,7 @@
def keep_cnxset_mode(self, mode):
"""set `mode`, e.g. how the session will keep its connections set:
- * if mode == 'write', the connections set is freed after each ready
+ * if mode == 'write', the connections set is freed after each read
query, but kept until the transaction's end (eg commit or rollback)
when a write query is detected (eg INSERT/SET/DELETE queries)
@@ -1631,7 +1629,7 @@
"""commit the current session's transaction"""
cstate = self._cnx.commit_state
if cstate == 'uncommitable':
- raise QueryError('transaction must be rollbacked')
+ raise QueryError('transaction must be rolled back')
try:
return self._cnx.commit(free_cnxset, reset_pool)
finally:
@@ -1652,7 +1650,7 @@
self._closed = True
tracker.close()
self.rollback()
- self.info('waiting for open connection of session: %s', self)
+ self.debug('waiting for open connection of session: %s', self)
timeout = 10
pendings = tracker.wait(timeout)
if pendings:
@@ -1747,6 +1745,7 @@
self.user._cw = self # XXX remove when "vreg = user._cw.vreg" hack in entity.py is gone
if not safe:
self.disable_hook_categories('integrity')
+ self._tx.ctx_count += 1
def __enter__(self):
return self
--- a/server/sources/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/sources/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -21,6 +21,7 @@
import itertools
from os.path import join, splitext
+from time import time
from datetime import datetime, timedelta
from logging import getLogger
@@ -37,7 +38,9 @@
def dbg_st_search(uri, union, varmap, args, cachekey=None, prefix='rql for'):
if server.DEBUG & server.DBG_RQL:
+ global t
print ' %s %s source: %s' % (prefix, uri, repr(union.as_string()))
+ t = time()
if varmap:
print ' using varmap', varmap
if server.DEBUG & server.DBG_MORE:
@@ -51,9 +54,10 @@
def dbg_results(results):
if server.DEBUG & server.DBG_RQL:
if len(results) > 10:
- print ' -->', results[:10], '...', len(results)
+ print ' -->', results[:10], '...', len(results),
else:
- print ' -->', results
+ print ' -->', results,
+ print 'time: ', time() - t
# return true so it can be used as assertion (and so be killed by python -O)
return True
@@ -179,7 +183,7 @@
elif value is not None:
# type check
try:
- value = configuration.convert(value, optdict, optname)
+ value = configuration._validate(value, optdict, optname)
except Exception as ex:
msg = unicode(ex) # XXX internationalization
raise ValidationError(eid, {role_name('config', 'subject'): msg})
--- a/server/sources/datafeed.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/sources/datafeed.py Mon Jan 13 13:47:47 2014 +0100
@@ -78,6 +78,12 @@
'help': ('Time before logs from datafeed imports are deleted.'),
'group': 'datafeed-source', 'level': 2,
}),
+ ('http-timeout',
+ {'type': 'time',
+ 'default': '1min',
+ 'help': ('Timeout of HTTP GET requests, when synchronizing a source.'),
+ 'group': 'datafeed-source', 'level': 2,
+ }),
)
def check_config(self, source_entity):
@@ -101,6 +107,7 @@
super(DataFeedSource, self).update_config(source_entity, typed_config)
self.synchro_interval = timedelta(seconds=typed_config['synchronization-interval'])
self.max_lock_lifetime = timedelta(seconds=typed_config['max-lock-lifetime'])
+ self.http_timeout = typed_config['http-timeout']
def init(self, activated, source_entity):
super(DataFeedSource, self).init(activated, source_entity)
@@ -438,7 +445,7 @@
if url.startswith('http'):
url = self.normalize_url(url)
self.source.info('GET %s', url)
- stream = _OPENER.open(url)
+ stream = _OPENER.open(url, timeout=self.source.http_timeout)
elif url.startswith('file://'):
stream = open(url[7:])
else:
@@ -454,7 +461,8 @@
def is_deleted(self, extid, etype, eid):
if extid.startswith('http'):
try:
- _OPENER.open(self.normalize_url(extid)) # XXX HTTP HEAD request
+ _OPENER.open(self.normalize_url(extid), # XXX HTTP HEAD request
+ timeout=self.source.http_timeout)
except urllib2.HTTPError as ex:
if ex.code == 404:
return True
--- a/server/sources/extlite.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/sources/extlite.py Mon Jan 13 13:47:47 2014 +0100
@@ -295,7 +295,7 @@
query, args, ex.args[0])
try:
session.cnxset.connection(self.uri).rollback()
- self.critical('transaction has been rollbacked')
+ self.critical('transaction has been rolled back')
except Exception:
pass
raise
--- a/server/sources/native.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/sources/native.py Mon Jan 13 13:47:47 2014 +0100
@@ -410,14 +410,14 @@
def init(self, activated, source_entity):
- super(NativeSQLSource, self).init(activated, source_entity)
- self.init_creating(source_entity._cw.cnxset)
try:
# test if 'asource' column exists
query = self.dbhelper.sql_add_limit_offset('SELECT asource FROM entities', 1)
source_entity._cw.system_sql(query)
except Exception as ex:
self.eid_type_source = self.eid_type_source_pre_131
+ super(NativeSQLSource, self).init(activated, source_entity)
+ self.init_creating(source_entity._cw.cnxset)
def shutdown(self):
if self._eid_creation_cnx:
@@ -751,28 +751,23 @@
try:
session.cnxset.connection(self.uri).rollback()
if self.repo.config.mode != 'test':
- self.critical('transaction has been rollbacked')
+ self.critical('transaction has been rolled back')
except Exception as ex:
pass
if ex.__class__.__name__ == 'IntegrityError':
# need string comparison because of various backends
for arg in ex.args:
- mo = re.search('unique_cw_[^ ]+_idx', arg)
+ # postgres, sqlserver
+ mo = re.search("unique_[a-z0-9]{32}", arg)
if mo is not None:
- index_name = mo.group(0)
- # right-chop '_idx' postfix
- # (garanteed to be there, see regexp above)
- elements = index_name[:-4].split('_cw_')[1:]
- etype = elements[0]
- rtypes = elements[1:]
- raise UniqueTogetherError(etype, rtypes)
+ raise UniqueTogetherError(session, cstrname=mo.group(0))
+ # sqlite
mo = re.search('columns (.*) are not unique', arg)
if mo is not None: # sqlite in use
# we left chop the 'cw_' prefix of attribute names
rtypes = [c.strip()[3:]
for c in mo.group(1).split(',')]
- etype = '???'
- raise UniqueTogetherError(etype, rtypes)
+ raise UniqueTogetherError(session, rtypes=rtypes)
raise
return cursor
@@ -795,7 +790,7 @@
try:
session.cnxset.connection(self.uri).rollback()
if self.repo.config.mode != 'test':
- self.critical('transaction has been rollbacked')
+ self.critical('transaction has been rolled back')
except Exception:
pass
raise
@@ -1537,6 +1532,7 @@
tx_time %s NOT NULL
);;
CREATE INDEX transactions_tx_user_idx ON transactions(tx_user);;
+CREATE INDEX transactions_tx_time_idx ON transactions(tx_time);;
CREATE TABLE tx_entity_actions (
tx_uuid CHAR(32) REFERENCES transactions(tx_uuid) ON DELETE CASCADE,
@@ -1551,6 +1547,7 @@
CREATE INDEX tx_entity_actions_txa_public_idx ON tx_entity_actions(txa_public);;
CREATE INDEX tx_entity_actions_eid_idx ON tx_entity_actions(eid);;
CREATE INDEX tx_entity_actions_etype_idx ON tx_entity_actions(etype);;
+CREATE INDEX tx_entity_actions_tx_uuid_idx ON tx_entity_actions(tx_uuid);;
CREATE TABLE tx_relation_actions (
tx_uuid CHAR(32) REFERENCES transactions(tx_uuid) ON DELETE CASCADE,
@@ -1565,6 +1562,7 @@
CREATE INDEX tx_relation_actions_txa_public_idx ON tx_relation_actions(txa_public);;
CREATE INDEX tx_relation_actions_eid_from_idx ON tx_relation_actions(eid_from);;
CREATE INDEX tx_relation_actions_eid_to_idx ON tx_relation_actions(eid_to);;
+CREATE INDEX tx_relation_actions_tx_uuid_idx ON tx_relation_actions(tx_uuid);;
""" % (helper.sql_create_sequence('entities_id_seq').replace(';', ';;'),
typemap['Datetime'], typemap['Datetime'], typemap['Datetime'],
typemap['Boolean'], typemap['Bytes'], typemap['Boolean'])
--- a/server/sources/pyrorql.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/sources/pyrorql.py Mon Jan 13 13:47:47 2014 +0100
@@ -20,6 +20,11 @@
__docformat__ = "restructuredtext en"
_ = unicode
+# module is lazily imported
+import warnings
+warnings.warn('Imminent drop of pyrorql source. Switch to datafeed now!',
+ DeprecationWarning)
+
import threading
from Pyro.errors import PyroError, ConnectionClosedError
--- a/server/sources/rql2sql.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/sources/rql2sql.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -62,8 +62,8 @@
Not, Comparison, ColumnAlias, Relation, SubQuery, Exists)
from cubicweb import QueryError
+from cubicweb.rqlrewrite import cleanup_solutions
from cubicweb.server.sqlutils import SQL_PREFIX
-from cubicweb.server.utils import cleanup_solutions
ColumnAlias._q_invariant = False # avoid to check for ColumnAlias / Variable
@@ -242,12 +242,6 @@
rhsconst = None # ColumnAlias
return lhs, lhsconst, rhs, rhsconst
-def switch_relation_field(sql, table=''):
- switchedsql = sql.replace(table + '.eid_from', '__eid_from__')
- switchedsql = switchedsql.replace(table + '.eid_to',
- table + '.eid_from')
- return switchedsql.replace('__eid_from__', table + '.eid_to')
-
def sort_term_selection(sorts, rqlst, groups):
# XXX beurk
if isinstance(rqlst, list):
@@ -486,13 +480,10 @@
return relation._q_sqltable
rid = 'rel_%s%s' % (relation.r_type, self.count)
# relation's table is belonging to the root scope if it is the principal
- # table of one of it's variable and if that variable belong's to parent
+ # table of one of its variable and that variable belong's to parent
# scope
for varref in relation.iget_nodes(VariableRef):
var = varref.variable
- if isinstance(var, ColumnAlias):
- scope = 0
- break
# XXX may have a principal without being invariant for this generation,
# not sure this is a pb or not
if var.stinfo.get('principal') is relation and var.scope is var.stmt:
@@ -1135,8 +1126,6 @@
sqls += self._process_relation_term(relation, rid, lhsvar, lhsconst, 'eid_from')
sqls += self._process_relation_term(relation, rid, rhsvar, rhsconst, 'eid_to')
sql = ' AND '.join(sqls)
- if rschema.symmetric:
- sql = '(%s OR %s)' % (sql, switch_relation_field(sql))
return sql
def _visit_outer_join_relation(self, relation, rschema):
@@ -1248,6 +1237,8 @@
except KeyError:
if lhsalias is None:
lhssql = lhsconst.accept(self)
+ elif attr == 'eid':
+ lhssql = lhsvar.accept(self)
else:
lhssql = '%s.%s%s' % (lhsalias, SQL_PREFIX, attr)
condition = '%s=%s' % (lhssql, (rhsconst or rhsvar).accept(self))
--- a/server/sqlutils.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/sqlutils.py Mon Jan 13 13:47:47 2014 +0100
@@ -41,11 +41,6 @@
SQL_PREFIX = 'cw_'
def _run_command(cmd):
- """backup/restore command are string w/ lgc < 0.47, lists with earlier versions
- """
- if isinstance(cmd, basestring):
- print '->', cmd
- return subprocess.call(cmd, shell=True)
print ' '.join(cmd)
return subprocess.call(cmd)
@@ -332,12 +327,13 @@
class group_concat(object):
def __init__(self):
- self.values = []
+ self.values = set()
def step(self, value):
if value is not None:
- self.values.append(value)
+ self.values.add(value)
def finalize(self):
- return ', '.join(self.values)
+ return ', '.join(unicode(v) for v in self.values)
+
cnx.create_aggregate("GROUP_CONCAT", 1, group_concat)
def _limit_size(text, maxsize, format='text/plain'):
@@ -378,7 +374,7 @@
def init_postgres_connexion(cnx):
cnx.cursor().execute('SET TIME ZONE UTC')
# commit is needed, else setting are lost if the connection is first
- # rollbacked
+ # rolled back
cnx.commit()
postgres_hooks = SQL_CONNECT_HOOKS.setdefault('postgres', [])
--- a/server/ssplanner.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/ssplanner.py Mon Jan 13 13:47:47 2014 +0100
@@ -101,23 +101,16 @@
Return None when no query actually needed, else the given select node that
will be used as substep query.
-
- When select has nothing selected, search in origrqlst for restriction that
- should be considered.
"""
if origrqlst.where is not None and not select.selection:
# no selection, append one randomly by searching for a relation which is
- # neither a type restriction (is) nor an eid specification (not neged
- # eid with constant node)
+ # not neged neither a type restriction (is/is_instance_of)
for rel in origrqlst.where.iget_nodes(Relation):
- if rel.neged(strict=True) or not (
- rel.is_types_restriction() or
- (rel.r_type == 'eid'
- and isinstance(rel.get_variable_parts()[1], Constant))):
+ if not (rel.neged(traverse_scope=True) or rel.is_types_restriction()):
select.append_selected(rel.children[0].copy(select))
break
else:
- return
+ return None
if select.selection:
if origrqlst.where is not None:
select.set_where(origrqlst.where.copy(select))
--- a/server/test/data/extern_mapping.py Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""mapping file for source used in unittest_multisources.py"""
-
-support_entities = {'Card': True, 'Affaire': True, 'State': True}
-support_relations = {'in_state': True, 'documented_by': True, 'multisource_inlined_rel': True}
-
-cross_relations = set( ('documented_by',) )
--- a/server/test/data/migratedapp/schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/data/migratedapp/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""cw.server.migraction test"""
+import datetime as dt
from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
SubjectRelation, Bytes,
RichString, String, Int, Boolean, Datetime, Date)
@@ -38,13 +39,27 @@
concerne = SubjectRelation('Societe')
opt_attr = Bytes()
-class concerne(RelationType):
+class Societe(WorkflowableEntityType):
__permissions__ = {
- 'read': ('managers', 'users', 'guests'),
- 'add': ('managers', RRQLExpression('U has_update_permission S')),
- 'delete': ('managers', RRQLExpression('O owned_by U')),
+ 'read': ('managers', 'users', 'guests'),
+ 'update': ('managers', 'owners'),
+ 'delete': ('managers', 'owners'),
+ 'add': ('managers', 'users',)
}
+ nom = String(maxsize=64, fulltextindexed=True)
+ web = String(maxsize=128)
+ tel = Int()
+ fax = Int()
+ rncs = String(maxsize=128)
+ ad1 = String(maxsize=128)
+ ad2 = String(maxsize=128)
+ ad3 = String(maxsize=128)
+ cp = String(maxsize=12)
+ ville= String(maxsize=32)
+# Division and SubDivision are gone
+
+# New
class Para(EntityType):
para = String(maxsize=512)
newattr = String()
@@ -62,43 +77,18 @@
'PE require_permission P, P name "add_note", '
'P require_group G'),)}
- whatever = Int(default=2) # keep it before `date` for unittest_migraction.test_add_attribute_int
+ whatever = Int(default=0) # keep it before `date` for unittest_migraction.test_add_attribute_int
+ yesno = Boolean(default=False)
date = Datetime()
type = String(maxsize=1)
unique_id = String(maxsize=1, required=True, unique=True)
mydate = Date(default='TODAY')
+ oldstyledefaultdate = Date(default='2013/01/01')
+ newstyledefaultdate = Date(default=dt.date(2013, 1, 1))
shortpara = String(maxsize=64, default='hop')
ecrit_par = SubjectRelation('Personne', constraints=[RQLConstraint('S concerne A, O concerne A')])
attachment = SubjectRelation('File')
-class Text(Para):
- __specializes_schema__ = True
- summary = String(maxsize=512)
-
-class ecrit_par(RelationType):
- __permissions__ = {'read': ('managers', 'users', 'guests',),
- 'delete': ('managers', ),
- 'add': ('managers',
- RRQLExpression('O require_permission P, P name "add_note", '
- 'U in_group G, P require_group G'),)
- }
- inlined = True
- cardinality = '?*'
-
-
-class Folder2(EntityType):
- """folders are used to classify entities. They may be defined as a tree.
- When you include the Folder entity, all application specific entities
- may then be classified using the "filed_under" relation.
- """
- name = String(required=True, indexed=True, internationalizable=True,
- constraints=[UniqueConstraint(), SizeConstraint(64)])
- description = RichString(fulltextindexed=True)
-
-class filed_under2(RelationDefinition):
- subject ='*'
- object = 'Folder2'
-
class Personne(EntityType):
__unique_together__ = [('nom', 'prenom', 'datenaiss')]
@@ -120,32 +110,71 @@
concerne2 = SubjectRelation(('Affaire', 'Note'), cardinality='1*')
connait = SubjectRelation('Personne', symmetric=True)
+class concerne(RelationType):
+ __permissions__ = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': ('managers', RRQLExpression('U has_update_permission S')),
+ 'delete': ('managers', RRQLExpression('O owned_by U')),
+ }
+# `Old` entity type is gonce
+# `comments` is gone
+# `fiche` is gone
+# `multisource_*` rdefs are gone
+# `see_also_*` rdefs are gone
+
+class evaluee(RelationDefinition):
+ subject = ('Personne', 'CWUser', 'Societe')
+ object = ('Note')
+
+class ecrit_par(RelationType):
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
+ 'delete': ('managers', ),
+ 'add': ('managers',
+ RRQLExpression('O require_permission P, P name "add_note", '
+ 'U in_group G, P require_group G'),)
+ }
+ inlined = True
+ cardinality = '?*'
+
+# `copain` rdef is gone
+# `tags` rdef is gone
+# `filed_under` rdef is gone
+# `require_permission` rdef is gone
+# `require_state` rdef is gone
+# `personne_composite` rdef is gone
+# `personne_inlined` rdef is gone
+# `login_user` rdef is gone
+# `ambiguous_inlined` rdef is gone
+
+# New
+class Text(Para):
+ __specializes_schema__ = True
+ summary = String(maxsize=512)
+
+
+# New
+class Folder2(EntityType):
+ """folders are used to classify entities. They may be defined as a tree.
+ When you include the Folder entity, all application specific entities
+ may then be classified using the "filed_under" relation.
+ """
+ name = String(required=True, indexed=True, internationalizable=True,
+ constraints=[UniqueConstraint(), SizeConstraint(64)])
+ description = RichString(fulltextindexed=True)
+
+# New
+class filed_under2(RelationDefinition):
+ subject ='*'
+ object = 'Folder2'
+
+
+# New
class New(EntityType):
new_name = String()
-class Societe(WorkflowableEntityType):
- __permissions__ = {
- 'read': ('managers', 'users', 'guests'),
- 'update': ('managers', 'owners'),
- 'delete': ('managers', 'owners'),
- 'add': ('managers', 'users',)
- }
- nom = String(maxsize=64, fulltextindexed=True)
- web = String(maxsize=128)
- tel = Int()
- fax = Int()
- rncs = String(maxsize=128)
- ad1 = String(maxsize=128)
- ad2 = String(maxsize=128)
- ad3 = String(maxsize=128)
- cp = String(maxsize=12)
- ville= String(maxsize=32)
-
+# New
class same_as(RelationDefinition):
subject = ('Societe',)
object = 'ExternalUri'
-class evaluee(RelationDefinition):
- subject = ('Personne', 'CWUser', 'Societe')
- object = ('Note')
--- a/server/test/data/schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/data/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -94,7 +94,12 @@
'read': ('managers', 'users', 'guests'),
'update': ('managers', ERQLExpression('X in_state S, S name "todo"')),
})
-
+ something = String(maxsize=1,
+ __permissions__ = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': (ERQLExpression('NOT X para NULL'),),
+ 'update': ('managers', 'owners')
+ })
migrated_from = SubjectRelation('Note')
attachment = SubjectRelation('File')
inline1 = SubjectRelation('Affaire', inlined=True, cardinality='?*',
@@ -119,6 +124,7 @@
tzdatenaiss = TZDatetime()
test = Boolean(__permissions__={
'read': ('managers', 'users', 'guests'),
+ 'add': ('managers',),
'update': ('managers',),
})
description = String()
--- a/server/test/unittest_ldapsource.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_ldapsource.py Mon Jan 13 13:47:47 2014 +0100
@@ -142,16 +142,26 @@
return self._pull(self.session)
def setup_database(self):
- if self.test_db_id == 'ldap-feed':
- with self.session.repo.internal_session(safe=True) as session:
- session.execute('DELETE Any E WHERE E cw_source S, S name "ldap"')
- session.commit()
- if self.test_db_id == 'ldap-feed':
- src = self.sexecute('CWSource S WHERE S name "ldap"').get_entity(0,0)
- src.cw_set(config=CONFIG_LDAPFEED)
- self.session.commit()
+ with self.session.repo.internal_session(safe=True) as session:
+ session.execute('DELETE Any E WHERE E cw_source S, S name "ldap"')
+ session.execute('SET S config %(conf)s, S url %(url)s '
+ 'WHERE S is CWSource, S name "ldap"',
+ {"conf": CONFIG_LDAPFEED, 'url': URL} )
+ session.commit()
self.pull()
+ def add_ldap_entry(self, dn, mods):
+ """
+ add an LDAP entity
+ """
+ modcmd = ['dn: %s'%dn, 'changetype: add']
+ for key, values in mods.iteritems():
+ if isinstance(values, basestring):
+ values = [values]
+ for value in values:
+ modcmd.append('%s: %s'%(key, value))
+ self._ldapmodify(modcmd)
+
def delete_ldap_entry(self, dn):
"""
delete an LDAP entity
@@ -328,9 +338,23 @@
'deactivated')
# check that it doesn't choke
self.pull()
- # reset the ldap database
- self.tearDownClass()
- self.setUpClass()
+ # reinsert syt
+ self.add_ldap_entry('uid=syt,ou=People,dc=cubicweb,dc=test',
+ { 'objectClass': ['OpenLDAPperson','posixAccount','top','shadowAccount'],
+ 'cn': 'Sylvain Thenault',
+ 'sn': 'Thenault',
+ 'gidNumber': '1004',
+ 'uid': 'syt',
+ 'homeDirectory': '/home/syt',
+ 'shadowFlag': '134538764',
+ 'uidNumber': '1004',
+ 'givenName': 'Sylvain',
+ 'telephoneNumber': '106',
+ 'displayName': 'sthenault',
+ 'gecos': 'Sylvain Thenault',
+ 'mail': ['sylvain.thenault@logilab.fr','syt@logilab.fr'],
+ 'userPassword': 'syt',
+ })
self.pull()
self.assertEqual(self.execute('Any N WHERE U login "syt", '
'U in_state S, S name N').rows[0][0],
@@ -429,8 +453,5 @@
-
-
-
if __name__ == '__main__':
unittest_main()
--- a/server/test/unittest_migractions.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_migractions.py Mon Jan 13 13:47:47 2014 +0100
@@ -71,6 +71,22 @@
CubicWebTC.tearDown(self)
self.repo.vreg['etypes'].clear_caches()
+ def test_add_attribute_bool(self):
+ self.assertFalse('yesno' in self.schema)
+ self.session.create_entity('Note')
+ self.commit()
+ self.mh.cmd_add_attribute('Note', 'yesno')
+ self.assertTrue('yesno' in self.schema)
+ self.assertEqual(self.schema['yesno'].subjects(), ('Note',))
+ self.assertEqual(self.schema['yesno'].objects(), ('Boolean',))
+ self.assertEqual(self.schema['Note'].default('yesno'), False)
+ # test default value set on existing entities
+ note = self.session.execute('Note X').get_entity(0, 0)
+ self.assertEqual(note.yesno, False)
+ # test default value set for next entities
+ self.assertEqual(self.session.create_entity('Note').yesno, False)
+ self.mh.rollback()
+
def test_add_attribute_int(self):
self.assertFalse('whatever' in self.schema)
self.session.create_entity('Note')
@@ -81,12 +97,13 @@
self.assertTrue('whatever' in self.schema)
self.assertEqual(self.schema['whatever'].subjects(), ('Note',))
self.assertEqual(self.schema['whatever'].objects(), ('Int',))
- self.assertEqual(self.schema['Note'].default('whatever'), 2)
+ self.assertEqual(self.schema['Note'].default('whatever'), 0)
# test default value set on existing entities
note = self.session.execute('Note X').get_entity(0, 0)
- self.assertEqual(note.whatever, 2)
+ self.assertIsInstance(note.whatever, int)
+ self.assertEqual(note.whatever, 0)
# test default value set for next entities
- self.assertEqual(self.session.create_entity('Note').whatever, 2)
+ self.assertEqual(self.session.create_entity('Note').whatever, 0)
# test attribute order
orderdict2 = dict(self.mh.rqlexec('Any RTN, O WHERE X name "Note", RDEF from_entity X, '
'RDEF relation_type RT, RDEF ordernum O, RT name RTN'))
@@ -126,9 +143,14 @@
def test_add_datetime_with_default_value_attribute(self):
self.assertFalse('mydate' in self.schema)
- self.assertFalse('shortpara' in self.schema)
+ self.assertFalse('oldstyledefaultdate' in self.schema)
+ self.assertFalse('newstyledefaultdate' in self.schema)
self.mh.cmd_add_attribute('Note', 'mydate')
+ self.mh.cmd_add_attribute('Note', 'oldstyledefaultdate')
+ self.mh.cmd_add_attribute('Note', 'newstyledefaultdate')
self.assertTrue('mydate' in self.schema)
+ self.assertTrue('oldstyledefaultdate' in self.schema)
+ self.assertTrue('newstyledefaultdate' in self.schema)
self.assertEqual(self.schema['mydate'].subjects(), ('Note', ))
self.assertEqual(self.schema['mydate'].objects(), ('Date', ))
testdate = date(2005, 12, 13)
@@ -136,8 +158,13 @@
eid2 = self.mh.rqlexec('INSERT Note N: N mydate %(mydate)s', {'mydate' : testdate})[0][0]
d1 = self.mh.rqlexec('Any D WHERE X eid %(x)s, X mydate D', {'x': eid1})[0][0]
d2 = self.mh.rqlexec('Any D WHERE X eid %(x)s, X mydate D', {'x': eid2})[0][0]
+ d3 = self.mh.rqlexec('Any D WHERE X eid %(x)s, X oldstyledefaultdate D', {'x': eid1})[0][0]
+ d4 = self.mh.rqlexec('Any D WHERE X eid %(x)s, X newstyledefaultdate D', {'x': eid1})[0][0]
self.assertEqual(d1, date.today())
self.assertEqual(d2, testdate)
+ myfavoritedate = date(2013, 1, 1)
+ self.assertEqual(d3, myfavoritedate)
+ self.assertEqual(d4, myfavoritedate)
self.mh.rollback()
def test_drop_chosen_constraints_ctxmanager(self):
@@ -369,14 +396,14 @@
'X description D')[0][0],
'title for this person')
rinorder = [n for n, in cursor.execute(
- 'Any N ORDERBY O WHERE X is CWAttribute, X relation_type RT, RT name N,'
+ 'Any N ORDERBY O,N WHERE X is CWAttribute, X relation_type RT, RT name N,'
'X from_entity FE, FE name "Personne",'
'X ordernum O')]
expected = [u'nom', u'prenom', u'sexe', u'promo', u'ass', u'adel', u'titre',
- u'web', u'tel', u'fax', u'datenaiss', u'tzdatenaiss', u'test',
+ u'web', u'tel', u'fax', u'datenaiss', u'test', u'tzdatenaiss',
u'description', u'firstname',
u'creation_date', u'cwuri', u'modification_date']
- self.assertEqual(rinorder, expected)
+ self.assertEqual(expected, rinorder)
# test permissions synchronization ####################################
# new rql expr to add note entity
@@ -388,8 +415,8 @@
self.assertEqual(eexpr.reverse_read_permission, ())
self.assertEqual(eexpr.reverse_delete_permission, ())
self.assertEqual(eexpr.reverse_update_permission, ())
- # no more rqlexpr to delete and add para attribute
- self.assertFalse(self._rrqlexpr_rset('add', 'para'))
+ self.assertTrue(self._rrqlexpr_rset('add', 'para'))
+ # no rqlexpr to delete para attribute
self.assertFalse(self._rrqlexpr_rset('delete', 'para'))
# new rql expr to add ecrit_par relation
rexpr = self._rrqlexpr_entity('add', 'ecrit_par')
@@ -417,28 +444,33 @@
self.assertEqual(len(self._rrqlexpr_rset('delete', 'concerne')), len(delete_concerne_rqlexpr))
self.assertEqual(len(self._rrqlexpr_rset('add', 'concerne')), len(add_concerne_rqlexpr))
# * migrschema involve:
- # * 7 rqlexprs deletion (2 in (Affaire read + Societe + travaille) + 1
- # in para attribute)
+ # * 7 erqlexprs deletions (2 in (Affaire + Societe + Note.para) + 1 Note.something
+ # * 2 rrqlexprs deletions (travaille)
# * 1 update (Affaire update)
# * 2 new (Note add, ecrit_par add)
- # * 2 implicit new for attributes update_permission (Note.para, Personne.test)
+ # * 2 implicit new for attributes (Note.para, Person.test)
# remaining orphan rql expr which should be deleted at commit (composite relation)
- self.assertEqual(cursor.execute('Any COUNT(X) WHERE X is RQLExpression, '
- 'NOT ET1 read_permission X, NOT ET2 add_permission X, '
- 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0],
- 7+1)
+ # unattached expressions -> pending deletion on commit
+ self.assertEqual(cursor.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "ERQLExpression",'
+ 'NOT ET1 read_permission X, NOT ET2 add_permission X, '
+ 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0],
+ 7)
+ self.assertEqual(cursor.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "RRQLExpression",'
+ 'NOT ET1 read_permission X, NOT ET2 add_permission X, '
+ 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0],
+ 2)
# finally
self.assertEqual(cursor.execute('Any COUNT(X) WHERE X is RQLExpression')[0][0],
- nbrqlexpr_start + 1 + 2 + 2)
+ nbrqlexpr_start + 1 + 2 + 2 + 2)
self.mh.commit()
# unique_together test
self.assertEqual(len(self.schema.eschema('Personne')._unique_together), 1)
- self.assertItemsEqual(self.schema.eschema('Personne')._unique_together[0],
+ self.assertCountEqual(self.schema.eschema('Personne')._unique_together[0],
('nom', 'prenom', 'datenaiss'))
rset = cursor.execute('Any C WHERE C is CWUniqueTogetherConstraint, C constraint_of ET, ET name "Personne"')
self.assertEqual(len(rset), 1)
relations = [r.name for r in rset.get_entity(0, 0).relations]
- self.assertItemsEqual(relations, ('nom', 'prenom', 'datenaiss'))
+ self.assertCountEqual(relations, ('nom', 'prenom', 'datenaiss'))
def _erqlexpr_rset(self, action, ertype):
rql = 'RQLExpression X WHERE ET is CWEType, ET %s_permission X, ET name %%(name)s' % action
--- a/server/test/unittest_querier.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_querier.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,5 +1,5 @@
# -*- coding: iso-8859-1 -*-
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -383,9 +383,9 @@
self.execute("INSERT Personne X: X nom 'bidule'")[0]
rset = self.execute('Any Y where X name TMP, Y nom in (TMP, "bidule")')
#self.assertEqual(rset.description, [('Personne',), ('Personne',)])
- self.assert_(('Personne',) in rset.description)
+ self.assertIn(('Personne',), rset.description)
rset = self.execute('DISTINCT Any Y where X name TMP, Y nom in (TMP, "bidule")')
- self.assert_(('Personne',) in rset.description)
+ self.assertIn(('Personne',), rset.description)
def test_select_not_attr(self):
peid = self.execute("INSERT Personne X: X nom 'bidule'")[0][0]
@@ -466,8 +466,8 @@
self.execute("SET X tags Y WHERE X eid %(t)s, Y eid %(g)s",
{'g': geid, 't': teid})
rset = self.execute("Any GN,TN ORDERBY GN WHERE T? tags G, T name TN, G name GN")
- self.assertTrue(['users', 'tag'] in rset.rows)
- self.assertTrue(['activated', None] in rset.rows)
+ self.assertIn(['users', 'tag'], rset.rows)
+ self.assertIn(['activated', None], rset.rows)
rset = self.execute("Any GN,TN ORDERBY GN WHERE T tags G?, T name TN, G name GN")
self.assertEqual(rset.rows, [[None, 'tagbis'], ['users', 'tag']])
@@ -576,7 +576,7 @@
self.assertListEqual(rset.rows,
[[u'description_format', 12],
[u'description', 13],
- [u'name', 16],
+ [u'name', 17],
[u'created_by', 43],
[u'creation_date', 43],
[u'cw_source', 43],
@@ -818,11 +818,11 @@
self.execute("INSERT Tag X: X name 'bidule', X creation_date NOW")
self.execute("INSERT Tag Y: Y name 'toto'")
rset = self.execute("Any D WHERE X name in ('bidule', 'toto') , X creation_date D")
- self.assert_(isinstance(rset.rows[0][0], datetime), rset.rows)
+ self.assertIsInstance(rset.rows[0][0], datetime)
rset = self.execute('Tag X WHERE X creation_date TODAY')
self.assertEqual(len(rset.rows), 2)
rset = self.execute('Any MAX(D) WHERE X is Tag, X creation_date D')
- self.assertTrue(isinstance(rset[0][0], datetime), (rset[0][0], type(rset[0][0])))
+ self.assertIsInstance(rset[0][0], datetime)
def test_today(self):
self.execute("INSERT Tag X: X name 'bidule', X creation_date TODAY")
@@ -1268,12 +1268,21 @@
newname = self.execute('Any XN WHERE X eid %(x)s, X title XN', {'x': beid})[0][0]
self.assertEqual(newname, 'toto-moved')
+ def test_update_not_exists(self):
+ rset = self.execute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
+ eid1, eid2 = rset[0][0], rset[0][1]
+ rset = self.execute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s, "
+ "NOT EXISTS(Z ecrit_par X)",
+ {'x': unicode(eid1), 'y': unicode(eid2)})
+ self.assertEqual(tuplify(rset.rows), [(eid1, eid2)])
+
def test_update_query_error(self):
self.execute("INSERT Personne Y: Y nom 'toto'")
self.assertRaises(Exception, self.execute, "SET X nom 'toto', X is Personne")
self.assertRaises(QueryError, self.execute, "SET X nom 'toto', X has_text 'tutu' WHERE X is Personne")
self.assertRaises(QueryError, self.execute, "SET X login 'tutu', X eid %s" % cnx.user(self.session).eid)
+
# HAVING on write queries test #############################################
def test_update_having(self):
--- a/server/test/unittest_repository.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_repository.py Mon Jan 13 13:47:47 2014 +0100
@@ -52,16 +52,18 @@
and relation
"""
- def test_uniquetogether(self):
+ def test_unique_together_constraint(self):
self.execute('INSERT Societe S: S nom "Logilab", S type "SSLL", S cp "75013"')
with self.assertRaises(ValidationError) as wraperr:
self.execute('INSERT Societe S: S nom "Logilab", S type "SSLL", S cp "75013"')
- self.assertEqual({'nom': u'violates unique_together constraints (cp, nom, type)',
- 'cp': u'violates unique_together constraints (cp, nom, type)',
- 'type': u'violates unique_together constraints (cp, nom, type)'},
- wraperr.exception.args[1])
+ self.assertEqual(
+ {'cp': u'cp is part of violated unicity constraint',
+ 'nom': u'nom is part of violated unicity constraint',
+ 'type': u'type is part of violated unicity constraint',
+ 'unicity constraint': u'some relations violate a unicity constraint'},
+ wraperr.exception.args[1])
- def test_unique_together(self):
+ def test_unique_together_schema(self):
person = self.repo.schema.eschema('Personne')
self.assertEqual(len(person._unique_together), 1)
self.assertItemsEqual(person._unique_together[0],
@@ -135,7 +137,7 @@
self.assertTrue(self.execute('Any X WHERE X is CWGroup, X name "toto"'))
with self.assertRaises(QueryError) as cm:
self.commit()
- self.assertEqual(str(cm.exception), 'transaction must be rollbacked')
+ self.assertEqual(str(cm.exception), 'transaction must be rolled back')
self.rollback()
self.assertFalse(self.execute('Any X WHERE X is CWGroup, X name "toto"'))
@@ -152,7 +154,7 @@
self.assertTrue(self.execute('Any X WHERE X is CWGroup, X name "toto"'))
with self.assertRaises(QueryError) as cm:
self.commit()
- self.assertEqual(str(cm.exception), 'transaction must be rollbacked')
+ self.assertEqual(str(cm.exception), 'transaction must be rolled back')
self.rollback()
self.assertFalse(self.execute('Any X WHERE X is CWGroup, X name "toto"'))
@@ -272,19 +274,21 @@
def test_initial_schema(self):
schema = self.repo.schema
# check order of attributes is respected
- self.assertListEqual([r.type for r in schema.eschema('CWAttribute').ordered_relations()
- if not r.type in ('eid', 'is', 'is_instance_of', 'identity',
- 'creation_date', 'modification_date', 'cwuri',
- 'owned_by', 'created_by', 'cw_source',
- 'update_permission', 'read_permission',
- 'in_basket')],
- ['relation_type',
- 'from_entity', 'to_entity',
- 'constrained_by',
- 'cardinality', 'ordernum',
- 'indexed', 'fulltextindexed', 'internationalizable',
- 'defaultval', 'extra_props',
- 'description', 'description_format'])
+ notin = set(('eid', 'is', 'is_instance_of', 'identity',
+ 'creation_date', 'modification_date', 'cwuri',
+ 'owned_by', 'created_by', 'cw_source',
+ 'update_permission', 'read_permission',
+ 'add_permission', 'in_basket'))
+ self.assertListEqual(['relation_type',
+ 'from_entity', 'to_entity',
+ 'constrained_by',
+ 'cardinality', 'ordernum',
+ 'indexed', 'fulltextindexed', 'internationalizable',
+ 'defaultval', 'extra_props',
+ 'description', 'description_format'],
+ [r.type
+ for r in schema.eschema('CWAttribute').ordered_relations()
+ if r.type not in notin])
self.assertEqual(schema.eschema('CWEType').main_attribute(), 'name')
self.assertEqual(schema.eschema('State').main_attribute(), 'name')
@@ -554,6 +558,30 @@
req.create_entity('Affaire', ref=u'AFF02')
req.execute('SET A duration 10 WHERE A is Affaire')
+
+ def test_user_friendly_error(self):
+ from cubicweb.entities.adapters import IUserFriendlyUniqueTogether
+ class MyIUserFriendlyUniqueTogether(IUserFriendlyUniqueTogether):
+ __select__ = IUserFriendlyUniqueTogether.__select__ & is_instance('Societe')
+ def raise_user_exception(self):
+ raise ValidationError(self.entity.eid, {'hip': 'hop'})
+
+ with self.temporary_appobjects(MyIUserFriendlyUniqueTogether):
+ req = self.request()
+ s = req.create_entity('Societe', nom=u'Logilab', type=u'ssll', cp=u'75013')
+ self.commit()
+ with self.assertRaises(ValidationError) as cm:
+ req.create_entity('Societe', nom=u'Logilab', type=u'ssll', cp=u'75013')
+ self.assertEqual(cm.exception.errors, {'hip': 'hop'})
+ self.rollback()
+ req.create_entity('Societe', nom=u'Logilab', type=u'ssll', cp=u'31400')
+ with self.assertRaises(ValidationError) as cm:
+ s.cw_set(cp=u'31400')
+ self.assertEqual(cm.exception.entity, s.eid)
+ self.assertEqual(cm.exception.errors, {'hip': 'hop'})
+ self.rollback()
+
+
class SchemaDeserialTC(CubicWebTC):
appid = 'data-schemaserial'
--- a/server/test/unittest_rql2sql.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_rql2sql.py Mon Jan 13 13:47:47 2014 +0100
@@ -1070,68 +1070,6 @@
FROM cw_Personne AS _P'''),
]
-SYMMETRIC = [
- ('Any P WHERE X eid 0, X connait P',
- '''SELECT DISTINCT _P.cw_eid
-FROM connait_relation AS rel_connait0, cw_Personne AS _P
-WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=_P.cw_eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=_P.cw_eid)'''
- ),
-
- ('Any P WHERE X connait P',
- '''SELECT DISTINCT _P.cw_eid
-FROM connait_relation AS rel_connait0, cw_Personne AS _P
-WHERE (rel_connait0.eid_to=_P.cw_eid OR rel_connait0.eid_from=_P.cw_eid)'''
- ),
-
- ('Any X WHERE X connait P',
- '''SELECT DISTINCT _X.cw_eid
-FROM connait_relation AS rel_connait0, cw_Personne AS _X
-WHERE (rel_connait0.eid_from=_X.cw_eid OR rel_connait0.eid_to=_X.cw_eid)'''
- ),
-
- ('Any P WHERE X eid 0, NOT X connait P',
- '''SELECT _P.cw_eid
-FROM cw_Personne AS _P
-WHERE NOT (EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=_P.cw_eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=_P.cw_eid)))'''),
-
- ('Any P WHERE NOT X connait P',
- '''SELECT _P.cw_eid
-FROM cw_Personne AS _P
-WHERE NOT (EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_to=_P.cw_eid OR rel_connait0.eid_from=_P.cw_eid)))'''),
-
- ('Any X WHERE NOT X connait P',
- '''SELECT _X.cw_eid
-FROM cw_Personne AS _X
-WHERE NOT (EXISTS(SELECT 1 FROM connait_relation AS rel_connait0 WHERE (rel_connait0.eid_from=_X.cw_eid OR rel_connait0.eid_to=_X.cw_eid)))'''),
-
- ('Any P WHERE X connait P, P nom "nom"',
- '''SELECT DISTINCT _P.cw_eid
-FROM connait_relation AS rel_connait0, cw_Personne AS _P
-WHERE (rel_connait0.eid_to=_P.cw_eid OR rel_connait0.eid_from=_P.cw_eid) AND _P.cw_nom=nom'''),
-
- ('Any X WHERE X connait P, P nom "nom"',
- '''SELECT DISTINCT _X.cw_eid
-FROM connait_relation AS rel_connait0, cw_Personne AS _P, cw_Personne AS _X
-WHERE (rel_connait0.eid_from=_X.cw_eid AND rel_connait0.eid_to=_P.cw_eid OR rel_connait0.eid_to=_X.cw_eid AND rel_connait0.eid_from=_P.cw_eid) AND _P.cw_nom=nom'''
- ),
-
- ('DISTINCT Any P WHERE P connait S OR S connait P, S nom "chouette"',
- '''SELECT DISTINCT _P.cw_eid
-FROM connait_relation AS rel_connait0, cw_Personne AS _P, cw_Personne AS _S
-WHERE (rel_connait0.eid_from=_P.cw_eid AND rel_connait0.eid_to=_S.cw_eid OR rel_connait0.eid_to=_P.cw_eid AND rel_connait0.eid_from=_S.cw_eid) AND _S.cw_nom=chouette'''
- )
- ]
-
-SYMMETRIC_WITH_LIMIT = [
- ('Any X ORDERBY X DESC LIMIT 9 WHERE E eid 0, E connait X',
- '''SELECT DISTINCT _X.cw_eid
-FROM connait_relation AS rel_connait0, cw_Personne AS _X
-WHERE (rel_connait0.eid_from=0 AND rel_connait0.eid_to=_X.cw_eid OR rel_connait0.eid_to=0 AND rel_connait0.eid_from=_X.cw_eid)
-ORDER BY 1 DESC
-LIMIT 9'''
- ),
-]
-
INLINE = [
('Any P WHERE N eid 1, N ecrit_par P, NOT P owned_by P2',
@@ -1478,6 +1416,20 @@
def test_subquery(self):
for t in self._parse((
+ ('Any X,N '
+ 'WHERE NOT EXISTS(X owned_by U) '
+ 'WITH X,N BEING '
+ '((Any X,N WHERE X name N, X is State)'
+ ' UNION '
+ '(Any XX,NN WHERE XX name NN, XX is Transition))',
+ '''SELECT _T0.C0, _T0.C1
+FROM ((SELECT _X.cw_eid AS C0, _X.cw_name AS C1
+FROM cw_State AS _X)
+UNION ALL
+(SELECT _XX.cw_eid AS C0, _XX.cw_name AS C1
+FROM cw_Transition AS _XX)) AS _T0
+WHERE NOT (EXISTS(SELECT 1 FROM owned_by_relation AS rel_owned_by0 WHERE rel_owned_by0.eid_from=_T0.C0))'''),
+
('Any N ORDERBY 1 WITH N BEING '
'((Any N WHERE X name N, X is State)'
' UNION '
@@ -1541,7 +1493,18 @@
FROM (SELECT MAX(_A.cw_ordernum) AS C0
FROM cw_CWAttribute AS _A) AS _T0 LEFT OUTER JOIN (SELECT MAX(_A.cw_ordernum) AS C0
FROM cw_CWRelation AS _A) AS _T1 ON (_T0.C0=_T1.C0)'''),
- )):
+
+ ('''Any TT1,STD,STDD WHERE TT2 identity TT1?
+ WITH TT1,STDD BEING (Any T,SUM(TD) GROUPBY T WHERE T is Affaire, T duration TD, TAG? tags T, TAG name "t"),
+ TT2,STD BEING (Any T,SUM(TD) GROUPBY T WHERE T is Affaire, T duration TD)''',
+ '''SELECT _T0.C0, _T1.C1, _T0.C1
+FROM (SELECT _T.cw_eid AS C0, SUM(_T.cw_duration) AS C1
+FROM cw_Affaire AS _T
+GROUP BY _T.cw_eid) AS _T1 LEFT OUTER JOIN (SELECT _T.cw_eid AS C0, SUM(_T.cw_duration) AS C1
+FROM cw_Affaire AS _T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_to=_T.cw_eid) LEFT OUTER JOIN cw_Tag AS _TAG ON (rel_tags0.eid_from=_TAG.cw_eid AND _TAG.cw_name=t)
+GROUP BY _T.cw_eid) AS _T0 ON (_T1.C0=_T0.C0)'''),
+
+ )):
yield t
@@ -1553,10 +1516,6 @@
rqlst = self._prepare(rql)
self.assertRaises(BadRQLQuery, self.o.generate, rqlst)
- def test_symmetric(self):
- for t in self._parse(SYMMETRIC + SYMMETRIC_WITH_LIMIT):
- yield t
-
def test_inline(self):
for t in self._parse(INLINE):
yield t
@@ -1781,10 +1740,6 @@
'''SELECT DATEPART(WEEKDAY, _P.cw_creation_date)
FROM cw_Personne AS _P''')
- def test_symmetric(self):
- for t in self._parse(SYMMETRIC):
- yield t
-
def test_basic_parse(self):
for t in self._parse(BASIC):# + BASIC_WITH_LIMIT):
yield t
--- a/server/test/unittest_schemaserial.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_schemaserial.py Mon Jan 13 13:47:47 2014 +0100
@@ -22,12 +22,14 @@
from logilab.common.testlib import TestCase, unittest_main
+from cubicweb import Binary
from cubicweb.schema import CubicWebSchemaLoader
from cubicweb.devtools import TestServerConfiguration
from logilab.database import get_db_helper
from yams import register_base_type, unregister_base_type
+schema = config = None
def setUpModule(*args):
register_base_type('BabarTestType', ('jungle_speed',))
helper = get_db_helper('sqlite')
@@ -44,7 +46,7 @@
def tearDownModule(*args):
global schema, config
- del schema, config
+ schema = config = None
unregister_base_type('BabarTestType')
helper = get_db_helper('sqlite')
@@ -63,29 +65,29 @@
class Schema2RQLTC(TestCase):
def test_eschema2rql1(self):
- self.assertListEqual(list(eschema2rql(schema.eschema('CWAttribute'))),
- [
+ self.assertListEqual([
('INSERT CWEType X: X description %(description)s,X final %(final)s,X name %(name)s',
{'description': u'define a final relation: link a final relation type from a non final entity to a final entity type. used to build the instance schema',
- 'name': u'CWAttribute', 'final': False})
- ])
+ 'name': u'CWAttribute', 'final': False})],
+ list(eschema2rql(schema.eschema('CWAttribute'))))
def test_eschema2rql2(self):
- self.assertListEqual(list(eschema2rql(schema.eschema('String'))), [
+ self.assertListEqual([
('INSERT CWEType X: X description %(description)s,X final %(final)s,X name %(name)s',
- {'description': u'', 'final': True, 'name': u'String'})])
+ {'description': u'', 'final': True, 'name': u'String'})],
+ list(eschema2rql(schema.eschema('String'))))
def test_eschema2rql_specialization(self):
# x: None since eschema.eid are None
- self.assertListEqual(sorted(specialize2rql(schema)),
- [('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None}),
- ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None}),
- ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None}),
- ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
- {'et': None, 'x': None})])
+ self.assertListEqual([('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None}),
+ ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None}),
+ ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None}),
+ ('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
+ {'et': None, 'x': None})],
+ sorted(specialize2rql(schema)))
def test_esche2rql_custom_type(self):
expected = [('INSERT CWEType X: X description %(description)s,X final %(final)s,X name %(name)s',
@@ -95,8 +97,7 @@
self.assertListEqual(expected, got)
def test_rschema2rql1(self):
- self.assertListEqual(list(rschema2rql(schema.rschema('relation_type'), cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWRType X: X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s',
{'description': u'link a relation definition to its relation type', 'symmetric': False, 'name': u'relation_type', 'final' : False, 'fulltext_container': None, 'inlined': True}),
@@ -113,11 +114,11 @@
'ordernum': 1, 'cardinality': u'1*'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
{'x': None, 'ct': u'RQLConstraint_eid', 'value': u';O;O final FALSE\n'}),
- ])
+ ],
+ list(rschema2rql(schema.rschema('relation_type'), cstrtypemap)))
def test_rschema2rql2(self):
- self.assertListEqual(list(rschema2rql(schema.rschema('add_permission'), cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWRType X: X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s', {'description': u'', 'symmetric': False, 'name': u'add_permission', 'final': False, 'fulltext_container': None, 'inlined': False}),
('INSERT CWRelation X: X cardinality %(cardinality)s,X composite %(composite)s,X description %(description)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
@@ -133,11 +134,15 @@
('INSERT CWRelation X: X cardinality %(cardinality)s,X composite %(composite)s,X description %(description)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
{'se': None, 'rt': None, 'oe': None,
'description': u'rql expression allowing to add entities/relations of this type', 'composite': 'subject', 'ordernum': 9999, 'cardinality': u'*?'}),
- ])
+ ('INSERT CWRelation X: X cardinality %(cardinality)s,X composite %(composite)s,X description %(description)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
+ {'cardinality': u'**', 'composite': None, 'description': u'groups allowed to add entities/relations of this type',
+ 'oe': None, 'ordernum': 9999, 'rt': None, 'se': None}),
+ ('INSERT CWRelation X: X cardinality %(cardinality)s,X composite %(composite)s,X description %(description)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
+ {'cardinality': u'*?', 'composite': u'subject', 'description': u'rql expression allowing to add entities/relations of this type', 'oe': None, 'ordernum': 9999, 'rt': None, 'se': None})],
+ list(rschema2rql(schema.rschema('add_permission'), cstrtypemap)))
def test_rschema2rql3(self):
- self.assertListEqual(list(rschema2rql(schema.rschema('cardinality'), cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWRType X: X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s',
{'description': u'', 'symmetric': False, 'name': u'cardinality', 'final': True, 'fulltext_container': None, 'inlined': False}),
@@ -155,8 +160,8 @@
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
{'x': None, 'ct': u'SizeConstraint_eid', 'value': u'max=2'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
- {'x': None, 'ct': u'StaticVocabularyConstraint_eid', 'value': u"u'?*', u'1*', u'+*', u'**', u'?+', u'1+', u'++', u'*+', u'?1', u'11', u'+1', u'*1', u'??', u'1?', u'+?', u'*?'"}),
- ])
+ {'x': None, 'ct': u'StaticVocabularyConstraint_eid', 'value': u"u'?*', u'1*', u'+*', u'**', u'?+', u'1+', u'++', u'*+', u'?1', u'11', u'+1', u'*1', u'??', u'1?', u'+?', u'*?'"})],
+ list(rschema2rql(schema.rschema('cardinality'), cstrtypemap)))
def test_rschema2rql_custom_type(self):
expected = [('INSERT CWRType X: X description %(description)s,X final %(final)s,'
@@ -189,43 +194,40 @@
self.assertIn('extra_props', got[1][1])
# this extr
extra_props = got[1][1]['extra_props']
- from cubicweb import Binary
self.assertIsInstance(extra_props, Binary)
got[1][1]['extra_props'] = got[1][1]['extra_props'].getvalue()
self.assertListEqual(expected, got)
def test_rdef2rql(self):
- self.assertListEqual(list(rdef2rql(schema['description_format'].rdefs[('CWRType', 'String')], cstrtypemap)),
- [
+ self.assertListEqual([
('INSERT CWAttribute X: X cardinality %(cardinality)s,X defaultval %(defaultval)s,X description %(description)s,X fulltextindexed %(fulltextindexed)s,X indexed %(indexed)s,X internationalizable %(internationalizable)s,X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
{'se': None, 'rt': None, 'oe': None,
- 'description': u'', 'internationalizable': True, 'fulltextindexed': False, 'ordernum': 3, 'defaultval': u'text/plain', 'indexed': False, 'cardinality': u'?1'}),
+ 'description': u'', 'internationalizable': True, 'fulltextindexed': False,
+ 'ordernum': 3, 'defaultval': Binary('text/plain'), 'indexed': False, 'cardinality': u'?1'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
{'x': None, 'value': u'None', 'ct': 'FormatConstraint_eid'}),
('INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE CT eid %(ct)s, EDEF eid %(x)s',
- {'x': None, 'value': u'max=50', 'ct': 'SizeConstraint_eid'})])
+ {'x': None, 'value': u'max=50', 'ct': 'SizeConstraint_eid'})],
+ list(rdef2rql(schema['description_format'].rdefs[('CWRType', 'String')], cstrtypemap)))
def test_updateeschema2rql1(self):
- self.assertListEqual(list(updateeschema2rql(schema.eschema('CWAttribute'), 1)),
- [('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
- {'description': u'define a final relation: link a final relation type from a non final entity to a final entity type. used to build the instance schema', 'x': 1, 'final': False, 'name': u'CWAttribute'}),
- ])
+ self.assertListEqual([('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
+ {'description': u'define a final relation: link a final relation type from a non final entity to a final entity type. used to build the instance schema', 'x': 1, 'final': False, 'name': u'CWAttribute'})],
+ list(updateeschema2rql(schema.eschema('CWAttribute'), 1)))
def test_updateeschema2rql2(self):
- self.assertListEqual(list(updateeschema2rql(schema.eschema('String'), 1)),
- [('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
- {'description': u'', 'x': 1, 'final': True, 'name': u'String'})
- ])
+ self.assertListEqual([('SET X description %(description)s,X final %(final)s,X name %(name)s WHERE X eid %(x)s',
+ {'description': u'', 'x': 1, 'final': True, 'name': u'String'})],
+ list(updateeschema2rql(schema.eschema('String'), 1)))
def test_updaterschema2rql1(self):
- self.assertListEqual(list(updaterschema2rql(schema.rschema('relation_type'), 1)),
- [
+ self.assertListEqual([
('SET X description %(description)s,X final %(final)s,X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,X name %(name)s,X symmetric %(symmetric)s WHERE X eid %(x)s',
{'x': 1, 'symmetric': False,
'description': u'link a relation definition to its relation type',
- 'final': False, 'fulltext_container': None, 'inlined': True, 'name': u'relation_type'})
- ])
+ 'final': False, 'fulltext_container': None, 'inlined': True, 'name': u'relation_type'})],
+ list(updaterschema2rql(schema.rschema('relation_type'), 1)))
def test_updaterschema2rql2(self):
expected = [
@@ -235,7 +237,7 @@
'inlined': False, 'name': u'add_permission'})
]
for i, (rql, args) in enumerate(updaterschema2rql(schema.rschema('add_permission'), 1)):
- yield self.assertEqual, (rql, args), expected[i]
+ yield self.assertEqual, expected[i], (rql, args)
class Perms2RQLTC(TestCase):
GROUP_MAPPING = {
@@ -246,31 +248,34 @@
}
def test_eperms2rql1(self):
- self.assertListEqual([(rql, kwargs) for rql, kwargs in erperms2rql(schema.eschema('CWEType'), self.GROUP_MAPPING)],
- [('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
- ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ])
+ self.assertListEqual([('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
+ ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0})],
+ [(rql, kwargs)
+ for rql, kwargs in erperms2rql(schema.eschema('CWEType'), self.GROUP_MAPPING)])
def test_rperms2rql2(self):
- self.assertListEqual([(rql, kwargs) for rql, kwargs in erperms2rql(schema.rschema('read_permission').rdef('CWEType', 'CWGroup'), self.GROUP_MAPPING)],
- [('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
- ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ])
+ self.assertListEqual([('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
+ ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X delete_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0})],
+ [(rql, kwargs)
+ for rql, kwargs in erperms2rql(schema.rschema('read_permission').rdef('CWEType', 'CWGroup'),
+ self.GROUP_MAPPING)])
def test_rperms2rql3(self):
- self.assertListEqual([(rql, kwargs) for rql, kwargs in erperms2rql(schema.rschema('name').rdef('CWEType', 'String'), self.GROUP_MAPPING)],
- [('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
- ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
- ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
- ])
+ self.assertListEqual([('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 1}),
+ ('SET X read_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 2}),
+ ('SET X add_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0}),
+ ('SET X update_permission Y WHERE Y eid %(g)s, X eid %(x)s', {'g': 0})],
+ [(rql, kwargs)
+ for rql, kwargs in erperms2rql(schema.rschema('name').rdef('CWEType', 'String'),
+ self.GROUP_MAPPING)])
#def test_perms2rql(self):
# self.assertListEqual(perms2rql(schema, self.GROUP_MAPPING),
--- a/server/test/unittest_security.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_security.py Mon Jan 13 13:47:47 2014 +0100
@@ -413,6 +413,16 @@
self.commit()
cu.execute("SET X para 'chouette' WHERE X eid %(x)s", {'x': note2.eid})
self.commit()
+ cu.execute("INSERT Note X: X something 'A'")
+ self.assertRaises(Unauthorized, self.commit)
+ cu.execute("INSERT Note X: X para 'zogzog', X something 'A'")
+ self.commit()
+ note = cu.execute("INSERT Note X").get_entity(0,0)
+ self.commit()
+ note.cw_set(something=u'B')
+ self.commit()
+ note.cw_set(something=None, para=u'zogzog')
+ self.commit()
def test_attribute_read_security(self):
# anon not allowed to see users'login, but they can see users
--- a/server/test/unittest_session.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_session.py Mon Jan 13 13:47:47 2014 +0100
@@ -25,6 +25,15 @@
self.assertFalse(session.running_dbapi_query)
session.close()
+ def test_integrity_hooks(self):
+ with self.repo.internal_session() as session:
+ self.assertEqual(HOOKS_ALLOW_ALL, session.hooks_mode)
+ self.assertEqual(set(('integrity',)), session.disabled_hook_categories)
+ self.assertEqual(set(), session.enabled_hook_categories)
+ session.commit()
+ self.assertEqual(HOOKS_ALLOW_ALL, session.hooks_mode)
+ self.assertEqual(set(('integrity',)), session.disabled_hook_categories)
+ self.assertEqual(set(), session.enabled_hook_categories)
class SessionTC(CubicWebTC):
--- a/server/test/unittest_sqlutils.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_sqlutils.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,5 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# -*- coding: utf-8 -*-
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -24,6 +25,8 @@
from cubicweb.server.sqlutils import *
+from cubicweb.devtools.testlib import CubicWebTC
+
BASE_CONFIG = {
'db-driver' : 'Postgres',
'db-host' : 'crater',
@@ -44,5 +47,22 @@
o = SQLAdapterMixIn(config)
self.assertEqual(o.dbhelper.dbencoding, 'ISO-8859-1')
+
+class SQLUtilsTC(CubicWebTC):
+
+ def test_group_concat(self):
+ req = self.request()
+ g = req.create_entity('CWGroup', name=u'héhé')
+ u = req.create_entity('CWUser', login=u'toto', upassword=u'',
+ in_group=g.eid)
+ rset = self.execute(u'Any L,GROUP_CONCAT(G) GROUPBY L WHERE X login L,'
+ u'X in_group G, G name GN, NOT G name IN ("users", "héhé")')
+ self.assertEqual([[u'admin', u'3'], [u'anon', u'2']],
+ rset.rows)
+ rset = self.execute('Any L,GROUP_CONCAT(GN) GROUPBY L WHERE X login L,'
+ 'X in_group G, G name GN, NOT G name "users"')
+ self.assertEqual([[u'admin', u'managers'], [u'anon', u'guests'], [u'toto', u'héhé']],
+ rset.rows)
+
if __name__ == '__main__':
unittest_main()
--- a/server/test/unittest_storage.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/test/unittest_storage.py Mon Jan 13 13:47:47 2014 +0100
@@ -237,7 +237,7 @@
self.assertEqual(osp.splitext(new_path)[1], '.jpg')
@tag('update', 'extension', 'rollback')
- def test_bfss_update_with_different_extension_rollbacked(self):
+ def test_bfss_update_with_different_extension_rolled_back(self):
# use self.session to use server-side cache
f1 = self.session.create_entity('File', data=Binary('some data'),
data_format=u'text/plain', data_name=u'foo.txt')
--- a/server/utils.py Tue Jul 02 17:09:04 2013 +0200
+++ b/server/utils.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -91,13 +91,6 @@
return rloop(seqin, [])
-def cleanup_solutions(rqlst, solutions):
- for sol in solutions:
- for vname in list(sol):
- if not (vname in rqlst.defined_vars or vname in rqlst.aliases):
- del sol[vname]
-
-
def eschema_eid(session, eschema):
"""get eid of the CWEType entity for the given yams type. You should use
this because when schema has been loaded from the file-system, not from the
--- a/setup.py Tue Jul 02 17:09:04 2013 +0200
+++ b/setup.py Mon Jan 13 13:47:47 2014 +0100
@@ -63,7 +63,7 @@
ext_modules = getattr(__pkginfo__, 'ext_modules', None)
package_data = getattr(__pkginfo__, 'package_data', {})
-BASE_BLACKLIST = ('CVS', 'debian', 'dist', 'build', '__buildlog')
+BASE_BLACKLIST = ('CVS', 'dist', 'build', '__buildlog')
IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc')
--- a/skeleton/debian/control.tmpl Tue Jul 02 17:09:04 2013 +0200
+++ b/skeleton/debian/control.tmpl Mon Jan 13 13:47:47 2014 +0100
@@ -8,7 +8,10 @@
Package: %(distname)s
Architecture: all
-Depends: cubicweb-common (>= %(version)s), ${python:Depends}
+Depends:
+ cubicweb-common (>= %(version)s),
+ ${python:Depends},
+ ${misc:Depends},
Description: %(shortdesc)s
CubicWeb is a semantic web application framework.
.
--- a/skeleton/debian/rules.tmpl Tue Jul 02 17:09:04 2013 +0200
+++ b/skeleton/debian/rules.tmpl Mon Jan 13 13:47:47 2014 +0100
@@ -15,10 +15,9 @@
clean:
dh_testdir
- dh_testroot
rm -f build-stamp configure-stamp
rm -rf build
- find . -name "*.pyc" | xargs rm -f
+ find . -name "*.pyc" -delete
dh_clean
install: build
@@ -38,7 +37,7 @@
dh_install -i
dh_installchangelogs -i
dh_installexamples -i
- dh_installdocs -i
+ dh_installdocs -i README
dh_installman -i
dh_pysupport -i /usr/share/cubicweb
dh_link -i
--- a/skeleton/i18n/en.po Tue Jul 02 17:09:04 2013 +0200
+++ b/skeleton/i18n/en.po Mon Jan 13 13:47:47 2014 +0100
@@ -5,4 +5,5 @@
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
--- a/skeleton/i18n/es.po Tue Jul 02 17:09:04 2013 +0200
+++ b/skeleton/i18n/es.po Mon Jan 13 13:47:47 2014 +0100
@@ -5,4 +5,5 @@
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
--- a/skeleton/i18n/fr.po Tue Jul 02 17:09:04 2013 +0200
+++ b/skeleton/i18n/fr.po Mon Jan 13 13:47:47 2014 +0100
@@ -5,4 +5,5 @@
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
--- a/sobjects/ldapparser.py Tue Jul 02 17:09:04 2013 +0200
+++ b/sobjects/ldapparser.py Mon Jan 13 13:47:47 2014 +0100
@@ -71,7 +71,7 @@
return {}
def _process(self, etype, sdict):
- self.warning('fetched %s %s', etype, sdict)
+ self.debug('fetched %s %s', etype, sdict)
extid = sdict['dn']
entity = self.extid2entity(extid, etype, **sdict)
if entity is not None and not self.created_during_pull(entity):
@@ -105,7 +105,7 @@
for etype, eids in byetype.iteritems():
if etype != 'CWUser':
continue
- self.warning('deactivate %s %s entities', len(eids), etype)
+ self.info('deactivate %s %s entities', len(eids), etype)
for eid in eids:
wf = session.entity_from_eid(eid).cw_adapt_to('IWorkflowable')
wf.fire_transition_if_possible('deactivate')
@@ -119,7 +119,7 @@
wf = entity.cw_adapt_to('IWorkflowable')
if wf.state == 'deactivated':
wf.fire_transition('activate')
- self.warning('user %s reactivated', entity.login)
+ self.info('user %s reactivated', entity.login)
mdate = attrs.get('modification_date')
if not mdate or mdate > entity.modification_date:
attrs = dict( (k, v) for k, v in attrs.iteritems()
--- a/sobjects/notification.py Tue Jul 02 17:09:04 2013 +0200
+++ b/sobjects/notification.py Mon Jan 13 13:47:47 2014 +0100
@@ -128,26 +128,34 @@
# since the same view (eg self) may be called multiple time and we
# need a fresh stream at each iteration, reset it explicitly
self.w = None
- # XXX call render before subject to set .row/.col attributes on the
- # view
try:
- content = self.render(row=0, col=0, **kwargs)
- subject = self.subject()
- except SkipEmail:
- continue
- except Exception as ex:
- # shouldn't make the whole transaction fail because of rendering
- # error (unauthorized or such) XXX check it doesn't actually
- # occurs due to rollback on such error
- self.exception(str(ex))
- continue
- msg = format_mail(self.user_data, [emailaddr], content, subject,
- config=self._cw.vreg.config, msgid=msgid, references=refs)
- yield [emailaddr], msg
- if isinstance(something, Entity):
- self._cw.commit()
- self._cw.close()
- self._cw = req
+ # XXX call render before subject to set .row/.col attributes on the
+ # view
+ try:
+ content = self.render(row=0, col=0, **kwargs)
+ subject = self.subject()
+ except SkipEmail:
+ continue
+ except Exception as ex:
+ # shouldn't make the whole transaction fail because of rendering
+ # error (unauthorized or such) XXX check it doesn't actually
+ # occurs due to rollback on such error
+ self.exception(str(ex))
+ continue
+ msg = format_mail(self.user_data, [emailaddr], content, subject,
+ config=self._cw.vreg.config, msgid=msgid, references=refs)
+ yield [emailaddr], msg
+ except:
+ if isinstance(something, Entity):
+ self._cw.rollback()
+ raise
+ else:
+ if isinstance(something, Entity):
+ self._cw.commit()
+ finally:
+ if isinstance(something, Entity):
+ self._cw.close()
+ self._cw = req
# restore language
req.set_language(origlang)
@@ -198,7 +206,7 @@
kwargs.update({'user': self.user_data['login'],
'eid': entity.eid,
'etype': entity.dc_type(),
- 'url': entity.absolute_url(),
+ 'url': entity.absolute_url(__secure__=True),
'title': entity.dc_long_title(),})
return kwargs
--- a/test/data/entities.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/data/entities.py Mon Jan 13 13:47:47 2014 +0100
@@ -28,6 +28,9 @@
fetch_attrs, cw_fetch_order = fetch_config(['nom', 'prenom'])
rest_attr = 'nom'
+class Ami(Societe):
+ __regid__ = 'Ami'
+ rest_attr = 'nom'
class Note(AnyEntity):
__regid__ = 'Note'
--- a/test/data/migration/0.1.0_web.py Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""web only
-
-"""
--- a/test/data/rewrite/schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/data/rewrite/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -38,6 +38,7 @@
'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
'add': ('managers', 'users',)
}
+ nom = String()
class Division(Societe):
@@ -75,3 +76,9 @@
object = 'Affaire'
inlined = True
cardinality = '?*'
+
+class responsable(RelationDefinition):
+ subject = 'Societe'
+ object = 'CWUser'
+ inlined = True
+ cardinality = '1*'
--- a/test/data/schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/data/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -41,9 +41,13 @@
constraints=[RQLConstraint('NOT EXISTS(O contrat_exclusif S)')])
dirige = SubjectRelation('Societe', cardinality='??',
constraints=[RQLConstraint('S actionnaire O')])
- associe = SubjectRelation('Personne', cardinality='1*',
+ associe = SubjectRelation('Personne', cardinality='?*',
constraints=[RQLConstraint('S actionnaire SOC, O actionnaire SOC')])
+class Ami(EntityType):
+ """A Person, for which surname is not required"""
+ prenom = String()
+ nom = String()
class Societe(EntityType):
nom = String()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/unittest_dataimport.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,26 @@
+from StringIO import StringIO
+from logilab.common.testlib import TestCase, unittest_main
+from cubicweb import dataimport
+class UcsvreaderTC(TestCase):
+
+ def test_empty_lines_skipped(self):
+ stream = StringIO('''a,b,c,d,
+1,2,3,4,
+,,,,
+,,,,
+''')
+ self.assertEqual([[u'a', u'b', u'c', u'd', u''],
+ [u'1', u'2', u'3', u'4', u''],
+ ],
+ list(dataimport.ucsvreader(stream)))
+ stream.seek(0)
+ self.assertEqual([[u'a', u'b', u'c', u'd', u''],
+ [u'1', u'2', u'3', u'4', u''],
+ [u'', u'', u'', u'', u''],
+ [u'', u'', u'', u'', u'']
+ ],
+ list(dataimport.ucsvreader(stream, skip_empty=False)))
+
+
+if __name__ == '__main__':
+ unittest_main()
--- a/test/unittest_entity.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_entity.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -26,6 +26,7 @@
from cubicweb import Binary, Unauthorized
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.mttransforms import HAS_TAL
+from cubicweb.entity import can_use_rest_path
from cubicweb.entities import fetch_config
from cubicweb.uilib import soup2xhtml
from cubicweb.schema import RQLVocabularyConstraint, RRQLExpression
@@ -132,6 +133,12 @@
self.assertEqual(sorted(user._cw_related_cache), ['in_group_subject', 'primary_email_subject'])
for group in groups:
self.assertFalse('in_group_subject' in group._cw_related_cache, list(group._cw_related_cache))
+ user.cw_clear_all_caches()
+ user.related('in_group', entities=True)
+ self.assertIn('in_group_subject', user._cw_related_cache)
+ user.cw_clear_all_caches()
+ user.related('in_group', targettypes=('CWGroup',), entities=True)
+ self.assertNotIn('in_group_subject', user._cw_related_cache)
def test_related_limit(self):
req = self.request()
@@ -145,29 +152,41 @@
self.assertEqual(len(p.related('tags', 'object', entities=True, limit=2)), 2)
self.assertEqual(len(p.related('tags', 'object', entities=True)), 4)
+ def test_related_targettypes(self):
+ req = self.request()
+ p = req.create_entity('Personne', nom=u'Loxodonta', prenom=u'Babar')
+ n = req.create_entity('Note', type=u'scratch', ecrit_par=p)
+ t = req.create_entity('Tag', name=u'a tag', tags=(p, n))
+ self.commit()
+ req = self.request()
+ t = req.entity_from_eid(t.eid)
+ self.assertEqual(2, t.related('tags').rowcount)
+ self.assertEqual(1, t.related('tags', targettypes=('Personne',)).rowcount)
+ self.assertEqual(1, t.related('tags', targettypes=('Note',)).rowcount)
+
def test_cw_instantiate_relation(self):
req = self.request()
p1 = req.create_entity('Personne', nom=u'di')
p2 = req.create_entity('Personne', nom=u'mascio')
t = req.create_entity('Tag', name=u't0', tags=[])
- self.assertItemsEqual(t.tags, [])
+ self.assertCountEqual(t.tags, [])
t = req.create_entity('Tag', name=u't1', tags=p1)
- self.assertItemsEqual(t.tags, [p1])
+ self.assertCountEqual(t.tags, [p1])
t = req.create_entity('Tag', name=u't2', tags=p1.eid)
- self.assertItemsEqual(t.tags, [p1])
+ self.assertCountEqual(t.tags, [p1])
t = req.create_entity('Tag', name=u't3', tags=[p1, p2.eid])
- self.assertItemsEqual(t.tags, [p1, p2])
+ self.assertCountEqual(t.tags, [p1, p2])
def test_cw_instantiate_reverse_relation(self):
req = self.request()
t1 = req.create_entity('Tag', name=u't1')
t2 = req.create_entity('Tag', name=u't2')
p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=t1)
- self.assertItemsEqual(p.reverse_tags, [t1])
+ self.assertCountEqual(p.reverse_tags, [t1])
p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=t1.eid)
- self.assertItemsEqual(p.reverse_tags, [t1])
+ self.assertCountEqual(p.reverse_tags, [t1])
p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=[t1, t2.eid])
- self.assertItemsEqual(p.reverse_tags, [t1, t2])
+ self.assertCountEqual(p.reverse_tags, [t1, t2])
def test_fetch_rql(self):
user = self.user()
@@ -188,43 +207,43 @@
# testing basic fetch_attrs attribute
self.assertEqual(Personne.fetch_rql(user),
'Any X,AA,AB,AC ORDERBY AA '
- 'WHERE X is Personne, X nom AA, X prenom AB, X modification_date AC')
+ 'WHERE X is_instance_of Personne, X nom AA, X prenom AB, X modification_date AC')
# testing unknown attributes
Personne.fetch_attrs = ('bloug', 'beep')
- self.assertEqual(Personne.fetch_rql(user), 'Any X WHERE X is Personne')
+ self.assertEqual(Personne.fetch_rql(user), 'Any X WHERE X is_instance_of Personne')
# testing one non final relation
Personne.fetch_attrs = ('nom', 'prenom', 'travaille')
self.assertEqual(Personne.fetch_rql(user),
'Any X,AA,AB,AC,AD ORDERBY AA '
- 'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD')
+ 'WHERE X is_instance_of Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD')
# testing two non final relations
Personne.fetch_attrs = ('nom', 'prenom', 'travaille', 'evaluee')
self.assertEqual(Personne.fetch_rql(user),
'Any X,AA,AB,AC,AD,AE ORDERBY AA '
- 'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
+ 'WHERE X is_instance_of Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
'X evaluee AE?')
# testing one non final relation with recursion
Personne.fetch_attrs = ('nom', 'prenom', 'travaille')
Societe.fetch_attrs = ('nom', 'evaluee')
self.assertEqual(Personne.fetch_rql(user),
'Any X,AA,AB,AC,AD,AE,AF ORDERBY AA,AF DESC '
- 'WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
+ 'WHERE X is_instance_of Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD, '
'AC evaluee AE?, AE modification_date AF'
)
# testing symmetric relation
Personne.fetch_attrs = ('nom', 'connait')
self.assertEqual(Personne.fetch_rql(user), 'Any X,AA,AB ORDERBY AA '
- 'WHERE X is Personne, X nom AA, X connait AB?')
+ 'WHERE X is_instance_of Personne, X nom AA, X connait AB?')
# testing optional relation
peschema.subjrels['travaille'].rdef(peschema, seschema).cardinality = '?*'
Personne.fetch_attrs = ('nom', 'prenom', 'travaille')
Societe.fetch_attrs = ('nom',)
self.assertEqual(Personne.fetch_rql(user),
- 'Any X,AA,AB,AC,AD ORDERBY AA WHERE X is Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD')
+ 'Any X,AA,AB,AC,AD ORDERBY AA WHERE X is_instance_of Personne, X nom AA, X prenom AB, X travaille AC?, AC nom AD')
# testing relation with cardinality > 1
peschema.subjrels['travaille'].rdef(peschema, seschema).cardinality = '**'
self.assertEqual(Personne.fetch_rql(user),
- 'Any X,AA,AB ORDERBY AA WHERE X is Personne, X nom AA, X prenom AB')
+ 'Any X,AA,AB ORDERBY AA WHERE X is_instance_of Personne, X nom AA, X prenom AB')
# XXX test unauthorized attribute
finally:
# fetch_attrs restored by generic tearDown
@@ -288,7 +307,7 @@
rql = user.cw_unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
'WHERE NOT A use_email O, S eid %(x)s, '
- 'O is EmailAddress, O address AA, O alias AB, O modification_date AC')
+ 'O is_instance_of EmailAddress, O address AA, O alias AB, O modification_date AC')
def test_unrelated_rql_security_1_user(self):
req = self.request()
@@ -298,7 +317,7 @@
rql = user.cw_unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
'WHERE NOT A use_email O, S eid %(x)s, '
- 'O is EmailAddress, O address AA, O alias AB, O modification_date AC')
+ 'O is_instance_of EmailAddress, O address AA, O alias AB, O modification_date AC')
user = self.execute('Any X WHERE X login "admin"').get_entity(0, 0)
rql = user.cw_unrelated_rql('use_email', 'EmailAddress', 'subject')[0]
self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC '
@@ -319,7 +338,7 @@
email = self.execute('INSERT EmailAddress X: X address "hop"').get_entity(0, 0)
rql = email.cw_unrelated_rql('use_email', 'CWUser', 'object')[0]
self.assertEqual(rql, 'Any S,AA,AB,AC,AD ORDERBY AA '
- 'WHERE NOT S use_email O, O eid %(x)s, S is CWUser, '
+ 'WHERE NOT S use_email O, O eid %(x)s, S is_instance_of CWUser, '
'S login AA, S firstname AB, S surname AC, S modification_date AD')
self.login('anon')
rperms = self.schema['EmailAddress'].permissions['read']
@@ -353,7 +372,7 @@
rql = person.cw_unrelated_rql('connait', 'Personne', 'subject')[0]
self.assertEqual(
rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
- 'O is Personne, O nom AA, O prenom AB, O modification_date AC')
+ 'O is_instance_of Personne, O nom AA, O prenom AB, O modification_date AC')
def test_unrelated_rql_constraints_creation_object(self):
person = self.vreg['etypes'].etype_class('Personne')(self.request())
@@ -373,7 +392,7 @@
person = self.vreg['etypes'].etype_class('Personne')(self.request())
rql = person.cw_unrelated_rql('connait', 'Personne', 'subject')[0]
self.assertEqual(rql, 'Any O,AA,AB,AC ORDERBY AC DESC WHERE '
- 'O is Personne, O nom AA, O prenom AB, '
+ 'O is_instance_of Personne, O nom AA, O prenom AB, '
'O modification_date AC')
def test_unrelated_rql_constraints_edition_subject(self):
@@ -416,7 +435,7 @@
rql, args = person.cw_unrelated_rql('actionnaire', 'Societe', 'subject',
lt_infos=lt_infos)
self.assertEqual(u'Any O ORDERBY O WHERE NOT A actionnaire O, '
- u'O is Societe, NOT EXISTS(O eid %(O)s), '
+ u'O is_instance_of Societe, NOT EXISTS(O eid %(O)s), '
u'A is Personne', rql)
self.assertEqual({'O': soc.eid}, args)
@@ -429,7 +448,7 @@
rql, args = soc.cw_unrelated_rql('actionnaire', 'Personne', 'object',
lt_infos=lt_infos)
self.assertEqual(u'Any S ORDERBY S WHERE NOT S actionnaire A, '
- u'S is Personne, NOT EXISTS(S eid %(S)s), '
+ u'S is_instance_of Personne, NOT EXISTS(S eid %(S)s), '
u'A is Societe', rql)
self.assertEqual({'S': person.eid}, args)
@@ -442,7 +461,7 @@
rql, args = soc.cw_unrelated_rql('dirige', 'Personne', 'object',
lt_infos=lt_infos)
self.assertEqual(u'Any S ORDERBY S WHERE NOT S dirige A, '
- u'S is Personne, EXISTS(S eid %(S)s), '
+ u'S is_instance_of Personne, EXISTS(S eid %(S)s), '
u'A is Societe', rql)
self.assertEqual({'S': person.eid}, args)
@@ -452,7 +471,7 @@
self.vreg['etypes'].etype_class('Personne').fetch_attrs = ()
soc = req.create_entity('Societe', nom=u'logilab')
rql, args = person.cw_unrelated_rql('associe', 'Personne', 'subject')
- self.assertEqual(u'Any O ORDERBY O WHERE O is Personne', rql)
+ self.assertEqual(u'Any O ORDERBY O WHERE O is_instance_of Personne', rql)
self.assertEqual({}, args)
def test_unrelated_rql_s_linkto_s_unused_info(self):
@@ -463,7 +482,7 @@
lt_infos = {('dirige', 'subject'): [other_p.eid]}
rql, args = person.cw_unrelated_rql('associe', 'Personne', 'subject',
lt_infos=lt_infos)
- self.assertEqual(u'Any O ORDERBY O WHERE O is Personne', rql)
+ self.assertEqual(u'Any O ORDERBY O WHERE O is_instance_of Personne', rql)
def test_unrelated_base(self):
req = self.request()
@@ -643,8 +662,10 @@
e.cw_attr_cache['data_format'] = 'text/html'
e.cw_attr_cache['data_encoding'] = 'ascii'
e._cw.transaction_data = {} # XXX req should be a session
- self.assertEqual(e.cw_adapt_to('IFTIndexable').get_words(),
- {'C': ['an', 'html', 'file', 'du', 'html', 'some', 'data']})
+ words = e.cw_adapt_to('IFTIndexable').get_words()
+ words['C'].sort()
+ self.assertEqual({'C': sorted(['an', 'html', 'file', 'du', 'html', 'some', 'data'])},
+ words)
def test_nonregr_relation_cache(self):
@@ -690,17 +711,16 @@
person.cw_clear_all_caches()
self.assertEqual(person.rest_path(), unicode(person.eid))
self.assertEqual(person2.rest_path(), unicode(person2.eid))
- # unique attr with None value (wikiid in this case)
- card1 = req.create_entity('Card', title=u'hop')
- self.assertEqual(card1.rest_path(), unicode(card1.eid))
+ # unique attr with None value (nom in this case)
+ friend = req.create_entity('Ami', prenom=u'bob')
+ self.assertEqual(friend.rest_path(), unicode(friend.eid))
+
+ def test_can_use_rest_path(self):
+ self.assertTrue(can_use_rest_path(u'zobi'))
# don't use rest if we have /, ? or & in the path (breaks mod_proxy)
- card2 = req.create_entity('Card', title=u'pod', wikiid=u'zo/bi')
- self.assertEqual(card2.rest_path(), unicode(card2.eid))
- card3 = req.create_entity('Card', title=u'pod', wikiid=u'zo&bi')
- self.assertEqual(card3.rest_path(), unicode(card3.eid))
- card4 = req.create_entity('Card', title=u'pod', wikiid=u'zo?bi')
- self.assertEqual(card4.rest_path(), unicode(card4.eid))
-
+ self.assertFalse(can_use_rest_path(u'zo/bi'))
+ self.assertFalse(can_use_rest_path(u'zo&bi'))
+ self.assertFalse(can_use_rest_path(u'zo?bi'))
def test_cw_set_attributes(self):
req = self.request()
@@ -740,7 +760,7 @@
self.assertEqual(card.absolute_url(),
'http://testing.fr/cubicweb/%s' % card.eid)
- def test_create_entity(self):
+ def test_create_and_compare_entity(self):
req = self.request()
p1 = req.create_entity('Personne', nom=u'fayolle', prenom=u'alexandre')
p2 = req.create_entity('Personne', nom=u'campeas', prenom=u'aurelien')
@@ -754,6 +774,15 @@
self.assertEqual(sorted([c.nom for c in p.evaluee]), ['campeas', 'fayolle'])
self.assertEqual([c.type for c in p.reverse_ecrit_par], ['z'])
+ req = self.request()
+ auc = req.execute('Personne P WHERE P prenom "aurelien"').get_entity(0,0)
+ persons = set()
+ persons.add(p1)
+ persons.add(p2)
+ persons.add(auc)
+ self.assertEqual(2, len(persons))
+ self.assertNotEqual(p1, p2)
+ self.assertEqual(p2, auc)
if __name__ == '__main__':
--- a/test/unittest_mail.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_mail.py Mon Jan 13 13:47:47 2014 +0100
@@ -31,7 +31,7 @@
def getlogin():
- """avoid usinng os.getlogin() because of strange tty / stdin problems
+ """avoid using os.getlogin() because of strange tty / stdin problems
(man 3 getlogin)
Another solution would be to use $LOGNAME, $USER or $USERNAME
"""
--- a/test/unittest_migration.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_migration.py Mon Jan 13 13:47:47 2014 +0100
@@ -79,10 +79,6 @@
self.assert_(not isinstance(config.migration_handler(), ServerMigrationHelper))
self.assertIsInstance(config.migration_handler(), MigrationHelper)
config = self.config
- config.__class__.name = 'twisted'
- self.assertListEqual(filter_scripts(config, TMIGRDIR, (0,0,4), (0,1,0)),
- [((0, 1 ,0), TMIGRDIR+'0.1.0_common.py'),
- ((0, 1 ,0), TMIGRDIR+'0.1.0_web.py')])
config.__class__.name = 'repository'
self.assertListEqual(filter_scripts(config, TMIGRDIR, (0,0,4), (0,1,0)),
[((0, 1 ,0), TMIGRDIR+'0.1.0_Any.py'),
@@ -92,8 +88,7 @@
self.assertListEqual(filter_scripts(config, TMIGRDIR, (0,0,4), (0,1,0)),
[((0, 1 ,0), TMIGRDIR+'0.1.0_Any.py'),
((0, 1 ,0), TMIGRDIR+'0.1.0_common.py'),
- ((0, 1 ,0), TMIGRDIR+'0.1.0_repository.py'),
- ((0, 1 ,0), TMIGRDIR+'0.1.0_web.py')])
+ ((0, 1 ,0), TMIGRDIR+'0.1.0_repository.py')])
config.__class__.name = 'repository'
--- a/test/unittest_predicates.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_predicates.py Mon Jan 13 13:47:47 2014 +0100
@@ -203,6 +203,17 @@
select=select, filtered_variable=select.defined_vars['X'])
self.assertEqual(score, 1)
+ def test_ambiguous(self):
+ # Ambiguous relations are :
+ # (Service, fabrique_par, Personne) and (Produit, fabrique_par, Usine)
+ # There used to be a crash here with a bad rdef choice in the strict
+ # checking case.
+ selector = relation_possible('fabrique_par', role='object',
+ target_etype='Personne', strict=True)
+ req = self.request()
+ usine = req.create_entity('Usine', lieu=u'here')
+ score = selector(None, req, rset=usine.as_rset())
+ self.assertEqual(0, score)
class MatchUserGroupsTC(CubicWebTC):
def test_owners_group(self):
--- a/test/unittest_req.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_req.py Mon Jan 13 13:47:47 2014 +0100
@@ -18,7 +18,7 @@
from logilab.common.testlib import TestCase, unittest_main
from cubicweb import ObjectNotFound
-from cubicweb.req import RequestSessionBase
+from cubicweb.req import RequestSessionBase, FindEntityError
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb import Unauthorized
@@ -53,11 +53,97 @@
class RequestCWTC(CubicWebTC):
+
+ def test_base_url(self):
+ base_url = self.config['base-url']
+ self.assertEqual(self.session.base_url(), base_url)
+ assert 'https-url' not in self.config
+ self.assertEqual(self.session.base_url(secure=True), base_url)
+ secure_base_url = base_url.replace('http', 'https')
+ self.config.global_set_option('https-url', secure_base_url)
+ self.assertEqual(self.session.base_url(secure=True), secure_base_url)
+
def test_view_catch_ex(self):
req = self.request()
rset = self.execute('CWUser X WHERE X login "hop"')
self.assertEqual(req.view('oneline', rset, 'null'), '')
self.assertRaises(ObjectNotFound, req.view, 'onelinee', rset, 'null')
+ def test_find_one_entity(self):
+ self.request().create_entity(
+ 'CWUser', login=u'cdevienne', upassword=u'cdevienne',
+ surname=u'de Vienne', firstname=u'Christophe',
+ in_group=self.request().find('CWGroup', name=u'users').one())
+
+ self.request().create_entity(
+ 'CWUser', login=u'adim', upassword='adim', surname=u'di mascio',
+ firstname=u'adrien',
+ in_group=self.request().find('CWGroup', name=u'users').one())
+
+ u = self.request().find_one_entity('CWUser', login=u'cdevienne')
+ self.assertEqual(u.firstname, u"Christophe")
+
+ with self.assertRaises(FindEntityError):
+ self.request().find_one_entity('CWUser', login=u'patanok')
+
+ with self.assertRaises(FindEntityError):
+ self.request().find_one_entity('CWUser')
+
+ def test_find_entities(self):
+ self.request().create_entity(
+ 'CWUser', login=u'cdevienne', upassword=u'cdevienne',
+ surname=u'de Vienne', firstname=u'Christophe',
+ in_group=self.request().find('CWGroup', name=u'users').one())
+
+ self.request().create_entity(
+ 'CWUser', login=u'adim', upassword='adim', surname=u'di mascio',
+ firstname=u'adrien',
+ in_group=self.request().find('CWGroup', name=u'users').one())
+
+ l = list(self.request().find_entities('CWUser', login=u'cdevienne'))
+ self.assertEqual(1, len(l))
+ self.assertEqual(l[0].firstname, u"Christophe")
+
+ l = list(self.request().find_entities('CWUser', login=u'patanok'))
+ self.assertEqual(0, len(l))
+
+ l = list(self.request().find_entities('CWUser'))
+ self.assertEqual(4, len(l))
+
+ def test_find(self):
+ self.request().create_entity(
+ 'CWUser', login=u'cdevienne', upassword=u'cdevienne',
+ surname=u'de Vienne', firstname=u'Christophe',
+ in_group=self.request().find('CWGroup', name=u'users').one())
+
+ self.request().create_entity(
+ 'CWUser', login=u'adim', upassword='adim', surname=u'di mascio',
+ firstname=u'adrien',
+ in_group=self.request().find('CWGroup', name=u'users').one())
+
+ u = self.request().find('CWUser', login=u'cdevienne').one()
+ self.assertEqual(u.firstname, u"Christophe")
+
+ users = list(self.request().find('CWUser').entities())
+ self.assertEqual(len(users), 4)
+
+ groups = list(
+ self.request().find('CWGroup', reverse_in_group=u).entities())
+ self.assertEqual(len(groups), 1)
+ self.assertEqual(groups[0].name, u'users')
+
+ users = self.request().find('CWUser', in_group=groups[0]).entities()
+ users = list(users)
+ self.assertEqual(len(users), 2)
+
+ with self.assertRaises(AssertionError):
+ self.request().find('CWUser', chapeau=u"melon")
+
+ with self.assertRaises(AssertionError):
+ self.request().find('CWUser', reverse_buddy=users[0])
+
+ with self.assertRaises(NotImplementedError):
+ self.request().find('CWUser', in_group=[1, 2])
+
if __name__ == '__main__':
unittest_main()
--- a/test/unittest_rqlrewrite.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_rqlrewrite.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -23,7 +23,7 @@
from cubicweb import Unauthorized, rqlrewrite
from cubicweb.schema import RRQLExpression, ERQLExpression
-from cubicweb.devtools import repotest, TestServerConfiguration
+from cubicweb.devtools import repotest, TestServerConfiguration, BaseApptestConfiguration
def setUpModule(*args):
@@ -46,7 +46,8 @@
def eid_func_map(eid):
return {1: 'CWUser',
- 2: 'Card'}[eid]
+ 2: 'Card',
+ 3: 'Affaire'}[eid]
def rewrite(rqlst, snippets_map, kwargs, existingvars=None):
class FakeVReg:
@@ -72,9 +73,7 @@
for snippet in exprs]
snippets.append((dict([v]), rqlexprs))
rqlhelper.compute_solutions(rqlst.children[0], {'eid': eid_func_map}, kwargs=kwargs)
- solutions = rqlst.children[0].solutions
- rewriter.rewrite(rqlst.children[0], snippets, solutions, kwargs,
- existingvars)
+ rewriter.rewrite(rqlst.children[0], snippets, kwargs, existingvars)
test_vrefs(rqlst.children[0])
return rewriter.rewritten
@@ -202,6 +201,17 @@
'WITH LA BEING (Any LA WHERE (EXISTS(A created_by B, LA documented_by A)) OR (EXISTS(E created_by B, LA concerne E)), '
'B eid %(D)s, LA is Affaire)')
+
+ def test_ambiguous_optional_same_exprs(self):
+ """See #3013535"""
+ # see test of the same name in RewriteFullTC: original problem is
+ # unreproducible here because it actually lies in
+ # RQLRewriter.insert_local_checks
+ rqlst = parse('Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s, X creation_date CD')
+ rewrite(rqlst, {('X', 'X'): ('X created_by U',),}, {'a': 3})
+ self.assertEqual(rqlst.as_string(),
+ u'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X created_by B), B eid %(A)s, X is IN(Division, Note, Societe))')
+
def test_optional_var_inlined(self):
c1 = ('X require_permission P')
c2 = ('X inlined_card O, O require_permission P')
@@ -292,6 +302,7 @@
self.assertEqual(rqlst.as_string(),
"Any C WHERE C in_state STATE, C is Card, "
"EXISTS(STATE name 'hop'), STATE is State")
+
def test_relation_optimization_3_rhs(self):
snippet = ('TW? subworkflow_exit X, TW name "hop"')
rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT')
@@ -308,6 +319,7 @@
self.assertEqual(rqlst.as_string(),
"Any C WHERE C in_state STATE?, C is Card, "
"EXISTS(C in_state A, A name 'hop', A is State), STATE is State")
+
def test_relation_non_optimization_1_rhs(self):
snippet = ('TW subworkflow_exit X, TW name "hop"')
rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
@@ -317,6 +329,21 @@
"EXISTS(A subworkflow_exit EXIT, A name 'hop', A is WorkflowTransition), "
"C is WorkflowTransition")
+ def test_relation_non_optimization_2(self):
+ """See #3024730"""
+ # 'X inlined_note N' must not be shared with 'C inlined_note N'
+ # previously inserted, else this may introduce duplicated results, as N
+ # will then be shared by multiple EXISTS and so at SQL generation time,
+ # the table will be in the FROM clause of the outermost query
+ rqlst = parse('Any A,C WHERE A inlined_card C')
+ rewrite(rqlst, {('A', 'X'): ('X inlined_card C, C inlined_note N, N owned_by U',),
+ ('C', 'X'): ('X inlined_note N, N owned_by U',)}, {})
+ self.assertEqual(rqlst.as_string(),
+ 'Any A,C WHERE A inlined_card C, D eid %(E)s, '
+ 'EXISTS(C inlined_note B, B owned_by D, B is Note), '
+ 'EXISTS(C inlined_note F, F owned_by D, F is Note), '
+ 'A is Affaire, C is Card')
+
def test_unsupported_constraint_1(self):
# CWUser doesn't have require_permission
trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
@@ -411,30 +438,30 @@
u"Any C WHERE C is Card, EXISTS(C owned_by A, A is CWUser)")
def test_rqlexpr_not_relation_1_1(self):
- constraint = RRQLExpression('X owned_by Z, Z login "hop"', 'X')
+ constraint = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
rqlst = parse('Affaire A WHERE NOT EXISTS(A documented_by C)')
rewrite(rqlst, {('C', 'X'): (constraint,)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
u'Any A WHERE NOT EXISTS(A documented_by C, EXISTS(C owned_by B, B login "hop", B is CWUser), C is Card), A is Affaire')
def test_rqlexpr_not_relation_1_2(self):
- constraint = RRQLExpression('X owned_by Z, Z login "hop"', 'X')
+ constraint = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
rqlst = parse('Affaire A WHERE NOT EXISTS(A documented_by C)')
rewrite(rqlst, {('A', 'X'): (constraint,)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
u'Any A WHERE NOT EXISTS(A documented_by C, C is Card), A is Affaire, EXISTS(A owned_by B, B login "hop", B is CWUser)')
def test_rqlexpr_not_relation_2(self):
- constraint = RRQLExpression('X owned_by Z, Z login "hop"', 'X')
+ constraint = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
rqlst = rqlhelper.parse('Affaire A WHERE NOT A documented_by C', annotate=False)
rewrite(rqlst, {('C', 'X'): (constraint,)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
u'Any A WHERE NOT EXISTS(A documented_by C, EXISTS(C owned_by B, B login "hop", B is CWUser), C is Card), A is Affaire')
def test_rqlexpr_multiexpr_outerjoin(self):
- c1 = RRQLExpression('X owned_by Z, Z login "hop"', 'X')
- c2 = RRQLExpression('X owned_by Z, Z login "hip"', 'X')
- c3 = RRQLExpression('X owned_by Z, Z login "momo"', 'X')
+ c1 = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
+ c2 = ERQLExpression('X owned_by Z, Z login "hip"', 'X')
+ c3 = ERQLExpression('X owned_by Z, Z login "momo"', 'X')
rqlst = rqlhelper.parse('Any A WHERE A documented_by C?', annotate=False)
rewrite(rqlst, {('C', 'X'): (c1, c2, c3)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
@@ -459,5 +486,74 @@
rqlst = parse('Any A, R WHERE A ref R, S is Affaire')
rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {})
+ def test_nonregr_is_instance_of(self):
+ user_expr = ERQLExpression('NOT X in_group AF, AF name "guests"')
+ rqlst = parse('Any O WHERE S use_email O, S is CWUser, O is_instance_of EmailAddress')
+ rewrite(rqlst, {('S', 'X'): (user_expr,)}, {})
+ self.assertEqual(rqlst.as_string(),
+ 'Any O WHERE S use_email O, S is CWUser, O is EmailAddress, '
+ 'EXISTS(NOT S in_group A, A name "guests", A is CWGroup)')
+
+from cubicweb.devtools.testlib import CubicWebTC
+from logilab.common.decorators import classproperty
+
+class RewriteFullTC(CubicWebTC):
+ @classproperty
+ def config(cls):
+ return BaseApptestConfiguration(apphome=cls.datapath('rewrite'))
+
+ def process(self, rql, args=None):
+ if args is None:
+ args = {}
+ querier = self.repo.querier
+ union = querier.parse(rql)
+ querier.solutions(self.session, union, args)
+ querier._annotate(union)
+ plan = querier.plan_factory(union, args, self.session)
+ plan.preprocess(union)
+ return union
+
+ def test_ambiguous_optional_same_exprs(self):
+ """See #3013535"""
+ edef1 = self.schema['Societe']
+ edef2 = self.schema['Division']
+ edef3 = self.schema['Note']
+ with self.temporary_permissions((edef1, {'read': (ERQLExpression('X owned_by U'),)}),
+ (edef2, {'read': (ERQLExpression('X owned_by U'),)}),
+ (edef3, {'read': (ERQLExpression('X owned_by U'),)})):
+ union = self.process('Any A,AR,X,CD WHERE A concerne X?, A ref AR, X creation_date CD')
+ self.assertEqual('Any A,AR,X,CD WHERE A concerne X?, A ref AR, A is Affaire '
+ 'WITH X,CD BEING (Any X,CD WHERE X creation_date CD, '
+ 'EXISTS(X owned_by %(A)s), X is IN(Division, Note, Societe))',
+ union.as_string())
+
+ def test_ambiguous_optional_diff_exprs(self):
+ """See #3013554"""
+ self.skipTest('bad request generated (may generate duplicated results)')
+ edef1 = self.schema['Societe']
+ edef2 = self.schema['Division']
+ edef3 = self.schema['Note']
+ with self.temporary_permissions((edef1, {'read': (ERQLExpression('X created_by U'),)}),
+ (edef2, {'read': ('users',)}),
+ (edef3, {'read': (ERQLExpression('X owned_by U'),)})):
+ union = self.process('Any A,AR,X,CD WHERE A concerne X?, A ref AR, X creation_date CD')
+ self.assertEqual(union.as_string(), 'not generated today')
+
+
+ def test_xxxx(self):
+ edef1 = self.schema['Societe']
+ edef2 = self.schema['Division']
+ read_expr = ERQLExpression('X responsable E, U has_read_permission E')
+ with self.temporary_permissions((edef1, {'read': (read_expr,)}),
+ (edef2, {'read': (read_expr,)})):
+ union = self.process('Any X,AA,AC,AD ORDERBY AD DESC '
+ 'WHERE X responsable E, X nom AA, '
+ 'X responsable AC?, AC modification_date AD')
+ self.assertEqual('Any X,AA,AC,AD ORDERBY AD DESC '
+ 'WHERE X responsable E, X nom AA, '
+ 'X responsable AC?, AC modification_date AD, '
+ 'AC is CWUser, E is CWUser, X is IN(Division, Societe)',
+ union.as_string())
+
if __name__ == '__main__':
unittest_main()
--- a/test/unittest_rset.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_rset.py Mon Jan 13 13:47:47 2014 +0100
@@ -28,6 +28,8 @@
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.rset import NotAnEntity, ResultSet, attr_desc_iterator
+from cubicweb import NoResultError, MultipleResultsError
+
def pprelcachedict(d):
res = {}
@@ -181,6 +183,7 @@
rs2 = rs.filtered_rset(test_filter)
self.assertEqual(len(rs2), 2)
self.assertEqual([login for _, login in rs2], ['adim', 'syt'])
+ self.assertEqual(rs2.description, rs.description[1:])
def test_transform(self):
rs = ResultSet([[12, 'adim'], [13, 'syt'], [14, 'nico']],
@@ -367,6 +370,39 @@
attr = etype == 'Bookmark' and 'title' or 'name'
self.assertEqual(entity.cw_attr_cache[attr], n)
+ def test_one(self):
+ self.request().create_entity('CWUser', login=u'cdevienne',
+ upassword=u'cdevienne',
+ surname=u'de Vienne',
+ firstname=u'Christophe')
+ e = self.execute('Any X WHERE X login "cdevienne"').one()
+
+ self.assertEqual(e.surname, u'de Vienne')
+
+ e = self.execute(
+ 'Any X, N WHERE X login "cdevienne", X surname N').one()
+ self.assertEqual(e.surname, u'de Vienne')
+
+ e = self.execute(
+ 'Any N, X WHERE X login "cdevienne", X surname N').one(col=1)
+ self.assertEqual(e.surname, u'de Vienne')
+
+ def test_one_no_rows(self):
+ with self.assertRaises(NoResultError):
+ self.execute('Any X WHERE X login "patanok"').one()
+
+ def test_one_multiple_rows(self):
+ self.request().create_entity(
+ 'CWUser', login=u'cdevienne', upassword=u'cdevienne',
+ surname=u'de Vienne', firstname=u'Christophe')
+
+ self.request().create_entity(
+ 'CWUser', login=u'adim', upassword='adim', surname=u'di mascio',
+ firstname=u'adrien')
+
+ with self.assertRaises(MultipleResultsError):
+ self.execute('Any X WHERE X is CWUser').one()
+
def test_related_entity_optional(self):
e = self.request().create_entity('Bookmark', title=u'aaaa', path=u'path')
rset = self.execute('Any B,U,L WHERE B bookmarked_by U?, U login L')
--- a/test/unittest_schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/test/unittest_schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -132,6 +132,8 @@
self.assertRaises(RQLSyntaxError, ERQLExpression, '1')
expr = ERQLExpression('X travaille S, S owned_by U')
self.assertEqual(str(expr), 'Any X WHERE X travaille S, S owned_by U, X eid %(x)s, U eid %(u)s')
+ expr = ERQLExpression('X foo S, S bar U, X baz XE, S quux SE HAVING XE > SE')
+ self.assertEqual(str(expr), 'Any X WHERE X foo S, S bar U, X baz XE, S quux SE, X eid %(x)s, U eid %(u)s HAVING XE > SE')
def test_rrqlexpression(self):
self.assertRaises(Exception, RRQLExpression, '1')
@@ -157,7 +159,7 @@
self.assert_(isinstance(schema, CubicWebSchema))
self.assertEqual(schema.name, 'data')
entities = sorted([str(e) for e in schema.entities()])
- expected_entities = ['BaseTransition', 'BigInt', 'Bookmark', 'Boolean', 'Bytes', 'Card',
+ expected_entities = ['Ami', 'BaseTransition', 'BigInt', 'Bookmark', 'Boolean', 'Bytes', 'Card',
'Date', 'Datetime', 'Decimal',
'CWCache', 'CWConstraint', 'CWConstraintType', 'CWDataImport',
'CWEType', 'CWAttribute', 'CWGroup', 'EmailAddress', 'CWRelation',
@@ -216,6 +218,8 @@
'value',
'wf_info_for', 'wikiid', 'workflow_of', 'tr_count']
+ if config.cube_version('file') >= (1, 14, 0):
+ expected_relations.append('data_sha1hex')
self.assertListEqual(sorted(expected_relations), relations)
--- a/uilib.py Tue Jul 02 17:09:04 2013 +0200
+++ b/uilib.py Mon Jan 13 13:47:47 2014 +0100
@@ -453,7 +453,7 @@
def rest_traceback(info, exception):
- """return a ReST formated traceback"""
+ """return a unicode ReST formated traceback"""
res = [u'Traceback\n---------\n::\n']
for stackentry in traceback.extract_tb(info[2]):
res.append(u'\tFile %s, line %s, function %s' % tuple(stackentry[:3]))
--- a/utils.py Tue Jul 02 17:09:04 2013 +0200
+++ b/utils.py Mon Jan 13 13:47:47 2014 +0100
@@ -49,10 +49,10 @@
"""Return a unique identifier string.
if specified, `key` is used to prefix the generated uid so it can be used
- for instance as a DOM id or as sql table names.
+ for instance as a DOM id or as sql table name.
See uuid.uuid4 documentation for the shape of the generated identifier, but
- this is basicallly a 32 bits hexadecimal string.
+ this is basically a 32 bits hexadecimal string.
"""
if key is None:
return uuid4().hex
@@ -195,6 +195,8 @@
if isinstance(other, RepeatList):
return other._size == self._size and other._item == self._item
return self[:] == other
+ # py3k future warning "Overriding __eq__ blocks inheritance of __hash__ in 3.x"
+ # is annoying but won't go away because we don't want to hash() the repeatlist
def pop(self, i):
self._size -= 1
--- a/view.py Tue Jul 02 17:09:04 2013 +0200
+++ b/view.py Mon Jan 13 13:47:47 2014 +0100
@@ -558,34 +558,6 @@
__registry__ = 'adapters'
-def implements_adapter_compat(iface):
- def _pre39_compat(func):
- def decorated(self, *args, **kwargs):
- entity = self.entity
- if hasattr(entity, func.__name__):
- warn('[3.9] %s method is deprecated, define it on a custom '
- '%s for %s instead' % (func.__name__, iface,
- entity.__class__),
- DeprecationWarning)
- member = getattr(entity, func.__name__)
- if callable(member):
- return member(*args, **kwargs)
- return member
- return func(self, *args, **kwargs)
- decorated.decorated = func
- return decorated
- return _pre39_compat
-
-
-def unwrap_adapter_compat(cls):
- parent = cls.__bases__[0]
- for member_name in dir(parent):
- member = getattr(parent, member_name)
- if isinstance(member, types.MethodType) and hasattr(member.im_func, 'decorated') and not member_name in cls.__dict__:
- method = new.instancemethod(member.im_func.decorated, None, cls)
- setattr(cls, member_name, method)
-
-
class auto_unwrap_bw_compat(type):
def __new__(mcs, name, bases, classdict):
cls = type.__new__(mcs, name, bases, classdict)
@@ -596,7 +568,6 @@
class EntityAdapter(Adapter):
"""base class for entity adapters (eg adapt an entity to an interface)"""
- __metaclass__ = auto_unwrap_bw_compat
def __init__(self, _cw, **kwargs):
try:
self.entity = kwargs.pop('entity')
--- a/web/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -31,8 +31,6 @@
from cubicweb.uilib import eid_param
assert json_dumps is not None, 'no json module installed'
-dumps = deprecated('[3.9] use cubicweb.utils.json_dumps instead of dumps')(
- json_dumps)
INTERNAL_FIELD_VALUE = '__cubicweb_internal_field__'
--- a/web/application.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/application.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -68,7 +68,7 @@
self.session_time = vreg.config['http-session-time'] or None
self.authmanager = vreg['components'].select('authmanager', repo=repo)
interval = (self.session_time or 0) / 2.
- if vreg.config.anonymous_user() is not None:
+ if vreg.config.anonymous_user()[0] is not None:
self.cleanup_anon_session_time = vreg.config['cleanup-anonymous-session-time'] or 5 * 60
assert self.cleanup_anon_session_time > 0
if self.session_time is not None:
@@ -319,17 +319,17 @@
def main_handle_request(self, req, path):
- """Process and http request
+ """Process an http request
Arguments are:
- a Request object
- path of the request object
- It return the content of the http response. HTTP header and status are
- are set on the Request Object.
+ It returns the content of the http response. HTTP header and status are
+ set on the Request object.
"""
if not isinstance(req, CubicWebRequestBase):
- warn('[3.15] Application entry poin arguments are now (req, path) '
+ warn('[3.15] Application entry point arguments are now (req, path) '
'not (path, req)', DeprecationWarning, 2)
req, path = path, req
if req.authmode == 'http':
@@ -393,7 +393,7 @@
# Wrong, absent or Reseted credential
except AuthenticationError:
# If there is an https url configured and
- # the request do not used https, redirect to login form
+ # the request does not use https, redirect to login form
https_url = self.vreg.config['https-url']
if https_url and req.base_url() != https_url:
req.status_out = httplib.SEE_OTHER
@@ -449,8 +449,8 @@
req.update_search_state()
result = controller.publish(rset=rset)
except StatusResponse as ex:
- warn('StatusResponse is deprecated use req.status_out',
- DeprecationWarning)
+ warn('[3.16] StatusResponse is deprecated use req.status_out',
+ DeprecationWarning, stacklevel=2)
result = ex.content
req.status_out = ex.status
except Redirect as ex:
--- a/web/controller.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/controller.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -21,6 +21,7 @@
from logilab.mtconverter import xml_escape
from logilab.common.registry import yes
+from logilab.common.deprecation import deprecated
from cubicweb.appobject import AppObject
from cubicweb.mail import format_mail
@@ -103,6 +104,8 @@
if not self._edited_entity:
self._edited_entity = entity
+ @deprecated('[3.18] call view.set_http_cache_headers then '
+ '.is_client_cache_valid() method and return instead')
def validate_cache(self, view):
view.set_http_cache_headers()
self._cw.validate_cache()
--- a/web/data/cubicweb.ajax.box.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.ajax.box.js Mon Jan 13 13:47:47 2014 +0100
@@ -81,12 +81,12 @@
});
$input.cwautocomplete(unrelated, {multiple: Boolean(separator)});
var buttons = DIV({'class' : "sgformbuttons"},
- A({href : "javascript: noop();",
+ A({href : "javascript: $.noop();",
onclick : cw.utils.strFuncCall('ajaxBoxValidateSelectorInput',
boxid, eid, separator, addfname, msg)},
oklabel),
' / ',
- A({'href' : "javascript: noop();",
+ A({'href' : "javascript: $.noop();",
'onclick' : '$("#' + holderid + '").empty()'},
cancellabel));
holder.append(buttons);
--- a/web/data/cubicweb.ajax.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.ajax.js Mon Jan 13 13:47:47 2014 +0100
@@ -339,11 +339,6 @@
cw.log('loadxhtml called without an element');
}
var callback = null;
- if (form && form.callback) {
- cw.log('[3.9] callback given through form.callback is deprecated, add ' + 'callback on the defered');
- callback = form.callback;
- delete form.callback;
- }
var node = this.get(0); // only consider the first element
if (cursor) {
setProgressCursor();
@@ -734,13 +729,7 @@
/* DEPRECATED *****************************************************************/
-preprocessAjaxLoad = cw.utils.deprecatedFunction(
- '[3.9] preprocessAjaxLoad() is deprecated, use loadAjaxHtmlHead instead',
- function(node, newdomnode) {
- return loadAjaxHtmlHead(newdomnode);
- }
-);
-
+// still used in cwo and keyword cubes at least
reloadComponent = cw.utils.deprecatedFunction(
'[3.9] reloadComponent() is deprecated, use loadxhtml instead',
function(compid, rql, registry, nodeid, extraargs) {
@@ -754,52 +743,6 @@
}
);
-reloadBox = cw.utils.deprecatedFunction(
- '[3.9] reloadBox() is deprecated, use loadxhtml instead',
- function(boxid, rql) {
- return reloadComponent(boxid, rql, 'ctxcomponents', boxid);
- }
-);
-
-replacePageChunk = cw.utils.deprecatedFunction(
- '[3.9] replacePageChunk() is deprecated, use loadxhtml instead',
- function(nodeId, rql, vid, extraparams, /* ... */ swap, callback) {
- var params = null;
- if (callback) {
- params = {
- callback: callback
- };
- }
- var node = jQuery('#' + nodeId)[0];
- var props = {};
- if (node) {
- props['rql'] = rql;
- props['fname'] = 'view';
- props['pageid'] = pageid;
- if (vid) {
- props['vid'] = vid;
- }
- if (extraparams) {
- jQuery.extend(props, extraparams);
- }
- // FIXME we need to do asURL(props) manually instead of
- // passing `props` directly to loadxml because replacePageChunk
- // is sometimes called (abusively) with some extra parameters in `vid`
- var mode = swap ? 'swap': 'replace';
- var url = AJAX_BASE_URL + asURL(props);
- jQuery(node).loadxhtml(url, params, 'get', mode);
- } else {
- cw.log('Node', nodeId, 'not found');
- }
- }
-);
-
-loadxhtml = cw.utils.deprecatedFunction(
- '[3.9] loadxhtml() function is deprecated, use loadxhtml method instead',
- function(nodeid, url, /* ... */ replacemode) {
- jQuery('#' + nodeid).loadxhtml(url, null, 'post', replacemode);
- }
-);
function remoteExec(fname /* ... */) {
setProgressCursor();
--- a/web/data/cubicweb.calendar.css Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.calendar.css Mon Jan 13 13:47:47 2014 +0100
@@ -231,6 +231,8 @@
font-weight:bold;
padding-bottom:0.2em;
background: %(incontextBoxBodyBgColor)s;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
}
.calendar th.month a{
--- a/web/data/cubicweb.compat.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.compat.js Mon Jan 13 13:47:47 2014 +0100
@@ -1,34 +1,3 @@
-cw.utils.movedToNamespace(['log', 'jqNode', 'getNode', 'evalJSON', 'urlEncode',
- 'swapDOM'], cw);
-cw.utils.movedToNamespace(['nodeWalkDepthFirst', 'formContents', 'isArray',
- 'isString', 'isArrayLike', 'sliceList',
- 'toISOTimestamp'], cw.utils);
-
-
-if ($.noop === undefined) {
- function noop() {}
-} else {
- noop = cw.utils.deprecatedFunction(
- '[3.9] noop() is deprecated, use $.noop() instead (XXX requires jQuery 1.4)',
- $.noop);
-}
-
-// ========== ARRAY EXTENSIONS ========== ///
-Array.prototype.contains = cw.utils.deprecatedFunction(
- '[3.9] array.contains(elt) is deprecated, use $.inArray(elt, array)!=-1 instead',
- function(element) {
- return jQuery.inArray(element, this) != - 1;
- }
-);
-
-// ========== END OF ARRAY EXTENSIONS ========== ///
-forEach = cw.utils.deprecatedFunction(
- '[3.9] forEach() is deprecated, use $.each() instead',
- function(array, func) {
- return $.each(array, func);
- }
-);
-
/**
* .. function:: cw.utils.deprecatedFunction(msg, function)
*
@@ -41,64 +10,20 @@
* [ ["a", "b", "c"], ["d", "e"] ]
*/
// XXX why not the same argument order as $.map and forEach ?
-map = cw.utils.deprecatedFunction(
- '[3.9] map() is deprecated, use $.map instead',
- function(func, array) {
- var result = [];
- for (var i = 0, length = array.length; i < length; i++) {
- result.push(func(array[i]));
- }
- return result;
- }
-);
-findValue = cw.utils.deprecatedFunction(
- '[3.9] findValue(array, elt) is deprecated, use $.inArray(elt, array) instead',
- function(array, element) {
- return jQuery.inArray(element, array);
- }
-);
-
-filter = cw.utils.deprecatedFunction(
- '[3.9] filter(func, array) is deprecated, use $.grep(array, f) instead',
- function(func, array) {
- return $.grep(array, func);
+function map(func, array) {
+ var result = [];
+ for (var i = 0, length = array.length; i < length; i++) {
+ result.push(func(array[i]));
}
-);
-
-addElementClass = cw.utils.deprecatedFunction(
- '[3.9] addElementClass(node, cls) is deprecated, use $(node).addClass(cls) instead',
- function(node, klass) {
- $(node).addClass(klass);
- }
-);
+ return result;
+}
-removeElementClass = cw.utils.deprecatedFunction(
- '[3.9] removeElementClass(node, cls) is deprecated, use $(node).removeClass(cls) instead',
- function(node, klass) {
- $(node).removeClass(klass);
- }
-);
-hasElementClass = cw.utils.deprecatedFunction(
- '[3.9] hasElementClass(node, cls) is deprecated, use $(node).hasClass(cls)',
- function(node, klass) {
- return $(node).hasClass(klass);
- }
-);
-
+// skm cube still uses this
getNodeAttribute = cw.utils.deprecatedFunction(
'[3.9] getNodeAttribute(node, attr) is deprecated, use $(node).attr(attr)',
function(node, attribute) {
return $(node).attr(attribute);
}
);
-
-/**
- * The only known usage of KEYS is in the tag cube. Once cubicweb-tag 1.7.0 is out,
- * this current definition can be removed.
- */
-var KEYS = {
- KEY_ESC: 27,
- KEY_ENTER: 13
-};
--- a/web/data/cubicweb.css Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.css Mon Jan 13 13:47:47 2014 +0100
@@ -17,9 +17,6 @@
}
h1, h2, h3 { margin-top:0; margin-bottom:0; }
-/* got rhythm ? beat of 12*1.25 = 15 px */
-.rhythm_bg { background: url("%(baseRhythmBg)s") repeat ! important; }
-
h1,
.vtitle {
font-size: %(h1FontSize)s;
@@ -297,7 +294,6 @@
div#pageContent {
clear: both;
- /* margin-top:-1px; *//* enable when testing rhythm */
background: %(pageContentBgColor)s;
border: 1px solid %(pageContentBorderColor)s;
padding: 0 %(pageContentPadding)s %(pageContentPadding)s;
@@ -358,17 +354,20 @@
div.shadow{
height: 14px;
- background: url("shadow.gif") no-repeat top right;
}
div.sideBoxTitle {
background: %(incontextBoxBodyBg)s;
display: block;
font-weight: bold;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
}
div.sideBox {
margin-bottom: 1em;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
}
ul.sideBox,
@@ -403,6 +402,8 @@
div.boxTitle {
overflow: hidden;
font-weight: bold;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
}
div.boxTitle span {
@@ -467,7 +468,10 @@
#navColumnLeft div.boxFooter, #navColumnRight div.boxFooter{
height: 14px;
- background: url("shadow.gif") no-repeat top right;
+}
+
+.boxBody, .boxTitle, #pageContent, #appMsg {
+ box-shadow: 1px 1px 3px Gray;
}
/* boxes lists and menus */
--- a/web/data/cubicweb.facets.css Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.facets.css Mon Jan 13 13:47:47 2014 +0100
@@ -8,6 +8,8 @@
background: #fff;
padding: %(facet_Padding)s;
margin-bottom: %(facet_MarginBottom)s;
+ border-top-left-radius: 5px;
+ border-bottom-right-radius: 7px;
}
.facetGroup {
--- a/web/data/cubicweb.facets.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.facets.js Mon Jan 13 13:47:47 2014 +0100
@@ -1,14 +1,13 @@
/** filter form, aka facets, javascript functions
*
* :organization: Logilab
- * :copyright: 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+ * :copyright: 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
*/
-var SELECTED_IMG = baseuri() + "data/black-check.png";
-var UNSELECTED_IMG = baseuri() + "data/no-check-no-border.png";
-var UNSELECTED_BORDER_IMG = baseuri() + "data/black-uncheck.png";
-
+var SELECTED_IMG = DATA_URL + 'black-check.png';
+var UNSELECTED_IMG = DATA_URL + 'no-check-no-border.png';
+var UNSELECTED_BORDER_IMG = DATA_URL + 'black-uncheck.png';
function copyParam(origparams, newparams, param) {
var index = $.inArray(param, origparams[0]);
@@ -30,7 +29,7 @@
});
// FacetStringWidget (e.g. has-text)
$(this).find('input:text').each(function(){
- names.push(facetName);
+ names.push(this.name);
values.push(this.value);
});
});
@@ -110,7 +109,7 @@
$node.loadxhtml(AJAX_BASE_URL, ajaxFuncArgs('render', {
'rql': rql
},
- 'ctxcomponents', 'edit_box'));
+ 'ctxcomponents', 'edit_box'), 'GET', 'swap');
}
$node = $('#breadcrumbs');
if ($node.length) {
@@ -170,7 +169,6 @@
if ($('#'+divid).length) {
var $loadingDiv = $(DIV({id:'facetLoading'},
facetLoadingMsg));
- $loadingDiv.corner();
$($('#'+divid).get(0).parentNode).append($loadingDiv);
}
form.find('div.facet').each(function() {
@@ -328,7 +326,6 @@
if ($('div.facetBody').length) {
var $loadingDiv = $(DIV({id:'facetLoading'},
facetLoadingMsg));
- $loadingDiv.corner();
$('body').append($loadingDiv);
}
});
--- a/web/data/cubicweb.htmlhelpers.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.htmlhelpers.js Mon Jan 13 13:47:47 2014 +0100
@@ -78,10 +78,10 @@
// generate a list of couple key=value if key is multivalued
if (cw.utils.isArrayLike(value)) {
for (var i = 0; i < value.length; i++) {
- chunks.push(key + '=' + urlEncode(value[i]));
+ chunks.push(key + '=' + cw.urlEncode(value[i]));
}
} else {
- chunks.push(key + '=' + urlEncode(value));
+ chunks.push(key + '=' + cw.urlEncode(value));
}
}
return chunks.join('&');
@@ -195,19 +195,4 @@
}
}
}
-//============= page loading events ==========================================//
-cw.rounded = [['div.sideBoxBody', 'bottom 6px'],
- ['div.boxTitle, div.sideBoxTitle, th.month', 'top 6px']];
-function roundedCorners(node) {
- if (jQuery.fn.corner !== undefined) {
- node = jQuery(node);
- for (var r = 0; r < cw.rounded.length; r++) {
- node.find(cw.rounded[r][0]).corner(cw.rounded[r][1]);
- }
- }
-}
-
-jQuery(document).ready(function() {
- roundedCorners(this.body);
-});
--- a/web/data/cubicweb.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.js Mon Jan 13 13:47:47 2014 +0100
@@ -45,6 +45,15 @@
return null;
},
+ // escapes string selectors (e.g. "foo.[subject]:42" -> "foo\.\[subject\]\:42"
+ escape: function(selector) {
+ if (typeof(selector) == 'string') {
+ return selector.replace( /(:|\.|\[|\])/g, "\\$1" );
+ }
+ // cw.log('non string selector', selector);
+ return '';
+ },
+
getNode: function (node) {
if (typeof(node) == 'string') {
return document.getElementById(node);
@@ -105,15 +114,6 @@
};
},
- movedToNamespace: function (funcnames, namespace) {
- for (var i = 0; i < funcnames.length; i++) {
- var funcname = funcnames[i];
- var msg = ('[3.9] ' + funcname + ' is deprecated, use ' +
- namespace.__name__ + '.' + funcname + ' instead');
- window[funcname] = cw.utils.deprecatedFunction(msg, namespace[funcname]);
- }
- },
-
createDomFunction: function (tag) {
function builddom(params, children) {
var node = document.createElement(tag);
@@ -388,14 +388,6 @@
});
-String.prototype.startsWith = cw.utils.deprecatedFunction('[3.9] str.startsWith() is deprecated, use str.startswith() instead', function (prefix) {
- return this.startswith(prefix);
-});
-
-String.prototype.endsWith = cw.utils.deprecatedFunction('[3.9] str.endsWith() is deprecated, use str.endswith() instead', function (suffix) {
- return this.endswith(prefix);
-});
-
/** DOM factories ************************************************************/
A = cw.utils.createDomFunction('a');
BUTTON = cw.utils.createDomFunction('button');
@@ -472,7 +464,8 @@
return node;
}
-// XXX avoid crashes / backward compat
+// cubes: tag, keyword and apycot seem to use this, including require/provide
+// backward compat
CubicWeb = cw;
jQuery.extend(cw, {
--- a/web/data/cubicweb.old.css Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.old.css Mon Jan 13 13:47:47 2014 +0100
@@ -411,13 +411,14 @@
div.shadow{
height: 14px;
- background: url("shadow.gif") no-repeat top right;
}
div.sideBoxTitle {
background: #cfceb7;
display: block;
font: bold 100% Georgia;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
}
div.sideBox {
@@ -434,6 +435,8 @@
div.sideBoxBody {
padding: 0.2em 5px;
background: #eeedd9;
+ border-bottom-left-radius: 6px;
+ border-bottom-right-radius: 6px;
}
div.sideBoxBody a {
@@ -457,6 +460,8 @@
div.boxTitle {
overflow: hidden;
font-weight: bold;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
}
div.boxTitle span {
@@ -521,7 +526,14 @@
#navColumnLeft div.boxFooter, #navColumnRight div.boxFooter{
height: 14px;
- background: url("shadow.gif") no-repeat top right;
+}
+
+.navboxes {
+ padding: 2px;
+}
+
+.boxBody, .boxTitle, #pageContent, #appMsg {
+ box-shadow: 1px 1px 3px Gray;
}
/* boxes lists and menus */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.pictograms.css Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,343 @@
+/*The included Entypo font have been created by Daniel Bruce (www.entypo.com) as
+proposed by fontello (https://github.com/fontello/entypo).
+The Entypo pictograms are licensed under CC BY 3.0 and the font under
+SIL Open Font License.*/
+@font-face {
+ font-family: 'entypo';
+ src: url('entypo.eot?8644018');
+ src: url('entypo.eot?8644018#iefix') format('embedded-opentype'),
+ url('entypo.woff?8644018') format('woff'),
+ url('entypo.ttf?8644018') format('truetype'),
+ url('entypo.svg?8644018#entypo') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
+/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
+/*
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ @font-face {
+ font-family: 'entypo';
+ src: url('../font/entypo.svg?8644018#entypo') format('svg');
+ }
+}
+*/
+
+[class^="icon-"]:before,
+[class*=" icon-"]:before {
+ font-family: "entypo";
+ font-style: normal;
+ font-weight: normal;
+ speak: none;
+
+ display: inline-block;
+ text-decoration: inherit;
+ width: 1em;
+ margin-right: .1em;
+ text-align: center;
+ /* opacity: .8; */
+
+ /* For safety - reset parent styles, that can break glyph codes*/
+ font-variant: normal;
+ text-transform: none;
+
+ /* fix buttons height, for twitter bootstrap */
+ line-height: 1em;
+
+ /* Animation center compensation - magrins should be symmetric */
+ /* remove if not needed */
+ margin-left: .1em;
+
+ /* you can be more comfortable with increased icons size */
+ font-size: 160%;
+ vertical-align: middle;
+
+ /* Uncomment for 3D effect */
+ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
+}
+
+.icon-note:before { content: '\266a'; } /* '♪' */
+.icon-note-beamed:before { content: '\266b'; } /* '♫' */
+.icon-music:before { content: '\1f3b5'; } /* '\1f3b5' */
+.icon-search:before { content: '\1f50d'; } /* '\1f50d' */
+.icon-flashlight:before { content: '\1f526'; } /* '\1f526' */
+.icon-mail:before { content: '\2709'; } /* '✉' */
+.icon-heart:before { content: '\2665'; } /* '♥' */
+.icon-heart-empty:before { content: '\2661'; } /* '♡' */
+.icon-star:before { content: '\2605'; } /* '★' */
+.icon-star-empty:before { content: '\2606'; } /* '☆' */
+.icon-user:before { content: '\1f464'; }
+.icon-users:before { content: '\1f465'; }
+.icon-user-add:before { content: '\e700'; } /* '' */
+.icon-video:before { content: '\1f3ac'; }
+.icon-picture:before { content: '\1f304'; }
+.icon-camera:before { content: '\1f4f7'; }
+.icon-layout:before { content: '\268f'; } /* '⚏' */
+.icon-menu:before { content: '\2630'; } /* '☰' */
+.icon-check:before { content: '\2713'; } /* '✓' */
+.icon-cancel:before { content: '\2715'; } /* '✕' */
+.icon-cancel-circled:before { content: '\2716'; } /* '✖' */
+.icon-cancel-squared:before { content: '\274e'; } /* '❎' */
+.icon-plus:before { content: '\2b'; } /* '+' */
+.icon-plus-circled:before { content: '\2795'; } /* '➕' */
+.icon-plus-squared:before { content: '\229e'; } /* '⊞' */
+.icon-minus:before { content: '\2d'; } /* '-' */
+.icon-minus-circled:before { content: '\2796'; } /* '➖' */
+.icon-minus-squared:before { content: '\229f'; } /* '⊟' */
+.icon-help:before { content: '\2753'; } /* '❓' */
+.icon-help-circled:before { content: '\e704'; } /* '' */
+.icon-info:before { content: '\2139'; } /* 'ℹ' */
+.icon-info-circled:before { content: '\e705'; } /* '' */
+.icon-back:before { content: '\1f519'; }
+.icon-home:before { content: '\2302'; } /* '⌂' */
+.icon-link:before { content: '\1f517'; }
+.icon-attach:before { content: '\1f4ce'; }
+.icon-lock:before { content: '\1f512'; }
+.icon-lock-open:before { content: '\1f513'; }
+.icon-eye:before { content: '\e70a'; } /* '' */
+.icon-tag:before { content: '\e70c'; } /* '' */
+.icon-bookmark:before { content: '\1f516'; }
+.icon-bookmarks:before { content: '\1f4d1'; }
+.icon-flag:before { content: '\2691'; } /* '⚑' */
+.icon-thumbs-up:before { content: '\1f44d'; }
+.icon-thumbs-down:before { content: '\1f44e'; }
+.icon-download:before { content: '\1f4e5'; }
+.icon-upload:before { content: '\1f4e4'; }
+.icon-upload-cloud:before { content: '\e711'; } /* '' */
+.icon-reply:before { content: '\e712'; } /* '' */
+.icon-reply-all:before { content: '\e713'; } /* '' */
+.icon-forward:before { content: '\27a6'; } /* '➦' */
+.icon-quote:before { content: '\275e'; } /* '❞' */
+.icon-code:before { content: '\e714'; } /* '' */
+.icon-export:before { content: '\e715'; } /* '' */
+.icon-pencil:before { content: '\270e'; } /* '✎' */
+.icon-feather:before { content: '\2712'; } /* '✒' */
+.icon-print:before { content: '\e716'; } /* '' */
+.icon-retweet:before { content: '\e717'; } /* '' */
+.icon-keyboard:before { content: '\2328'; } /* '⌨' */
+.icon-comment:before { content: '\e718'; } /* '' */
+.icon-chat:before { content: '\e720'; } /* '' */
+.icon-bell:before { content: '\1f514'; }
+.icon-attention:before { content: '\26a0'; } /* '⚠' */
+.icon-alert:before { content: '\1f4a5'; }
+.icon-vcard:before { content: '\e722'; } /* '' */
+.icon-address:before { content: '\e723'; } /* '' */
+.icon-location:before { content: '\e724'; } /* '' */
+.icon-map:before { content: '\e727'; } /* '' */
+.icon-direction:before { content: '\27a2'; } /* '➢' */
+.icon-compass:before { content: '\e728'; } /* '' */
+.icon-cup:before { content: '\2615'; } /* '☕' */
+.icon-trash:before { content: '\e729'; } /* '' */
+.icon-doc:before { content: '\e730'; } /* '' */
+.icon-docs:before { content: '\e736'; } /* '' */
+.icon-doc-landscape:before { content: '\e737'; } /* '' */
+.icon-doc-text:before { content: '\1f4c4'; }
+.icon-doc-text-inv:before { content: '\e731'; } /* '' */
+.icon-newspaper:before { content: '\1f4f0'; }
+.icon-book-open:before { content: '\1f4d6'; }
+.icon-book:before { content: '\1f4d5'; }
+.icon-folder:before { content: '\1f4c1'; }
+.icon-archive:before { content: '\e738'; } /* '' */
+.icon-box:before { content: '\1f4e6'; }
+.icon-rss:before { content: '\e73a'; } /* '' */
+.icon-phone:before { content: '\1f4de'; }
+.icon-cog:before { content: '\2699'; } /* '⚙' */
+.icon-tools:before { content: '\2692'; } /* '⚒' */
+.icon-share:before { content: '\e73c'; } /* '' */
+.icon-shareable:before { content: '\e73e'; } /* '' */
+.icon-basket:before { content: '\e73d'; } /* '' */
+.icon-bag:before { content: '\1f45c'; }
+.icon-calendar:before { content: '\1f4c5'; }
+.icon-login:before { content: '\e740'; } /* '' */
+.icon-logout:before { content: '\e741'; } /* '' */
+.icon-mic:before { content: '\1f3a4'; }
+.icon-mute:before { content: '\1f507'; }
+.icon-sound:before { content: '\1f50a'; }
+.icon-volume:before { content: '\e742'; } /* '' */
+.icon-clock:before { content: '\1f554'; }
+.icon-hourglass:before { content: '\23f3'; } /* '⏳' */
+.icon-lamp:before { content: '\1f4a1'; }
+.icon-light-down:before { content: '\1f505'; }
+.icon-light-up:before { content: '\1f506'; }
+.icon-adjust:before { content: '\25d1'; } /* '◑' */
+.icon-block:before { content: '\1f6ab'; }
+.icon-resize-full:before { content: '\e744'; } /* '' */
+.icon-resize-small:before { content: '\e746'; } /* '' */
+.icon-popup:before { content: '\e74c'; } /* '' */
+.icon-publish:before { content: '\e74d'; } /* '' */
+.icon-window:before { content: '\e74e'; } /* '' */
+.icon-arrow-combo:before { content: '\e74f'; } /* '' */
+.icon-down-circled:before { content: '\e758'; } /* '' */
+.icon-left-circled:before { content: '\e759'; } /* '' */
+.icon-right-circled:before { content: '\e75a'; } /* '' */
+.icon-up-circled:before { content: '\e75b'; } /* '' */
+.icon-down-open:before { content: '\e75c'; } /* '' */
+.icon-left-open:before { content: '\e75d'; } /* '' */
+.icon-right-open:before { content: '\e75e'; } /* '' */
+.icon-up-open:before { content: '\e75f'; } /* '' */
+.icon-down-open-mini:before { content: '\e760'; } /* '' */
+.icon-left-open-mini:before { content: '\e761'; } /* '' */
+.icon-right-open-mini:before { content: '\e762'; } /* '' */
+.icon-up-open-mini:before { content: '\e763'; } /* '' */
+.icon-down-open-big:before { content: '\e764'; } /* '' */
+.icon-left-open-big:before { content: '\e765'; } /* '' */
+.icon-right-open-big:before { content: '\e766'; } /* '' */
+.icon-up-open-big:before { content: '\e767'; } /* '' */
+.icon-down:before { content: '\2b07'; } /* '⬇' */
+.icon-left:before { content: '\2b05'; } /* '⬅' */
+.icon-right:before { content: '\27a1'; } /* '➡' */
+.icon-up:before { content: '\2b06'; } /* '⬆' */
+.icon-down-dir:before { content: '\25be'; } /* '▾' */
+.icon-left-dir:before { content: '\25c2'; } /* '◂' */
+.icon-right-dir:before { content: '\25b8'; } /* '▸' */
+.icon-up-dir:before { content: '\25b4'; } /* '▴' */
+.icon-down-bold:before { content: '\e4b0'; } /* '' */
+.icon-left-bold:before { content: '\e4ad'; } /* '' */
+.icon-right-bold:before { content: '\e4ae'; } /* '' */
+.icon-up-bold:before { content: '\e4af'; } /* '' */
+.icon-down-thin:before { content: '\2193'; } /* '↓' */
+.icon-left-thin:before { content: '\2190'; } /* '←' */
+.icon-right-thin:before { content: '\2192'; } /* '→' */
+.icon-up-thin:before { content: '\2191'; } /* '↑' */
+.icon-ccw:before { content: '\27f2'; } /* '⟲' */
+.icon-cw:before { content: '\27f3'; } /* '⟳' */
+.icon-arrows-ccw:before { content: '\1f504'; }
+.icon-level-down:before { content: '\21b3'; } /* '↳' */
+.icon-level-up:before { content: '\21b0'; } /* '↰' */
+.icon-shuffle:before { content: '\1f500'; }
+.icon-loop:before { content: '\1f501'; }
+.icon-switch:before { content: '\21c6'; } /* '⇆' */
+.icon-play:before { content: '\25b6'; } /* '▶' */
+.icon-stop:before { content: '\25a0'; } /* '■' */
+.icon-pause:before { content: '\2389'; } /* '⎉' */
+.icon-record:before { content: '\26ab'; } /* '⚫' */
+.icon-to-end:before { content: '\23ed'; } /* '⏭' */
+.icon-to-start:before { content: '\23ee'; } /* '⏮' */
+.icon-fast-forward:before { content: '\23e9'; } /* '⏩' */
+.icon-fast-backward:before { content: '\23ea'; } /* '⏪' */
+.icon-progress-0:before { content: '\e768'; } /* '' */
+.icon-progress-1:before { content: '\e769'; } /* '' */
+.icon-progress-2:before { content: '\e76a'; } /* '' */
+.icon-progress-3:before { content: '\e76b'; } /* '' */
+.icon-target:before { content: '\1f3af'; }
+.icon-palette:before { content: '\1f3a8'; }
+.icon-list:before { content: '\e005'; } /* '' */
+.icon-list-add:before { content: '\e003'; } /* '' */
+.icon-signal:before { content: '\1f4f6'; }
+.icon-trophy:before { content: '\1f3c6'; }
+.icon-battery:before { content: '\1f50b'; }
+.icon-back-in-time:before { content: '\e771'; } /* '' */
+.icon-monitor:before { content: '\1f4bb'; }
+.icon-mobile:before { content: '\1f4f1'; }
+.icon-network:before { content: '\e776'; } /* '' */
+.icon-cd:before { content: '\1f4bf'; }
+.icon-inbox:before { content: '\e777'; } /* '' */
+.icon-install:before { content: '\e778'; } /* '' */
+.icon-globe:before { content: '\1f30e'; }
+.icon-cloud:before { content: '\2601'; } /* '☁' */
+.icon-cloud-thunder:before { content: '\26c8'; } /* '⛈' */
+.icon-flash:before { content: '\26a1'; } /* '⚡' */
+.icon-moon:before { content: '\263d'; } /* '☽' */
+.icon-flight:before { content: '\2708'; } /* '✈' */
+.icon-paper-plane:before { content: '\e79b'; } /* '' */
+.icon-leaf:before { content: '\1f342'; }
+.icon-lifebuoy:before { content: '\e788'; } /* '' */
+.icon-mouse:before { content: '\e789'; } /* '' */
+.icon-briefcase:before { content: '\1f4bc'; }
+.icon-suitcase:before { content: '\e78e'; } /* '' */
+.icon-dot:before { content: '\e78b'; } /* '' */
+.icon-dot-2:before { content: '\e78c'; } /* '' */
+.icon-dot-3:before { content: '\e78d'; } /* '' */
+.icon-brush:before { content: '\e79a'; } /* '' */
+.icon-magnet:before { content: '\e7a1'; } /* '' */
+.icon-infinity:before { content: '\221e'; } /* '∞' */
+.icon-erase:before { content: '\232b'; } /* '⌫' */
+.icon-chart-pie:before { content: '\e751'; } /* '' */
+.icon-chart-line:before { content: '\1f4c8'; }
+.icon-chart-bar:before { content: '\1f4ca'; }
+.icon-chart-area:before { content: '\1f53e'; }
+.icon-tape:before { content: '\2707'; } /* '✇' */
+.icon-graduation-cap:before { content: '\1f393'; }
+.icon-language:before { content: '\e752'; } /* '' */
+.icon-ticket:before { content: '\1f3ab'; }
+.icon-water:before { content: '\1f4a6'; }
+.icon-droplet:before { content: '\1f4a7'; }
+.icon-air:before { content: '\e753'; } /* '' */
+.icon-credit-card:before { content: '\1f4b3'; }
+.icon-floppy:before { content: '\1f4be'; }
+.icon-clipboard:before { content: '\1f4cb'; }
+.icon-megaphone:before { content: '\1f4e3'; }
+.icon-database:before { content: '\e754'; } /* '' */
+.icon-drive:before { content: '\e755'; } /* '' */
+.icon-bucket:before { content: '\e756'; } /* '' */
+.icon-thermometer:before { content: '\e757'; } /* '' */
+.icon-key:before { content: '\1f511'; }
+.icon-flow-cascade:before { content: '\e790'; } /* '' */
+.icon-flow-branch:before { content: '\e791'; } /* '' */
+.icon-flow-tree:before { content: '\e792'; } /* '' */
+.icon-flow-line:before { content: '\e793'; } /* '' */
+.icon-flow-parallel:before { content: '\e794'; } /* '' */
+.icon-rocket:before { content: '\1f680'; }
+.icon-gauge:before { content: '\e7a2'; } /* '' */
+.icon-traffic-cone:before { content: '\e7a3'; } /* '' */
+.icon-cc:before { content: '\e7a5'; } /* '' */
+.icon-cc-by:before { content: '\e7a6'; } /* '' */
+.icon-cc-nc:before { content: '\e7a7'; } /* '' */
+.icon-cc-nc-eu:before { content: '\e7a8'; } /* '' */
+.icon-cc-nc-jp:before { content: '\e7a9'; } /* '' */
+.icon-cc-sa:before { content: '\e7aa'; } /* '' */
+.icon-cc-nd:before { content: '\e7ab'; } /* '' */
+.icon-cc-pd:before { content: '\e7ac'; } /* '' */
+.icon-cc-zero:before { content: '\e7ad'; } /* '' */
+.icon-cc-share:before { content: '\e7ae'; } /* '' */
+.icon-cc-remix:before { content: '\e7af'; } /* '' */
+.icon-github:before { content: '\f300'; } /* '' */
+.icon-github-circled:before { content: '\f301'; } /* '' */
+.icon-flickr:before { content: '\f303'; } /* '' */
+.icon-flickr-circled:before { content: '\f304'; } /* '' */
+.icon-vimeo:before { content: '\f306'; } /* '' */
+.icon-vimeo-circled:before { content: '\f307'; } /* '' */
+.icon-twitter:before { content: '\f309'; } /* '' */
+.icon-twitter-circled:before { content: '\f30a'; } /* '' */
+.icon-facebook:before { content: '\f30c'; } /* '' */
+.icon-facebook-circled:before { content: '\f30d'; } /* '' */
+.icon-facebook-squared:before { content: '\f30e'; } /* '' */
+.icon-gplus:before { content: '\f30f'; } /* '' */
+.icon-gplus-circled:before { content: '\f310'; } /* '' */
+.icon-pinterest:before { content: '\f312'; } /* '' */
+.icon-pinterest-circled:before { content: '\f313'; } /* '' */
+.icon-tumblr:before { content: '\f315'; } /* '' */
+.icon-tumblr-circled:before { content: '\f316'; } /* '' */
+.icon-linkedin:before { content: '\f318'; } /* '' */
+.icon-linkedin-circled:before { content: '\f319'; } /* '' */
+.icon-dribbble:before { content: '\f31b'; } /* '' */
+.icon-dribbble-circled:before { content: '\f31c'; } /* '' */
+.icon-stumbleupon:before { content: '\f31e'; } /* '' */
+.icon-stumbleupon-circled:before { content: '\f31f'; } /* '' */
+.icon-lastfm:before { content: '\f321'; } /* '' */
+.icon-lastfm-circled:before { content: '\f322'; } /* '' */
+.icon-rdio:before { content: '\f324'; } /* '' */
+.icon-rdio-circled:before { content: '\f325'; } /* '' */
+.icon-spotify:before { content: '\f327'; } /* '' */
+.icon-spotify-circled:before { content: '\f328'; } /* '' */
+.icon-qq:before { content: '\f32a'; } /* '' */
+.icon-instagram:before { content: '\f32d'; } /* '' */
+.icon-dropbox:before { content: '\f330'; } /* '' */
+.icon-evernote:before { content: '\f333'; } /* '' */
+.icon-flattr:before { content: '\f336'; } /* '' */
+.icon-skype:before { content: '\f339'; } /* '' */
+.icon-skype-circled:before { content: '\f33a'; } /* '' */
+.icon-renren:before { content: '\f33c'; } /* '' */
+.icon-sina-weibo:before { content: '\f33f'; } /* '' */
+.icon-paypal:before { content: '\f342'; } /* '' */
+.icon-picasa:before { content: '\f345'; } /* '' */
+.icon-soundcloud:before { content: '\f348'; } /* '' */
+.icon-mixi:before { content: '\f34b'; } /* '' */
+.icon-behance:before { content: '\f34e'; } /* '' */
+.icon-google-circles:before { content: '\f351'; } /* '' */
+.icon-vkontakte:before { content: '\f354'; } /* '' */
+.icon-smashing:before { content: '\f357'; } /* '' */
+.icon-sweden:before { content: '\f601'; } /* '' */
+.icon-db-shape:before { content: '\f600'; } /* '' */
+.icon-logo-db:before { content: '\f603'; } /* '' */
+
--- a/web/data/cubicweb.rhythm.js Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-$(document).ready(function() {
- $('a.rhythm').click(function (event){
- $('div#pageContent').toggleClass('rhythm_bg');
- $('div#page').toggleClass('rhythm_bg');
- event.preventDefault();
- });
-});
--- a/web/data/cubicweb.widgets.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/cubicweb.widgets.js Mon Jan 13 13:47:47 2014 +0100
@@ -92,7 +92,8 @@
if (($(instanceData.userInput).attr('cubicweb:initialvalue') !== undefined) && !instanceData.hiddenInput){
hiHandlers.initializeHiddenInput(instanceData);
}
- $.ui.autocomplete.prototype._search = methods.search;
+ $.ui.autocomplete.prototype._value = methods._value;
+ $.data(this, 'settings', settings);
if (settings.multiple) {
$.ui.autocomplete.filter = methods.multiple.makeFilter(this);
$(this).bind({
@@ -125,6 +126,20 @@
});
},
+ _value: function() {
+ /* We extend the widget with the ability to lookup and
+ handle several terms at once ('multiple' option). E.g.:
+ toto, titi, tu.... The autocompletion must be
+ performed only on the last of such a list of terms.
+ */
+ var settings = $(this.element).data('settings');
+ var value = this.valueMethod.apply( this.element, arguments );
+ if (settings.multiple & arguments.length === 0) {
+ return extractLast(value);
+ }
+ return value
+ },
+
multiple: {
focus: function() {
// prevent value inserted on focus
@@ -140,7 +155,7 @@
return false;
},
keydown: function(evt) {
- if ($(this).data('autocomplete').menu.active && evt.keyCode == $.ui.keyCode.TAB) {
+ if (evt.keyCode == $.ui.keyCode.TAB) {
evt.preventDefault();
}
},
@@ -161,13 +176,7 @@
methods.resetValues(instanceData);
}
},
- search: function(value) {
- this.element.addClass("ui-autocomplete-loading");
- if (this.options.multiple) {
- value = extractLast(value);
- }
- this.source({term: value}, this.response);
- },
+
ensureExactMatch: function(evt) {
var instanceData = $(this).data('cwautocomplete');
if (evt.keyCode == $.ui.keyCode.ENTER || evt.keyCode == $.ui.keyCode.TAB) {
@@ -179,6 +188,7 @@
}
}
},
+
resetValues: function(instanceData){
$(instanceData.userInput).val('');
$(instanceData.hiddenInput).val('');
@@ -544,105 +554,77 @@
// IE things can not handle hide/show options on select, this cloned list solition (should propably have 2 widgets)
(function ($) {
- var defaultSettings = {
- bindDblClick: true
- };
+
var methods = {
- __init__: function(fromSelect, toSelect, options) {
- var settings = $.extend({}, defaultSettings, options);
- var bindDblClick = settings['bindDblClick'];
- var $fromNode = $(cw.jqNode(fromSelect));
- var clonedSelect = $fromNode.clone();
- var $toNode = $(cw.jqNode(toSelect));
- var $addButton = $(this.find('.cwinoutadd')[0]);
- var $removeButton = $(this.find('.cwinoutremove')[0]);
- // bind buttons
- var name = this.attr('id');
- var instanceData = {'fromNode':fromSelect,
- 'toNode':toSelect,
- 'cloned':clonedSelect,
- 'bindDblClick':bindDblClick,
- 'name': name};
- $addButton.bind('click', {'instanceData':instanceData}, methods.inOutWidgetAddValues);
- $removeButton.bind('click', {'instanceData':instanceData}, methods.inOutWidgetRemoveValues);
- if(bindDblClick){
- $toNode.bind('dblclick', {'instanceData': instanceData}, methods.inOutWidgetRemoveValues);
- }
- methods.inOutWidgetRemplaceSelect($fromNode, $toNode, clonedSelect, bindDblClick, name);
- },
+ __init__: function(fromSelect, toSelect) {
+ // closed over state
+ var state = {'$fromNode' : $(cw.escape('#' + fromSelect)),
+ '$toNode' : $(cw.escape('#' + toSelect)),
+ 'name' : this.attr('id')};
- inOutWidgetRemplaceSelect: function($fromNode, $toNode, clonedSelect, bindDblClick, name){
- var $newSelect = clonedSelect.clone();
- $toNode.find('option').each(function() {
- $newSelect.find('$(this)[value='+$(this).val()+']').remove();
- });
- var fromparent = $fromNode.parent();
- if (bindDblClick) {
- //XXX jQuery live binding does not seem to work here
- $newSelect.bind('dblclick', {'instanceData': {'fromNode':$fromNode.attr('id'),
- 'toNode': $toNode.attr('id'),
- 'cloned':clonedSelect,
- 'bindDblClick':bindDblClick,
- 'name': name}},
- methods.inOutWidgetAddValues);
- }
- $fromNode.remove();
- fromparent.append($newSelect);
- },
+ function sortoptions($optionlist) {
+ var $sorted = $optionlist.find('option').sort(function(opt1, opt2) {
+ return $(opt1).text() > $(opt2).text() ? 1 : -1;
+ });
+ // this somehow translates to an inplace sort
+ $optionlist.append($sorted);
+ };
+ sortoptions(state.$fromNode);
+ sortoptions(state.$toNode);
- inOutWidgetAddValues: function(event){
- var $fromNode = $(cw.jqNode(event.data.instanceData.fromNode));
- var $toNode = $(cw.jqNode(event.data.instanceData.toNode));
- $fromNode.find('option:selected').each(function() {
- var option = $(this);
- var newoption = OPTION({'value':option.val()},
- value=option.text());
- $toNode.append(newoption);
- var hiddenInput = INPUT({
- type: "hidden", name: event.data.instanceData.name,
- value:option.val()
+ // will move selected options from one list to the other
+ // and call an option handler on each option
+ function moveoptions ($fromlist, $tolist, opthandler) {
+ $fromlist.find('option:selected').each(function(index, option) {
+ var $option = $(option);
+ // add a new option to the target list
+ $tolist.append(OPTION({'value' : $option.val()},
+ $option.text()));
+ // process callback on the option
+ opthandler.call(null, $option);
+ // remove option from the source list
+ $option.remove();
});
- $toNode.parent().append(hiddenInput);
- });
- methods.inOutWidgetRemplaceSelect($fromNode, $toNode, event.data.instanceData.cloned,
- event.data.instanceData.bindDblClick,
- event.data.instanceData.name);
- // for ie 7 : ie does not resize correctly the select
- if($.browser.msie && $.browser.version.substr(0,1) < 8){
- var p = $toNode.parent();
- var newtoNode = $toNode.clone();
- if (event.data.instanceData.bindDblClick) {
- newtoNode.bind('dblclick', {'fromNode': $fromNode.attr('id'),
- 'toNode': $toNode.attr('id'),
- 'cloned': event.data.instanceData.cloned,
- 'bindDblClick': true,
- 'name': event.data.instanceData.name},
- methods.inOutWidgetRemoveValues);
- }
- $toNode.remove();
- p.append(newtoNode);
- }
- },
+ // re-sort both lists
+ sortoptions($fromlist);
+ sortoptions($tolist);
+ };
+
+ function addvalues () {
+ moveoptions(state.$fromNode, state.$toNode, function ($option) {
+ // add an hidden input for the edit controller
+ var hiddenInput = INPUT({
+ type: 'hidden', name: state.name,
+ value : $option.val()
+ });
+ state.$toNode.parent().append(hiddenInput);
+ });
+ };
- inOutWidgetRemoveValues: function(event){
- var $fromNode = $(cw.jqNode(event.data.instanceData.toNode));
- var $toNode = $(cw.jqNode(event.data.instanceData.fromNode));
- var name = event.data.instanceData.name.replace(':', '\\:');
- $fromNode.find('option:selected').each(function(){
- var option = $(this);
- var newoption = OPTION({'value':option.val()},
- value=option.text());
- option.remove();
- $fromNode.parent().find('input[name]='+ name).each(function() {
- $(this).val()==option.val()?$(this).remove():null;
- });
- });
- methods.inOutWidgetRemplaceSelect($toNode, $fromNode, event.data.instanceData.cloned,
- event.data.instanceData.bindDblClick,
- event.data.instanceData.name);
+ function removevalues () {
+ moveoptions(state.$toNode, state.$fromNode, function($option) {
+ // remove hidden inputs for the edit controller
+ var selector = 'input[name=' + cw.escape(state.name) + ']'
+ state.$toNode.parent().find(selector).each(function(index, input) {
+ if ($(input).val() == $option.val()) {
+ $(input).remove();
+ }
+ });
+ });
+ };
+
+ var $this = $(this);
+ $this.find('.cwinoutadd').bind( // 'add >>>' symbol
+ 'click', {'state' : state}, addvalues);
+ $this.find('.cwinoutremove').bind( // 'remove <<<' symbol
+ 'click', {'state' : state}, removevalues);
+
+ state.$fromNode.bind('dblclick', {'state': state}, addvalues);
+ state.$toNode.bind('dblclick', {'state': state}, removevalues);
+
}
};
- $.fn.cwinoutwidget = function(fromSelect, toSelect, options){
- return methods.__init__.apply(this, [fromSelect, toSelect, options]);
+ $.fn.cwinoutwidget = function(fromSelect, toSelect) {
+ return methods.__init__.apply(this, [fromSelect, toSelect]);
};
-})(jQuery);
\ No newline at end of file
+})(jQuery);
Binary file web/data/entypo.eot has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/entypo.svg Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,295 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>Copyright (C) 2012 by Daniel Bruce</metadata>
+<defs>
+<font id="entypo" horiz-adv-x="1000" >
+<font-face font-family="Font Awesome" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
+<missing-glyph horiz-adv-x="1000" />
+<glyph glyph-name="note" unicode="♪" d="M381 820q0-42 46-97t90-100 61-119-39-154q-20-34-26-16-2 6 0 16 10 18 6 56t-13 78-43 73-82 41v-536q2-48-37-95t-105-71q-74-28-143-8t-89 76 20 115 116 85q86 30 158 4v652h80z" horiz-adv-x="582" />
+<glyph glyph-name="note-beamed" unicode="♫" d="M206 714l534 116v-704q2-42-30-81t-86-59q-64-24-110-8t-62 64q-18 48 7 97t85 73q52 20 106 10v376l-354-82v-490q0-42-32-81t-86-59q-64-22-109-7t-61 63q-18 48 6 97t84 73q54 20 108 10v592z" horiz-adv-x="740" />
+<glyph glyph-name="music" unicode="🎵" d="M600 800q42 0 71-29t29-71v-700q0-40-29-70t-71-30h-500q-40 0-70 30t-30 70v700q0 42 30 71t70 29h500z m-110-476q32 44 23 92t-33 80-49 66-25 54h-60v-368q-42 16-90-2-42-14-64-48t-12-64q12-32 53-45t85 1q88 30 88 98v262q36-6 55-32t18-52-3-42q-4-10 2-10 4 0 12 10z" horiz-adv-x="700" />
+<glyph glyph-name="search" unicode="🔍" d="M772 78q30-34 6-62l-46-46q-36-32-68 0l-190 190q-74-42-156-42-128 0-223 95t-95 223 90 219 218 91 224-95 96-223q0-88-46-162z m-678 358q0-88 68-156t156-68 151 63 63 153q0 88-68 155t-156 67-151-63-63-151z" horiz-adv-x="789" />
+<glyph glyph-name="flashlight" unicode="🔦" d="M806 706q62-62 85-130t-5-92l-134-134q-16-16-62-26t-96-4l-408-408q-18-18-57-6t-75 50q-36 36-49 74t5 56l408 408q-6 50 4 96t26 62l136 136q24 28 92 4t130-86z m-448-408q32-32 80 14 46 46 14 82-14 14-38 10t-44-24-23-43 11-39z m336 298q30-30 68-50t62-25 28-1q2 4-4 27t-26 60-50 67-66 50-59 26-27 2 1-28 25-62 48-66z" horiz-adv-x="902" />
+<glyph glyph-name="mail" unicode="✉" d="M30 586q-32 18-28 40 2 14 26 14h846q38 0 20-32-8-14-24-22-14-6-192-102t-182-98q-16-10-46-10-28 0-46 10-4 2-182 98t-192 102z m850-100q20 10 20-10v-368q0-16-17-32t-33-16h-800q-16 0-33 16t-17 32v368q0 20 20 10l384-200q18-10 46-10t46 10z" horiz-adv-x="900" />
+<glyph glyph-name="heart" unicode="♥" d="M790 644q70-64 70-156t-70-158l-360-330-360 330q-70 66-70 158t70 156q62 58 151 58t153-58l56-52 58 52q62 58 150 58t152-58z" horiz-adv-x="860" />
+<glyph glyph-name="heart-empty" unicode="♡" d="M790 642q70-64 70-156t-70-156l-360-330-360 330q-70 64-70 156t70 156q64 58 152 58t150-58l58-52 56 52q64 58 152 58t152-58z m-54-260q42 40 42 104 0 66-38 100-38 38-102 38-52 0-104-48l-104-92-106 92q-48 48-102 48-64 0-104-38-38-36-38-100 0-66 44-104l306-286z" horiz-adv-x="860" />
+<glyph glyph-name="star" unicode="★" d="M440 790l120-336h320l-262-196 94-348-272 208-272-208 94 348-262 196h320z" horiz-adv-x="880" />
+<glyph glyph-name="star-empty" unicode="☆" d="M880 454l-262-196 94-348-272 208-272-208 94 348-262 196h320l120 336 120-336h320z m-440-238l150-124-62 178 144 114-176-4-56 202-54-202-176 4 142-114-62-178z" horiz-adv-x="880" />
+<glyph glyph-name="user" unicode="👤" d="M736 128q204-72 204-122v-106h-940v106q0 50 204 122 94 34 128 69t34 95q0 22-22 49t-32 73q-2 12-9 18t-14 8-14 17-9 43q0 16 5 26t9 12l4 4q-8 50-12 88-4 54 41 112t157 58 158-58 40-112l-12-88q18-8 18-42-2-28-9-43t-14-17-14-8-9-18q-8-48-31-74t-23-48q0-60 35-95t127-69z" horiz-adv-x="940" />
+<glyph glyph-name="users" unicode="👥" d="M1000-90h-224v150q0 54-30 81t-154 89q40 30 40 84 0 16-13 33t-19 51q-2 8-14 16t-14 42q0 24 12 30-6 34-8 60-4 38 23 78t95 40 96-40 24-78l-8-60q12-6 12-30-2-34-14-42t-14-16q-6-34-19-51t-13-33q0-42 21-66t77-48q112-46 130-80 6-8 9-61t5-101v-48z m-488 262q182-78 182-124v-138h-694v184q0 44 84 78 76 32 104 64t28 88q0 20-19 44t-25 68q-2 10-18 22t-20 56q0 14 3 23t7 13l4 2q-6 46-10 82-4 50 33 103t127 53 127-53 33-103l-10-82q14-8 14-38-4-44-20-56t-18-22q-6-44-25-68t-19-44q0-56 28-88t104-64z" horiz-adv-x="1000" />
+<glyph glyph-name="user-add" unicode="" d="M620 128q180-64 180-122v-106h-800v202q36 14 82 26 94 34 129 69t35 95q0 22-23 48t-31 74q-2 12-23 25t-25 61q0 16 5 26t9 12l4 4q-8 50-12 88-6 54 40 112t160 58 160-58 42-112l-14-88q18-8 18-42-2-28-9-43t-14-17-14-8-9-18q-10-46-33-73t-23-49q0-60 36-95t130-69z m230 272h150v-100h-150v-150h-100v150h-150v100h150v150h100v-150z" horiz-adv-x="1000" />
+<glyph glyph-name="video" unicode="🎬" d="M980 600h-100v-100h100v-100h-100v-100h100v-100h-100v-100h100v-60q0-16-12-28t-28-12h-900q-16 0-28 12t-12 28v60h100v100h-100v100h100v100h-100v100h100v100h-100v60q0 18 12 29t28 11h900q16 0 28-11t12-29v-60z m-600-400l250 150-250 150v-300z" horiz-adv-x="980" />
+<glyph glyph-name="picture" unicode="🌄" d="M856 518h-100l-124 150-214-150h-180q-52 0-90-39t-38-91v-160l-108 296q-10 38 22 52l680 248q36 10 50-24z m106-90q16 0 27-12t11-28v-472q0-16-11-28t-27-12h-724q-16 0-27 12t-11 28v472q0 16 11 28t27 12h724z m-56-452v162l-72 160-166-60-130-132-138 170-92-214v-86h598z" horiz-adv-x="1000" />
+<glyph glyph-name="camera" unicode="📷" d="M500 450q64 0 107-44t43-106-44-106-106-44-106 44-44 106 44 106 106 44z m400 150q42 0 71-29t29-71v-450q0-40-29-70t-71-30h-800q-40 0-70 30t-30 70v450q0 42 30 71t70 29h120q28 0 40 30l30 92q10 28 40 28h340q30 0 40-28l30-92q12-30 40-30h120z m-400-550q104 0 177 73t73 177-73 177-177 73-177-73-73-177 73-177 177-73z m366 380q14 0 24 11t10 25-10 24-24 10q-36 0-36-34 0-16 11-26t25-10z" horiz-adv-x="1000" />
+<glyph glyph-name="layout" unicode="⚏" d="M170 650q80 0 80-80v-90q0-80-80-80h-90q-80 0-80 80v90q0 80 80 80h90z m350 0q80 0 80-80v-90q0-80-80-80h-90q-80 0-80 80v90q0 80 80 80h90z m-350-350q80 0 80-80v-90q0-80-80-80h-90q-80 0-80 80v90q0 80 80 80h90z m350 0q80 0 80-80v-90q0-80-80-80h-90q-80 0-80 80v90q0 80 80 80h90z" horiz-adv-x="600" />
+<glyph glyph-name="menu" unicode="☰" d="M650 400q22 0 36-15t14-35-15-35-35-15h-600q-20 0-35 15t-15 35 14 35 36 15h600z m-600 100q-20 0-35 15t-15 35 14 35 36 15h600q22 0 36-15t14-35-15-35-35-15h-600z m600-300q22 0 36-15t14-35-15-35-35-15h-600q-20 0-35 15t-15 35 14 35 36 15h600z" horiz-adv-x="700" />
+<glyph glyph-name="check" unicode="✓" d="M249 0q-34 0-56 28l-180 236q-16 24-12 52t26 46 51 14 47-28l118-154 296 474q16 24 43 30t53-8q24-16 30-43t-8-53l-350-560q-20-32-56-32z" horiz-adv-x="667" />
+<glyph glyph-name="cancel" unicode="✕" d="M452 194q18-18 18-43t-18-43q-18-16-43-16t-43 16l-132 152-132-152q-18-16-43-16t-43 16q-16 18-16 43t16 43l138 156-138 158q-16 18-16 43t16 43q18 16 43 16t43-16l132-152 132 152q18 16 43 16t43-16q18-18 18-43t-18-43l-138-158z" horiz-adv-x="470" />
+<glyph glyph-name="cancel-circled" unicode="✖" d="M420 770q174 0 297-123t123-297-123-297-297-123-297 123-123 297 123 297 297 123z m86-420l154 154-86 86-154-152-152 152-88-86 154-154-154-152 88-86 152 152 154-152 86 86z" horiz-adv-x="840" />
+<glyph glyph-name="cancel-squared" unicode="❎" d="M700 750q42 0 71-29t29-71v-600q0-40-29-70t-71-30h-600q-40 0-70 30t-30 70v600q0 42 30 71t70 29h600z m-146-638l86 86-154 152 154 154-86 86-154-152-152 152-88-86 154-154-154-152 88-86 152 152z" horiz-adv-x="800" />
+<glyph glyph-name="plus" unicode="+" d="M550 400q30 0 30-50t-30-50h-210v-210q0-30-50-30t-50 30v210h-210q-30 0-30 50t30 50h210v210q0 30 50 30t50-30v-210h210z" horiz-adv-x="580" />
+<glyph glyph-name="plus-circled" unicode="➕" d="M420 770q174 0 297-123t123-297-123-297-297-123-297 123-123 297 123 297 297 123z m52-470h200v102h-200v202h-102v-202h-202v-102h202v-202h102v202z" horiz-adv-x="840" />
+<glyph glyph-name="plus-squared" unicode="⊞" d="M700 750q42 0 71-29t29-71v-600q0-40-29-70t-71-30h-600q-40 0-70 30t-30 70v600q0 42 30 71t70 29h600z m-50-450v100h-200v200h-100v-200h-200v-100h200v-200h100v200h200z" horiz-adv-x="800" />
+<glyph glyph-name="minus" unicode="-" d="M550 400q30 0 30-50t-30-50h-520q-30 0-30 50t30 50h520z" horiz-adv-x="580" />
+<glyph glyph-name="minus-circled" unicode="➖" d="M420 770q174 0 297-123t123-297-123-297-297-123-297 123-123 297 123 297 297 123z m252-368h-504v-102h504v102z" horiz-adv-x="840" />
+<glyph glyph-name="minus-squared" unicode="⊟" d="M700 750q42 0 71-29t29-71v-600q0-40-29-70t-71-30h-600q-40 0-70 30t-30 70v600q0 42 30 71t70 29h600z m-50-450v100h-500v-100h500z" horiz-adv-x="800" />
+<glyph glyph-name="help" unicode="❓" d="M494 740q86-62 86-184 0-64-42-124-12-20-88-80l-46-30q-40-34-48-60-6-16-8-44 0-14-16-14h-128q-16 0-16 12 4 98 28 124 16 22 48 48t56 42l24 14q22 16 34 34 28 44 28 70 0 40-26 78-28 36-92 36-68 0-94-44-28-42-28-92h-166q6 162 114 232 70 42 166 42 130 0 214-60z m-216-636q44 0 73-30t27-74q-2-46-32-73t-74-25q-44 0-73 29t-27 75 32 73 74 25z" horiz-adv-x="580" />
+<glyph glyph-name="help-circled" unicode="" d="M454 810q190 2 326-130t140-322q2-190-131-327t-323-141q-190-2-327 131t-139 323q-4 190 130 327t324 139z m-2-740q30 0 49 19t19 47q2 30-17 49t-49 19h-2q-28 0-47-18t-21-46q0-30 19-49t47-21h2z m166 328q26 34 26 78 0 78-54 116-52 38-134 38-64 0-104-26-68-42-72-146v-4h110v4q0 26 16 54 16 24 54 24 40 0 52-20 16-20 16-44 0-18-16-40-8-12-20-20l-6-4q-6-4-16-11t-20-15-21-17-17-17q-14-20-18-78v-8h108v4q0 12 4 28 6 20 28 36l28 18q46 34 56 50z" horiz-adv-x="920" />
+<glyph glyph-name="info" unicode="ℹ" d="M352 850q48 0 74-27t26-69q0-50-39-88t-95-38q-48 0-74 26t-24 72q0 46 35 85t97 39z m-206-1000q-100 0-54 178l60 254q14 56 0 56-12 0-54-18t-72-38l-26 44q90 78 189 126t151 48q78 0 36-162l-70-266q-16-64 6-64 44 0 118 60l30-40q-84-86-175-132t-139-46z" horiz-adv-x="460" />
+<glyph glyph-name="info-circled" unicode="" d="M454 810q190 2 326-130t140-322q2-190-131-327t-323-141q-190-2-327 131t-139 323q-4 190 130 327t324 139z m52-152q-42 0-65-24t-23-50q-2-28 15-44t49-16q38 0 61 22t23 54q0 58-60 58z m-120-594q30 0 84 26t106 78l-18 24q-48-36-72-36-14 0-4 38l42 160q26 96-22 96-30 0-89-29t-115-75l16-26q52 34 74 34 12 0 0-34l-36-152q-26-104 34-104z" horiz-adv-x="920" />
+<glyph glyph-name="back" unicode="🔙" d="M750 540q40 0 70-29t30-71v-290q0-40-30-70t-70-30h-690v140h650v210h-500v-110l-210 180 210 180v-110h540z" horiz-adv-x="850" />
+<glyph glyph-name="home" unicode="⌂" d="M888 336q16-16 11-27t-27-11h-84v-310q0-14-1-21t-8-13-23-6h-204v310h-204v-310h-194q-28 0-35 10t-7 30v310h-84q-22 0-27 11t11 27l400 402q16 16 38 16t38-16z" horiz-adv-x="900" />
+<glyph glyph-name="link" unicode="🔗" d="M294 116q14 14 34 14t36-14q32-34 0-70l-42-40q-56-56-132-56-78 0-134 56t-56 132q0 78 56 134l148 148q70 68 144 77t128-43q16-16 16-36t-16-36q-36-32-70 0-50 48-132-34l-148-146q-26-26-26-64t26-62q26-26 63-26t63 26z m450 574q56-56 56-132 0-78-56-134l-158-158q-74-72-150-72-62 0-112 50-14 14-14 34t14 36q14 14 35 14t35-14q50-48 122 24l158 156q28 28 28 64 0 38-28 62-24 26-56 31t-60-21l-50-50q-16-14-36-14t-34 14q-34 34 0 70l50 50q54 54 127 51t129-61z" horiz-adv-x="800" />
+<glyph glyph-name="attach" unicode="📎" d="M244-140q-102 0-170 72-72 70-74 166t84 190l496 496q80 80 174 54 44-12 79-47t47-79q26-96-54-176l-474-474q-40-40-88-46-48-4-80 28-30 24-27 74t47 92l332 334q24 26 50 0t0-50l-332-332q-44-44-20-70 12-8 24-6 24 4 46 26l474 474q50 50 34 108-16 60-76 76-54 14-108-36l-494-494q-66-76-64-143t52-117q50-48 117-50t141 62l496 494q24 24 50 0 26-22 0-48l-496-496q-82-82-186-82z" horiz-adv-x="939" />
+<glyph glyph-name="lock" unicode="🔒" d="M640 476q20 0 40-19t20-41v-390q0-48-48-66l-60-18q-42-16-96-16h-290q-56 0-98 16l-60 18q-48 18-48 66v390q0 22 15 41t35 19h100v70q0 110 51 170t149 60 149-60 51-170v-70h90z m-390 90v-90h200v90q0 52-27 81t-73 29-73-29-27-81z" horiz-adv-x="700" />
+<glyph glyph-name="lock-open" unicode="🔓" d="M640 450q20 0 40-20t20-40v-390q0-20-14-39t-34-25l-60-20q-52-16-96-16h-290q-46 0-98 16l-60 20q-20 6-34 25t-14 39v390q0 22 15 41t35 19h400v140q0 110-100 110t-100-110v-40h-100v20q0 110 51 170t149 60q200 0 200-230v-120h90z" horiz-adv-x="700" />
+<glyph glyph-name="eye" unicode="" d="M500 630q92 0 177-25t141-62 99-77 63-71 20-45-20-44-63-71-99-78-141-62-177-25-177 25-141 62-99 78-63 71-20 44 20 45 63 71 99 77 141 62 177 25z m0-494q92 0 157 63t65 151q0 90-65 153t-157 63-157-63-65-153q0-88 65-151t157-63z m0 214q8-8 37-2t50 11 25-9q0-44-33-75t-79-31-78 31-32 75q0 46 32 77t78 31q14 0 10-23t-12-47 2-38z" horiz-adv-x="1000" />
+<glyph glyph-name="tag" unicode="" d="M944 830q36-106-8-199t-128-157l18-24q16-28 6-54l-48-158q-12-30-36-46l-464-328q-42-30-64 4l-210 304q-12 18-9 39t21 33l464 328q26 18 54 18h158q30 0 48-26l28-40q168 130 114 286-10 28 18 40 32 8 38-20z m-216-468q40 32 34 80l-32-16q-8-4-12-4-18 0-28 18-12 30 16 40l24 14q-48 34-92 0-28-18-34-51t14-61q18-26 51-32t59 12z" horiz-adv-x="960" />
+<glyph glyph-name="bookmark" unicode="🔖" d="M310 800q22 0 36-15t14-35v-850l-180 180-180-180v850q0 50 40 50h270z" horiz-adv-x="360" />
+<glyph glyph-name="bookmarks" unicode="📑" d="M500 850q20 0 35-15t15-35v-850l-150 180v620q0 20-15 35t-35 15h-100q0 50 40 50h210z m-250-150q20 0 35-15t15-35v-800l-150 180-150-180v800q0 50 40 50h210z" horiz-adv-x="550" />
+<glyph glyph-name="flag" unicode="⚑" d="M874 616q14 6 22-1t0-19q-96-138-164-213t-110-90-73-2-60 37-63 40-93-4-139-86l90-352h-100l-184 720 92 34q90 66 152 86t98 3 64-51 62-71 79-62 129-20 198 51z" horiz-adv-x="900" />
+<glyph glyph-name="thumbs-up" unicode="👍" d="M582 480q2-6 58-13t108-24 52-47q0-72-61-284t-107-212q-144 0-288 42t-144 88v342q0 14 15 34t46 45 53 41 62 43 46 31q50 34 104 100t85 104 41 26q48-76 29-137t-59-119-40-60z m-432-4q14 0 0-14-50-50-50-104v-318q0-50 52-104 10-10-2-10-26 0-55 8t-62 45-33 99v242q0 62 33 100t63 47 54 9z" horiz-adv-x="800" />
+<glyph glyph-name="thumbs-down" unicode="👎" d="M218 218q-2 6-57 13t-108 24-53 47q0 72 62 285t106 213q144 0 288-43t144-89v-342q0-10-8-24t-25-30-32-29-42-32-41-29-41-28l-33-22q-50-34-104-100t-85-104-41-26q-48 76-29 137t59 119 40 60z m432 4q-12 0 2 14 48 50 48 104v318q0 50-52 104-10 10 2 10 26 0 55-8t62-45 33-99v-242q0-48-18-81t-45-48-48-21-39-6z" horiz-adv-x="800" />
+<glyph glyph-name="download" unicode="📥" d="M968 198q18-10 27-32t3-40l-28-154q-4-20-22-33t-40-13h-816q-22 0-40 13t-22 33l-28 154q-10 48 32 72l158 108h98l-170-130h178q8 0 12-8l40-110h300l40 110q8 8 12 8h178l-170 130h98z m-208 322l-260-244-260 244h166v256h190v-256h164z" horiz-adv-x="1000" />
+<glyph glyph-name="upload" unicode="📤" d="M500 776l260-244h-164v-256h-190v256h-166z m468-578q18-10 27-32t3-40l-28-154q-4-20-22-33t-40-13h-816q-22 0-40 13t-22 33l-28 154q-10 48 32 72l158 108h98l-170-130h178q8 0 12-8l40-110h300l40 110q8 8 12 8h178l-170 130h98z" horiz-adv-x="1000" />
+<glyph glyph-name="upload-cloud" unicode="" d="M760 494q100 0 170-68t70-166-70-166-170-68h-190v190h106l-176 230-174-230h104v-190h-248q-74 0-128 52t-54 124q0 74 53 126t129 52q14 0 20-2-2 12-2 38 0 108 78 184t188 76q90 0 160-52t94-134q28 4 40 4z" horiz-adv-x="1000" />
+<glyph glyph-name="reply" unicode="" d="M900 10q-86 152-208 197t-330 45v-218l-362 334 362 322v-192q90 0 168-27t131-70 96-95 69-104 44-95 24-69z" horiz-adv-x="900" />
+<glyph glyph-name="reply-all" unicode="" d="M362 556l-212-188 212-196v-138l-362 334 362 322v-134z m250-58q104 0 182-50t115-122 60-144 27-122l4-50q-86 154-168 198t-220 44v-218l-362 334 362 322v-192z" horiz-adv-x="1000" />
+<glyph glyph-name="forward" unicode="➦" d="M540 252q-210 0-332-45t-208-197q4 20 13 53t50 117 96 148 156 117 225 53v192l360-322-360-334v218z" horiz-adv-x="900" />
+<glyph glyph-name="quote" unicode="❞" d="M146 680q146 0 184-146 38-140-40-302-80-168-224-204-32-8-66-8v70q112 0 182 108 54 86 26 146-16 36-62 36-60 0-103 44t-43 106 43 106 103 44z m420 0q146 0 184-146 38-140-40-302-80-168-224-204-32-8-66-8v70q112 0 182 108 54 86 26 146-16 36-62 36-60 0-103 44t-43 106 43 106 103 44z" horiz-adv-x="762" />
+<glyph glyph-name="code" unicode="" d="M380 636q16-14 16-32t-16-30l-246-224 246-226q16-12 16-30t-16-32q-30-30-60 0l-320 288 320 286q30 30 60 0z m302 0l318-286-318-288q-32-30-62 0-32 32 0 62l248 226-248 224q-32 30 0 62 30 30 62 0z" horiz-adv-x="1000" />
+<glyph glyph-name="export" unicode="" d="M750 60v56l100 82v-188q0-20-15-35t-35-15h-750q-20 0-35 15t-15 35v550q0 22 14 36t36 14h288q-32-24-59-49t-39-39l-10-12h-130v-450h650z m-82 348q-166 0-242-41t-160-181q0 8 1 22t9 56 22 79 44 83 70 79 107 56 149 23v156l332-250-332-260v178z" horiz-adv-x="1000" />
+<glyph glyph-name="pencil" unicode="✎" d="M718 680q32-32 47-64t15-48v-16l-252-252-290-288-238-52 50 240 290 288 252 252q54 12 126-60z m-494-640l24 24q-2 44-52 94-22 22-45 35t-35 13l-14 2-22-24-18-80q28-16 46-34 24-24 36-48z" horiz-adv-x="780" />
+<glyph glyph-name="feather" unicode="✒" d="M60-138q-6-20-26-8-18 8-16 34 4 100 50 226-100 154-52 316 10-32 32-78t44-80 32-30q8 4 0 83t-11 166 25 157q22 44 80 94t104 70q-24-46-33-94t-4-78 21-32q12 0 84 120t106 122q46 4 114-29t82-65q12-24 0-79t-40-83q-44-44-146-62t-114-24q-16-10 12-34 54-48 176-20-56-80-136-114t-132-38-54-10q-4-24 49-54t101-14q-30-56-63-84t-54-35-76-11-85-8z" horiz-adv-x="698" />
+<glyph glyph-name="print" unicode="" d="M66 526q-26 0-22 22 4 10 12 14 2 0 49 17t93 32 58 15h44v150h380v-150h46q12 0 57-15t92-32 49-17q18-8 12-26-4-10-20-10h-850z m860-56q20 0 37-19t17-41v-174q0-22-17-41t-37-19h-100l44-250h-760l44 250h-98q-20 0-38 19t-18 41v174q0 22 18 41t38 19h870z m-716-444h560l-70 324h-420z" horiz-adv-x="980" />
+<glyph glyph-name="retweet" unicode="" d="M250 190h272l128-140h-448q-42 0-71 30t-29 70v302h-102l176 198 174-198h-100v-262z m650 60h100l-174-200-176 200h102v260h-274l-128 140h450q40 0 70-29t30-71v-300z" horiz-adv-x="1000" />
+<glyph glyph-name="keyboard" unicode="⌨" d="M930 650q28 0 49-21t21-49v-460q0-30-21-50t-49-20h-860q-28 0-49 20t-21 50v460q0 28 21 49t49 21h860z m-380-100v-100h100v100h-100z m150-150h-100v-100h100v100z m-300 150v-100h100v100h-100z m150-150h-100v-100h100v100z m-300 150v-100h100v100h-100z m150-150h-100v-100h100v100z m-300 150v-100h100v100h-100z m150-150h-100v-100h100v100z m-50-250v100h-100v-100h100z m550 0v100h-500v-100h500z m150 0v100h-100v-100h100z m-150 150h100v100h-100v-100z m150 150v100h-200v-100h200z" horiz-adv-x="1000" />
+<glyph glyph-name="comment" unicode="" d="M700 700q42 0 71-29t29-71v-350q0-40-29-70t-71-30h-200v-150l-200 150h-200q-40 0-70 30t-30 70v350q0 42 30 71t70 29h600z" horiz-adv-x="800" />
+<glyph glyph-name="chat" unicode="" d="M290 240h350q2 0 6 2h4v-92q0-40-29-70t-71-30h-250l-150-150v150h-50q-40 0-70 30t-30 70v300q0 42 30 71t70 29h190v-310z m610 560q42 0 71-29t29-71v-300q0-40-29-70t-71-30h-50v-150l-150 150h-350v400q0 42 30 71t70 29h450z" horiz-adv-x="1000" />
+<glyph glyph-name="bell" unicode="🔔" d="M632 426q16-34 40-52t45-22 44-23 35-55q22-62-74-161t-252-157q-164-58-297-45t-155 75q-20 54 12 111t18 111q-56 192-47 300t113 192q26 22 29 51t29 39q24 8 46-12t56-18q132 2 198-66t160-268z m-186-404q88 32 159 85t100 91 25 50q-8 22-49 33t-124 1-187-48q-102-38-173-87t-94-84-17-53q4-12 50-22t134-4 176 38z m-62 174q8 2 21 7t17 7l2-2q14-40-17-83t-89-63q-96-36-152 14 78 68 218 120z" horiz-adv-x="800" />
+<glyph glyph-name="attention" unicode="⚠" d="M957-24q10-16 0-34-10-16-30-16h-892q-18 0-28 16-12 18-2 34l446 782q8 18 30 18t30-18z m-420 50v100h-110v-100h110z m0 174v300h-110v-300h110z" horiz-adv-x="962" />
+<glyph glyph-name="alert" unicode="💥" d="M885 234q20-16 16-33t-28-23l-78-22q-24-6-40-28t-14-48l4-82q2-24-14-34t-38 0l-86 44q-22 12-47 4t-35-30l-46-88q-12-22-29-23t-33 19l-50 78q-34 48-88 20l-122-70q-22-14-32-6t-2 32l54 164q8 24-4 44t-36 22l-106 12q-24 4-29 18t15 30l86 76q20 16 20 41t-20 41l-86 76q-20 16-16 33t28 23l78 22q24 6 41 28t15 48l-6 82q0 26 15 36t37 0l80-38q24-10 49-2t37 30l46 80q12 22 30 21t30-23l50-86q12-22 35-29t45 7l136 84q22 14 30 6t0-32l-60-170q-10-22 2-41t38-21l114-12q26-2 30-16t-16-30l-86-76q-18-16-18-41t18-41z m-384-92v104h-100v-104h100z m0 160v260h-100v-260h100z" horiz-adv-x="901" />
+<glyph glyph-name="vcard" unicode="" d="M900 750q42 0 71-29t29-71v-600q0-40-29-70t-71-30h-800q-40 0-70 30t-30 70v600q0 42 30 71t70 29h800z m0-700v600h-800v-600h800z m-450 196v-90h-250v90h250z m0 150v-90h-250v90h250z m0 150v-90h-250v90h250z m346-320l4-70h-250q0 70 6 70 84 22 84 66 0 16-27 56t-27 88q0 110 90 110t90-110q0-48-28-88t-28-56q0-20 21-36t43-22z" horiz-adv-x="1000" />
+<glyph glyph-name="address" unicode="" d="M426 800q20 0 20-20v-860q0-20-20-20h-46q-20 0-20 20v440h-176q-16 0-28 6-12 2-26 12l-120 82q-10 6-10 16t10 16l120 82q14 10 26 12 8 4 28 4h176v190q0 20 20 20h46z m564-208q10-6 10-16t-10-16l-118-82q-22-12-26-12-14-6-28-6h-302l-40 230h342q18 0 28-4t26-12z" horiz-adv-x="1000" />
+<glyph glyph-name="location" unicode="" d="M250 750q104 0 177-73t73-177q0-106-62-243t-126-223l-62-84q-10 12-27 35t-60 89-76 130-60 147-27 149q0 104 73 177t177 73z m0-388q56 0 96 40t40 96-40 95-96 39-95-39-39-95 39-96 95-40z" horiz-adv-x="500" />
+<glyph glyph-name="map" unicode="" d="M984 600q16-10 16-30v-584q0-20-16-30-8-6-16-6t-18 6l-216 136-216-136q-18-10-34 0l-218 136-216-136q-16-10-34 0-16 10-16 30v584q0 20 16 30l234 146q18 10 34 0l216-136 218 136q16 10 32 0z m-750-450v506l-168-104v-506z m234-104v506l-168 104v-506z m234 104v506l-170-104v-506z m232-104v506l-168 104v-506z" horiz-adv-x="1000" />
+<glyph glyph-name="direction" unicode="➢" d="M848 768q8-8 11-16t-2-22-10-26-19-39-24-49q-54-112-147-286t-157-292l-66-118-54 380-380 56q442 246 696 368 20 10 48 25t39 20 25 9 23 1 17-11z m-92-96l-304-280 28-234z" horiz-adv-x="860" />
+<glyph glyph-name="compass" unicode="" d="M474 830q198 2 340-136t146-336q2-200-136-342t-338-146q-198-2-341 137t-145 337q-4 200 135 342t339 144z m12-858q156 2 266 114t108 270-115 267-269 107q-158-2-267-114t-107-270 114-267 270-107z m-234 154q4 26 12 66t41 128 77 132 125 76 141 42l60 10q-4-26-12-66t-41-128-77-132q-42-42-124-74t-142-42z m180 276q-22-20-22-48t22-50q20-22 49-22t49 22q52 52 88 186-136-36-186-88z" horiz-adv-x="960" />
+<glyph glyph-name="cup" unicode="☕" d="M340 760q152 0 249-41t91-87l-72-594q-2-14-34-36t-97-42-137-20-136 20-97 42-35 36l-72 594q-4 28 36 57t121 50 183 21z m0-216q72 0 137 15t98 33 33 30-33 29-98 32-137 15-137-15-98-32-33-29 33-30 98-33 137-15z" horiz-adv-x="681" />
+<glyph glyph-name="trash" unicode="" d="M50 458q122-70 330-70t330 70l-54-486q-2-14-35-36t-100-43-141-21-140 21-100 43-36 36z m488 300q94-18 158-55t64-71v-10q0-58-112-99t-268-41-268 41-112 99v10q0 34 64 71t158 55l42 48q22 26 70 26h92q52 0 70-26z m-54-112h84q-92 110-104 126-14 16-32 16h-102q-22 0-32-16l-106-126h84l64 66h82z" horiz-adv-x="760" />
+<glyph glyph-name="doc" unicode="" d="M600 800q42 0 71-29t29-71v-700q0-40-29-70t-71-30h-500q-40 0-70 30t-30 70v700q0 42 30 71t70 29h500z m0-800v700h-500v-700h500z" horiz-adv-x="700" />
+<glyph glyph-name="docs" unicode="" d="M970 480q38-10 30-46l-150-556q-4-16-18-23t-30-3l-406 110q-16 4-24 18t-4 28l24 92-180-48q-40-10-50 26l-160 602q-10 36 28 48l454 122q16 4 30-3t18-23l66-244z m-888 190l144-542 392 106-144 540z m702-742l132 492-298 82 76-282q10-34-28-46l-196-52-26-102z" horiz-adv-x="1001" />
+<glyph glyph-name="doc-landscape" unicode="" d="M0 600q0 42 30 71t70 29h800q42 0 71-29t29-71v-500q0-40-29-70t-71-30h-800q-40 0-70 30t-30 70v500z m900 0h-800v-500h800v500z" horiz-adv-x="1000" />
+<glyph glyph-name="doc-text" unicode="📄" d="M212 308v90h280v-90h-280z m388 492q42 0 71-29t29-71v-700q0-40-29-70t-71-30h-500q-40 0-70 30t-30 70v700q0 42 30 71t70 29h500z m0-800v700h-500v-700h500z m-110 592v-88h-280v88h280z m0-392v-88h-280v88h280z" horiz-adv-x="700" />
+<glyph glyph-name="doc-text-inv" unicode="" d="M600 800q42 0 71-29t29-71v-700q0-40-29-70t-71-30h-500q-40 0-70 30t-30 70v700q0 42 30 71t70 29h500z m-460-208v-88h420v88h-420z m420-480v88h-420v-88h420z m0 196v90h-418v-90h418z" horiz-adv-x="700" />
+<glyph glyph-name="newspaper" unicode="📰" d="M700 800q42 0 71-29t29-71v-700q0-40-29-70t-71-30h-600q-40 0-70 30t-30 70v700q0 42 30 71t70 29h600z m0-800v700h-600v-700h600z m-250 250v-50h-250v50h250z m150 200v-50h-200v50h200z m-200 50v100h200v-100h-200z m-50 100v-200h-150v200h150z m-50-250v-50h-100v50h100z m50-50v50h250v-50h-250z m250-150v-50h-400v50h400z m-100 50v50h100v-50h-100z" horiz-adv-x="800" />
+<glyph glyph-name="book-open" unicode="📖" d="M340 238v-68l-200 80v68z m0 208v-68l-200 80v68z m538 346q22-12 22-42v-640q0-34-32-46l-398-160q-8-2-10-2t-5-1-5-1-5 1-5 1l-10 2-398 160q-32 12-32 46v640q0 30 22 42 22 16 46 6l382-154 382 154q24 10 46-6z m-478-788v560l-320 128v-560z m420 128v560l-320-128v-560z m-60 186v-68l-200-80v68z m0 208v-68l-200-80v68z" horiz-adv-x="900" />
+<glyph glyph-name="book" unicode="📕" d="M682 594q18-8 18-28v-562q0-14-12-25t-28-11q-46 0-46 36v522q0 12-12 18l-404 216q-32 10-68-10-44-20-56-44l408-228q18-8 18-28v-550q0-22-18-28-6-4-16-4-14 0-20 4-8 6-202 127t-212 131q-26 18-26 34l-6 524q0 28 14 52 28 46 102 77t116 9z" horiz-adv-x="700" />
+<glyph glyph-name="folder" unicode="📁" d="M954 500q32 0 40-12t6-36l-42-452q-2-24-12-37t-42-13h-806q-52 0-56 50l-42 452q-2 24 6 36t40 12h908z m-34 110l10-40h-846l14 132q4 20 20 34t36 14h164q52 0 86-34l30-30q32-36 86-36h340q20 0 38-12t22-28z" horiz-adv-x="1001" />
+<glyph glyph-name="archive" unicode="" d="M840 600v-50h-696v50q0 22 13 35t25 15h608q6 0 14-1t22-14 14-35z m-148 150q6 0 14-1t22-14 14-35h-498q0 22 13 35t25 15h410z m248-200q34-32 38-46 6-18 0-54l-76-450q-4-22-20-35t-28-15h-710q-52 0-60 50-6 26-39 223t-39 227q-10 22-3 44t10 26 21 20l10 10 30 30v-80h836v80z m-248-270v100h-70v-80h-260v80h-68v-100q0-50 48-50h300q22 0 35 12t13 24z" horiz-adv-x="981" />
+<glyph glyph-name="box" unicode="📦" d="M870 750q12 0 21-9t9-21v-120h-900v120q0 12 9 21t21 9h840z m-820-730v530h800v-530q0-30-21-50t-49-20h-660q-28 0-49 20t-21 50z m250 430v-100h300v100h-300z" horiz-adv-x="900" />
+<glyph glyph-name="rss" unicode="" d="M0 730q314 0 537-223t223-537h-118q0 266-188 453t-454 187v120z m0-238q218 0 371-153t153-369h-118q0 166-119 285t-287 119v118z m114-296q46 0 80-33t34-81q0-46-34-79t-80-33-80 33-34 79q0 48 34 81t80 33z" horiz-adv-x="760" />
+<glyph glyph-name="phone" unicode="📞" d="M461 290q162 162 118 206l-8 8q-30 30-41 48t-4 54 49 88q20 24 37 39t35 16 30 1 29-13 24-18 26-25 21-22q48-48-6-194t-204-294q-150-150-295-205t-193-7q-2 2-23 22t-25 25-18 24-13 31 2 30 15 35 38 37q42 34 70 47t54 2 35-18 39-37q44-44 208 120z" horiz-adv-x="800" />
+<glyph glyph-name="cog" unicode="⚙" d="M760 350q0-72 80-122-12-40-34-82-70 18-136-44-54-58-34-136-40-20-84-36-46 82-132 82t-132-82q-44 16-84 36 20 80-34 136-54 54-136 34-14 26-34 82 82 52 82 132 0 72-82 124 20 56 34 82 74-18 136 44 54 56 34 136 42 22 84 34 46-80 132-80t132 80q42-12 84-34-20-78 34-136 66-62 136-44 22-42 34-82-80-50-80-124z m-340-182q76 0 129 53t53 129-53 130-129 54-129-54-53-130 53-129 129-53z" horiz-adv-x="840" />
+<glyph glyph-name="tools" unicode="⚒" d="M155 506q-8-8-11-22t-3-25-2-11q-2-2-17-15t-19-17q-16-14-28 4l-70 76q-10 12 2 24 2 2 18 14t20 16q6 6 27 6t37 14q14 14 18 38t10 30q2 0 9 7t26 22 41 31q134 90 186 96 122 0 148-2 12 0-8-8-120-52-152-76-80-56-36-114 34-46 38-48 8-8-2-14-2-2-38-35t-38-35q-14-8-18-4-42 48-71 60t-67-12z m286-26l410-476q18-22-2-38l-48-42q-22-14-38 4l-414 472q-8 8 0 20l72 62q12 8 20-2z m554 202q16-104-16-166-50-88-154-62-56 12-100-32l-82-78-68 78 68 70q24 24 31 53t6 65 5 58q12 56 140 112 12 6 18-3t2-15q-12-12-46-80-14-10-12-35t40-53q58-40 96 22 6 12 26 41t22 33q4 10 13 9t11-17z m-858-684l254 248 76-86-246-242q-20-20-38-4l-46 46q-22 18 0 38z" horiz-adv-x="1000" />
+<glyph glyph-name="share" unicode="" d="M650 200q62 0 106-43t44-107q0-62-44-106t-106-44-106 44-44 106q0 6 1 14t1 12l-260 156q-42-32-92-32-62 0-106 44t-44 106 44 106 106 44q54 0 92-30l260 156q0 4-1 12t-1 12q0 62 44 106t106 44 106-43 44-107q0-62-44-106t-106-44q-52 0-90 32l-262-156q2-8 2-26 0-16-2-24l262-156q36 30 90 30z" horiz-adv-x="800" />
+<glyph glyph-name="shareable" unicode="" d="M340 350q0 68 47 114t113 46 113-46 47-114q0-66-47-113t-113-47-113 47-47 113z m-114 60q-14-60-66-60h-160v120h118q40 124 145 202t237 78q164 0 284-116 16-18 16-43t-16-43q-18-16-43-16t-43 16q-78 82-198 82-100 0-176-62t-98-158z m614-60h160v-120h-118q-40-124-144-202t-238-78q-164 0-282 118-18 18-18 43t18 41q16 18 41 18t43-18q82-82 198-82 100 0 176 63t98 157q12 60 66 60z" horiz-adv-x="1000" />
+<glyph glyph-name="basket" unicode="" d="M150 0q0 40 30 70t70 30q42 0 71-30t29-70q0-42-29-71t-71-29q-40 0-70 29t-30 71z m500 0q0 40 30 70t70 30q42 0 71-30t29-70q0-42-29-71t-71-29q-40 0-70 29t-30 71z m-322 236q-36-10-34-23t44-13h562v-76q0-20-20-20h-654q-20 0-20 20v76l-10 46-98 454h-98v80q0 20 20 20h156q20 0 20-20v-86h704v-274q0-22-18-26z" horiz-adv-x="900" />
+<glyph glyph-name="bag" unicode="👜" d="M835 668q28-26 24-60l-98-648q-8-30-38-30h-586q-28 0-40 30-94 620-96 648-4 34 22 60 6 6 54 43t56 43q18 16 56 16h480q38 0 56-16 78-58 110-86z m-406-436q56 0 98 34t63 89 30 89 13 66h-92q-38-188-112-188t-112 188h-92q46-278 204-278z m-352 368h704l-110 116h-484z" horiz-adv-x="859" />
+<glyph glyph-name="calendar" unicode="📅" d="M800 700q42 0 71-29t29-71v-600q0-40-29-70t-71-30h-700q-40 0-70 30t-30 70v600q0 42 30 71t70 29h46v-100h160v100h290v-100h160v100h44z m0-700v400h-700v-400h700z m-540 800v-170h-70v170h70z m450 0v-170h-70v170h70z" horiz-adv-x="900" />
+<glyph glyph-name="login" unicode="" d="M800 800q42 0 71-29t29-71v-700q0-40-29-70t-71-30h-450q-40 0-69 30t-29 70v100h98v-100h450v700h-450v-150h-98v150q0 42 29 71t69 29h450z m-350-670v120h-450v150h450v120l200-194z" horiz-adv-x="900" />
+<glyph glyph-name="logout" unicode="" d="M502 0v100h98v-100q0-40-29-70t-71-30h-400q-40 0-70 30t-30 70v700q0 42 30 71t70 29h400q42 0 71-29t29-71v-150h-98v150h-402v-700h402z m398 326l-198-196v120h-450v150h450v120z" horiz-adv-x="900" />
+<glyph glyph-name="mic" unicode="🎤" d="M620 488q20 0 20-20v-138q0-92-69-164t-201-84v-132h130q20 0 20-20v-60q0-20-20-20h-360q-20 0-20 20v60q0 20 20 20h130v132q-132 12-201 84t-69 164v138q0 20 20 20h30q20 0 20-20v-138q0-66 59-123t191-57 191 57 59 123v138q0 20 20 20h30z m-300-238q-80 0-115 25t-35 55v158h300v-158q0-30-35-55t-115-25z m150 520v-212h-300v212q0 30 35 55t115 25 115-25 35-55z" horiz-adv-x="640" />
+<glyph glyph-name="mute" unicode="🔇" d="M868 778q16-16 16-36t-16-36l-782-782q-18-14-34-14-18 0-36 14-16 14-16 36t16 36l782 782q34 32 70 0z m-216-386l50 50q74-92 101-172t-7-116q-24-24-75-57t-131-71-161-45-165 23l278 276q44-32 88-54t67-25 33 1q6 10 2 34t-26 68-54 88z m-276 62l-270-270q-40 132 28 283t132 215q34 32 105 11t159-85l-52-50q-58 38-105 53t-57 5q-4-8-2-28t19-58 43-76z" horiz-adv-x="884" />
+<glyph glyph-name="sound" unicode="🔊" d="M176 588q42 42 149-5t217-157 157-217 5-149q-28-28-92-67t-156-78-194-29-176 84-84 176 29 194 78 156 67 92z m464-480q8 10-3 49t-49 101-96 118q-56 58-118 96t-101 49-49 3q-8-10 3-49t49-101 94-120q58-56 120-94t101-49 49-3z m6 394q-18 0-34 16-16 14-16 35t16 35l94 96q36 32 72 0 32-36 0-72l-96-94q-16-16-36-16z m-180 124q-18 10-23 30t5 38l54 96q26 44 68 20 18-10 23-30t-5-38l-54-96q-14-26-42-26-14 0-26 6z m438-150q10-18 4-38t-24-30l-96-54q-16-8-24-8-28 0-44 26-10 18-4 38t24 30l96 54q18 10 38 5t30-23z" horiz-adv-x="910" />
+<glyph glyph-name="volume" unicode="" d="M896 180q0-34-24-57t-56-23h-780q-22 0-31 5t-3 15 24 20l802 452q28 18 48 7t20-45v-374z" horiz-adv-x="896" />
+<glyph glyph-name="clock" unicode="🕔" d="M460 810q190 0 325-135t135-325-135-325-325-135-325 135-135 325 135 325 325 135z m0-820q150 0 255 106t105 254q0 150-105 255t-255 105q-148 0-254-105t-106-255q0-148 106-254t254-106z m36 620v-244l150-150-50-50-170 170v274h70z" horiz-adv-x="920" />
+<glyph glyph-name="hourglass" unicode="⏳" d="M560 622q0-44-48-96t-97-99-49-77 49-76 97-97 48-97v-118q0-34-86-73t-194-39-194 39-86 73v118q0 46 48 97t97 97 49 76-49 77-97 99-48 96v118q0 32 87 71t193 39 193-39 87-71v-118z m-482 112l-18-14q-4-8 4-14 92-52 216-52 132 0 220 50 14 10-16 30-96 54-202 54-120 0-204-54z m228-384q0 18 4 33t18 33 20 25 31 31 29 28q92 92 92 122l2 50q-100-54-222-54t-222 54l4-50q0-32 90-122 6-6 22-21t23-22l19-19t17-21 11-20 9-23 3-24q0-10-1-19t-6-18-8-16-11-17l-12-15t-15-16-16-15-18-16-17-16q-90-90-90-122v-66q8 4 66 23t92 43 34 58q0 30 26 30t26-30q0-34 33-58t94-43 67-23v66q0 30-92 122-4 4-21 20t-22 21-18 19-18 22-12 20-9 23-2 23z" horiz-adv-x="560" />
+<glyph glyph-name="lamp" unicode="💡" d="M209-110v104h282v-104q-70-42-142-40-70-2-140 40z m276 164h-270q0 72-36 140t-78 113-74 112-26 139q8 120 94 206t254 86q170 0 255-86t95-206q4-60-16-113t-52-96-65-85-57-96-24-114z m-378 496q-4-4 0-20t2-20 5-19 6-18 8-18 11-19 13-19 14-19 15-21 16-23q88-122 112-212h82q24 94 112 212 4 6 25 35t25 36 17 29 16 33 6 28 1 35q-16 196-244 196-226 0-242-196z" horiz-adv-x="700" />
+<glyph glyph-name="light-down" unicode="🔅" d="M350 510q68 0 114-47t46-113q0-68-46-114t-114-46q-66 0-113 46t-47 114q0 66 47 113t113 47z m0-264q44 0 73 30t29 74q0 42-29 72t-73 30q-42 0-72-30t-30-72q0-44 30-74t72-30z m-300 144q20 0 35-12t15-28q0-40-50-40t-50 40q0 16 15 28t35 12z m546 204q28-28-8-64-14-14-33-16t-29 10q-12 12-10 31t16 33q36 34 64 6z m54-204q20 0 35-12t15-28q0-40-50-40-48 0-48 40 0 16 14 28t34 12z m-300-290q16 0 28-15t12-35-12-35-28-15-28 15-12 35 12 35 28 15z m-238 62q36 36 64 8t-8-64q-14-14-33-16t-29 8q-30 28 6 64z m-10 430q28 28 64-8 14-14 16-33t-8-29q-30-28-64 6-36 36-8 64z m432-484q-34 36-6 64t64-8q14-14 16-33t-10-29q-30-28-64 6z m-184 492q-16 0-28 15t-12 35 12 35 28 15 28-15 12-35-12-35-28-15z" horiz-adv-x="700" />
+<glyph glyph-name="light-up" unicode="🔆" d="M950 390q20 0 35-12t15-28q0-40-50-40h-48q-50 0-50 40 0 16 15 28t35 12h48z m-450 234q114 0 195-80t81-194q0-116-81-196t-195-80-194 80-80 196q0 114 80 194t194 80z m0-474q82 0 141 58t59 142q0 82-59 141t-141 59-141-59-59-141q0-84 59-142t141-58z m-350 200q0-40-50-40h-50q-50 0-50 40 0 16 15 28t35 12h50q20 0 35-12t15-28z m350 350q-16 0-28 15t-12 35v50q0 20 12 35t28 15 28-15 12-35v-50q0-20-12-35t-28-15z m0-700q16 0 28-15t12-35v-50q0-20-12-35t-28-15-28 15-12 35v50q0 20 12 35t28 15z m368 660l-34-34q-34-34-64-8-28 28 8 64 4 6 34 36 36 34 64 6t-8-64z m-700-588q14 16 33 18t29-10q12-12 10-31t-16-33l-36-36q-14-14-33-16t-29 10q-30 28 6 64 6 4 36 34z m20 646l36-36q36-36 6-64-10-10-29-8t-33 16q-30 30-36 34-14 14-16 33t10 31q10 12 29 10t33-16z m590-702q-36 36-8 64t64-8l34-34q36-36 8-64t-64 6q-30 30-34 36z" horiz-adv-x="1000" />
+<glyph glyph-name="adjust" unicode="◑" d="M950 390q20 0 35-12t15-28q0-40-50-40h-48q-50 0-50 40 0 16 15 28t35 12h48z m-450 234q114 0 195-80t81-194q0-116-81-196t-195-80-194 80-80 196q0 114 80 194t194 80z m6-474v400q-86 0-146-59t-60-141q0-84 60-142t146-58z m-356 200q0-40-50-40h-50q-50 0-50 40 0 16 15 28t35 12h50q20 0 35-12t15-28z m350 350q-16 0-28 15t-12 35v50q0 20 12 35t28 15 28-15 12-35v-50q0-20-12-35t-28-15z m0-700q16 0 28-15t12-35v-50q0-20-12-35t-28-15-28 15-12 35v50q0 20 12 35t28 15z m368 660l-34-34q-34-34-64-8-28 28 8 64 4 6 34 36 36 34 64 6t-8-64z m-700-588q14 16 33 18t29-10q12-12 10-31t-16-33l-36-36q-14-14-33-16t-29 10q-30 28 6 64 6 4 36 34z m20 646l36-36q36-36 6-64-10-10-29-8t-33 16q-30 30-36 34-14 14-16 33t10 31q10 12 29 10t33-16z m590-702q-36 36-8 64t64-8l34-34q36-36 8-64t-64 6q-30 30-34 36z" horiz-adv-x="1000" />
+<glyph glyph-name="block" unicode="🚫" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m258-220z m-622-260q0-132 82-230l514 514q-100 82-232 82-152 0-258-107t-106-259z m106-258z m258-106q152 0 259 107t107 257q0 130-82 232l-514-514q98-82 230-82z" horiz-adv-x="960" />
+<glyph glyph-name="resize-full" unicode="" d="M476 746h316v-316l-100 124-146-152-100 100 152 146z m-230-444l100-100-152-146 122-100h-316v316l100-122z" horiz-adv-x="792" />
+<glyph glyph-name="resize-small" unicode="" d="M156 146l-106 100h296v-296l-100 106-146-156-100 100z m744 554l-154-144 104-100h-294v294l100-104 144 154z" horiz-adv-x="900" />
+<glyph glyph-name="popup" unicode="" d="M700 750q42 0 71-29t29-71v-400q0-40-29-70t-71-30h-400q-40 0-70 30t-30 70v402q0 40 29 69t71 29h400z m0-500v400h-400v-400h400z m-600 100v-300h300v-100h-300q-40 0-70 30t-30 70v300h100z" horiz-adv-x="800" />
+<glyph glyph-name="publish" unicode="" d="M900 800q42 0 71-30t29-70v-600q0-42-29-71t-71-29h-198v98h200v462h-802v-462h200v-98h-200q-40 0-70 29t-30 71v600q0 40 30 70t70 30h800z m-770-168q38 0 38 38 0 16-11 26t-27 10-27-11-11-25q0-16 11-27t27-11z m100 0q38 0 38 38 0 16-11 26t-27 10-27-11-11-25q0-16 11-27t27-11z m672 6v62h-602v-62h602z m-404-198l242-240h-150v-300h-184v300h-150z" horiz-adv-x="1000" />
+<glyph glyph-name="window" unicode="" d="M900 750q42 0 71-30t29-70v-600q0-42-29-71t-71-29h-800q-40 0-70 29t-30 71v600q0 40 30 70t70 30h800z m-670-94q-16 0-27-11t-11-25q0-16 11-27t27-11q38 0 38 38 0 16-11 26t-27 10z m-138-36q0-16 11-27t27-11q38 0 38 38 0 16-11 26t-27 10-27-11-11-25z m810-570v460h-802v-460h802z m0 540v60h-602v-60h602z" horiz-adv-x="1000" />
+<glyph glyph-name="arrow-combo" unicode="" d="M230 850l230-364h-460z m0-1000l-230 366h460z" horiz-adv-x="460" />
+<glyph glyph-name="down-circled" unicode="" d="M460 810q190 0 325-135t135-325-135-325-325-135-325 135-135 325 135 325 325 135z m0-820q148 0 254 106t106 254q0 150-106 255t-254 105-254-105-106-255q0-148 106-254t254-106z m90 554v-206h112l-202-190-202 190h112v206h180z" horiz-adv-x="920" />
+<glyph glyph-name="left-circled" unicode="" d="M920 350q0-190-135-325t-325-135-325 135-135 325q0 192 135 326t325 134 325-134 135-326z m-820 0q0-148 106-254t254-106 254 106 106 254q0 150-106 255t-254 105-254-105-106-255z m552-90h-204v-112l-190 202 190 204v-114h204v-180z" horiz-adv-x="920" />
+<glyph glyph-name="right-circled" unicode="" d="M0 350q0 190 135 325t325 135 325-135 135-325-135-325-325-135-325 135-135 325z m820 0q0 150-105 255t-255 105q-148 0-254-105t-106-255q0-148 106-254t254-106q150 0 255 106t105 254z m-552 90h204v114l190-204-190-202v112h-204v180z" horiz-adv-x="920" />
+<glyph glyph-name="up-circled" unicode="" d="M460-110q-190 0-325 135t-135 325q0 192 135 326t325 134 325-134 135-326q0-190-135-325t-325-135z m0 820q-148 0-254-105t-106-255q0-148 106-254t254-106q150 0 255 106t105 254q0 150-105 255t-255 105z m-90-552v204h-112l202 192 202-192h-112v-204h-180z" horiz-adv-x="920" />
+<glyph glyph-name="down-open" unicode="" d="M564 422l-234-224q-18-18-40-18t-40 18l-234 224q-16 16-16 41t16 41q38 38 78 0l196-188 196 188q40 38 78 0 16-16 16-41t-16-41z" horiz-adv-x="580" />
+<glyph glyph-name="left-open" unicode="" d="M242 626q14 16 39 16t41-16q38-36 0-80l-186-196 186-194q38-44 0-80-16-16-40-16t-40 16l-226 236q-16 16-16 38 0 24 16 40 206 214 226 236z" horiz-adv-x="341" />
+<glyph glyph-name="right-open" unicode="" d="M98 626l226-236q16-16 16-40 0-22-16-38l-226-236q-16-16-40-16t-40 16q-36 36 0 80l186 194-186 196q-36 44 0 80 16 16 41 16t39-16z" horiz-adv-x="340" />
+<glyph glyph-name="up-open" unicode="" d="M564 280q16-16 16-41t-16-41q-38-38-78 0l-196 188-196-188q-40-38-78 0-16 16-16 41t16 41l234 224q16 16 40 16t40-16z" horiz-adv-x="580" />
+<glyph glyph-name="down-open-mini" unicode="" d="M405 470q22 26 48 0 26-22 0-48l-196-192q-22-22-48 0l-196 192q-26 26 0 48 24 24 50 0l170-156z" horiz-adv-x="466" />
+<glyph glyph-name="left-open-mini" unicode="" d="M252 180q26-26 0-48-26-26-48 0l-192 194q-24 24 0 50l192 194q22 26 48 0 26-22 0-48l-156-172z" horiz-adv-x="265" />
+<glyph glyph-name="right-open-mini" unicode="" d="M13 180l158 170-158 172q-26 26 0 48 26 26 48 0l192-194q24-26 0-50l-192-194q-22-26-48 0-26 22 0 48z" horiz-adv-x="265" />
+<glyph glyph-name="up-open-mini" unicode="" d="M62 230q-26-22-50 0-24 24 0 50l196 190q26 26 48 0l196-190q24-26 0-50-24-22-50 0l-170 158z" horiz-adv-x="464" />
+<glyph glyph-name="down-open-big" unicode="" d="M63 570l370-356 372 356q22 26 48 0 26-22 0-48l-396-392q-22-22-48 0l-396 392q-26 26 0 48 24 24 50 0z" horiz-adv-x="866" />
+<glyph glyph-name="left-open-big" unicode="" d="M452-20q26-26 0-48-26-26-48 0l-392 394q-24 24 0 50l392 394q22 26 48 0 26-22 0-48l-358-372z" horiz-adv-x="465" />
+<glyph glyph-name="right-open-big" unicode="" d="M13-20l358 370-358 372q-26 26 0 48 26 26 48 0l392-394q24-26 0-50l-392-394q-22-26-48 0-26 22 0 48z" horiz-adv-x="465" />
+<glyph glyph-name="up-open-big" unicode="" d="M804 130l-372 358-370-358q-26-22-50 0-24 24 0 50l396 390q26 26 48 0l396-390q24-26 0-50-26-22-48 0z" horiz-adv-x="864" />
+<glyph glyph-name="down" unicode="⬇" d="M660 366l-330-380-330 380h192v350h276v-350h192z" horiz-adv-x="660" />
+<glyph glyph-name="left" unicode="⬅" d="M378 20l-378 330 378 330v-190h352v-278h-352v-192z" horiz-adv-x="730" />
+<glyph glyph-name="right" unicode="➡" d="M350 680l380-330-380-330v192h-350v278h350v190z" horiz-adv-x="730" />
+<glyph glyph-name="up" unicode="⬆" d="M660 336h-192v-350h-276v350h-192l330 380z" horiz-adv-x="660" />
+<glyph glyph-name="down-dir" unicode="▾" d="M460 550l-230-400-230 400h460z" horiz-adv-x="460" />
+<glyph glyph-name="left-dir" unicode="◂" d="M400 580v-460l-400 230z" horiz-adv-x="400" />
+<glyph glyph-name="right-dir" unicode="▸" d="M0 580l400-230-400-230v460z" horiz-adv-x="400" />
+<glyph glyph-name="up-dir" unicode="▴" d="M0 150l230 400 230-400h-460z" horiz-adv-x="460" />
+<glyph glyph-name="down-bold" unicode="" d="M760 366l-380-380-380 380h192v350h376v-350h192z" horiz-adv-x="760" />
+<glyph glyph-name="left-bold" unicode="" d="M378 730v-190h352v-378h-352v-192l-378 380z" horiz-adv-x="730" />
+<glyph glyph-name="right-bold" unicode="" d="M350 730l380-380-380-380v192h-350v378h350v190z" horiz-adv-x="730" />
+<glyph glyph-name="up-bold" unicode="" d="M760 336h-192v-350h-376v350h-192l380 380z" horiz-adv-x="760" />
+<glyph glyph-name="down-thin" unicode="↓" d="M500 100l-250-240-250 240h162v740h176v-740h162z" horiz-adv-x="500" />
+<glyph glyph-name="left-thin" unicode="←" d="M240 100l-240 250 240 250v-160h740v-178h-740v-162z" horiz-adv-x="980" />
+<glyph glyph-name="right-thin" unicode="→" d="M742 100v162h-742v178h742v160l238-250z" horiz-adv-x="980" />
+<glyph glyph-name="up-thin" unicode="↑" d="M500 602h-162v-742h-176v742h-162l250 238z" horiz-adv-x="500" />
+<glyph glyph-name="ccw" unicode="⟲" d="M532 736q170 0 289-120t119-290-119-290-289-120q-142 0-252 88l70 74q84-60 182-60 126 0 216 90t90 218-90 218-216 90q-124 0-214-87t-92-211h142l-184-204-184 204h124q2 166 122 283t286 117z" horiz-adv-x="940" />
+<glyph glyph-name="cw" unicode="⟳" d="M408 760q168 0 287-116t123-282h122l-184-206-184 206h144q-4 124-94 210t-214 86q-126 0-216-90t-90-218q0-126 90-216t216-90q104 0 182 60l70-76q-110-88-252-88-168 0-288 120t-120 290 120 290 288 120z" horiz-adv-x="940" />
+<glyph glyph-name="arrows-ccw" unicode="🔄" d="M186 140l116 116v-292l-276 16 88 86q-116 122-114 290t120 288q100 100 240 116l4-102q-100-16-172-88-88-88-90-213t84-217z m332 598l276-16-88-86q116-122 114-290t-120-288q-96-98-240-118l-2 104q98 16 170 88 88 88 90 213t-84 217l-114-116z" horiz-adv-x="820" />
+<glyph glyph-name="level-down" unicode="↳" d="M100 200q-42 0-71 30t-29 70v350h140v-310h364v150l240-220-240-220v150h-404z" horiz-adv-x="744" />
+<glyph glyph-name="level-up" unicode="↰" d="M200 350v-90l-200 160 200 170v-100h550q40 0 70-29t30-71v-280h-140v240h-510z" horiz-adv-x="850" />
+<glyph glyph-name="shuffle" unicode="🔀" d="M754 516q-54 0-105-32t-80-66-83-104q-48-62-75-94t-78-77-107-66-122-21h-104v140h104q54 0 106 32t81 66 83 104q62 82 101 126t116 88 163 44h36v120l210-180-210-180v100h-36z m-484-88q-74 78-166 78h-104v140h104q140 0 254-108-14-16-37-45t-27-33q-8-12-24-32z m520-242v100l210-180-210-180v120h-36q-140 0-260 116 46 58 72 92 0 2 6 9t8 11q84-88 174-88h36z" horiz-adv-x="1000" />
+<glyph glyph-name="loop" unicode="🔁" d="M800 540q42 0 71-29t29-71v-290q0-40-29-70t-71-30h-700q-40 0-70 30t-30 70v290q0 42 30 71t70 29h250v110l200-180-200-180v110h-210v-210h620v210h-150v140h190z" horiz-adv-x="900" />
+<glyph glyph-name="switch" unicode="⇆" d="M700 592v-140h-500v-90l-200 160 200 170v-100h500z m300-420l-200-160v90h-500v140h500v100z" horiz-adv-x="1000" />
+<glyph glyph-name="play" unicode="▶" d="M486 376q14-10 14-26 0-14-14-24l-428-266q-24-16-41-6t-17 40v514q0 30 17 40t41-6z" horiz-adv-x="500" />
+<glyph glyph-name="stop" unicode="■" d="M526 650q74 0 74-64v-470q0-66-74-66h-450q-76 0-76 66v470q0 36 18 50t58 14h450z" horiz-adv-x="600" />
+<glyph glyph-name="pause" unicode="⎉" d="M440 700q90 0 90-64v-570q0-66-90-66t-90 66v570q0 64 90 64z m-350 0q90 0 90-64v-570q0-66-90-66t-90 66v570q0 64 90 64z" horiz-adv-x="530" />
+<glyph glyph-name="record" unicode="⚫" d="M350 700q146 0 248-102t102-248q0-144-102-247t-248-103-248 103-102 247q0 146 102 248t248 102z" horiz-adv-x="700" />
+<glyph glyph-name="to-end" unicode="⏭" d="M412 374q14-10 14-24 0-12-14-22l-362-228q-22-14-36-5t-14 35v442q0 26 14 35t36-5z m114 268q74 0 74-58v-466q0-58-74-58-76 0-76 58v466q0 58 76 58z" horiz-adv-x="600" />
+<glyph glyph-name="to-start" unicode="⏮" d="M174 350q0 14 14 24l364 228q20 14 34 5t14-35v-442q0-26-14-35t-34 5l-364 228q-14 10-14 22z m-174 234q0 58 76 58 74 0 74-58v-466q0-58-74-58-76 0-76 58v466z" horiz-adv-x="600" />
+<glyph glyph-name="fast-forward" unicode="⏩" d="M866 374q14-10 14-24t-14-22l-372-248q-22-14-37-6t-15 36v482q0 28 15 36t37-6z m-454 0q14-10 14-24t-14-22l-360-248q-20-14-36-6t-16 36v482q0 28 16 36t36-6z" horiz-adv-x="880" />
+<glyph glyph-name="fast-backward" unicode="⏪" d="M0 350q0 14 14 24l374 248q20 14 36 6t16-36v-482q0-28-16-36t-36 6l-374 248q-14 8-14 22z m454 0q0 14 14 24l360 248q20 14 36 6t16-36v-482q0-28-16-36t-36 6l-360 248q-14 8-14 22z" horiz-adv-x="880" />
+<glyph glyph-name="progress-0" unicode="" d="M1000 450v-250q0-42-29-71t-71-29h-800q-40 0-70 29t-30 71v300q0 40 30 70t70 30h800q42 0 71-30t29-70v-50z m-100-250v300h-800v-300h800z" horiz-adv-x="1000" />
+<glyph glyph-name="progress-1" unicode="" d="M1000 450v-250q0-42-29-71t-71-29h-800q-40 0-70 29t-30 71v300q0 40 30 70t70 30h800q42 0 71-30t29-70v-50z m-100-250v300h-800v-300h800z m-750 50v198h200v-198h-200z" horiz-adv-x="1000" />
+<glyph glyph-name="progress-2" unicode="" d="M1000 450v-250q0-42-29-71t-71-29h-800q-40 0-70 29t-30 71v300q0 40 30 70t70 30h800q42 0 71-30t29-70v-50z m-100-250v300h-800v-300h800z m-750 50v198h200v-198h-200z m250 0v198h200v-198h-200z" horiz-adv-x="1000" />
+<glyph glyph-name="progress-3" unicode="" d="M1000 450v-250q0-42-29-71t-71-29h-800q-40 0-70 29t-30 71v300q0 40 30 70t70 30h800q42 0 71-30t29-70v-50z m-100-250v300h-800v-300h800z m-750 50v198h200v-198h-200z m250 0v198h200v-198h-200z m250 198h200v-198h-200v198z" horiz-adv-x="1000" />
+<glyph glyph-name="target" unicode="🎯" d="M430 780q178 0 304-126t126-304-126-304-304-126-304 126-126 304 126 304 304 126z m36-778q124 14 212 102t100 212h-192v70h192q-12 124-100 212t-212 102v-194h-70v194q-124-14-213-102t-101-212h194v-70h-194q12-124 101-212t213-102v194h70v-194z" horiz-adv-x="860" />
+<glyph glyph-name="palette" unicode="🎨" d="M857 622q72-48 101-110t20-104-35-48q-16-4-54 10t-80 10-80-46q-30-46-21-75t34-65 23-50q-2-26-36-63t-126-74-216-37q-186 0-291 101t-95 245q8 118 104 235t216 151q290 84 536-80z m-318-466q30 0 52 22t22 54-22 53-52 21q-32 0-54-21t-22-53 22-54 54-22z" horiz-adv-x="980" />
+<glyph glyph-name="list" unicode="" d="M100 200q20 0 35-15t15-35-15-35-35-15h-50q-20 0-35 15t-15 35 14 35 36 15h50z m0 200q20 0 35-15t15-35-15-35-35-15h-50q-20 0-35 15t-15 35 14 35 36 15h50z m0 200q20 0 35-15t15-35-15-35-35-15h-50q-20 0-35 15t-15 35 14 35 36 15h50z m200-100q-20 0-35 15t-15 35 15 35 35 15h350q22 0 36-15t14-35-15-35-35-15h-350z m350-100q22 0 36-15t14-35-15-35-35-15h-350q-20 0-35 15t-15 35 15 35 35 15h350z m0-200q22 0 36-15t14-35-15-35-35-15h-350q-20 0-35 15t-15 35 15 35 35 15h350z" horiz-adv-x="700" />
+<glyph glyph-name="list-add" unicode="" d="M350 400q22 0 36-15t14-35-15-35-35-15h-300q-20 0-35 15t-15 35 14 35 36 15h300z m0-200q22 0 36-15t14-35-15-35-35-15h-300q-20 0-35 15t-15 35 14 35 36 15h300z m620 200q30 0 30-50t-30-50h-170v-170q0-30-50-30t-50 30v170h-164q-30 0-30 50t30 50h164v170q0 30 50 30t50-30v-170h170z m-620 200q22 0 36-15t14-35-15-35-35-15h-300q-20 0-35 15t-15 35 14 35 36 15h300z" horiz-adv-x="1000" />
+<glyph glyph-name="signal" unicode="📶" d="M490 150q42 0 71-30t29-70q0-42-29-71t-71-29q-40 0-69 29t-29 71q0 40 29 70t69 30z m-210 112q88 88 210 88t210-88l-70-72q-58 58-140 58t-140-58z m-140 140q146 148 351 148t349-148l-70-70q-116 118-279 118t-281-118z m-140 142q204 206 491 206t489-206l-70-70q-174 176-420 176t-420-176z" horiz-adv-x="980" />
+<glyph glyph-name="trophy" unicode="🏆" d="M510 134v-66q70-8 116-32t46-56q0-36-65-63t-157-27q-90 0-156 27t-66 63q0 32 46 56t118 32v66q0 50-33 84t-113 88q-56 36-87 61t-75 72-64 108-20 137q0 14 11 24t25 10h172q48 92 242 92 196 0 244-92h170q14 0 25-10t11-24q0-76-20-137t-64-108-75-72-87-61q-78-52-111-87t-33-85z m138 252q80 56 126 114t54 148h-126q-6-158-54-262z m-198 364q-62 0-108-15t-64-32-18-29q0-14 18-31t64-32 108-15 108 15 64 32 18 31q0 12-18 29t-64 32-108 15z m-378-102q8-90 54-148t126-114q-48 104-54 262h-126z" horiz-adv-x="900" />
+<glyph glyph-name="battery" unicode="🔋" d="M770 350q0-98 36-157t78-59h66q-30-46-64-65t-118-19h-500q-130 0-199 94t-69 206q0 110 69 205t199 95h500q84 0 118-19t64-65h-66q-42 0-78-60t-36-156z m-136-90q10 12-8 26-136 134-178 164-16 10-26 13t-18-5-10-12-8-18l-22-56-148 66q-26 12-34 0-8-14 8-28 136-132 180-162 34-16 42-11t18 31l24 58 146-68q26-12 34 2z m310 192q22 0 39-27t17-71-17-72-39-28h-38q-22 0-38 28t-16 72 16 71 38 27h38z" horiz-adv-x="1000" />
+<glyph glyph-name="back-in-time" unicode="" d="M532 760q170 0 289-120t119-290-119-290-289-120q-138 0-252 88l70 76q82-60 182-60 126 0 216 90t90 216q0 128-90 218t-216 90q-124 0-213-86t-93-210h142l-184-206-184 206h124q4 166 123 282t285 116z m-36-190h70v-204l130-130-50-50-150 150v234z" horiz-adv-x="940" />
+<glyph glyph-name="monitor" unicode="💻" d="M900 790q42 0 71-30t29-70v-550q0-42-29-77t-69-43l-218-44 86-38q50-28-20-28h-500q-98 0 32 52l36 14-220 44q-40 8-69 43t-29 77v550q0 40 30 70t70 30h800z m0-646v556h-800v-556h800z" horiz-adv-x="1000" />
+<glyph glyph-name="mobile" unicode="📱" d="M480 840q42 0 71-29t29-71v-780q0-40-29-70t-71-30h-380q-40 0-70 30t-30 70v780q0 42 30 71t70 29h380z m-190-940q30 0 50 15t20 35q0 22-20 36t-50 14q-28 0-49-15t-21-35 21-35 49-15z m210 150v660h-420v-660h420z" horiz-adv-x="580" />
+<glyph glyph-name="network" unicode="" d="M224 504q-22 0-42-10-48 52-92 128 54 74 128 118 92-38 152-82-6-16-6-32 0-6 4-22-62-48-116-104-16 4-28 4z m-98-98q0-34 20-60-60-114-80-232-66 106-66 236 0 110 50 206 38-62 84-112-8-24-8-38z m336 318q-28 0-50-14-58 42-114 70 84 30 162 30 120 0 230-62-76-14-162-50-26 26-66 26z m146-460q-160 24-290 112 4 20 4 30 0 24-14 52 38 44 98 90 26-20 56-20 14 0 38 8 94-108 134-240-16-14-26-32z m128-132q38 14 54 60 58 4 108 18-46-146-166-232 6 48 6 98 0 10-1 28t-1 28z m-150 66q-190-96-304-272-90 36-158 110 12 144 80 274 6-2 20-2 30 0 52 14 142-98 310-124z m184 492q150-136 150-340 0-22-4-66-64-18-130-24-24 56-88 60-48 146-148 264 10 20 10 42v10q100 42 210 54z m-136-544q14-10 32-18 2-18 2-52 0-80-14-144-86-42-194-42-58 0-112 12 110 160 286 244z" horiz-adv-x="920" />
+<glyph glyph-name="cd" unicode="💿" d="M460 810q190 0 325-135t135-325-135-325-325-135-325 135-135 325 135 325 325 135z m0-610q62 0 106 44t44 106q0 64-43 107t-107 43q-62 0-106-44t-44-106 44-106 106-44z" horiz-adv-x="920" />
+<glyph glyph-name="inbox" unicode="" d="M967 398q40-42 30-72l-28-154q-4-20-22-33t-40-13h-816q-22 0-40 13t-22 33l-28 154q-8 32 32 72 8 10 36 38t68 67 52 51q22 22 52 22h516q30 0 52-22 16-16 53-52t67-65 38-39z m-266-32h178l-102 114h-556l-102-114h178q8 0 12-8l40-100h300l40 100q4 8 12 8z" horiz-adv-x="999" />
+<glyph glyph-name="install" unicode="" d="M884 306q24-52 14-96l-34-184q-2-20-19-35t-39-15h-712q-22 0-39 15t-19 35l-34 184q-8 50 14 96l158 374q22 46 72 46h104l-20-204h-134l254-210 256 210h-136l-18 204h102q50 0 74-46z m-68-132q2 22-10 38t-34 16h-644q-22 0-34-16t-10-38l14-74q2-22 19-37t37-15h592q22 0 39 15t19 37z" horiz-adv-x="901" />
+<glyph glyph-name="globe" unicode="🌎" d="M480 830q200 0 340-141t140-339q0-200-140-340t-340-140q-198 0-339 140t-141 340q0 198 141 339t339 141z m410-480q0 132-78 239t-202 149q-18-24-16-32 4-38 18-51t30-7l32 12t20 2q22-24 0-47t-45-56-1-77q34-64 96-64 28-2 43-36t17-66q10-80-14-140-22-44 14-76 86 112 86 250z m-466 404q-112-14-199-84t-127-174q6 0 22-2t28-3 26-4 24-8 12-13q4-12-14-45t-18-61q0-30 38-56t38-46q0-28 8-68t8-44q0-12 36-54t52-42q10 0 11 22t-2 54-3 40q0 32 14 74 12 42 59 70t55 46q16 34 9 61t-17 43-34 28-41 17-37 9-22 4q-16 6-42 7t-36-3-27 11-17 29q0 10 15 27t35 37 28 30q8 14 17 21t22 16 27 21q4 4 25 17t27 23z m-72-794q66-20 128-20 128 0 226 68-26 44-118 34-24-2-65-17t-47-17q-74-16-76-16-12-2-26-14t-22-18z" horiz-adv-x="960" />
+<glyph glyph-name="cloud" unicode="☁" d="M760 494q100 0 170-68t70-166-70-166-170-68h-578q-74 0-128 52t-54 124q0 74 53 126t129 52q2 0 10-1t10-1q-2 12-2 38 0 108 78 184t188 76q90 0 160-52t94-134q28 4 40 4z" horiz-adv-x="1000" />
+<glyph glyph-name="cloud-thunder" unicode="⛈" d="M760 494q100 0 170-68t70-166-70-166-170-68h-578q-74 0-128 52t-54 124q0 74 53 126t129 52q2 0 10-1t10-1q-2 12-2 38 0 108 78 184t188 76q90 0 160-52t94-134q28 4 40 4z m-192-216q14 16 14 30 0 20-30 32h-4q-26 14-38 16l50 116q6 0 6 20 0 14-8 18-16 10-34-8-2-2-30-32t-61-66-45-52q-12-18-12-30 0-22 30-30l4-2q8-4 38-16l-52-114-2-8q-2-8-2-14 0-10 8-18 18-10 34 10 100 100 134 148z" horiz-adv-x="1000" />
+<glyph glyph-name="flash" unicode="⚡" d="M40-100q-4 4 35 94t79 182 38 98-94 45-98 55q-4 12 84 120t180 209 96 97q6-4-74-186t-78-186 95-43 97-57q4-20-174-227t-186-201z" horiz-adv-x="400" />
+<glyph glyph-name="moon" unicode="☽" d="M524 238q106 106 125 252t-53 270q52-26 96-72 128-128 128-309t-128-309-310-128-310 128q-40 40-72 94 124-70 271-51t253 125z" horiz-adv-x="820" />
+<glyph glyph-name="flight" unicode="✈" d="M268-120l124 400h-180l-112-100h-100l80 170-80 170h100l112-100h180l-124 400h100l224-400h274t36-4 46-11 36-21 16-34q0-32-38-49t-74-19l-38-2h-258l-224-400h-100z" horiz-adv-x="1000" />
+<glyph glyph-name="paper-plane" unicode="" d="M894 720q14 4 22-3t4-19q-2-6-72-310t-74-316q-2-14-14-19t-24 1l-248 134-30 16 22 26q388 420 394 426 4 4-1 9t-9 1l-550-402-112 44-190 76q-12 4-12 12t12 12q8 4 441 157t441 155z m-582-728v204l160-82q-130-116-142-128-18-14-18 6z" horiz-adv-x="921" />
+<glyph glyph-name="leaf" unicode="🍂" d="M236 646q182 106 506 66 168-22 196-50 4-6-2-10-76-40-130-109t-78-132-65-132-93-105q-138-96-382-4-66-76-114-176-12-24-47-7t-25 39q44 100 129 193t176 153 176 106 141 68l54 20q-14 0-41-1t-104-14-148-38-162-84-161-141q-22 242 174 358z" horiz-adv-x="940" />
+<glyph glyph-name="lifebuoy" unicode="" d="M454 810q190 2 326-130t140-322q2-190-131-327t-323-141q-190-2-327 131t-139 323q-4 190 130 327t324 139z m0-60q-94 0-178-44l62-104q56 28 122 28t122-28l62 104q-88 46-190 44z m-246-522q-28 60-28 122 0 64 28 124l-102 62q-46-88-46-190 2-96 46-180z m258-278q98 4 178 46l-62 104q-60-30-122-30t-122 30l-62-104q86-46 190-46z m-6 180q92 0 156 65t64 155q0 92-64 156t-156 64-156-64-64-156q0-90 64-155t156-65z m252 98l104-62q46 96 44 190 0 96-44 180l-104-62q28-60 28-124 0-62-28-122z" horiz-adv-x="920" />
+<glyph glyph-name="mouse" unicode="" d="M551 130q28-80-17-157t-139-111q-94-28-175 9t-103 117l-106 384q-20 68 6 134t84 106l-96 186q-14 34 14 48 30 18 48-14l98-192q80 22 154-16t102-116z m-324 274q28 10 40 36t4 54q-10 28-35 41t-53 5q-28-10-40-36t-4-54q10-28 35-41t53-5z" horiz-adv-x="561" />
+<glyph glyph-name="briefcase" unicode="💼" d="M456 326v-100h-456q8 226 10 292 4 108 100 108h160q16 26 37 67t23 45q14 26 23 32t37 6h222q26 0 36-7t22-31q18-32 60-112h160q96 0 100-108l10-292h-454v100h-90z m-74 354l-28-54h292l-28 54q-14 26-42 26h-152q-28 0-42-26z m164-604v100h430q-6-88-10-166-6-84-90-84h-750q-90 0-90 84l-10 166h430v-100h90z" horiz-adv-x="1000" />
+<glyph glyph-name="suitcase" unicode="" d="M900 650q42 0 71-30t29-70v-550q0-42-29-71t-71-29h-50v750h50z m-900-100q0 40 30 70t70 30h50v-750h-50q-40 0-70 29t-30 71v550z m670 204v-104h110v-750h-560v750h110v104q98 46 170 46t170-46z m-60-104v66q-52 24-110 24-54 0-110-24v-66h220z" horiz-adv-x="1000" />
+<glyph glyph-name="dot" unicode="" d="M110 460q46 0 78-32t32-78q0-44-32-77t-78-33-78 33-32 77q0 46 32 78t78 32z" horiz-adv-x="220" />
+<glyph glyph-name="dot-2" unicode="" d="M110 460q46 0 78-32t32-78q0-44-32-77t-78-33-78 32-32 78 32 78 78 32z m350 0q46 0 78-32t32-78q0-44-33-77t-77-33q-46 0-78 32t-32 78 32 78 78 32z" horiz-adv-x="570" />
+<glyph glyph-name="dot-3" unicode="" d="M110 460q46 0 78-32t32-78q0-44-32-77t-78-33-78 33-32 77q0 46 32 78t78 32z m350 0q46 0 78-32t32-78q0-44-33-77t-77-33-77 33-33 77q0 46 32 78t78 32z m350 0q46 0 78-32t32-78q0-44-32-77t-78-33-78 33-32 77q0 46 32 78t78 32z" horiz-adv-x="920" />
+<glyph glyph-name="brush" unicode="" d="M118 170q38 34 85 29t87-45q42-40 48-87t-30-83q-86-84-228-102-84-12-80 14 0 4 6 10 52 60 64 145t48 119z m840 646q26-26-148-248t-292-338q-38-38-124-104-8-6-16 8-18 34-48 64-32 32-66 48-16 6-8 16 64 84 104 122 118 116 344 287t254 145z" horiz-adv-x="962" />
+<glyph glyph-name="magnet" unicode="" d="M518-44l16 164 260-20-16-166q-4-28-32-24l-200 16q-28 0-28 30z m-490 144l258 20 16-164q2-12-6-21t-22-9l-198-16q-12-2-22 6t-10 18z m-26 270q-2 12-2 34 0 160 120 273t290 113 290-113 120-273q0-22-2-34l-16-170-258 22 16 170v12q0 58-44 99t-106 41-106-41-44-99v-12l16-170-258-22z" horiz-adv-x="820" />
+<glyph glyph-name="infinity" unicode="∞" d="M796 570q84 0 144-53t60-167q0-112-60-166t-144-54q-78 0-157 40t-139 106q-58-66-137-106t-157-40q-86 0-146 54t-60 166q0 114 60 167t146 53q78 0 157-39t137-105q58 66 138 105t158 39z m-590-352q60 0 127 37t113 95q-46 58-112 95t-128 37q-114 0-114-132t114-132z m590 0q114 0 114 132t-114 132q-62 0-129-37t-111-95q44-58 111-95t129-37z" horiz-adv-x="1000" />
+<glyph glyph-name="erase" unicode="⌫" d="M902 700q42 0 71-29t29-71v-500q0-40-29-70t-71-30h-478q-38 0-70 28l-340 296q-28 26 0 54l340 296q30 26 70 26h478z m-140-550l72 74-128 126 128 128-72 72-128-126-128 126-72-72 128-128-128-126 72-74 128 128z" horiz-adv-x="1002" />
+<glyph glyph-name="chart-pie" unicode="" d="M368 770v-368h-368q18 146 121 249t247 119z m106 0q156-20 261-139t105-279q0-174-123-298t-299-124q-160 0-278 105t-140 263h424q20 0 35 14t15 36v422z" horiz-adv-x="840" />
+<glyph glyph-name="chart-line" unicode="📈" d="M34 284q-42 10-32 56 10 42 54 32l98-24-52-80z m890-12q14 12 33 11t31-15q32-32-2-64l-252-226q-12-12-30-12-14 0-28 10l-286 220-54 14 50 80 36-8q12-4 16-8l264-204z m-490 220l-350-550q-12-22-38-22-12 0-24 8-16 10-20 29t6 33l374 588q8 16 28 20 18 6 36-6l246-156 226 326q10 16 28 19t34-9q38-24 12-62l-252-362q-24-36-62-12z" horiz-adv-x="1003" />
+<glyph glyph-name="chart-bar" unicode="📊" d="M750 800q22 0 36-15t14-35v-850h-200v850q0 50 40 50h110z m-300-300q22 0 36-15t14-35v-550h-200v550q0 50 40 50h110z m-300-300q22 0 36-15t14-35v-250h-200v250q0 50 40 50h110z" horiz-adv-x="800" />
+<glyph glyph-name="chart-area" unicode="🔾" d="M964 732q16 22 16-4v-768h-964q-12 0-15 7t5 17l230 288q20 22 40 2l74-66q10-8 21-7t17 11l158 238q16 26 38 4l112-104q20-20 38 4z" horiz-adv-x="980" />
+<glyph glyph-name="tape" unicode="✇" d="M770 580q96 0 163-67t67-163q0-94-67-162t-163-68h-540q-94 0-162 68t-68 162q0 96 68 163t162 67q96 0 163-67t67-163q0-72-40-130h160q-40 64-40 130 0 96 68 163t162 67z m-670-230q0-52 38-91t92-39 92 39 38 91q0 54-38 92t-92 38-92-38-38-92z m670-130q54 0 92 39t38 91q0 54-38 92t-92 38-92-38-38-92q0-52 38-91t92-39z" horiz-adv-x="1000" />
+<glyph glyph-name="graduation-cap" unicode="🎓" d="M166 238l334-168 276 136q-4-22-8-47t-6-35-11-23-24-23-45-22q-40-18-80-41t-63-34-39-11-40 13-64 37-80 40q-72 32-103 69t-47 109z m810 246q24-14 24-33t-24-33l-78-44-308 102q-22 36-90 36-40 0-67-16t-27-40 27-40 67-16q26 0 36 4l292-68-268-152q-60-32-120 0l-416 234q-24 14-24 33t24 33l416 234q60 32 120 0z m-128-442q18 116 13 182t-19 90l-14 22 70 38q6-8 12-28t17-101-7-197q-4-26-22-30t-35 5-15 19z" horiz-adv-x="1000" />
+<glyph glyph-name="language" unicode="" d="M988 306q30-82-10-176t-134-160q-10 0-12 2t-16 19-16 19q-2 6 2 10 86 60 117 152t-11 148q-16-38-39-76t-59-80-86-65-106-15q-52 6-84 41t-32 93q0 84 60 148 50 50 114 66l-2 100q-140-24-146-24-6-2-10 4 0 2-5 29t-5 31q-2 2 1 4t7 2l156 28q0 110-2 114 0 8 8 8 46 0 52 2 10 0 10-8v-104q158 22 164 22 8 4 10-6 0-2 4-23t4-25q4-10-4-12l-176-30v-102h12q86 0 148-36t86-100z m-370-160q28-6 62 6l-4 214q-34-12-60-40-44-44-44-108 0-66 46-72z m122 28q28 24 58 68t45 79 7 41q-36 18-96 18-2 0-6-1t-6-1z m-448 382q10-28 53-165t83-261 40-126q0-4-4-4h-86q-6 0-6 4l-50 166h-176q-48-164-50-166 0-4-6-4h-86q-4 0-4 4 10 18 176 552 2 8 10 8h96q10 0 10-8z m-130-316h144l-72 264z" horiz-adv-x="1001" />
+<glyph glyph-name="ticket" unicode="🎫" d="M216 272l326 326 178-178-326-326z m710 244q14-14 14-36t-14-36l-550-550q-16-16-36-16t-36 16l-76 76q12 20 12 48 0 42-29 72t-71 30q-22 0-50-14l-74 76q-16 16-16 36t16 36l550 550q14 14 36 14t36-14l74-76q-12-22-12-48 0-42 30-71t72-29q26 0 48 12z m-532-502l406 406-258 258-408-406z" horiz-adv-x="940" />
+<glyph glyph-name="water" unicode="💦" d="M168 844q10-86 50-155t73-123 33-112q0-66-48-113t-114-47-114 47-48 113q0 58 33 112t73 123 50 155q2 4 7 4t5-4z m616 0q10-86 50-155t73-123 33-112q0-66-48-113t-114-47-114 47-48 113q0 48 21 93t48 78 53 92 34 127q2 4 7 4t5-4z m-320-444q2 4 7 4t5-4q10-86 50-155t73-123 33-112q0-66-48-113t-114-47-114 47-48 113q0 58 33 112t73 123 50 155z" horiz-adv-x="940" />
+<glyph glyph-name="droplet" unicode="💧" d="M290 822q14-118 60-219t92-159 82-136 36-160q0-114-83-196t-197-82-197 82-83 196q0 82 36 160t82 136 92 159 60 219q2 8 11 8t9-8z m-42-392q2 4-2 14-6 6-14 6t-12-6l-40-58q-32-46-48-70t-34-75-18-101q0-24 17-41t41-17q58 0 58 68 0 94 42 246 2 6 5 17t5 17z" horiz-adv-x="560" />
+<glyph glyph-name="air" unicode="" d="M85 534q-16-14-36-12t-34 18q-14 14-12 36t18 36q48 40 79 60t89 40 129 4 159-66 155-53 100 16 89 67q38 30 70-6 32-40-6-72-122-110-234-110-100 0-222 70-68 38-119 52t-93 0-65-29-67-51z m736-110q38 32 70-6 32-40-6-72-40-34-65-53t-72-38-97-19q-96 0-222 70-68 38-119 52t-93 0-65-29-67-51q-14-14-35-12t-35 18q-32 40 6 72 38 34 60 50t69 38 88 23 105-15 134-56q68-38 119-52t93 0 65 29 67 51z m0-256q38 32 70-6 14-14 12-36t-18-36q-40-34-65-53t-72-38-97-19q-96 0-222 70-68 38-119 52t-93 1-66-29-66-52q-14-14-35-12t-35 18q-32 40 6 72 38 34 60 50t69 38 88 23 105-15 134-56q68-38 119-52t93 0 65 29 67 51z" horiz-adv-x="905" />
+<glyph glyph-name="credit-card" unicode="💳" d="M900 700q42 0 71-30t29-70v-500q0-42-29-71t-71-29h-800q-40 0-70 29t-30 71v500q0 40 30 70t70 30h800z m0-600v300h-800v-300h800z m0 450v50h-800v-50h800z m-700-256h30v-30h-30v30z m180-60h30v30h30v30h60v-30h-30v-30h-30v-30h-60v30z m120-30h-30v30h30v-30z m-150 0h-60v30h60v-30z m30 60v-30h-30v60h60v-30h-30z m-120-30v-30h-60v30h30v30h30v30h60v-30h-30v-30h-30z" horiz-adv-x="1000" />
+<glyph glyph-name="floppy" unicode="💾" d="M658 750l142-156v-544q0-40-29-70t-71-30h-600q-40 0-70 30t-30 70v600q0 42 30 71t70 29h558z m-58-300v250h-400v-250q0-20 15-35t35-15h300q20 0 35 15t15 35z m-50 200v-200h-100v200h100z" horiz-adv-x="800" />
+<glyph glyph-name="clipboard" unicode="📋" d="M630 750q28 0 49-21t21-49v-760q0-30-21-50t-49-20h-560q-28 0-49 20t-21 50v760q0 28 21 49t49 21l60-150h440z m-100-100h-360l-44 100h108l36 100h160l36-100h110z" horiz-adv-x="700" />
+<glyph glyph-name="megaphone" unicode="📣" d="M791 500q58-138 67-258t-39-140q-28-12-61 3t-65 40-99 41-149 8q-28-4-42-19t-6-37q22-56 46-108 4-10 24-22t24-20q14-34-22-46-50-22-102-40-30-10-54 42-32 76-58 132-6 12-34 17t-46 31q-30-10-38-14-34-12-74 12t-54 60q-16 32-5 79t43 61q126 52 213 108t124 103 59 92 25 78 15 59 36 36q48 20 130-70t142-228z m-28-300q8 4 10 38t-11 98-41 128q-28 66-67 123t-67 84-36 23-10-42 10-105 40-133 68-119 68-76 36-19z" horiz-adv-x="860" />
+<glyph glyph-name="database" unicode="" d="M686 208q14 20 14-2v-100q0-74-104-135t-246-61q-140 0-245 61t-105 135v100q0 8 4 10t10-8q32-52 125-86t211-34 211 34 125 86z m2 254q8 16 12 0v-116q0-68-102-114t-248-46q-144 0-247 46t-103 114v116q0 20 14 0 30-46 124-75t212-29 212 29 126 75z m-338 328q144 0 247-39t103-93v-64q0-58-103-99t-247-41-247 41-103 99v64q0 54 103 93t247 39z" horiz-adv-x="700" />
+<glyph glyph-name="drive" unicode="" d="M884 304q26-44 14-96l-34-184q-2-20-19-35t-39-15h-712q-20 0-38 15t-20 35l-34 184q-8 52 14 96l158 374q22 46 72 46h408q50 0 74-46z m-68-132q2 22-10 38t-34 16h-644q-22 0-34-16t-10-38l14-74q2-22 19-37t39-15h590q22 0 39 15t19 37z" horiz-adv-x="902" />
+<glyph glyph-name="bucket" unicode="" d="M522 780q174 0 286-49t104-105q-6-38-48-307t-44-281q-2-18-37-44t-107-50-154-24-153 24-106 50-37 44q0 2-4 30 82-6 163 35t139 117q28 0 48 20t20 50q0 28-20 49t-50 21q-28 0-49-21t-21-49q0-20 10-36-48-58-115-89t-131-27q-102 10-157 57t-59 109q-8 122 156 184-18 94-22 138-8 56 104 105t284 49z m-452-470q4-32 37-59t91-39l-32 204q-100-44-96-106z m452 212q82 0 157 18t113 39 38 35-38 35-112 39-158 18q-82 0-156-18t-112-39-38-35 38-35 112-39 156-18z" horiz-adv-x="913" />
+<glyph glyph-name="thermometer" unicode="" d="M400 356q64-36 102-98t38-138q0-112-79-191t-191-79-191 79-79 191q0 76 38 138t102 98v444q0 50 40 50h170q20 0 35-15t15-35v-444z m-130-406q70 0 120 50t50 120q0 56-32 100t-84 60v370h-100v-368q-54-16-89-61t-35-101q0-70 50-120t120-50z" horiz-adv-x="540" />
+<glyph glyph-name="key" unicode="🔑" d="M774 612q20-116-28-215t-150-117q-66-12-130-2l-118-194-70-12-104-166q-14-28-46-32l-76-14q-12-4-22 4t-12 22l-16 98q-8 30 12 56l258 386q-24 50-38 120-18 106 53 187t185 101q106 20 195-45t107-177z m-126-76q30 44 21 97t-51 83q-42 32-92 22t-80-54q-8-12-12-23t-1-20 5-16 13-17 18-15 22-16 23-17q6-4 22-16t23-16 19-12 19-8 17 1 18 8 16 19z" horiz-adv-x="780" />
+<glyph glyph-name="flow-cascade" unicode="" d="M520 120q50 0 85-35t35-85-35-85-85-35q-80 0-110 74h-164q-88 0-131 54t-43 118v464q-72 34-72 110 0 50 35 85t85 35 85-35 35-85q0-76-72-110v-114q0-78 78-78h164q30 72 110 72 50 0 85-35t35-85-35-85-85-35q-80 0-110 74h-164q-42 0-78 16v-194q0-78 78-78h164q30 72 110 72z m0 300q-28 0-49-20t-21-50q0-28 21-48t49-20 49 20 21 48q0 30-21 50t-49 20z m-470 280q0-28 21-48t49-20 49 20 21 48q0 30-21 50t-49 20-49-20-21-50z m470-768q28 0 49 20t21 48q0 30-21 50t-49 20-49-20-21-50q0-28 21-48t49-20z" horiz-adv-x="640" />
+<glyph glyph-name="flow-branch" unicode="" d="M640 650q0-80-74-110-6-58-28-101t-61-69-68-38-75-26q-42-14-63-22t-47-24-38-40-16-60q70-30 70-110 0-50-35-85t-85-35-85 35-35 85q0 78 72 112v378q-72 34-72 110 0 50 35 85t85 35 85-35 35-85q0-76-72-110v-204q40 30 138 60 58 18 84 29t51 41 29 76q-70 32-70 108 0 50 35 85t85 35 85-35 35-85z m-588 0q0-28 20-48t48-20 49 20 21 48q0 30-21 50t-49 20-48-20-20-50z m68-668q28 0 49 20t21 48q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20z m400 600q28 0 49 20t21 48q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20z" horiz-adv-x="640" />
+<glyph glyph-name="flow-tree" unicode="" d="M868 112q72-34 72-112 0-50-35-85t-85-35-85 35-35 85q0 78 72 112v114q0 78-76 78h-100q-44 0-78 12v-204q72-34 72-112 0-50-35-85t-85-35-85 35-35 85q0 78 72 112v204q-30-12-76-12h-100q-34 0-53-19t-22-33-3-26v-114q72-34 72-112 0-50-35-85t-85-35-85 35-35 85q0 78 72 112v114q0 64 43 118t131 54h100q76 0 76 52v140q-72 34-72 110 0 50 35 85t85 35 85-35 35-85q0-76-72-110v-140q0-52 78-52h100q86 0 129-54t43-118v-114z m-678-112q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20 49 20 21 48z m212 700q0-28 20-48t48-20 49 20 21 48q0 30-21 50t-49 20-48-20-20-50z m138-700q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20 49 20 21 48z m280-68q28 0 49 20t21 48q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20z" horiz-adv-x="940" />
+<glyph glyph-name="flow-line" unicode="" d="M168 162q72-34 72-112 0-50-35-85t-85-35-85 35-35 85q0 78 72 112v378q-72 34-72 110 0 50 35 85t85 35 85-35 35-85q0-76-72-110v-378z m-116 488q0-28 20-48t48-20 49 20 21 48q0 30-21 50t-49 20-48-20-20-50z m68-668q28 0 49 20t21 48q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20z" horiz-adv-x="240" />
+<glyph glyph-name="flow-parallel" unicode="" d="M240 650q0-76-72-110v-378q72-34 72-112 0-50-35-85t-85-35-85 35-35 85q0 78 72 112v378q-72 34-72 110 0 50 35 85t85 35 85-35 35-85z m-50-600q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20 49 20 21 48z m-70 532q28 0 49 20t21 48q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20z m448-420q72-34 72-112 0-50-35-85t-85-35-85 35-35 85q0 78 72 112v378q-72 34-72 110 0 50 35 85t85 35 85-35 35-85q0-76-72-110v-378z m-116 488q0-28 20-48t48-20 49 20 21 48q0 30-21 50t-49 20-48-20-20-50z m68-668q28 0 49 20t21 48q0 30-21 50t-49 20-48-20-20-50q0-28 20-48t48-20z" horiz-adv-x="640" />
+<glyph glyph-name="rocket" unicode="🚀" d="M543 236q6-50 8-81t-8-59-13-40-35-32-45-26-70-31-85-37q-32-12-45 4t-3 44l40 110-130 132-106-40q-28-12-43 2t-3 46q12 30 31 79t27 65 22 45 25 36 29 20 41 13h52t71-6q10 14 29 39t77 85 118 104 145 75 165 19q8 0 14-6 4-4 6-14 10-82-18-168t-76-151-98-118-86-81z m50 296q22-22 54-22t54 22q22 24 22 56t-22 56q-22 22-54 22t-54-22q-22-24-22-56t22-56z" horiz-adv-x="860" />
+<glyph glyph-name="gauge" unicode="" d="M406 178q34 56 214 284t194 220q12-6-96-278t-138-326q-50-86-136-36t-38 136z m94 380q-168 0-284-127t-116-311q0-30 2-46 2-22-12-37t-34-17-36 12-18 34q0 8-1 26t-1 28q0 226 145 382t355 156q72 0 134-18l-70-86q-40 4-64 4z m362-62q138-154 138-376 0-38-2-56-2-20-16-33t-34-13h-4q-22 4-35 20t-11 36q2 14 2 46 0 150-80 268 6 14 20 51t22 57z" horiz-adv-x="1000" />
+<glyph glyph-name="traffic-cone" unicode="" d="M480 246q-90 0-156 27t-70 65q44 124 56 158 10-28 59-46t111-18q64 0 112 18t58 46q12-34 56-158-4-38-70-65t-156-27z m0 334q-96 0-124 44l52 142q10 34 72 34t74-34q12-38 50-142-28-44-124-44z m440-384q40-16 41-41t-37-47l-352-188q-38-22-91-22t-91 22l-354 188q-38 20-36 46t42 42l188 76-22-60q0-48 80-82t192-34 192 34 82 82l-22 60z" horiz-adv-x="961" />
+<glyph glyph-name="cc" unicode="" d="M474 830q198 2 340-136t146-336q2-200-136-342t-338-146q-198-2-341 137t-145 337q-4 200 135 342t339 144z m12-858q156 2 266 114t108 270-115 267-269 107q-158-2-267-114t-107-270 114-267 270-107z m-124 298q40 0 58 40l56-30q-20-36-50-52-32-20-70-20-62 0-100 38-38 36-38 104t38 106 96 38q86 0 124-66l-62-32q-10 20-24 28t-28 8q-60 0-60-82 0-38 14-58 18-22 46-22z m266 0q42 0 56 40l58-30q-18-32-50-52t-70-20q-64 0-100 38-38 36-38 104 0 64 38 106 38 38 98 38 84 0 120-66l-60-32q-10 20-24 28t-28 8q-62 0-62-82 0-36 16-58t46-22z" horiz-adv-x="960" />
+<glyph glyph-name="cc-by" unicode="" d="M480 526q-66 0-66 68t66 68q68 0 68-68t-68-68z m98-26q14 0 22-8 10-10 10-22v-196h-56v-234h-148v234h-56v196q0 12 10 22 8 8 22 8h196z m-98 330q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m0-872q162 0 277 115t115 277q0 164-115 278t-277 114-277-114-115-278q0-162 115-277t277-115z" horiz-adv-x="960" />
+<glyph glyph-name="cc-nc" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m-370-350q-22-62-22-130 0-162 115-277t277-115q110 0 202 56t142 148l-178 80q-8-46-46-74-38-30-86-34v-74h-56v74q-78 0-146 58l66 66q50-44 108-44 24 0 42 12t18 36q0 18-14 30l-46 20-56 26-76 32z m506-122l242-108q14 44 14 100 0 164-115 278t-277 114q-102 0-188-48t-140-130l182-82q12 36 46 62 32 22 78 24v74h56v-74q68-4 120-44l-62-64q-44 28-84 28-24 0-38-8-18-10-18-30 0-8 4-12l60-28 42-18z" horiz-adv-x="960" />
+<glyph glyph-name="cc-nc-eu" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m-370-352q-22-62-22-128 0-162 115-277t277-115q110 0 201 55t143 149l-246 108h-174q10-36 26-56 38-40 104-40 46 0 92 20l18-90q-56-30-124-30-128 0-196 92-34 44-46 104h-52v58h44v14q0 4 1 12t1 12h-46v56h10z m488-112l262-116q12 48 12 100 0 164-115 278t-277 114q-102 0-189-48t-141-130l158-70q8 14 28 38 72 82 184 82 70 0 122-24l-24-92q-40 20-88 20-64 0-100-44-10-10-16-28l56-24h136v-56h-8z" horiz-adv-x="960" />
+<glyph glyph-name="cc-nc-jp" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m-374-364q-18-54-18-116 0-162 115-277t277-115q106 0 195 52t141 140l-152 68v-68h-126v-108h-118v108h-124v74h124v36l-12 24h-112v74h54z m432-242h112l-106 48-6-12v-36z m126 100l192-86q16 58 16 112 0 164-115 278t-277 114q-106 0-194-51t-140-137l158-70-54 98h128l76-166 46-20 82 186h128l-122-224h76v-34z" horiz-adv-x="960" />
+<glyph glyph-name="cc-sa" unicode="" d="M478 604q114 0 180-74 66-72 66-186 0-110-68-184-74-74-180-74-80 0-142 50-58 48-70 138h120q6-86 106-86 50 0 82 42 30 44 30 118 0 76-28 116-30 40-82 40-96 0-108-86h36l-96-94-94 94h36q14 90 72 138t140 48z m2 226q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m0-872q162 0 277 115t115 277q0 164-115 278t-277 114-277-114-115-278q0-162 115-277t277-115z" horiz-adv-x="960" />
+<glyph glyph-name="cc-nd" unicode="" d="M306 382v82h348v-82h-348z m0-154v82h348v-82h-348z m174 602q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m0-872q162 0 277 115t115 277q0 164-115 278t-277 114-277-114-115-278q0-162 115-277t277-115z" horiz-adv-x="960" />
+<glyph glyph-name="cc-pd" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m-370-352q-22-62-22-128 0-162 115-277t277-115q110 0 201 55t143 149l-424 188q2-54 28-96t76-42q36 0 64 26l6 6 70-84q-4-2-10-7t-8-9q-62-42-136-42-86 0-159 58t-73 188q0 32 6 62z m310-34l440-194q12 48 12 100 0 164-115 278t-277 114q-102 0-189-48t-141-130l148-66q64 102 196 102 88 0 150-54l-78-80q-8 8-14 12-22 16-52 16-52 0-80-50z" horiz-adv-x="960" />
+<glyph glyph-name="cc-zero" unicode="" d="M480 628q108 0 153-81t45-197q0-114-45-195t-153-81-153 81-45 195q0 116 45 197t153 81z m-86-278q0-18 4-66l106 194q14 24-6 42-12 4-18 4-86 0-86-174z m86-172q86 0 86 172 0 40-6 84l-118-204q-22-30 12-46 2-2 6-2 2 0 2-2 2 0 8-1t10-1z m0 652q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m0-872q162 0 277 115t115 277q0 164-115 278t-277 114-277-114-115-278q0-162 115-277t277-115z" horiz-adv-x="960" />
+<glyph glyph-name="cc-share" unicode="" d="M676 488q12 0 20-8t8-18v-354q0-10-8-18t-20-8h-260q-12 0-20 8t-8 18v104h-104q-10 0-18 8t-8 20v352q0 12 6 18 4 6 18 10h264q10 0 18-8t8-20v-104h104z m-264 0h108v78h-210v-300h78v196q0 10 8 18 4 4 16 8z m238-354v302h-210v-302h210z m-170 696q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m0-872q162 0 277 115t115 277q0 164-115 278t-277 114-277-114-115-278q0-162 115-277t277-115z" horiz-adv-x="960" />
+<glyph glyph-name="cc-remix" unicode="" d="M794 342l10-4v-136l-10-4-116-50-4-2-6 2-252 104-8 4-124-52-124 54v122l116 48-2 2v136l130 56 294-122v-118z m-136-158v86h-2v2l-220 90v-86l220-92v2z m14 112l78 32-72 30-76-32z m102-74v84l-86-36v-84z m-294 608q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m0-872q162 0 277 115t115 277q0 164-115 278t-277 114-277-114-115-278q0-162 115-277t277-115z" horiz-adv-x="960" />
+<glyph glyph-name="github" unicode="" d="M620 286q26 0 45-26t19-64-19-64-45-26q-28 0-47 26t-19 64 19 64 47 26z m226 234q74-80 74-194 0-74-17-133t-43-96-64-65-70-41-73-20-62-8-45-1q-6 0-36-1t-50-1-50 1-36 1q-24 0-45 1t-62 8-73 20-70 41-64 65-43 96-17 133q0 114 74 194-8 4-1 80t33 140q92-10 228-104 46 12 126 12 84 0 126-12 62 42 119 68t83 30l26 6q26-64 33-140t-1-80z m-384-514q166 0 251 40t85 164q0 72-54 120-28 26-65 32t-113 0-104-6h-4q-32 0-83 4t-80 5-63-7-56-28q-52-46-52-120 0-124 84-164t250-40h4z m-160 280q26 0 45-26t19-64-19-64-45-26q-28 0-47 26t-19 64 19 64 47 26z" horiz-adv-x="920" />
+<glyph glyph-name="github-circled" unicode="" d="M480 354q16 0 42 2t41 2 32-4 29-14q26-26 26-60 0-64-43-84t-127-20-127 20-43 84q0 34 26 60 12 10 29 14t32 4 41-2 42-2z m-80-128q14 0 23 14t9 32q0 46-32 46t-32-46q0-18 9-32t23-14z m160 0q14 0 24 14t10 32q0 20-10 33t-24 13q-32 0-32-46 0-18 9-32t23-14z m-80 604q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m44-676q188 0 188 184 0 56-38 98 4 4 1 41t-17 71q-44-6-114-52-20 6-64 6-40 0-64-6-30 20-59 33t-41 17l-14 2q-14-34-17-71t1-41q-38-42-38-98 0-184 188-184h88z" horiz-adv-x="960" />
+<glyph glyph-name="flickr" unicode="" d="M196 150q-80 0-138 59t-58 141q0 84 57 142t139 58 139-58 57-142q0-82-58-141t-138-59z m508 0q-80 0-138 59t-58 141q0 84 57 142t139 58 139-58 57-142q0-82-58-141t-138-59z" horiz-adv-x="900" />
+<glyph glyph-name="flickr-circled" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m-128-580q40 0 70 30t30 70q0 42-30 72t-70 30-70-30-30-72q0-40 30-70t70-30z m256 0q42 0 71 30t29 70q0 42-29 72t-71 30q-40 0-69-30t-29-72q0-40 29-70t69-30z" horiz-adv-x="960" />
+<glyph glyph-name="vimeo" unicode="" d="M896 558q-32-186-171-351t-245-237q-42-28-81-17t-66 38-43 61q-16 32-78 239t-74 223q-16 12-38 5t-44-21l-20-14-36 50q18 20 46 52t100 89 124 67q30 6 53-7t36-35 23-60 15-70 12-75 13-67q14-54 21-80t17-54 18-39 18-11q40 0 126 166 42 76 6 124t-112 2q22 126 140 188 104 54 182 8 80-46 58-174z" horiz-adv-x="901" />
+<glyph glyph-name="vimeo-circled" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m220-386q14 82-48 94-60 14-110-40-28-28-34-66 38 24 56-1t-2-63q-44-84-64-84-14 0-36 94-4 14-8 40t-8 45-12 39-20 29-30 5q-26-6-60-32t-56-50l-20-24 18-24q4 4 10 8t22 10 20-2q6-8 37-113t39-121q14-28 38-43t58 1q54 36 124 120t86 178z" horiz-adv-x="960" />
+<glyph glyph-name="twitter" unicode="" d="M920 636q-36-54-94-98v-24q0-130-60-250t-186-203-290-83q-160 0-290 84 14-2 46-2 132 0 234 80-62 2-110 38t-66 94q10-4 34-4 26 0 50 6-66 14-108 66t-42 120v2q36-20 84-24-84 58-84 158 0 48 26 94 154-188 390-196-6 18-6 42 0 78 55 133t135 55q82 0 136-58 60 12 120 44-20-66-82-104 56 8 108 30z" horiz-adv-x="920" />
+<glyph glyph-name="twitter-circled" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m196-392q30 22 46 48-32-12-54-14 30 18 42 52-30-16-60-22-28 28-70 28-40 0-67-28t-27-66q0-2 1-10t1-12q-120 6-194 100-14-24-14-48 0-50 44-78-26 0-44 12v-2q0-34 21-60t55-32q-16-4-24-4-12 0-18 2 20-66 88-66-50-40-118-40h-22q68-42 144-42 122 0 196 83t74 187v12z" horiz-adv-x="960" />
+<glyph glyph-name="facebook" unicode="" d="M500 644h-142q-14 0-25-15t-11-37v-102h178v-148h-178v-442h-170v442h-152v148h152v86q0 94 59 159t147 65h142v-156z" horiz-adv-x="500" />
+<glyph glyph-name="facebook-circled" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141-340 141-140 339q0 200 140 340t340 140z m114-330v78h-72q-44 0-74-33t-30-81v-44h-76v-74h76v-222h86v222h90v74h-90v52q0 28 18 28h72z" horiz-adv-x="960" />
+<glyph glyph-name="facebook-squared" unicode="" d="M752 770q44 0 76-31t32-75v-646q0-44-32-76t-76-32h-162v310h114v134h-114v70q0 30 28 30h86v152h-96q-74 0-124-54t-50-132v-66h-104v-134h104v-310h-326q-44 0-76 32t-32 76v646q0 44 32 75t76 31h644z" horiz-adv-x="860" />
+<glyph glyph-name="gplus" unicode="" d="M48 572q0 58 25 102t56 65 69 34 56 15 26 2h230v-4q0-22-78-36-28 0-38-6 40-20 54-56t14-96q0-102-68-158-38-38-38-54 0-18 50-64 104-90 104-178 0-140-116-194-68-34-150-34h-4l-4 2q-2-2-4-2-24 0-54 5t-75 21-74 57-29 103q0 60 32 101t83 57 88 22 71 6h2q-16 22-24 47t-8 39l2 14h-14q-64 0-110 30-74 44-74 160z m370-452q-4 52-43 84t-103 32h-16q-64-2-114-46-46-42-42-94t53-80 119-24q68 4 109 40t37 88z m-60 500q-30 108-122 108-12 0-20-2-40-12-58-62-16-50-2-106 14-52 47-85t71-33q12 0 18 2 42 12 63 65t3 113z m388-174h150v-94h-150v-150h-94v150h-150v94h150v150h94v-150z" horiz-adv-x="896" />
+<glyph glyph-name="gplus-circled" unicode="" d="M434 486q8-30-1-57t-31-33h-10q-42 0-60 60-6 30 2 54 10 24 30 30 2 2 10 2 44 0 60-56z m46 344q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m-28-686q60 30 60 98 0 44-52 92-26 22-26 32 0 12 20 26 34 34 34 80 0 58-36 78 2 2 10 3t10 1q40 4 40 16v4h-116q-12 0-33-4t-53-32-32-76q0-56 38-80 22-16 56-16h6q-4-24 16-50h-2q-138 0-138-94 0-40 28-63t49-27 39-4h8q40 0 74 16z m254 208v48h-76v76h-48v-76h-76v-48h76v-76h48v76h76z m-314-58q32 0 52-17t22-43-19-44-55-20q-34-4-60 11t-28 41q0 26 22 48 20 20 58 24h8z" horiz-adv-x="960" />
+<glyph glyph-name="pinterest" unicode="" d="M320 190q-26-130-58-211t-96-129q-6 74-7 120t11 110 22 104 26 99 24 99q-24 52-19 116t48 106 99 20q40-16 44-59t-13-95-32-103-4-90 63-49q68-14 121 38t74 131 11 163-54 128q-62 64-151 70t-163-33-120-117-32-170q4-22 22-52t21-47-17-67q-146 34-140 230 4 138 105 234t233 112q164 18 290-57t144-219q26-176-66-317t-252-129q-22 2-42 9t-30 13-31 21-31 21z" horiz-adv-x="778" />
+<glyph glyph-name="pinterest-circled" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141-340 141-140 339q0 200 140 340t340 140z m32-592q82-8 128 64t34 162q-10 72-74 110t-146 28q-66-8-117-56t-53-118q-4-100 70-116 10 24 9 33t-10 24-11 27q-14 96 78 144t158-18q48-48 20-148t-98-86q-40 8-33 54t24 86-21 60q-42 18-65-33t1-89q-4-20-21-83t-18-87 1-98q52 38 78 172 46-30 66-32z" horiz-adv-x="960" />
+<glyph glyph-name="tumblr" unicode="" d="M560-58q-48-26-106-40-48-12-102-12-58 0-110 16-54 20-82 46-36 32-46 64-14 30-14 96v322h-100v130q54 18 92 50t62 80q24 52 30 116h130v-232h216v-144h-216v-236q0-84 8-102 10-24 32-36 28-20 68-20 68 0 138 46v-144z" horiz-adv-x="560" />
+<glyph glyph-name="tumblr-circled" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m130-686v74q-36-24-70-24-16 0-36 10-12 8-14 18-6 12-6 52v118h110v74h-110v118h-64q-8-42-16-60-10-22-32-40t-46-26v-66h50v-162q0-28 8-48 6-16 24-32 14-14 40-24 32-8 56-8 28 0 52 6 28 6 54 20z" horiz-adv-x="960" />
+<glyph glyph-name="linkedin" unicode="" d="M204 698q0-40-29-68t-75-28q-44 0-72 28t-28 68q0 42 28 69t74 27 73-27 29-69z m-198-790v618h192v-618h-192z m306 420q0 86-4 198h166l10-86h4q60 100 190 100 100 0 161-67t61-199v-366h-192v342q0 134-98 134-70 0-98-72-6-12-6-48v-356h-194v420z" horiz-adv-x="900" />
+<glyph glyph-name="linkedin-circled" unicode="" d="M480 830q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m-118-678v312h-96v-312h96z m-48 352q52 0 52 48t-52 48q-22 0-37-14t-15-34q0-48 52-48z m404-352v184q0 66-31 101t-81 35q-66 0-96-50h-2l-6 42h-84q2-28 2-100v-212h98v180q0 18 4 24 12 38 50 38 48 0 48-68v-174h98z" horiz-adv-x="960" />
+<glyph glyph-name="dribbble" unicode="" d="M438 480q-30 54-66 109t-56 84-24 33q-82-40-139-112t-77-162q182 0 362 48z m50-132q8 4 14 4-10 28-32 68-182-56-402-56v-14q0-150 100-262 4 8 13 21t39 50 64 69 89 66 115 54z m-270-306q-2 0-4 2l-4 4z m148 690z m354-86q-114 98-260 98-48 0-92-12 82-108 146-228 138 52 204 140z m-260-756q-190 0-325 135t-135 325 135 325 325 135 325-135 135-325-135-325-325-135z m68 396q-216-74-308-242l-2-2q110-84 242-84 78 0 154 32-24 140-84 298z m16 158q12-24 26-56 2-2 5-9t5-11q66 8 129 4t101-10 42-8q0 138-88 246l-8-10q-8-10-26-27t-42-36-62-42-82-41z m60-138q52-148 76-280 140 92 168 262-8 4-39 11t-88 12-117-5z" horiz-adv-x="920" />
+<glyph glyph-name="dribbble-circled" unicode="" d="M494 352q-44-14-82-44t-55-51-25-35q-48 58-48 128v4q106 0 200 28l14-28z m114 148q-32-42-100-68-26 48-70 110 14 4 42 4 72 0 128-46z m-246-304q40 80 152 120 34-92 40-146-36-16-74-16-68 0-118 42z m104 222q-92-24-176-24 18 92 104 134 32-40 72-110z m90-92q12 2 38 2 30 0 80-10-16-82-82-128-6 56-36 136z m-76 504q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m0-714q98 0 167 69t69 165q0 98-69 167t-167 69-166-69-68-167q0-96 68-165t166-69z m46 282q72 28 108 74 42-52 42-116-48 8-90 8-30 0-44-2-2 2-2 4 0 4-2 4-2 4-6 13t-6 15z" horiz-adv-x="960" />
+<glyph glyph-name="stumbleupon" unicode="" d="M552 448v60q0 22-15 37t-37 15q-20 0-36-15t-16-37v-314q0-92-66-158t-158-66-158 66-66 158v132h172v-132q0-20 16-36t36-16 36 16 16 36v314q0 92 66 157t158 65 158-65 66-157v-60l-102-34z m278-122h170v-132q0-92-66-158t-158-66-158 66-66 158v134l70-32 102 32v-134q0-20 16-36t36-16q22 0 38 15t16 37v132z" horiz-adv-x="1000" />
+<glyph glyph-name="stumbleupon-circled" unicode="" d="M480 830q198 0 339-140t141-340q0-198-141-339t-339-141q-200 0-340 141t-140 339q0 200 140 340t340 140z m0-368q26 0 26-26v-30l34-18 52 18v30q0 46-33 79t-79 33-80-33-34-79v-160q0-26-26-26t-26 26v68h-88v-68q0-46 34-79t80-33 79 33 33 79v160q0 26 28 26z m252-186v68h-86v-68q0-26-26-26-28 0-28 26v68l-52-16-34 16v-68q0-46 33-79t81-33q46 0 79 33t33 79z" horiz-adv-x="960" />
+<glyph glyph-name="lastfm" unicode="" d="M394 222l34-100q-64-52-168-52-106 0-183 73t-77 199q0 130 80 209t188 79q112 0 167-45t91-159l36-116q48-146 202-146 120 0 120 60 0 54-78 72l-78 18q-134 34-134 152 0 88 58 126t146 38q184 0 198-146l-114-14q-8 70-90 70t-82-62q0-50 66-66l74-16q150-36 150-166 0-160-238-160-136 0-204 53t-100 149l-36 116q-14 40-22 60t-25 43-42 33-61 10q-64 0-113-46t-49-142q0-80 46-130t110-50q60 0 128 56z" horiz-adv-x="1000" />
+<glyph glyph-name="lastfm-circled" unicode="" d="M480 830q198 0 339-140t141-340q0-198-141-339t-339-141q-200 0-340 141t-140 339q0 200 140 340t340 140z m132-620q120 0 120 80 0 66-76 84l-38 8q-32 8-32 34 0 30 40 30 44 0 46-34l58 6q-6 74-100 74-102 0-102-84 0-60 66-76l40-8q40-10 40-36 0-32-62-32-76 0-100 74l-20 58q-18 58-45 81t-85 23q-54 0-95-40t-41-106q0-62 39-99t93-37 86 26l-18 50q-28-28-66-28-32 0-55 25t-23 65q0 50 25 73t57 23q34 0 49-18t27-56l18-58q32-102 154-102z" horiz-adv-x="960" />
+<glyph glyph-name="rdio" unicode="" d="M766 402q4-32 4-52 0-160-113-275t-273-115q-158 0-271 115t-113 275q0 162 112 276t272 114q52 0 90-10v-222q-76 26-154-10-70-34-101-101t-5-129q26-60 95-79t139 15q52 26 87 80t35 122v286q16-8 24-14 174-108 310-114 32-2 4-52-42-76-130-106z" horiz-adv-x="921" />
+<glyph glyph-name="rdio-circled" unicode="" d="M480 830q198 0 339-140t141-340q0-198-141-339t-339-141q-200 0-340 141t-140 339q0 200 140 340t340 140z m170-454q52 16 72 60 12 22-4 22-72 4-156 58-2 2-6 4t-6 4v-146q0-74-62-100-34-18-69-9t-49 41q-14 30 2 64t52 50q36 20 78 6v112q-22 6-46 6-80 0-137-58t-57-140q0-80 57-138t137-58 138 58 58 138q0 6-1 14t-1 12z" horiz-adv-x="960" />
+<glyph glyph-name="spotify" unicode="" d="M440 790q182 0 311-129t129-311q0-110-51-205t-139-157q-100 170-310 176-162 6-272-104-108 124-108 290 0 184 128 312t312 128z m214-596q16 22-8 38-172 106-422 48-26-8-20-32 6-26 32-22 228 54 382-40 22-14 36 8z m54 124q18 30-12 48-100 62-235 77t-251-19q-32-10-24-44 12-32 42-22 104 32 225 18t209-68q28-20 46 10z m4 130q34-20 56 14 20 34-14 56-116 68-288 82t-282-24q-14-4-22-19t-4-31q10-38 50-28 94 34 249 22t255-72z m-336-414q120-6 172-110-64-14-108-14-114 0-214 56 58 72 150 68z" horiz-adv-x="880" />
+<glyph glyph-name="spotify-circled" unicode="" d="M480 830q198 0 339-140t141-340q0-120-56-224t-152-170q-108 186-338 192-176 6-296-114-118 138-118 316 0 200 140 340t340 140z m234-650q14 26-10 40-188 114-460 54-30-8-22-36 8-30 36-22 246 58 416-46 26-14 40 10z m58 136q18 34-12 50-110 68-256 85t-276-21q-34-10-24-46 10-34 46-26 112 34 244 19t228-73q32-20 50 12z m4 142q38-24 62 14 20 38-16 62-126 74-314 89t-306-27q-18-4-27-21t-3-33q6-18 22-27t34-3q102 36 271 23t277-77z m-364-454q130-4 186-118-60-16-118-16-126 0-234 62 66 74 166 72z" horiz-adv-x="960" />
+<glyph glyph-name="qq" unicode="" d="M812 200q30-22 38-53t-12-61q-110-154-298-187t-344 77q-24 16-38 30 76-24 148-25t128 18 101 43 80 57 53 52 28 35q20 30 53 33t63-19z m-612 30q14-32 1-61t-47-45q-32-16-64-7t-46 41q-80 172-14 352t238 260q24 10 44 16-84-76-123-170t-32-178 18-130 25-78z m302 580q190-18 312-164t106-336q-4-32-8-48-20 92-67 163t-98 109-110 63-92 32-57 9q-34 2-54 29t-16 63q4 38 26 60t58 20z m-196-486q16 38 34 46v6q0 12 8 24v2q0 8 2 12 4 50 33 82t79 32q48 0 78-32t32-82q2-4 2-12v-2q8-8 8-24v-6q18-8 34-46 26-54 6-66-12-6-30 22-6-28-30-46 26-10 26-26 0-14-18-23t-44-9q-52 0-60 26h-8q-12-26-62-26-26 0-44 9t-18 23q0 16 26 26-24 20-30 46-18-28-28-22-22 10 4 66z" horiz-adv-x="922" />
+<glyph glyph-name="instagram" unicode="" d="M690 350q0 26-6 50h176v-344q0-56-39-96t-95-40h-592q-56 0-95 40t-39 96v344h174q-4-32-4-50 0-106 76-183t184-77q106 0 183 77t77 183z m36 430q56 0 95-39t39-95v-146h-218q-78 110-212 110-138 0-212-110h-218v146q0 56 39 95t95 39h592z m64-166v72q0 24-24 24h-72q-24 0-24-24v-72q0-8 7-16t17-8h72q24 0 24 24z m-200-264q0-66-47-113t-113-47-113 47-47 113q0 68 47 114t113 46 113-46 47-114z" horiz-adv-x="860" />
+<glyph glyph-name="dropbox" unicode="" d="M286 806l194-158-284-184-196 164z m368-754q8 0 12 2l116 78v-46l-302-190-302 190v46l118-78q4-2 12-2 10 0 14 4l158 132 160-132q4-4 14-4z m306 576l-194-164-286 184 196 158z m-480-342l286 178 174-140-282-184z m-176-146l-282 184 174 140 284-178z" horiz-adv-x="960" />
+<glyph glyph-name="evernote" unicode="" d="M750 636q0-4 5-73t9-144-1-171-19-171-51-126-91-51q-154 0-194 26-26 20-18 130 2 40 37 59t69 19l34-2-4-70q-12-2-38-2-20 0-24-26-4-38 40-42l86 4q38 4 28 136-2 16-18 26t-34 13-49 8-47 9q-28 8-46 28t-27 37-11 17-8-58-30-58q-44 0-139 15t-115 35q-34 34-62 149t-28 151q0 34 58 30h116q78 0 78 72 0 12-1 52t-1 60q0 82 40 82 90 0 120-14 18-8 29-26t13-34l4-14 202-12q10 0 25-3t39-19 24-42z m-96-302q6 6-2 32t-29 52-49 26-45-23-21-46 0-29q8-6 15-5t26 5 31 4q14 0 31-6t28-10 15 0z m-482 308q0-22-28-22h-144l176 172q-4-138-4-150z" horiz-adv-x="766" />
+<glyph glyph-name="flattr" unicode="" d="M180 424v-210l-180-180v414q0 302 278 302h442l-312-310q-6-6-10-6-8 0-12 10v128q-98 0-112-2-94-16-94-146z m440 64l180 180v-414q0-304-278-304h-440l312 312q2 6 8 6 8 0 12-10v-128q98 0 112 2 94 16 94 146v210z" horiz-adv-x="800" />
+<glyph glyph-name="skype" unicode="" d="M894 250q26-58 26-118 0-108-75-185t-179-77q-62 0-120 32-52-8-80-8-182 0-311 132t-129 320q0 44 10 90-36 60-36 134 0 108 74 184t180 76q74 0 136-40 32 8 76 8 182 0 310-132t128-320q0-46-10-96z m-204-120q30 46 30 100 0 44-16 80-16 30-50 54-36 22-76 36-68 20-96 26-14 2-35 7t-27 7q-24 8-34 14-16 8-26 22-10 10-10 26 0 24 28 42 26 20 76 20t74-18q26-22 38-50 16-26 26-36 16-12 38-12 26 0 46 20 18 18 18 44 0 20-14 52-16 24-42 48-28 22-74 38-48 14-102 14-72 0-128-22-56-20-86-60t-30-92 28-90q34-40 76-56 48-22 116-36 12-2 29-7t30-8 21-5q28-10 46-28 18-14 18-42 0-34-32-56-36-24-90-24-40 0-64 12-26 14-36 28-24 44-26 46-8 24-24 40-20 14-40 14-28 0-46-18t-18-42q0-38 28-82 26-40 72-66 64-34 158-34 78 0 138 24 60 28 88 70z" horiz-adv-x="920" />
+<glyph glyph-name="skype-circled" unicode="" d="M588 358q20-12 28-30 10-20 10-44 0-32-18-56-12-22-48-40-38-14-78-14-54 0-88 20-22 12-40 36-16 26-16 46 0 14 10 24 14 10 26 10 14 0 22-8 8-4 14-22 2-6 7-15t7-11q6-8 20-16 16-6 36-6 32 0 50 12 18 14 18 32 0 16-10 24-10 10-26 16-6 2-21 5t-23 5q-20 4-66 20-20 10-42 32-16 22-16 52 0 28 18 50 16 22 48 34 30 12 72 12 34 0 56-8 20-4 42-20 18-18 24-28 6-16 6-30t-10-24-24-10q-12 0-22 6-8 8-14 20-10 18-22 28-10 10-42 10-26 0-42-10-16-12-16-24 0-10 6-16 8-8 14-10 4-2 20-8 18-6 34-10 36-8 54-14 28-10 42-20z m-108 472q200 0 340-140t140-340q0-198-140-339t-340-141q-198 0-339 141t-141 339q0 200 141 340t339 140z m116-748q58 0 100 43t42 103q0 34-16 66 6 28 6 54 0 104-72 178t-174 74q-28 0-42-2-34 22-74 22-60 0-102-43t-42-103q0-40 20-76-4-16-4-50 0-104 72-178t172-74q32 0 46 4 30-18 68-18z" horiz-adv-x="960" />
+<glyph glyph-name="renren" unicode="" d="M384 808v-292q-2-150-77-274t-197-184q-110 130-110 296 0 170 110 298t274 156z m76-570q42-174 222-288-102-56-222-56t-220 56q178 114 220 288z m76 280v290q164-28 274-156t110-298q0-168-108-296-124 60-200 184t-76 276z" horiz-adv-x="920" />
+<glyph glyph-name="sina-weibo" unicode="" d="M732 348q118-38 118-136 0-102-127-197t-313-95q-160 0-285 78t-125 196q0 130 146 280 92 92 186 129t134-3q36-36 10-116-4-14 8-14l16 2q74 34 134 34t84-34q24-36-2-100-6-18 16-24z m-322-354q122 12 202 77t72 145q-10 80-100 128t-212 36-202-77-70-145q8-80 98-128t212-36z m586 488v-2q0-14-11-24t-25-10-24 10-10 24q0 96-68 163t-162 67q-16 0-26 10t-10 26q0 34 36 34 124 0 212-87t88-211z m-140 4q4-14-4-27t-22-15q-34-4-42 28-8 38-36 66t-66 36q-34 8-26 40 8 36 42 28 58-12 100-55t54-101z m-528-210q48 10 88-12t48-62q10-40-19-77t-79-45q-48-10-88 12t-48 62 20 76 78 46z" horiz-adv-x="996" />
+<glyph glyph-name="paypal" unicode="" d="M771 610l8-4q38-22 60-62 20-38 20-96 0-130-110-210-106-80-306-80h-30q-16 0-32-12t-20-28l-36-156q-12-42-52-42h-106q-18 0-28 13t-6 29l6 24h68q16 0 32 13t20 29l36 156q10 40 52 40h30q196 0 306 80 110 82 110 210 0 56-22 96z m-580-516q-2-16-18-29t-32-13h-108q-18 0-27 13t-5 29l150 646q10 40 52 40h224q78 0 126-8 56-12 94-34 36-24 58-62 20-38 20-96 0-130-110-210-106-80-304-80h-32q-16 0-32-12t-18-28z m88 374q-4-16 6-28t26-12h28q86 0 134 36 48 34 48 98 0 44-30 64-32 20-94 20h-34q-42 0-52-40z" horiz-adv-x="859" />
+<glyph glyph-name="picasa" unicode="" d="M250 760q10-12 158-144l-396-362q-12 48-12 96 0 130 67 240t183 170z m400 10v-278l-328 296q64 22 138 22 98 0 190-40z m70-40q94-64 147-165t53-215q0-80-26-152h-174v532z m-686-550q12 12 66 60l102 92v-362q-116 80-168 210z m238-250v198h590q-56-100-151-163t-209-75h-84q-84 10-146 40z" horiz-adv-x="920" />
+<glyph glyph-name="soundcloud" unicode="" d="M34 178q0-4-10-4-6 0-10 4l-14 70 14 72q4 4 10 4 10 0 10-4l16-72z m102-38q0-8-12-8t-12 8l-12 108 12 166q0 8 12 8t12-8l14-166z m102 2q0-10-14-10t-14 8l-10 108 10 222q0 10 14 10t14-10l12-222z m102 0q0-10-16-10t-16 10l-8 106 8 224q0 10 16 10t16-10l10-224z m102 2q0-12-18-12-16 0-18 12l-6 104 6 256q4 14 18 14 18 0 18-14l8-256z m72-12q-14 0-14 14v396q0 10 12 14 36 14 84 14 88 0 153-58t73-142q24 10 50 10 52 0 90-37t38-87q0-52-38-89t-90-37z" horiz-adv-x="1000" />
+<glyph glyph-name="mixi" unicode="" d="M477-12q-184 0-319 101t-155 255q-22 170 108 308t336 164 366-77 182-273q14-118-35-244t-165-225-270-117v108h-48z m306 220v276q0 34-10 52-8 18-30 38-16 12-44 20-28 6-56 6-44 0-74-16-24-12-42-30-10 16-36 32-30 14-70 14-66 0-110-38v30h-88v-384h92v236q0 4 4 20 4 10 16 26 10 14 26 20 20 10 40 10 18 0 30-6 8-4 16-10 4-8 8-20 4-16 4-28v-248h90v236q0 36 22 54 22 22 62 22 20 0 32-6 10-2 16-12 8-8 8-18 4-20 4-28v-248h90z" horiz-adv-x="998" />
+<glyph glyph-name="behance" unicode="" d="M404 386q56 0 85-40t31-80v-40q0-56-20-96t-50-58-59-27-49-11h-342v646h322q78 0 127-44t49-128q0-50-23-81t-47-37z m-262 180v-144h170q26 0 40 15t14 61q0 30-11 47t-23 19l-10 2h-180z m172-416q74 0 74 84 0 40-16 62t-32 24l-18 2h-180v-172h172z m468 366q70 0 118-29t67-70 27-82 6-69l-2-30h-320q0-54 27-82t55-28l26-2q46 0 71 17t27 33l2 18h108q0-82-53-124t-105-44l-54-2q-72 0-122 25t-72 62-33 73-11 60v26q0 10 1 27t14 60 36 75 72 59 115 27z m98-194q0 4-1 11t-6 24-13 30-28 24-46 11q-42 0-70-25t-34-51l-6-24h204z m26 320v-78h-256v78h256z" horiz-adv-x="1000" />
+<glyph glyph-name="google-circles" unicode="" d="M556 810q152 0 258-106t106-256q0-142-96-247t-236-115q-34-86-112-141t-172-55q-126 0-215 90t-89 214q0 96 54 173t140 111q12 140 116 236t246 96z m-252-818q118 0 174 100-104 22-179 97t-97 179q-100-56-100-174 0-84 59-143t143-59z m4 404q16-76 70-129t128-69q-2 80-60 138t-138 60z m300-198q88 18 145 88t57 162q0 106-75 180t-179 74q-90 0-161-58t-87-146q124-2 211-89t89-211z m-504 398q-42 0-73 30t-31 72q0 44 31 74t73 30q44 0 74-30t30-74q0-42-30-72t-74-30z m0 160q-24 0-40-17t-16-41q0-22 16-39t40-17 41 17 17 39q0 24-17 41t-41 17z" horiz-adv-x="920" />
+<glyph glyph-name="vkontakte" unicode="" d="M532 302q26-16 26-48 0-36-24-50-14-10-62-10h-52v116h58q38 0 54-8z m-22 100q-14-10-56-10h-34v102h26q50 0 60-6 24-14 24-42t-20-44z m282 428q70 0 119-49t49-119v-622q0-70-49-120t-119-50h-624q-70 0-119 50t-49 120v622q0 70 49 119t119 49h624z m-286-724q84 0 125 42t41 102q0 96-96 116v2q68 22 68 102 0 50-35 79t-85 29h-214v-472h196z" horiz-adv-x="960" />
+<glyph glyph-name="smashing" unicode="" d="M418 286q150-58 160-142 8-60-56-84-22-10-50-10-56 0-110 20t-78 40l-26 18-74-170q64-32 136-56l-80-20q-28-6-52 9t-32 43l-154 646q-6 28 9 53t43 31l186 44q-66-72-60-182 6-78 72-141t166-99z m520-164q8-28-8-53t-44-31l-136-34q42 58 44 136 4 88-54 164t-186 118q-152 52-158 126-6 52 56 72 24 10 54 8 58-2 102-17t60-29l16-14 58 160q-80 42-176 60l134 32q28 6 52-9t32-43z" horiz-adv-x="940" />
+<glyph glyph-name="sweden" unicode="" d="M850 650q20 0 35-15t15-35v-200h-500v250h450z m-850-550v200h300v-250h-260q-40 0-40 50z m400-50v250h500v-200q0-22-14-36t-36-14h-450z m-400 550q0 50 40 50h260v-250h-300v200z" horiz-adv-x="900" />
+<glyph glyph-name="db-shape" unicode="" d="M450 800q276 0 363-88t87-362q0-276-87-363t-363-87q-274 0-362 87t-88 363q0 274 88 362t362 88z" horiz-adv-x="900" />
+<glyph glyph-name="logo-db" unicode="" d="M546 240q48-90-4-180-42-70-115-88t-151 26l-64 36-108-184-56 32 206 358q-68-10-134 28l-120 70 186 324 122-70q66-40 92-100l206 358 58-34-108-186 64-36q76-44 98-119t-20-143q-48-88-152-92z m44 302l-64 38-124-216q0-2-2-6l62-36q52-30 100-17t76 61 15 97-63 79z m-440-222q52-30 100-17t76 61 15 98-63 78l-64 38-128-222z m156-270q52-30 100-17t76 61 14 97-64 79l-62 36-4-4-124-216z" horiz-adv-x="726" />
+</font>
+</defs>
+</svg>
\ No newline at end of file
Binary file web/data/entypo.ttf has changed
Binary file web/data/entypo.woff has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/jquery-migrate.js Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,521 @@
+/*!
+ * jQuery Migrate - v1.2.1 - 2013-05-08
+ * https://github.com/jquery/jquery-migrate
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
+ */
+(function( jQuery, window, undefined ) {
+// See http://bugs.jquery.com/ticket/13335
+// "use strict";
+
+
+var warnedAbout = {};
+
+// List of warnings already given; public read only
+jQuery.migrateWarnings = [];
+
+// Set to true to prevent console output; migrateWarnings still maintained
+// jQuery.migrateMute = false;
+
+// Show a message on the console so devs know we're active
+if ( !jQuery.migrateMute && window.console && window.console.log ) {
+ window.console.log("JQMIGRATE: Logging is active");
+}
+
+// Set to false to disable traces that appear with warnings
+if ( jQuery.migrateTrace === undefined ) {
+ jQuery.migrateTrace = true;
+}
+
+// Forget any warnings we've already given; public
+jQuery.migrateReset = function() {
+ warnedAbout = {};
+ jQuery.migrateWarnings.length = 0;
+};
+
+function migrateWarn( msg) {
+ var console = window.console;
+ if ( !warnedAbout[ msg ] ) {
+ warnedAbout[ msg ] = true;
+ jQuery.migrateWarnings.push( msg );
+ if ( console && console.warn && !jQuery.migrateMute ) {
+ console.warn( "JQMIGRATE: " + msg );
+ if ( jQuery.migrateTrace && console.trace ) {
+ console.trace();
+ }
+ }
+ }
+}
+
+function migrateWarnProp( obj, prop, value, msg ) {
+ if ( Object.defineProperty ) {
+ // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
+ // allow property to be overwritten in case some other plugin wants it
+ try {
+ Object.defineProperty( obj, prop, {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ migrateWarn( msg );
+ return value;
+ },
+ set: function( newValue ) {
+ migrateWarn( msg );
+ value = newValue;
+ }
+ });
+ return;
+ } catch( err ) {
+ // IE8 is a dope about Object.defineProperty, can't warn there
+ }
+ }
+
+ // Non-ES5 (or broken) browser; just set the property
+ jQuery._definePropertyBroken = true;
+ obj[ prop ] = value;
+}
+
+if ( document.compatMode === "BackCompat" ) {
+ // jQuery has never supported or tested Quirks Mode
+ migrateWarn( "jQuery is not compatible with Quirks Mode" );
+}
+
+
+var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
+ oldAttr = jQuery.attr,
+ valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
+ function() { return null; },
+ valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
+ function() { return undefined; },
+ rnoType = /^(?:input|button)$/i,
+ rnoAttrNodeType = /^[238]$/,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ ruseDefault = /^(?:checked|selected)$/i;
+
+// jQuery.attrFn
+migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
+
+jQuery.attr = function( elem, name, value, pass ) {
+ var lowerName = name.toLowerCase(),
+ nType = elem && elem.nodeType;
+
+ if ( pass ) {
+ // Since pass is used internally, we only warn for new jQuery
+ // versions where there isn't a pass arg in the formal params
+ if ( oldAttr.length < 4 ) {
+ migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
+ }
+ if ( elem && !rnoAttrNodeType.test( nType ) &&
+ (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
+ return jQuery( elem )[ name ]( value );
+ }
+ }
+
+ // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
+ // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
+ if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
+ migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
+ }
+
+ // Restore boolHook for boolean property/attribute synchronization
+ if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
+ jQuery.attrHooks[ lowerName ] = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" &&
+ ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+ };
+
+ // Warn only for attributes that can remain distinct from their properties post-1.9
+ if ( ruseDefault.test( lowerName ) ) {
+ migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
+ }
+ }
+
+ return oldAttr.call( jQuery, elem, name, value );
+};
+
+// attrHooks: value
+jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrGet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value') no longer gets properties");
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrSet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+};
+
+
+var matched, browser,
+ oldInit = jQuery.fn.init,
+ oldParseJSON = jQuery.parseJSON,
+ // Note: XSS check is done below after string is trimmed
+ rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
+
+// $(html) "looks like html" rule change
+jQuery.fn.init = function( selector, context, rootjQuery ) {
+ var match;
+
+ if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
+ (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
+ // This is an HTML string according to the "old" rules; is it still?
+ if ( selector.charAt( 0 ) !== "<" ) {
+ migrateWarn("$(html) HTML strings must start with '<' character");
+ }
+ if ( match[ 3 ] ) {
+ migrateWarn("$(html) HTML text after last tag is ignored");
+ }
+ // Consistently reject any HTML-like string starting with a hash (#9521)
+ // Note that this may break jQuery 1.6.x code that otherwise would work.
+ if ( match[ 0 ].charAt( 0 ) === "#" ) {
+ migrateWarn("HTML string cannot start with a '#' character");
+ jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
+ }
+ // Now process using loose rules; let pre-1.8 play too
+ if ( context && context.context ) {
+ // jQuery object as context; parseHTML expects a DOM object
+ context = context.context;
+ }
+ if ( jQuery.parseHTML ) {
+ return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
+ context, rootjQuery );
+ }
+ }
+ return oldInit.apply( this, arguments );
+};
+jQuery.fn.init.prototype = jQuery.fn;
+
+// Let $.parseJSON(falsy_value) return null
+jQuery.parseJSON = function( json ) {
+ if ( !json && json !== null ) {
+ migrateWarn("jQuery.parseJSON requires a valid JSON string");
+ return null;
+ }
+ return oldParseJSON.apply( this, arguments );
+};
+
+jQuery.uaMatch = function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+// Don't clobber any existing jQuery.browser in case it's different
+if ( !jQuery.browser ) {
+ matched = jQuery.uaMatch( navigator.userAgent );
+ browser = {};
+
+ if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+ }
+
+ // Chrome is Webkit, but Webkit is also Safari.
+ if ( browser.chrome ) {
+ browser.webkit = true;
+ } else if ( browser.webkit ) {
+ browser.safari = true;
+ }
+
+ jQuery.browser = browser;
+}
+
+// Warn if the code tries to get jQuery.browser
+migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
+
+jQuery.sub = function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ migrateWarn( "jQuery.sub() is deprecated" );
+ return jQuerySub;
+};
+
+
+// Ensure that $.ajax gets the new parseJSON defined in core.js
+jQuery.ajaxSetup({
+ converters: {
+ "text json": jQuery.parseJSON
+ }
+});
+
+
+var oldFnData = jQuery.fn.data;
+
+jQuery.fn.data = function( name ) {
+ var ret, evt,
+ elem = this[0];
+
+ // Handles 1.7 which has this behavior and 1.8 which doesn't
+ if ( elem && name === "events" && arguments.length === 1 ) {
+ ret = jQuery.data( elem, name );
+ evt = jQuery._data( elem, name );
+ if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
+ migrateWarn("Use of jQuery.fn.data('events') is deprecated");
+ return evt;
+ }
+ }
+ return oldFnData.apply( this, arguments );
+};
+
+
+var rscriptType = /\/(java|ecma)script/i,
+ oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
+
+jQuery.fn.andSelf = function() {
+ migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
+ return oldSelf.apply( this, arguments );
+};
+
+// Since jQuery.clean is used internally on older versions, we only shim if it's missing
+if ( !jQuery.clean ) {
+ jQuery.clean = function( elems, context, fragment, scripts ) {
+ // Set context per 1.8 logic
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ migrateWarn("jQuery.clean() is deprecated");
+
+ var i, elem, handleScript, jsTags,
+ ret = [];
+
+ jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
+
+ // Complex logic lifted directly from jQuery 1.8
+ if ( fragment ) {
+ // Special handling of each script element
+ handleScript = function( elem ) {
+ // Check if we consider it executable
+ if ( !elem.type || rscriptType.test( elem.type ) ) {
+ // Detach the script and store it in the scripts array (if provided) or the fragment
+ // Return truthy to indicate that it has been handled
+ return scripts ?
+ scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+ fragment.appendChild( elem );
+ }
+ };
+
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ // Check if we're done after handling an executable script
+ if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+ // Append to fragment and handle embedded scripts
+ fragment.appendChild( elem );
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+ jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+ // Splice the scripts into ret after their former ancestor and advance our index beyond them
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ i += jsTags.length;
+ }
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var eventAdd = jQuery.event.add,
+ eventRemove = jQuery.event.remove,
+ eventTrigger = jQuery.event.trigger,
+ oldToggle = jQuery.fn.toggle,
+ oldLive = jQuery.fn.live,
+ oldDie = jQuery.fn.die,
+ ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
+ rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
+ rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+ hoverHack = function( events ) {
+ if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
+ return events;
+ }
+ if ( rhoverHack.test( events ) ) {
+ migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
+ }
+ return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+// Event props removed in 1.9, put them back if needed; no practical way to warn them
+if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
+ jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
+}
+
+// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
+if ( jQuery.event.dispatch ) {
+ migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
+}
+
+// Support for 'hover' pseudo-event and ajax event warnings
+jQuery.event.add = function( elem, types, handler, data, selector ){
+ if ( elem !== document && rajaxEvent.test( types ) ) {
+ migrateWarn( "AJAX events should be attached to document: " + types );
+ }
+ eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
+};
+jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
+ eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
+};
+
+jQuery.fn.error = function() {
+ var args = Array.prototype.slice.call( arguments, 0);
+ migrateWarn("jQuery.fn.error() is deprecated");
+ args.splice( 0, 0, "error" );
+ if ( arguments.length ) {
+ return this.bind.apply( this, args );
+ }
+ // error event should not bubble to window, although it does pre-1.7
+ this.triggerHandler.apply( this, args );
+ return this;
+};
+
+jQuery.fn.toggle = function( fn, fn2 ) {
+
+ // Don't mess with animation or css toggles
+ if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
+ return oldToggle.apply( this, arguments );
+ }
+ migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
+
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+};
+
+jQuery.fn.live = function( types, data, fn ) {
+ migrateWarn("jQuery.fn.live() is deprecated");
+ if ( oldLive ) {
+ return oldLive.apply( this, arguments );
+ }
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+};
+
+jQuery.fn.die = function( types, fn ) {
+ migrateWarn("jQuery.fn.die() is deprecated");
+ if ( oldDie ) {
+ return oldDie.apply( this, arguments );
+ }
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+};
+
+// Turn global events into document-triggered events
+jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
+ if ( !elem && !rajaxEvent.test( event ) ) {
+ migrateWarn( "Global events are undocumented and deprecated" );
+ }
+ return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
+};
+jQuery.each( ajaxEvents.split("|"),
+ function( _, name ) {
+ jQuery.event.special[ name ] = {
+ setup: function() {
+ var elem = this;
+
+ // The document needs no shimming; must be !== for oldIE
+ if ( elem !== document ) {
+ jQuery.event.add( document, name + "." + jQuery.guid, function() {
+ jQuery.event.trigger( name, null, elem, true );
+ });
+ jQuery._data( this, name, jQuery.guid++ );
+ }
+ return false;
+ },
+ teardown: function() {
+ if ( this !== document ) {
+ jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
+ }
+ return false;
+ }
+ };
+ }
+);
+
+
+})( jQuery, window );
--- a/web/data/jquery.corner.js Tue Jul 02 17:09:04 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-/*!
- * jQuery corner plugin: simple corner rounding
- * Examples and documentation at: http://jquery.malsup.com/corner/
- * version 2.11 (15-JUN-2010)
- * Requires jQuery v1.3.2 or later
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- * Authors: Dave Methvin and Mike Alsup
- */
-
-/**
- * corner() takes a single string argument: $('#myDiv').corner("effect corners width")
- *
- * effect: name of the effect to apply, such as round, bevel, notch, bite, etc (default is round).
- * corners: one or more of: top, bottom, tr, tl, br, or bl. (default is all corners)
- * width: width of the effect; in the case of rounded corners this is the radius.
- * specify this value using the px suffix such as 10px (yes, it must be pixels).
- */
-;(function($) {
-
-var style = document.createElement('div').style,
- moz = style['MozBorderRadius'] !== undefined,
- webkit = style['WebkitBorderRadius'] !== undefined,
- radius = style['borderRadius'] !== undefined || style['BorderRadius'] !== undefined,
- mode = document.documentMode || 0,
- noBottomFold = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8),
-
- expr = $.browser.msie && (function() {
- var div = document.createElement('div');
- try { div.style.setExpression('width','0+0'); div.style.removeExpression('width'); }
- catch(e) { return false; }
- return true;
- })();
-
-$.support = $.support || {};
-$.support.borderRadius = moz || webkit || radius; // so you can do: if (!$.support.borderRadius) $('#myDiv').corner();
-
-function sz(el, p) {
- return parseInt($.css(el,p))||0;
-};
-function hex2(s) {
- var s = parseInt(s).toString(16);
- return ( s.length < 2 ) ? '0'+s : s;
-};
-function gpc(node) {
- while(node) {
- var v = $.css(node,'backgroundColor'), rgb;
- if (v && v != 'transparent' && v != 'rgba(0, 0, 0, 0)') {
- if (v.indexOf('rgb') >= 0) {
- rgb = v.match(/\d+/g);
- return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
- }
- return v;
- }
- if (node.nodeName.toLowerCase() == 'html')
- break;
- node = node.parentNode; // keep walking if transparent
- }
- return '#ffffff';
-};
-
-function getWidth(fx, i, width) {
- switch(fx) {
- case 'round': return Math.round(width*(1-Math.cos(Math.asin(i/width))));
- case 'cool': return Math.round(width*(1+Math.cos(Math.asin(i/width))));
- case 'sharp': return Math.round(width*(1-Math.cos(Math.acos(i/width))));
- case 'bite': return Math.round(width*(Math.cos(Math.asin((width-i-1)/width))));
- case 'slide': return Math.round(width*(Math.atan2(i,width/i)));
- case 'jut': return Math.round(width*(Math.atan2(width,(width-i-1))));
- case 'curl': return Math.round(width*(Math.atan(i)));
- case 'tear': return Math.round(width*(Math.cos(i)));
- case 'wicked': return Math.round(width*(Math.tan(i)));
- case 'long': return Math.round(width*(Math.sqrt(i)));
- case 'sculpt': return Math.round(width*(Math.log((width-i-1),width)));
- case 'dogfold':
- case 'dog': return (i&1) ? (i+1) : width;
- case 'dog2': return (i&2) ? (i+1) : width;
- case 'dog3': return (i&3) ? (i+1) : width;
- case 'fray': return (i%2)*width;
- case 'notch': return width;
- case 'bevelfold':
- case 'bevel': return i+1;
- }
-};
-
-$.fn.corner = function(options) {
- // in 1.3+ we can fix mistakes with the ready state
- if (this.length == 0) {
- if (!$.isReady && this.selector) {
- var s = this.selector, c = this.context;
- $(function() {
- $(s,c).corner(options);
- });
- }
- return this;
- }
-
- return this.each(function(index){
- var $this = $(this),
- // meta values override options
- o = [$this.attr($.fn.corner.defaults.metaAttr) || '', options || ''].join(' ').toLowerCase(),
- keep = /keep/.test(o), // keep borders?
- cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]), // corner color
- sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]), // strip color
- width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10, // corner width
- re = /round|bevelfold|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dogfold|dog/,
- fx = ((o.match(re)||['round'])[0]),
- fold = /dogfold|bevelfold/.test(o),
- edges = { T:0, B:1 },
- opts = {
- TL: /top|tl|left/.test(o), TR: /top|tr|right/.test(o),
- BL: /bottom|bl|left/.test(o), BR: /bottom|br|right/.test(o)
- },
- // vars used in func later
- strip, pad, cssHeight, j, bot, d, ds, bw, i, w, e, c, common, $horz;
-
- if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
- opts = { TL:1, TR:1, BL:1, BR:1 };
-
- // support native rounding
- if ($.fn.corner.defaults.useNative && fx == 'round' && (radius || moz || webkit) && !cc && !sc) {
- if (opts.TL)
- $this.css(radius ? 'border-top-left-radius' : moz ? '-moz-border-radius-topleft' : '-webkit-border-top-left-radius', width + 'px');
- if (opts.TR)
- $this.css(radius ? 'border-top-right-radius' : moz ? '-moz-border-radius-topright' : '-webkit-border-top-right-radius', width + 'px');
- if (opts.BL)
- $this.css(radius ? 'border-bottom-left-radius' : moz ? '-moz-border-radius-bottomleft' : '-webkit-border-bottom-left-radius', width + 'px');
- if (opts.BR)
- $this.css(radius ? 'border-bottom-right-radius' : moz ? '-moz-border-radius-bottomright' : '-webkit-border-bottom-right-radius', width + 'px');
- return;
- }
-
- strip = document.createElement('div');
- $(strip).css({
- overflow: 'hidden',
- height: '1px',
- minHeight: '1px',
- fontSize: '1px',
- backgroundColor: sc || 'transparent',
- borderStyle: 'solid'
- });
-
- pad = {
- T: parseInt($.css(this,'paddingTop'))||0, R: parseInt($.css(this,'paddingRight'))||0,
- B: parseInt($.css(this,'paddingBottom'))||0, L: parseInt($.css(this,'paddingLeft'))||0
- };
-
- if (typeof this.style.zoom != undefined) this.style.zoom = 1; // force 'hasLayout' in IE
- if (!keep) this.style.border = 'none';
- strip.style.borderColor = cc || gpc(this.parentNode);
- cssHeight = $(this).outerHeight();
-
- for (j in edges) {
- bot = edges[j];
- // only add stips if needed
- if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) {
- strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none');
- d = document.createElement('div');
- $(d).addClass('jquery-corner');
- ds = d.style;
-
- bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild);
-
- if (bot && cssHeight != 'auto') {
- if ($.css(this,'position') == 'static')
- this.style.position = 'relative';
- ds.position = 'absolute';
- ds.bottom = ds.left = ds.padding = ds.margin = '0';
- if (expr)
- ds.setExpression('width', 'this.parentNode.offsetWidth');
- else
- ds.width = '100%';
- }
- else if (!bot && $.browser.msie) {
- if ($.css(this,'position') == 'static')
- this.style.position = 'relative';
- ds.position = 'absolute';
- ds.top = ds.left = ds.right = ds.padding = ds.margin = '0';
-
- // fix ie6 problem when blocked element has a border width
- if (expr) {
- bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
- ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"');
- }
- else
- ds.width = '100%';
- }
- else {
- ds.position = 'relative';
- ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' :
- (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px';
- }
-
- for (i=0; i < width; i++) {
- w = Math.max(0,getWidth(fx,i, width));
- e = strip.cloneNode(false);
- e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px';
- bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild);
- }
-
- if (fold && $.support.boxModel) {
- if (bot && noBottomFold) continue;
- for (c in opts) {
- if (!opts[c]) continue;
- if (bot && (c == 'TL' || c == 'TR')) continue;
- if (!bot && (c == 'BL' || c == 'BR')) continue;
-
- common = { position: 'absolute', border: 'none', margin: 0, padding: 0, overflow: 'hidden', backgroundColor: strip.style.borderColor };
- $horz = $('<div/>').css(common).css({ width: width + 'px', height: '1px' });
- switch(c) {
- case 'TL': $horz.css({ bottom: 0, left: 0 }); break;
- case 'TR': $horz.css({ bottom: 0, right: 0 }); break;
- case 'BL': $horz.css({ top: 0, left: 0 }); break;
- case 'BR': $horz.css({ top: 0, right: 0 }); break;
- }
- d.appendChild($horz[0]);
-
- var $vert = $('<div/>').css(common).css({ top: 0, bottom: 0, width: '1px', height: width + 'px' });
- switch(c) {
- case 'TL': $vert.css({ left: width }); break;
- case 'TR': $vert.css({ right: width }); break;
- case 'BL': $vert.css({ left: width }); break;
- case 'BR': $vert.css({ right: width }); break;
- }
- d.appendChild($vert[0]);
- }
- }
- }
- }
- });
-};
-
-$.fn.uncorner = function() {
- if (radius || moz || webkit)
- this.css(radius ? 'border-radius' : moz ? '-moz-border-radius' : '-webkit-border-radius', 0);
- $('div.jquery-corner', this).remove();
- return this;
-};
-
-// expose options
-$.fn.corner.defaults = {
- useNative: true, // true if plugin should attempt to use native browser support for border radius rounding
- metaAttr: 'data-corner' // name of meta attribute to use for options
-};
-
-})(jQuery);
--- a/web/data/jquery.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/jquery.js Mon Jan 13 13:47:47 2014 +0100
@@ -1,31 +1,38 @@
/*!
- * jQuery JavaScript Library v1.6.4
+ * jQuery JavaScript Library v1.10.2
* http://jquery.com/
*
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
* Includes Sizzle.js
* http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
*
- * Date: Mon Sep 12 18:54:48 2011 -0400
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-07-03T13:48Z
*/
(function( window, undefined ) {
-// Use the correct document accordingly with window argument (sandbox)
-var document = window.document,
- navigator = window.navigator,
- location = window.location;
-var jQuery = (function() {
-
-// Define a local copy of jQuery
-var jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context, rootjQuery );
- },
+// Can't do this because several apps including ASP.NET trace
+// the stack via arguments.caller.callee and Firefox dies if
+// you try to trace through "use strict" call chains. (#13335)
+// Support: Firefox 18+
+//"use strict";
+var
+ // The deferred used on DOM ready
+ readyList,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // Support: IE<10
+ // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
+ core_strundefined = typeof undefined,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ location = window.location,
+ document = window.document,
+ docElem = document.documentElement,
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
@@ -33,136 +40,136 @@
// Map over the $ in case of overwrite
_$ = window.$,
- // A central reference to the root jQuery(document)
- rootjQuery,
-
- // A simple way to check for HTML strings or ID strings
+ // [[Class]] -> type pairs
+ class2type = {},
+
+ // List of deleted data cache ids, so we can reuse them
+ core_deletedIds = [],
+
+ core_version = "1.10.2",
+
+ // Save a reference to some core methods
+ core_concat = core_deletedIds.concat,
+ core_push = core_deletedIds.push,
+ core_slice = core_deletedIds.slice,
+ core_indexOf = core_deletedIds.indexOf,
+ core_toString = class2type.toString,
+ core_hasOwn = class2type.hasOwnProperty,
+ core_trim = core_version.trim,
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Used for matching numbers
+ core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
+
+ // Used for splitting on whitespace
+ core_rnotwhite = /\S+/g,
+
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+
+ // A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
- quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
-
- // Check if a string has a non-whitespace character in it
- rnotwhite = /\S/,
-
- // Used for trimming whitespace
- trimLeft = /^\s+/,
- trimRight = /\s+$/,
-
- // Check for digits
- rdigit = /\d/,
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
// Match a standalone tag
- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
// JSON RegExp
rvalidchars = /^[\],:{}\s]*$/,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
-
- // Useragent RegExp
- rwebkit = /(webkit)[ \/]([\w.]+)/,
- ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
- rmsie = /(msie) ([\w.]+)/,
- rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
// Matches dashed string for camelizing
- rdashAlpha = /-([a-z]|[0-9])/ig,
rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([\da-z])/gi,
// Used by jQuery.camelCase as callback to replace()
fcamelCase = function( all, letter ) {
- return ( letter + "" ).toUpperCase();
- },
-
- // Keep a UserAgent string for use with jQuery.browser
- userAgent = navigator.userAgent,
-
- // For matching the engine and version of the browser
- browserMatch,
-
- // The deferred used on DOM ready
- readyList,
+ return letter.toUpperCase();
+ },
// The ready event handler
- DOMContentLoaded,
-
- // Save a reference to some core methods
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- push = Array.prototype.push,
- slice = Array.prototype.slice,
- trim = String.prototype.trim,
- indexOf = Array.prototype.indexOf,
-
- // [[Class]] -> type pairs
- class2type = {};
+ completed = function( event ) {
+
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+ },
+ // Clean-up method for dom ready events
+ detach = function() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+ };
jQuery.fn = jQuery.prototype = {
+ // The current version of jQuery being used
+ jquery: core_version,
+
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
- var match, elem, ret, doc;
-
- // Handle $(""), $(null), or $(undefined)
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
if ( !selector ) {
return this;
}
- // Handle $(DOMElement)
- if ( selector.nodeType ) {
- this.context = this[0] = selector;
- this.length = 1;
- return this;
- }
-
- // The body element only exists once, optimize finding it
- if ( selector === "body" && !context && document.body ) {
- this.context = document;
- this[0] = document.body;
- this.selector = selector;
- this.length = 1;
- return this;
- }
-
// Handle HTML strings
if ( typeof selector === "string" ) {
- // Are we dealing with HTML string or an ID?
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
- match = quickExpr.exec( selector );
- }
-
- // Verify a match, and that no context was specified for #id
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
- doc = (context ? context.ownerDocument || context : document);
-
- // If a single string is passed in and it's a single tag
- // just do a createElement and skip the rest
- ret = rsingleTag.exec( selector );
-
- if ( ret ) {
- if ( jQuery.isPlainObject( context ) ) {
- selector = [ document.createElement( ret[1] ) ];
- jQuery.fn.attr.call( selector, context, true );
-
- } else {
- selector = [ doc.createElement( ret[1] ) ];
+
+ // scripts is true for back-compat
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
}
-
- } else {
- ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
- selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
}
- return jQuery.merge( this, selector );
-
- // HANDLE: $("#id")
+ return this;
+
+ // HANDLE: $(#id)
} else {
elem = document.getElementById( match[2] );
@@ -187,7 +194,7 @@
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
- return (context || rootjQuery).find( selector );
+ return ( context || rootjQuery ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
@@ -195,13 +202,19 @@
return this.constructor( context ).find( selector );
}
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
- if (selector.selector !== undefined) {
+ if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
@@ -212,19 +225,11 @@
// Start with an empty selector
selector: "",
- // The current version of jQuery being used
- jquery: "1.6.4",
-
// The default length of a jQuery object is 0
length: 0,
- // The number of elements contained in the matched element set
- size: function() {
- return this.length;
- },
-
toArray: function() {
- return slice.call( this, 0 );
+ return core_slice.call( this );
},
// Get the Nth element in the matched element set OR
@@ -241,28 +246,15 @@
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
- pushStack: function( elems, name, selector ) {
+ pushStack: function( elems ) {
+
// Build a new jQuery matched element set
- var ret = this.constructor();
-
- if ( jQuery.isArray( elems ) ) {
- push.apply( ret, elems );
-
- } else {
- jQuery.merge( ret, elems );
- }
+ var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
-
ret.context = this.context;
- if ( name === "find" ) {
- ret.selector = this.selector + (this.selector ? " " : "") + selector;
- } else if ( name ) {
- ret.selector = this.selector + "." + name + "(" + selector + ")";
- }
-
// Return the newly-formed element set
return ret;
},
@@ -275,19 +267,14 @@
},
ready: function( fn ) {
- // Attach the listeners
- jQuery.bindReady();
-
// Add the callback
- readyList.done( fn );
+ jQuery.ready.promise().done( fn );
return this;
},
- eq: function( i ) {
- return i === -1 ?
- this.slice( i ) :
- this.slice( i, +i + 1 );
+ slice: function() {
+ return this.pushStack( core_slice.apply( this, arguments ) );
},
first: function() {
@@ -298,9 +285,10 @@
return this.eq( -1 );
},
- slice: function() {
- return this.pushStack( slice.apply( this, arguments ),
- "slice", slice.call(arguments).join(",") );
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
},
map: function( callback ) {
@@ -315,7 +303,7 @@
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
- push: push,
+ push: core_push,
sort: [].sort,
splice: [].splice
};
@@ -324,7 +312,7 @@
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
- var options, name, src, copy, copyIsArray, clone,
+ var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
@@ -388,6 +376,10 @@
};
jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
+
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
@@ -418,73 +410,31 @@
// Handle when the DOM is ready
ready: function( wait ) {
- // Either a released hold or an DOMready/load event and not yet ready
- if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( !document.body ) {
- return setTimeout( jQuery.ready, 1 );
- }
-
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If a normal DOM Ready event fired, decrement, and wait if need be
- if ( wait !== true && --jQuery.readyWait > 0 ) {
- return;
- }
-
- // If there are functions bound, to execute
- readyList.resolveWith( document, [ jQuery ] );
-
- // Trigger any bound ready events
- if ( jQuery.fn.trigger ) {
- jQuery( document ).trigger( "ready" ).unbind( "ready" );
- }
- }
- },
-
- bindReady: function() {
- if ( readyList ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
- readyList = jQuery._Deferred();
-
- // Catch cases where $(document).ready() is called after the
- // browser event has already occurred.
- if ( document.readyState === "complete" ) {
- // Handle it asynchronously to allow scripts the opportunity to delay ready
- return setTimeout( jQuery.ready, 1 );
- }
-
- // Mozilla, Opera and webkit nightlies currently support this event
- if ( document.addEventListener ) {
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
-
- // A fallback to window.onload, that will always work
- window.addEventListener( "load", jQuery.ready, false );
-
- // If IE event model is used
- } else if ( document.attachEvent ) {
- // ensure firing before onload,
- // maybe late but safe also for iframes
- document.attachEvent( "onreadystatechange", DOMContentLoaded );
-
- // A fallback to window.onload, that will always work
- window.attachEvent( "onload", jQuery.ready );
-
- // If IE and not a frame
- // continually check to see if the document is ready
- var toplevel = false;
-
- try {
- toplevel = window.frameElement == null;
- } catch(e) {}
-
- if ( document.documentElement.doScroll && toplevel ) {
- doScrollCheck();
- }
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger("ready").off("ready");
}
},
@@ -499,22 +449,27 @@
return jQuery.type(obj) === "array";
},
- // A crude way of determining if an object is a window
isWindow: function( obj ) {
- return obj && typeof obj === "object" && "setInterval" in obj;
- },
-
- isNaN: function( obj ) {
- return obj == null || !rdigit.test( obj ) || isNaN( obj );
+ /* jshint eqeqeq: false */
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
},
type: function( obj ) {
- return obj == null ?
- String( obj ) :
- class2type[ toString.call(obj) ] || "object";
+ if ( obj == null ) {
+ return String( obj );
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ core_toString.call(obj) ] || "object" :
+ typeof obj;
},
isPlainObject: function( obj ) {
+ var key;
+
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
@@ -525,8 +480,8 @@
try {
// Not own constructor property must be Object
if ( obj.constructor &&
- !hasOwn.call(obj, "constructor") &&
- !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ !core_hasOwn.call(obj, "constructor") &&
+ !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
} catch ( e ) {
@@ -534,54 +489,97 @@
return false;
}
+ // Support: IE<9
+ // Handle iteration over inherited properties before own properties.
+ if ( jQuery.support.ownLast ) {
+ for ( key in obj ) {
+ return core_hasOwn.call( obj, key );
+ }
+ }
+
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
-
- var key;
for ( key in obj ) {}
- return key === undefined || hasOwn.call( obj, key );
+ return key === undefined || core_hasOwn.call( obj, key );
},
isEmptyObject: function( obj ) {
- for ( var name in obj ) {
+ var name;
+ for ( name in obj ) {
return false;
}
return true;
},
error: function( msg ) {
- throw msg;
+ throw new Error( msg );
+ },
+
+ // data: string of html
+ // context (optional): If specified, the fragment will be created in this context, defaults to document
+ // keepScripts (optional): If true, will include scripts passed in the html string
+ parseHTML: function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+ if ( scripts ) {
+ jQuery( scripts ).remove();
+ }
+ return jQuery.merge( [], parsed.childNodes );
},
parseJSON: function( data ) {
- if ( typeof data !== "string" || !data ) {
- return null;
- }
-
- // Make sure leading/trailing whitespace is removed (IE can't handle it)
- data = jQuery.trim( data );
-
// Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
}
- // Make sure the incoming data is actual JSON
- // Logic borrowed from http://json.org/json2.js
- if ( rvalidchars.test( data.replace( rvalidescape, "@" )
- .replace( rvalidtokens, "]" )
- .replace( rvalidbraces, "")) ) {
-
- return (new Function( "return " + data ))();
-
- }
+ if ( data === null ) {
+ return data;
+ }
+
+ if ( typeof data === "string" ) {
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+ }
+ }
+ }
+
jQuery.error( "Invalid JSON: " + data );
},
// Cross-browser xml parsing
parseXML: function( data ) {
var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
try {
if ( window.DOMParser ) { // Standard
tmp = new DOMParser();
@@ -606,7 +604,7 @@
// Workarounds based on findings by Jim Driscoll
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
globalEval: function( data ) {
- if ( data && rnotwhite.test( data ) ) {
+ if ( data && jQuery.trim( data ) ) {
// We use execScript on Internet Explorer
// We use an anonymous function so that context is window
// rather than jQuery in Firefox
@@ -623,25 +621,30 @@
},
nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
// args is for internal usage only
- each: function( object, callback, args ) {
- var name, i = 0,
- length = object.length,
- isObj = length === undefined || jQuery.isFunction( object );
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
if ( args ) {
- if ( isObj ) {
- for ( name in object ) {
- if ( callback.apply( object[ name ], args ) === false ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
break;
}
}
} else {
- for ( ; i < length; ) {
- if ( callback.apply( object[ i++ ], args ) === false ) {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
break;
}
}
@@ -649,72 +652,77 @@
// A special, fast, case for the most common use of each
} else {
- if ( isObj ) {
- for ( name in object ) {
- if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
break;
}
}
} else {
- for ( ; i < length; ) {
- if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
break;
}
}
}
}
- return object;
+ return obj;
},
// Use native String.trim function wherever possible
- trim: trim ?
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
function( text ) {
return text == null ?
"" :
- trim.call( text );
+ core_trim.call( text );
} :
// Otherwise use our own trimming functionality
function( text ) {
return text == null ?
"" :
- text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+ ( text + "" ).replace( rtrim, "" );
},
// results is for internal usage only
- makeArray: function( array, results ) {
+ makeArray: function( arr, results ) {
var ret = results || [];
- if ( array != null ) {
- // The window, strings (and functions) also have 'length'
- // The extra typeof function check is to prevent crashes
- // in Safari 2 (See: #3039)
- // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
- var type = jQuery.type( array );
-
- if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
- push.call( ret, array );
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
} else {
- jQuery.merge( ret, array );
+ core_push.call( ret, arr );
}
}
return ret;
},
- inArray: function( elem, array ) {
- if ( !array ) {
- return -1;
- }
-
- if ( indexOf ) {
- return indexOf.call( array, elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( core_indexOf ) {
+ return core_indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
}
}
@@ -722,14 +730,14 @@
},
merge: function( first, second ) {
- var i = first.length,
+ var l = second.length,
+ i = first.length,
j = 0;
- if ( typeof second.length === "number" ) {
- for ( var l = second.length; j < l; j++ ) {
+ if ( typeof l === "number" ) {
+ for ( ; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
-
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
@@ -742,12 +750,15 @@
},
grep: function( elems, callback, inv ) {
- var ret = [], retVal;
+ var retVal,
+ ret = [],
+ i = 0,
+ length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
- for ( var i = 0, length = elems.length; i < length; i++ ) {
+ for ( ; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
@@ -759,11 +770,11 @@
// arg is for internal usage only
map: function( elems, callback, arg ) {
- var value, key, ret = [],
+ var value,
i = 0,
length = elems.length,
- // jquery objects are treated as arrays
- isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+ isArray = isArraylike( elems ),
+ ret = [];
// Go through the array, translating each of the items to their
if ( isArray ) {
@@ -777,8 +788,8 @@
// Go through every key on the object,
} else {
- for ( key in elems ) {
- value = callback( elems[ key ], key, arg );
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
@@ -787,7 +798,7 @@
}
// Flatten any nested arrays
- return ret.concat.apply( [], ret );
+ return core_concat.apply( [], ret );
},
// A global GUID counter for objects
@@ -796,8 +807,10 @@
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
if ( typeof context === "string" ) {
- var tmp = fn[ context ];
+ tmp = fn[ context ];
context = fn;
fn = tmp;
}
@@ -809,443 +822,2576 @@
}
// Simulated bind
- var args = slice.call( arguments, 2 ),
- proxy = function() {
- return fn.apply( context, args.concat( slice.call( arguments ) ) );
- };
+ args = core_slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
+ };
// Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
},
- // Mutifunctional method to get and set values to a collection
+ // Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
- access: function( elems, key, value, exec, fn, pass ) {
- var length = elems.length;
-
- // Setting many attributes
- if ( typeof key === "object" ) {
- for ( var k in key ) {
- jQuery.access( elems, k, key[k], exec, fn, value );
- }
- return elems;
- }
-
- // Setting one attribute
- if ( value !== undefined ) {
- // Optionally, function values get executed if exec is true
- exec = !pass && exec && jQuery.isFunction(value);
-
- for ( var i = 0; i < length; i++ ) {
- fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
- }
-
- return elems;
- }
-
- // Getting an attribute
- return length ? fn( elems[0], key ) : undefined;
+ access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
},
now: function() {
- return (new Date()).getTime();
- },
-
- // Use of jQuery.browser is frowned upon.
- // More details: http://docs.jquery.com/Utilities/jQuery.browser
- uaMatch: function( ua ) {
- ua = ua.toLowerCase();
-
- var match = rwebkit.exec( ua ) ||
- ropera.exec( ua ) ||
- rmsie.exec( ua ) ||
- ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
- [];
-
- return { browser: match[1] || "", version: match[2] || "0" };
- },
-
- sub: function() {
- function jQuerySub( selector, context ) {
- return new jQuerySub.fn.init( selector, context );
- }
- jQuery.extend( true, jQuerySub, this );
- jQuerySub.superclass = this;
- jQuerySub.fn = jQuerySub.prototype = this();
- jQuerySub.fn.constructor = jQuerySub;
- jQuerySub.sub = this.sub;
- jQuerySub.fn.init = function init( selector, context ) {
- if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
- context = jQuerySub( context );
- }
-
- return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
- };
- jQuerySub.fn.init.prototype = jQuerySub.fn;
- var rootjQuerySub = jQuerySub(document);
- return jQuerySub;
- },
-
- browser: {}
+ return ( new Date() ).getTime();
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations.
+ // Note: this method belongs to the css module but it's needed here for the support module.
+ // If support gets modularized, this method should be moved back to the css module.
+ swap: function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
});
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
-browserMatch = jQuery.uaMatch( userAgent );
-if ( browserMatch.browser ) {
- jQuery.browser[ browserMatch.browser ] = true;
- jQuery.browser.version = browserMatch.version;
-}
-
-// Deprecated, use jQuery.browser.webkit instead
-if ( jQuery.browser.webkit ) {
- jQuery.browser.safari = true;
-}
-
-// IE doesn't match non-breaking spaces with \s
-if ( rnotwhite.test( "\xA0" ) ) {
- trimLeft = /^[\s\xA0]+/;
- trimRight = /[\s\xA0]+$/;
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || type !== "function" &&
+ ( length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj );
}
// All jQuery objects should point back to these
rootjQuery = jQuery(document);
-
-// Cleanup functions for the document ready method
-if ( document.addEventListener ) {
- DOMContentLoaded = function() {
- document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
- jQuery.ready();
+/*!
+ * Sizzle CSS Selector Engine v1.10.2
+ * http://sizzlejs.com/
+ *
+ * Copyright 2013 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2013-07-03
+ */
+(function( window, undefined ) {
+
+var i,
+ support,
+ cachedruns,
+ Expr,
+ getText,
+ isXML,
+ compile,
+ outermostContext,
+ sortInput,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + -(new Date()),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ hasDuplicate = false,
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ strundefined = typeof undefined,
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf if we can't use a native one
+ indexOf = arr.indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments quoted,
+ // then not containing pseudos/brackets,
+ // then attribute selectors/non-parenthetical expressions,
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rsibling = new RegExp( whitespace + "*[+~]" ),
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ // BMP codepoint
+ high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
};
-} else if ( document.attachEvent ) {
- DOMContentLoaded = function() {
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( document.readyState === "complete" ) {
- document.detachEvent( "onreadystatechange", DOMContentLoaded );
- jQuery.ready();
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
}
};
}
-// The DOM ready check for Internet Explorer
-function doScrollCheck() {
- if ( jQuery.isReady ) {
- return;
- }
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( documentIsHTML && !seed ) {
+
+ // Shortcuts
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && context.parentNode || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key += " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
try {
- // If IE is used, use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- document.documentElement.doScroll("left");
- } catch(e) {
- setTimeout( doScrollCheck, 1 );
- return;
- }
-
- // and execute any waiting functions
- jQuery.ready();
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
}
-return jQuery;
-
-})();
-
-
-var // Promise methods
- promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
- // Static reference to slice
- sliceDeferred = [].slice;
-
-jQuery.extend({
- // Create a simple deferred (one callbacks list)
- _Deferred: function() {
- var // callbacks list
- callbacks = [],
- // stored [ context , args ]
- fired,
- // to avoid firing when already doing so
- firing,
- // flag to know if the deferred has been cancelled
- cancelled,
- // the deferred itself
- deferred = {
-
- // done( f1, f2, ...)
- done: function() {
- if ( !cancelled ) {
- var args = arguments,
- i,
- length,
- elem,
- type,
- _fired;
- if ( fired ) {
- _fired = fired;
- fired = 0;
+/**
+ * Detect xml
+ * @param {Element|Object} elem An element or a document
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var doc = node ? node.ownerDocument || node : preferredDoc,
+ parent = doc.defaultView;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+
+ // Support tests
+ documentIsHTML = !isXML( doc );
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent.attachEvent && parent !== parent.top ) {
+ parent.attachEvent( "onbeforeunload", function() {
+ setDocument();
+ });
+ }
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Check if getElementsByClassName can be trusted
+ support.getElementsByClassName = assert(function( div ) {
+ div.innerHTML = "<div class='a'></div><div class='a i'></div>";
+
+ // Support: Safari<4
+ // Catch class over-caching
+ div.firstChild.className = "i";
+ // Support: Opera<10
+ // Catch gEBCN failure to find non-leading classes
+ return div.getElementsByClassName("i").length === 2;
+ });
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "<select><option selected=''></option></select>";
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+
+ // Support: Opera 10-12/IE8
+ // ^= $= *= and empty values
+ // Should not select anything
+ // Support: Windows 8 Native Apps
+ // The type attribute is restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "t", "" );
+
+ if ( div.querySelectorAll("[t^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = docElem.compareDocumentPosition ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
+
+ if ( compare ) {
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ }
+
+ // Not directly comparable, sort on existence of method
+ return a.compareDocumentPosition ? -1 : 1;
+ } :
+ function( a, b ) {
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Parentless nodes are either documents or disconnected
+ } else if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, document, null, [elem] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val === undefined ?
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null :
+ val;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ for ( ; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[5] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] && match[4] !== undefined ) {
+ match[2] = match[4];
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
}
- for ( i = 0, length = args.length; i < length; i++ ) {
- elem = args[ i ];
- type = jQuery.type( elem );
- if ( type === "array" ) {
- deferred.done.apply( deferred, elem );
- } else if ( type === "function" ) {
- callbacks.push( elem );
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
}
}
- if ( _fired ) {
- deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
- }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
}
- return this;
- },
-
- // resolve with given context and args
- resolveWith: function( context, args ) {
- if ( !cancelled && !fired && !firing ) {
- // make sure args are available (#8421)
- args = args || [];
- firing = 1;
- try {
- while( callbacks[ 0 ] ) {
- callbacks.shift().apply( context, args );
- }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
}
- finally {
- fired = [ context, args ];
- firing = 0;
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
}
}
- return this;
- },
-
- // resolve with this as context and given arguments
- resolve: function() {
- deferred.resolveWith( this, arguments );
- return this;
- },
-
- // Has this deferred been resolved?
- isResolved: function() {
- return !!( firing || fired );
- },
-
- // Cancel
- cancel: function() {
- cancelled = 1;
- callbacks = [];
- return this;
- }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
};
-
- return deferred;
- },
-
- // Full fledged deferred (two callbacks list)
- Deferred: function( func ) {
- var deferred = jQuery._Deferred(),
- failDeferred = jQuery._Deferred(),
- promise;
- // Add errorDeferred methods, then and promise
- jQuery.extend( deferred, {
- then: function( doneCallbacks, failCallbacks ) {
- deferred.done( doneCallbacks ).fail( failCallbacks );
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( tokens = [] );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var data, cache, outerCache,
+ dirkey = dirruns + " " + doneName;
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
+ if ( (data = cache[1]) === true || data === cachedruns ) {
+ return data === true;
+ }
+ } else {
+ cache = outerCache[ dir ] = [ dirkey ];
+ cache[1] = matcher( elem, context, xml ) || cachedruns;
+ if ( cache[1] === true ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ // A counter to specify which element is currently being matched
+ var matcherCachedRuns = 0,
+ bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, expandContext ) {
+ var elem, j, matcher,
+ setMatched = [],
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ outermost = expandContext != null,
+ contextBackup = outermostContext,
+ // We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ cachedruns = matcherCachedRuns;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ cachedruns = ++matcherCachedRuns;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector );
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+ }
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && context.parentNode || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector )
+ );
+ return results;
+}
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome<14
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = "<input/>";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ elem[ name ] === true ? name.toLowerCase() : null;
+ }
+ });
+}
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})( window );
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
return this;
},
- always: function() {
- return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
},
- fail: failDeferred.done,
- rejectWith: failDeferred.resolveWith,
- reject: failDeferred.resolve,
- isRejected: failDeferred.isResolved,
- pipe: function( fnDone, fnFail ) {
- return jQuery.Deferred(function( newDefer ) {
- jQuery.each( {
- done: [ fnDone, "resolve" ],
- fail: [ fnFail, "reject" ]
- }, function( handler, data ) {
- var fn = data[ 0 ],
- action = data[ 1 ],
- returned;
- if ( jQuery.isFunction( fn ) ) {
- deferred[ handler ](function() {
- returned = fn.apply( this, arguments );
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var action = tuple[ 0 ],
+ fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
- returned.promise().then( newDefer.resolve, newDefer.reject );
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
} else {
- newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+ newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
}
});
- } else {
- deferred[ handler ]( newDefer[ action ] );
- }
- });
- }).promise();
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
},
- // Get a promise for this deferred
- // If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- if ( obj == null ) {
- if ( promise ) {
- return promise;
- }
- promise = obj = {};
- }
- var i = promiseMethods.length;
- while( i-- ) {
- obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
- }
- return obj;
- }
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
});
- // Make sure only one callback list will be used
- deferred.done( failDeferred.cancel ).fail( deferred.cancel );
- // Unexpose cancel
- delete deferred.cancel;
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
+
+ // All done!
return deferred;
},
// Deferred helper
- when: function( firstParam ) {
- var args = arguments,
- i = 0,
- length = args.length,
- count = length,
- deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
- firstParam :
- jQuery.Deferred();
- function resolveFunc( i ) {
- return function( value ) {
- args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
- if ( !( --count ) ) {
- // Strange bug in FF4:
- // Values changed onto the arguments object sometimes end up as undefined values
- // outside the $.when method. Cloning the object into a fresh array solves the issue
- deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
- }
- };
- }
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = core_slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
+ if( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+ } else if ( !( --remaining ) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
- for( ; i < length; i++ ) {
- if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
- args[ i ].promise().then( resolveFunc(i), deferred.reject );
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
} else {
- --count;
- }
- }
- if ( !count ) {
- deferred.resolveWith( deferred, args );
- }
- } else if ( deferred !== firstParam ) {
- deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
- }
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
return deferred.promise();
}
});
-
-
-
-jQuery.support = (function() {
-
- var div = document.createElement( "div" ),
- documentElement = document.documentElement,
- all,
- a,
- select,
- opt,
- input,
- marginDiv,
- support,
- fragment,
- body,
- testElementParent,
- testElement,
- testElementStyle,
- tds,
- events,
- eventName,
- i,
- isSupported;
-
- // Preliminary tests
- div.setAttribute("className", "t");
- div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
-
-
- all = div.getElementsByTagName( "*" );
- a = div.getElementsByTagName( "a" )[ 0 ];
-
- // Can't get basic test support
- if ( !all || !all.length || !a ) {
- return {};
- }
-
- // First batch of supports tests
- select = document.createElement( "select" );
+jQuery.support = (function( support ) {
+
+ var all, a, input, select, fragment, opt, eventName, isSupported, i,
+ div = document.createElement("div");
+
+ // Setup
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+
+ // Finish early in limited (non-browser) environments
+ all = div.getElementsByTagName("*") || [];
+ a = div.getElementsByTagName("a")[ 0 ];
+ if ( !a || !a.style || !all.length ) {
+ return support;
+ }
+
+ // First batch of tests
+ select = document.createElement("select");
opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName( "input" )[ 0 ];
-
- support = {
- // IE strips leading whitespace when .innerHTML is used
- leadingWhitespace: ( div.firstChild.nodeType === 3 ),
-
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- tbody: !div.getElementsByTagName( "tbody" ).length,
-
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName( "link" ).length,
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- style: /top/.test( a.getAttribute("style") ),
-
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
-
- // Make sure that element opacity exists
- // (IE uses filter instead)
- // Use a regex to work around a WebKit issue. See #5145
- opacity: /^0.55$/.test( a.style.opacity ),
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- cssFloat: !!a.style.cssFloat,
-
- // Make sure that if no value is specified for a checkbox
- // that it defaults to "on".
- // (WebKit defaults to "" instead)
- checkOn: ( input.value === "on" ),
-
- // Make sure that a selected-by-default option has a working selected property.
- // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
- optSelected: opt.selected,
-
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- getSetAttribute: div.className !== "t",
-
- // Will be defined later
- submitBubbles: true,
- changeBubbles: true,
- focusinBubbles: false,
- deleteExpando: true,
- noCloneEvent: true,
- inlineBlockNeedsLayout: false,
- shrinkWrapBlocks: false,
- reliableMarginRight: true
- };
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px;float:left;opacity:.5";
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ support.getSetAttribute = div.className !== "t";
+
+ // IE strips leading whitespace when .innerHTML is used
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ support.tbody = !div.getElementsByTagName("tbody").length;
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ support.htmlSerialize = !!div.getElementsByTagName("link").length;
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ support.style = /top/.test( a.getAttribute("style") );
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ support.hrefNormalized = a.getAttribute("href") === "/a";
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ support.opacity = /^0.5/.test( a.style.opacity );
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ support.cssFloat = !!a.style.cssFloat;
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ support.checkOn = !!input.value;
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ support.optSelected = opt.selected;
+
+ // Tests for enctype support on a form (#6743)
+ support.enctype = !!document.createElement("form").enctype;
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>";
+
+ // Will be defined later
+ support.inlineBlockNeedsLayout = false;
+ support.shrinkWrapBlocks = false;
+ support.pixelPosition = false;
+ support.deleteExpando = true;
+ support.noCloneEvent = true;
+ support.reliableMarginRight = true;
+ support.boxSizingReliable = true;
// Make sure checked status is properly cloned
input.checked = true;
@@ -1256,466 +3402,446 @@
select.disabled = true;
support.optDisabled = !opt.disabled;
- // Test to see if it's possible to delete an expando from an element
- // Fails in Internet Explorer
+ // Support: IE<9
try {
delete div.test;
} catch( e ) {
support.deleteExpando = false;
}
- if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
- div.attachEvent( "onclick", function() {
- // Cloning a node shouldn't copy over any
- // bound event handlers (IE does this)
- support.noCloneEvent = false;
- });
- div.cloneNode( true ).fireEvent( "onclick" );
- }
-
- // Check if a radio maintains it's value
- // after being appended to the DOM
+ // Check if we can trust getAttribute("value")
input = document.createElement("input");
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
input.value = "t";
- input.setAttribute("type", "radio");
+ input.setAttribute( "type", "radio" );
support.radioValue = input.value === "t";
- input.setAttribute("checked", "checked");
- div.appendChild( input );
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "checked", "t" );
+ input.setAttribute( "name", "t" );
+
fragment = document.createDocumentFragment();
- fragment.appendChild( div.firstChild );
-
- // WebKit doesn't clone checked state correctly in fragments
- support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
- div.innerHTML = "";
-
- // Figure out if the W3C box model works as expected
- div.style.width = div.style.paddingLeft = "1px";
-
- body = document.getElementsByTagName( "body" )[ 0 ];
- // We use our own, invisible, body unless the body is already present
- // in which case we use a div (#9239)
- testElement = document.createElement( body ? "div" : "body" );
- testElementStyle = {
- visibility: "hidden",
- width: 0,
- height: 0,
- border: 0,
- margin: 0,
- background: "none"
- };
- if ( body ) {
- jQuery.extend( testElementStyle, {
- position: "absolute",
- left: "-1000px",
- top: "-1000px"
- });
- }
- for ( i in testElementStyle ) {
- testElement.style[ i ] = testElementStyle[ i ];
- }
- testElement.appendChild( div );
- testElementParent = body || documentElement;
- testElementParent.insertBefore( testElement, testElementParent.firstChild );
+ fragment.appendChild( input );
// Check if a disconnected checkbox will retain its checked
// value of true after appended to the DOM (IE6/7)
support.appendChecked = input.checked;
- support.boxModel = div.offsetWidth === 2;
-
- if ( "zoom" in div.style ) {
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- // (IE < 8 does this)
- div.style.display = "inline";
- div.style.zoom = 1;
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
-
- // Check if elements with layout shrink-wrap their children
- // (IE 6 does this)
- div.style.display = "";
- div.innerHTML = "<div style='width:4px;'></div>";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
- }
-
- div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
- tds = div.getElementsByTagName( "td" );
-
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- // (only IE 8 fails this test)
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Check if empty table cells still have offsetWidth/Height
- // (IE < 8 fail this test)
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
- div.innerHTML = "";
-
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. For more
- // info see bug #3333
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- if ( document.defaultView && document.defaultView.getComputedStyle ) {
- marginDiv = document.createElement( "div" );
- marginDiv.style.width = "0";
- marginDiv.style.marginRight = "0";
- div.appendChild( marginDiv );
- support.reliableMarginRight =
- ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
- }
-
- // Remove the body element we added
- testElement.innerHTML = "";
- testElementParent.removeChild( testElement );
-
- // Technique from Juriy Zaytsev
- // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
- // We only care about the case where non-standard event systems
- // are used, namely in IE. Short-circuiting here helps us to
- // avoid an eval call (in setAttribute) which can cause CSP
- // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
if ( div.attachEvent ) {
- for( i in {
- submit: 1,
- change: 1,
- focusin: 1
- } ) {
- eventName = "on" + i;
- isSupported = ( eventName in div );
- if ( !isSupported ) {
- div.setAttribute( eventName, "return;" );
- isSupported = ( typeof div[ eventName ] === "function" );
- }
- support[ i + "Bubbles" ] = isSupported;
- }
- }
-
- // Null connected elements to avoid leaks in IE
- testElement = fragment = select = opt = body = marginDiv = div = input = null;
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ for ( i in { submit: true, change: true, focusin: true }) {
+ div.setAttribute( eventName = "on" + i, "t" );
+
+ support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
+ }
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Support: IE<9
+ // Iteration over object's inherited properties before its own.
+ for ( i in jQuery( support ) ) {
+ break;
+ }
+ support.ownLast = i !== "0";
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, marginDiv, tds,
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ container = document.createElement("div");
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
+
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName("td");
+ tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Support: IE8
+ // Check if empty table cells still have offsetWidth/Height
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check box-sizing and margin behavior.
+ div.innerHTML = "";
+ div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
+
+ // Workaround failing boxSizing test due to offsetWidth returning wrong value
+ // with some non-1 values of body zoom, ticket #13543
+ jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
+ support.boxSizing = div.offsetWidth === 4;
+ });
+
+ // Use window.getComputedStyle because jsdom on node.js will break without it.
+ if ( window.getComputedStyle ) {
+ support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. (#3333)
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ marginDiv = div.appendChild( document.createElement("div") );
+ marginDiv.style.cssText = div.style.cssText = divReset;
+ marginDiv.style.marginRight = marginDiv.style.width = "0";
+ div.style.width = "1px";
+
+ support.reliableMarginRight =
+ !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
+ }
+
+ if ( typeof div.style.zoom !== core_strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.innerHTML = "";
+ div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ div.style.display = "block";
+ div.innerHTML = "<div></div>";
+ div.firstChild.style.width = "5px";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+
+ if ( support.inlineBlockNeedsLayout ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+
+ // Null elements to avoid leaks in IE
+ container = div = tds = marginDiv = null;
+ });
+
+ // Null elements to avoid leaks in IE
+ all = select = fragment = opt = a = input = null;
return support;
-})();
-
-// Keep track of boxModel
-jQuery.boxModel = jQuery.support.boxModel;
-
-
-
-
-var rbrace = /^(?:\{.*\}|\[.*\])$/,
+})({});
+
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
rmultiDash = /([A-Z])/g;
+function internalData( elem, name, data, pvt /* Internal Use Only */ ){
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var ret, thisCache,
+ internalKey = jQuery.expando,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ // Avoid exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ /* jshint eqeqeq: false */
+ } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
+ /* jshint eqeqeq: true */
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
jQuery.extend({
cache: {},
- // Please use with caution
- uuid: 0,
-
- // Unique for each copy of jQuery on the page
- // Non-digits removed to match rinlinejQuery
- expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
-
// The following elements throw uncatchable exceptions if you
// attempt to add expando properties to them.
noData: {
+ "applet": true,
"embed": true,
// Ban all objects except for Flash (which handle expandos)
- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
- "applet": true
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
},
hasData: function( elem ) {
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
-
return !!elem && !isEmptyDataObject( elem );
},
- data: function( elem, name, data, pvt /* Internal Use Only */ ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, ret,
- internalKey = jQuery.expando,
- getByName = typeof name === "string",
-
- // We have to handle DOM nodes and JS objects differently because IE6-7
- // can't GC object references properly across the DOM-JS boundary
- isNode = elem.nodeType,
-
- // Only DOM nodes need the global jQuery cache; JS object data is
- // attached directly to the object so GC can occur automatically
- cache = isNode ? jQuery.cache : elem,
-
- // Only defining an ID for JS objects if its cache already exists allows
- // the code to shortcut on the same path as a DOM node with no cache
- id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
-
- // Avoid doing any more work than we need to when trying to get data on an
- // object that has no data at all
- if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) {
- return;
- }
-
- if ( !id ) {
- // Only DOM nodes need a new unique ID for each element since their data
- // ends up in the global cache
- if ( isNode ) {
- elem[ jQuery.expando ] = id = ++jQuery.uuid;
- } else {
- id = jQuery.expando;
- }
- }
-
- if ( !cache[ id ] ) {
- cache[ id ] = {};
-
- // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
- // metadata on plain JS objects when the object is serialized using
- // JSON.stringify
- if ( !isNode ) {
- cache[ id ].toJSON = jQuery.noop;
- }
- }
-
- // An object can be passed to jQuery.data instead of a key/value pair; this gets
- // shallow copied over onto the existing cache
- if ( typeof name === "object" || typeof name === "function" ) {
- if ( pvt ) {
- cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
- } else {
- cache[ id ] = jQuery.extend(cache[ id ], name);
- }
- }
-
- thisCache = cache[ id ];
-
- // Internal jQuery data is stored in a separate object inside the object's data
- // cache in order to avoid key collisions between internal data and user-defined
- // data
- if ( pvt ) {
- if ( !thisCache[ internalKey ] ) {
- thisCache[ internalKey ] = {};
- }
-
- thisCache = thisCache[ internalKey ];
- }
-
- if ( data !== undefined ) {
- thisCache[ jQuery.camelCase( name ) ] = data;
- }
-
- // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
- // not attempt to inspect the internal events object using jQuery.data, as this
- // internal data object is undocumented and subject to change.
- if ( name === "events" && !thisCache[name] ) {
- return thisCache[ internalKey ] && thisCache[ internalKey ].events;
- }
-
- // Check for both converted-to-camel and non-converted data property names
- // If a data property was specified
- if ( getByName ) {
-
- // First Try to find as-is property data
- ret = thisCache[ name ];
-
- // Test for null|undefined property data
- if ( ret == null ) {
-
- // Try to find the camelCased property
- ret = thisCache[ jQuery.camelCase( name ) ];
- }
- } else {
- ret = thisCache;
- }
-
- return ret;
- },
-
- removeData: function( elem, name, pvt /* Internal Use Only */ ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache,
-
- // Reference to internal data cache key
- internalKey = jQuery.expando,
-
- isNode = elem.nodeType,
-
- // See jQuery.data for more information
- cache = isNode ? jQuery.cache : elem,
-
- // See jQuery.data for more information
- id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
-
- // If there is already no cache entry for this object, there is no
- // purpose in continuing
- if ( !cache[ id ] ) {
- return;
- }
-
- if ( name ) {
-
- thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
-
- if ( thisCache ) {
-
- // Support interoperable removal of hyphenated or camelcased keys
- if ( !thisCache[ name ] ) {
- name = jQuery.camelCase( name );
- }
-
- delete thisCache[ name ];
-
- // If there is no data left in the cache, we want to continue
- // and let the cache object itself get destroyed
- if ( !isEmptyDataObject(thisCache) ) {
- return;
- }
- }
- }
-
- // See jQuery.data for more information
- if ( pvt ) {
- delete cache[ id ][ internalKey ];
-
- // Don't destroy the parent cache unless the internal data object
- // had been the only thing left in it
- if ( !isEmptyDataObject(cache[ id ]) ) {
- return;
- }
- }
-
- var internalCache = cache[ id ][ internalKey ];
-
- // Browsers that fail expando deletion also refuse to delete expandos on
- // the window, but it will allow it on all other JS objects; other browsers
- // don't care
- // Ensure that `cache` is not a window object #10080
- if ( jQuery.support.deleteExpando || !cache.setInterval ) {
- delete cache[ id ];
- } else {
- cache[ id ] = null;
- }
-
- // We destroyed the entire user cache at once because it's faster than
- // iterating through each key, but we need to continue to persist internal
- // data if it existed
- if ( internalCache ) {
- cache[ id ] = {};
- // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
- // metadata on plain JS objects when the object is serialized using
- // JSON.stringify
- if ( !isNode ) {
- cache[ id ].toJSON = jQuery.noop;
- }
-
- cache[ id ][ internalKey ] = internalCache;
-
- // Otherwise, we need to eliminate the expando on the node to avoid
- // false lookups in the cache for entries that no longer exist
- } else if ( isNode ) {
- // IE does not allow us to delete expando properties from nodes,
- // nor does it have a removeAttribute function on Document nodes;
- // we must handle all of these cases
- if ( jQuery.support.deleteExpando ) {
- delete elem[ jQuery.expando ];
- } else if ( elem.removeAttribute ) {
- elem.removeAttribute( jQuery.expando );
- } else {
- elem[ jQuery.expando ] = null;
- }
- }
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
},
// For internal use only.
_data: function( elem, name, data ) {
- return jQuery.data( elem, name, data, true );
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
},
// A method for determining if a DOM node can handle the data expando
acceptData: function( elem ) {
- if ( elem.nodeName ) {
- var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
-
- if ( match ) {
- return !(match === true || elem.getAttribute("classid") !== match);
- }
- }
-
- return true;
+ // Do not set data on non-element because it will not be cleared (#8335).
+ if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
+ return false;
+ }
+
+ var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ // nodes accept data unless otherwise specified; rejection can be conditional
+ return !noData || noData !== true && elem.getAttribute("classid") === noData;
}
});
jQuery.fn.extend({
data: function( key, value ) {
- var data = null;
-
- if ( typeof key === "undefined" ) {
+ var attrs, name,
+ data = null,
+ i = 0,
+ elem = this[0];
+
+ // Special expections of .data basically thwart jQuery.access,
+ // so implement the relevant behavior ourselves
+
+ // Gets all values
+ if ( key === undefined ) {
if ( this.length ) {
- data = jQuery.data( this[0] );
-
- if ( this[0].nodeType === 1 ) {
- var attr = this[0].attributes, name;
- for ( var i = 0, l = attr.length; i < l; i++ ) {
- name = attr[i].name;
-
- if ( name.indexOf( "data-" ) === 0 ) {
- name = jQuery.camelCase( name.substring(5) );
-
- dataAttr( this[0], name, data[ name ] );
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attrs = elem.attributes;
+ for ( ; i < attrs.length; i++ ) {
+ name = attrs[i].name;
+
+ if ( name.indexOf("data-") === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+
+ dataAttr( elem, name, data[ name ] );
}
}
+ jQuery._data( elem, "parsedAttrs", true );
}
}
return data;
-
- } else if ( typeof key === "object" ) {
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}
- var parts = key.split(".");
- parts[1] = parts[1] ? "." + parts[1] : "";
-
- if ( value === undefined ) {
- data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
-
+ return arguments.length > 1 ?
+
+ // Sets one value
+ this.each(function() {
+ jQuery.data( this, key, value );
+ }) :
+
+ // Gets one value
// Try to fetch any internally stored data first
- if ( data === undefined && this.length ) {
- data = jQuery.data( this[0], key );
- data = dataAttr( this[0], key, data );
- }
-
- return data === undefined && parts[1] ?
- this.data( parts[0] ) :
- data;
-
- } else {
- return this.each(function() {
- var $this = jQuery( this ),
- args = [ parts[0], value ];
-
- $this.triggerHandler( "setData" + parts[1] + "!", args );
- jQuery.data( this, key, value );
- $this.triggerHandler( "changeData" + parts[1] + "!", args );
- });
- }
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
},
removeData: function( key ) {
@@ -1737,11 +3863,12 @@
if ( typeof data === "string" ) {
try {
data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- !jQuery.isNaN( data ) ? parseFloat( data ) :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
- data;
+ data;
} catch( e ) {}
// Make sure we set the data so it isn't changed later
@@ -1755,11 +3882,15 @@
return data;
}
-// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
-// property to be considered empty objects; this property always exists in
-// order to make sure JSON.stringify does not expose internal metadata
+// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
- for ( var name in obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
if ( name !== "toJSON" ) {
return false;
}
@@ -1767,71 +3898,23 @@
return true;
}
-
-
-
-
-function handleQueueMarkDefer( elem, type, src ) {
- var deferDataKey = type + "defer",
- queueDataKey = type + "queue",
- markDataKey = type + "mark",
- defer = jQuery.data( elem, deferDataKey, undefined, true );
- if ( defer &&
- ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
- ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
- // Give room for hard-coded callbacks to fire first
- // and eventually mark/queue something else on the element
- setTimeout( function() {
- if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
- !jQuery.data( elem, markDataKey, undefined, true ) ) {
- jQuery.removeData( elem, deferDataKey, true );
- defer.resolve();
- }
- }, 0 );
- }
-}
-
jQuery.extend({
-
- _mark: function( elem, type ) {
+ queue: function( elem, type, data ) {
+ var queue;
+
if ( elem ) {
- type = (type || "fx") + "mark";
- jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
- }
- },
-
- _unmark: function( force, elem, type ) {
- if ( force !== true ) {
- type = elem;
- elem = force;
- force = false;
- }
- if ( elem ) {
- type = type || "fx";
- var key = type + "mark",
- count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
- if ( count ) {
- jQuery.data( elem, key, count, true );
- } else {
- jQuery.removeData( elem, key, true );
- handleQueueMarkDefer( elem, type, "mark" );
- }
- }
- },
-
- queue: function( elem, type, data ) {
- if ( elem ) {
- type = (type || "fx") + "queue";
- var q = jQuery.data( elem, type, undefined, true );
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
- if ( !q || jQuery.isArray(data) ) {
- q = jQuery.data( elem, type, jQuery.makeArray(data), true );
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
- q.push( data );
- }
- }
- return q || [];
+ queue.push( data );
+ }
+ }
+ return queue || [];
}
},
@@ -1839,50 +3922,75 @@
type = type || "fx";
var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
fn = queue.shift(),
- defer;
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
+ startLength--;
}
if ( fn ) {
+
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
- queue.unshift("inprogress");
- }
-
- fn.call(elem, function() {
- jQuery.dequeue(elem, type);
- });
- }
-
- if ( !queue.length ) {
- jQuery.removeData( elem, type + "queue", true );
- handleQueueMarkDefer( elem, type, "queue" );
- }
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
}
});
jQuery.fn.extend({
queue: function( type, data ) {
+ var setter = 2;
+
if ( typeof type !== "string" ) {
data = type;
type = "fx";
- }
-
- if ( data === undefined ) {
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
return jQuery.queue( this[0], type );
}
- return this.each(function() {
- var queue = jQuery.queue( this, type, data );
-
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
},
dequeue: function( type ) {
return this.each(function() {
@@ -1892,14 +4000,14 @@
// Based off of the plugin by Clint Helfers, with permission.
// http://blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
- return this.queue( type, function() {
- var elem = this;
- setTimeout(function() {
- jQuery.dequeue( elem, type );
- }, time );
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
});
},
clearQueue: function( type ) {
@@ -1907,54 +4015,47 @@
},
// Get a promise resolved when queues of a certain type
// are emptied (fx is the type by default)
- promise: function( type, object ) {
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
if ( typeof type !== "string" ) {
- object = type;
+ obj = type;
type = undefined;
}
type = type || "fx";
- var defer = jQuery.Deferred(),
- elements = this,
- i = elements.length,
- count = 1,
- deferDataKey = type + "defer",
- queueDataKey = type + "queue",
- markDataKey = type + "mark",
- tmp;
- function resolve() {
- if ( !( --count ) ) {
- defer.resolveWith( elements, [ elements ] );
- }
- }
+
while( i-- ) {
- if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
- ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
- jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
- jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
count++;
- tmp.done( resolve );
+ tmp.empty.add( resolve );
}
}
resolve();
- return defer.promise();
+ return defer.promise( obj );
}
});
-
-
-
-
-var rclass = /[\n\t\r]/g,
- rspace = /\s+/,
+var nodeHook, boolHook,
+ rclass = /[\t\r\n\f]/g,
rreturn = /\r/g,
- rtype = /^(?:button|input)$/i,
- rfocusable = /^(?:button|input|object|select|textarea)$/i,
- rclickable = /^a(?:rea)?$/i,
- rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
- nodeHook, boolHook;
+ rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ getSetInput = jQuery.support.input;
jQuery.fn.extend({
attr: function( name, value ) {
- return jQuery.access( this, name, value, true, jQuery.attr );
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
@@ -1962,11 +4063,11 @@
jQuery.removeAttr( this, name );
});
},
-
+
prop: function( name, value ) {
- return jQuery.access( this, name, value, true, jQuery.prop );
- },
-
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
removeProp: function( name ) {
name = jQuery.propFix[ name ] || name;
return this.each(function() {
@@ -1979,35 +4080,37 @@
},
addClass: function( value ) {
- var classNames, i, l, elem,
- setClass, c, cl;
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
- jQuery( this ).addClass( value.call(this, j, this.className) );
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
});
}
- if ( value && typeof value === "string" ) {
- classNames = value.split( rspace );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
elem = this[ i ];
-
- if ( elem.nodeType === 1 ) {
- if ( !elem.className && classNames.length === 1 ) {
- elem.className = value;
-
- } else {
- setClass = " " + elem.className + " ";
-
- for ( c = 0, cl = classNames.length; c < cl; c++ ) {
- if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
- setClass += classNames[ c ] + " ";
- }
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
}
- elem.className = jQuery.trim( setClass );
}
+ elem.className = jQuery.trim( cur );
+
}
}
}
@@ -2016,31 +4119,36 @@
},
removeClass: function( value ) {
- var classNames, i, l, elem, className, c, cl;
+ var classes, elem, cur, clazz, j,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
- jQuery( this ).removeClass( value.call(this, j, this.className) );
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
});
}
-
- if ( (value && typeof value === "string") || value === undefined ) {
- classNames = (value || "").split( rspace );
-
- for ( i = 0, l = this.length; i < l; i++ ) {
+ if ( proceed ) {
+ classes = ( value || "" ).match( core_rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
elem = this[ i ];
-
- if ( elem.nodeType === 1 && elem.className ) {
- if ( value ) {
- className = (" " + elem.className + " ").replace( rclass, " " );
- for ( c = 0, cl = classNames.length; c < cl; c++ ) {
- className = className.replace(" " + classNames[ c ] + " ", " ");
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
}
- elem.className = jQuery.trim( className );
-
- } else {
- elem.className = "";
}
+ elem.className = value ? jQuery.trim( cur ) : "";
}
}
}
@@ -2049,8 +4157,11 @@
},
toggleClass: function( value, stateVal ) {
- var type = typeof value,
- isBool = typeof stateVal === "boolean";
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
if ( jQuery.isFunction( value ) ) {
return this.each(function( i ) {
@@ -2064,31 +4175,39 @@
var className,
i = 0,
self = jQuery( this ),
- state = stateVal,
- classNames = value.split( rspace );
+ classNames = value.match( core_rnotwhite ) || [];
while ( (className = classNames[ i++ ]) ) {
- // check each className given, space seperated list
- state = isBool ? state : !self.hasClass( className );
- self[ state ? "addClass" : "removeClass" ]( className );
- }
-
- } else if ( type === "undefined" || type === "boolean" ) {
+ // check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === core_strundefined || type === "boolean" ) {
if ( this.className ) {
// store className if set
jQuery._data( this, "__className__", this.className );
}
- // toggle whole className
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
}
});
},
hasClass: function( selector ) {
- var className = " " + selector + " ";
- for ( var i = 0, l = this.length; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
return true;
}
}
@@ -2097,12 +4216,12 @@
},
val: function( value ) {
- var hooks, ret,
+ var ret, hooks, isFunction,
elem = this[0];
-
+
if ( !arguments.length ) {
if ( elem ) {
- hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
return ret;
@@ -2110,27 +4229,27 @@
ret = elem.value;
- return typeof ret === "string" ?
+ return typeof ret === "string" ?
// handle most common string cases
- ret.replace(rreturn, "") :
+ ret.replace(rreturn, "") :
// handle cases where value is null/undef or number
ret == null ? "" : ret;
}
- return undefined;
- }
-
- var isFunction = jQuery.isFunction( value );
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
return this.each(function( i ) {
- var self = jQuery(this), val;
+ var val;
if ( this.nodeType !== 1 ) {
return;
}
if ( isFunction ) {
- val = value.call( this, i, self.val() );
+ val = value.call( this, i, jQuery( this ).val() );
} else {
val = value;
}
@@ -2146,7 +4265,7 @@
});
}
- hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
// If set returns undefined, fall back to normal setting
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
@@ -2160,32 +4279,34 @@
valHooks: {
option: {
get: function( elem ) {
- // attributes.value is undefined in Blackberry 4.7 but
- // uses .value. See #6932
- var val = elem.attributes.value;
- return !val || val.specified ? elem.value : elem.text;
+ // Use proper attribute retrieval(#6932, #12072)
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+ elem.text;
}
},
select: {
get: function( elem ) {
- var value,
- index = elem.selectedIndex,
- values = [],
+ var value, option,
options = elem.options,
- one = elem.type === "select-one";
-
- // Nothing was selected
- if ( index < 0 ) {
- return null;
- }
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
// Loop through all the selected options
- for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
- var option = options[ i ];
-
- // Don't return options that are disabled or in a disabled optgroup
- if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
- (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
// Get the specific value for the option
value = jQuery( option ).val();
@@ -2200,22 +4321,24 @@
}
}
- // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
- if ( one && !values.length && options.length ) {
- return jQuery( options[ index ] ).val();
- }
-
return values;
},
set: function( elem, value ) {
- var values = jQuery.makeArray( value );
-
- jQuery(elem).find("option").each(function() {
- this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
- });
-
- if ( !values.length ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+ if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
+ optionSet = true;
+ }
+ }
+
+ // force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
elem.selectedIndex = -1;
}
return values;
@@ -2223,99 +4346,81 @@
}
},
- attrFn: {
- val: true,
- css: true,
- html: true,
- text: true,
- data: true,
- width: true,
- height: true,
- offset: true
- },
-
- attrFix: {
- // Always normalize to ensure hook usage
- tabindex: "tabIndex"
- },
-
- attr: function( elem, name, value, pass ) {
- var nType = elem.nodeType;
-
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
// don't get/set attributes on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return undefined;
- }
-
- if ( pass && name in jQuery.attrFn ) {
- return jQuery( elem )[ name ]( value );
+ return;
}
// Fallback to prop when attributes are not supported
- if ( !("getAttribute" in elem) ) {
+ if ( typeof elem.getAttribute === core_strundefined ) {
return jQuery.prop( elem, name, value );
}
- var ret, hooks,
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- // Normalize the name if needed
- if ( notxml ) {
- name = jQuery.attrFix[ name ] || name;
-
- hooks = jQuery.attrHooks[ name ];
-
- if ( !hooks ) {
- // Use boolHook for boolean attributes
- if ( rboolean.test( name ) ) {
- hooks = boolHook;
-
- // Use nodeHook if available( IE6/7 )
- } else if ( nodeHook ) {
- hooks = nodeHook;
- }
- }
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
}
if ( value !== undefined ) {
if ( value === null ) {
jQuery.removeAttr( elem, name );
- return undefined;
-
- } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
} else {
- elem.setAttribute( name, "" + value );
+ elem.setAttribute( name, value + "" );
return value;
}
- } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
return ret;
} else {
-
- ret = elem.getAttribute( name );
+ ret = jQuery.find.attr( elem, name );
// Non-existent attributes return null, we normalize to undefined
- return ret === null ?
+ return ret == null ?
undefined :
ret;
}
},
- removeAttr: function( elem, name ) {
- var propName;
- if ( elem.nodeType === 1 ) {
- name = jQuery.attrFix[ name ] || name;
-
- jQuery.attr( elem, name, "" );
- elem.removeAttribute( name );
-
- // Set corresponding property to false for boolean attributes
- if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) {
- elem[ propName ] = false;
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( core_rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ elem[ propName ] = false;
+ // Support: IE<9
+ // Also clear defaultChecked/defaultSelected (if appropriate)
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
}
}
},
@@ -2323,13 +4428,9 @@
attrHooks: {
type: {
set: function( elem, value ) {
- // We can't allow the type property to be changed (since it causes problems in IE)
- if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
- jQuery.error( "type property can't be changed" );
- } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
// Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to it's default in case type is set after value
- // This is for element creation
+ // Reset value to default in case type is set after value during creation
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
@@ -2338,53 +4439,24 @@
return value;
}
}
- },
- // Use the value property for back compat
- // Use the nodeHook for button elements in IE6/7 (#1954)
- value: {
- get: function( elem, name ) {
- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
- return nodeHook.get( elem, name );
- }
- return name in elem ?
- elem.value :
- null;
- },
- set: function( elem, value, name ) {
- if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
- return nodeHook.set( elem, value, name );
- }
- // Does not return so that setAttribute is also used
- elem.value = value;
- }
}
},
propFix: {
- tabindex: "tabIndex",
- readonly: "readOnly",
"for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder",
- contenteditable: "contentEditable"
- },
-
+ "class": "className"
+ },
+
prop: function( elem, name, value ) {
- var nType = elem.nodeType;
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
// don't get/set properties on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return undefined;
- }
-
- var ret, hooks,
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
if ( notxml ) {
// Fix name and attach hooks
@@ -2393,122 +4465,170 @@
}
if ( value !== undefined ) {
- if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- return (elem[ name ] = value);
- }
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
} else {
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- return elem[ name ];
- }
- }
- },
-
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
propHooks: {
tabIndex: {
get: function( elem ) {
// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
- var attributeNode = elem.getAttributeNode("tabindex");
-
- return attributeNode && attributeNode.specified ?
- parseInt( attributeNode.value, 10 ) :
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ return tabindex ?
+ parseInt( tabindex, 10 ) :
rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
0 :
- undefined;
+ -1;
}
}
}
});
-// Add the tabindex propHook to attrHooks for back-compat
-jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex;
-
-// Hook for boolean attributes
+// Hooks for boolean attributes
boolHook = {
- get: function( elem, name ) {
- // Align boolean attributes with corresponding properties
- // Fall back to attribute presence where some booleans are not supported
- var attrNode;
- return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ?
- name.toLowerCase() :
- undefined;
- },
set: function( elem, value, name ) {
- var propName;
if ( value === false ) {
// Remove boolean attributes when set to false
jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
} else {
- // value is true since we know at this point it's type boolean and not false
- // Set boolean attributes to the same name and set the DOM property
- propName = jQuery.propFix[ name ] || name;
- if ( propName in elem ) {
- // Only set the IDL specifically if it already exists on the element
- elem[ propName ] = true;
- }
-
- elem.setAttribute( name, name.toLowerCase() );
- }
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
return name;
}
};
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+ var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
+
+ jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+ function( elem, name, isXML ) {
+ var fn = jQuery.expr.attrHandle[ name ],
+ ret = isXML ?
+ undefined :
+ /* jshint eqeqeq: false */
+ (jQuery.expr.attrHandle[ name ] = undefined) !=
+ getter( elem, name, isXML ) ?
+
+ name.toLowerCase() :
+ null;
+ jQuery.expr.attrHandle[ name ] = fn;
+ return ret;
+ } :
+ function( elem, name, isXML ) {
+ return isXML ?
+ undefined :
+ elem[ jQuery.camelCase( "default-" + name ) ] ?
+ name.toLowerCase() :
+ null;
+ };
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !jQuery.support.getSetAttribute ) {
-
+if ( !getSetAttribute ) {
+
// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
- nodeHook = jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret;
- ret = elem.getAttributeNode( name );
- // Return undefined if nodeValue is empty string
- return ret && ret.nodeValue !== "" ?
- ret.nodeValue :
- undefined;
- },
+ nodeHook = {
set: function( elem, value, name ) {
// Set the existing or create a new attribute node
var ret = elem.getAttributeNode( name );
if ( !ret ) {
- ret = document.createAttribute( name );
- elem.setAttributeNode( ret );
- }
- return (ret.nodeValue = value + "");
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ return name === "value" || value === elem.getAttribute( name ) ?
+ value :
+ undefined;
+ }
+ };
+ jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
+ // Some attributes are constructed with empty-string values when not defined
+ function( elem, name, isXML ) {
+ var ret;
+ return isXML ?
+ undefined :
+ (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+ ret.value :
+ null;
+ };
+ jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ return ret && ret.specified ?
+ ret.value :
+ undefined;
+ },
+ set: nodeHook.set
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
}
};
// Set width and height to auto instead of 0 on empty string( Bug #8150 )
// This is for removals
jQuery.each([ "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ jQuery.attrHooks[ name ] = {
set: function( elem, value ) {
if ( value === "" ) {
elem.setAttribute( name, "auto" );
return value;
}
}
- });
+ };
});
}
// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !jQuery.support.hrefNormalized ) {
- jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
get: function( elem ) {
- var ret = elem.getAttribute( name, 2 );
- return ret === null ? undefined : ret;
- }
- });
+ return elem.getAttribute( name, 4 );
+ }
+ };
});
}
@@ -2516,11 +4636,12 @@
jQuery.attrHooks.style = {
get: function( elem ) {
// Return undefined in the case of empty string
- // Normalize to lowercase since IE uppercases css property names
- return elem.style.cssText.toLowerCase() || undefined;
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
},
set: function( elem, value ) {
- return (elem.style.cssText = "" + value);
+ return ( elem.style.cssText = value + "" );
}
};
}
@@ -2528,7 +4649,7 @@
// Safari mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ jQuery.propHooks.selected = {
get: function( elem ) {
var parent = elem.parentNode;
@@ -2542,143 +4663,153 @@
}
return null;
}
- });
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
}
// Radios and checkboxes getter/setter
-if ( !jQuery.support.checkOn ) {
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- get: function( elem ) {
- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- }
- };
- });
-}
jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ jQuery.valHooks[ this ] = {
set: function( elem, value ) {
if ( jQuery.isArray( value ) ) {
- return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
- }
- }
- });
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !jQuery.support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
});
-
-
-
-
-var rnamespaces = /\.(.*)$/,
- rformElems = /^(?:textarea|input|select)$/i,
- rperiod = /\./g,
- rspaces = / /g,
- rescape = /[^\w\s.|`]/g,
- fcleanup = function( nm ) {
- return nm.replace(rescape, "\\$&");
- };
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
/*
- * A number of helper functions used for managing events.
- * Many of the ideas behind this code originated from
- * Dean Edwards' addEvent library.
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
*/
jQuery.event = {
- // Bind an event to an element
- // Original by Dean Edwards
- add: function( elem, types, handler, data ) {
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
return;
}
- if ( handler === false ) {
- handler = returnFalse;
- } else if ( !handler ) {
- // Fixes bug #7229. Fix recommended by jdalton
- return;
- }
-
- var handleObjIn, handleObj;
-
+ // Caller can pass in an object of custom data in lieu of the handler
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
- }
-
- // Make sure that the function being executed has a unique ID
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
- // Init the element's event structure
- var elemData = jQuery._data( elem );
-
- // If no elemData is found then we must be trying to bind to one of the
- // banned noData elements
- if ( !elemData ) {
- return;
- }
-
- var events = elemData.events,
- eventHandle = elemData.handle;
-
- if ( !events ) {
- elemData.events = events = {};
- }
-
- if ( !eventHandle ) {
- elemData.handle = eventHandle = function( e ) {
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
- return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
- jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+ return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
- }
-
- // Add elem as a property of the handle function
- // This is to prevent a memory leak with non-native events in IE.
- eventHandle.elem = elem;
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
// Handle multiple events separated by a space
- // jQuery(...).bind("mouseover mouseout", fn);
- types = types.split(" ");
-
- var type, i = 0, namespaces;
-
- while ( (type = types[ i++ ]) ) {
- handleObj = handleObjIn ?
- jQuery.extend({}, handleObjIn) :
- { handler: handler, data: data };
-
- // Namespaced event handlers
- if ( type.indexOf(".") > -1 ) {
- namespaces = type.split(".");
- type = namespaces.shift();
- handleObj.namespace = namespaces.slice(0).sort().join(".");
-
- } else {
- namespaces = [];
- handleObj.namespace = "";
- }
-
- handleObj.type = type;
- if ( !handleObj.guid ) {
- handleObj.guid = handler.guid;
- }
-
- // Get the current list of functions bound to this event
- var handlers = events[ type ],
- special = jQuery.event.special[ type ] || {};
-
- // Init the event handler queue
- if ( !handlers ) {
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
handlers = events[ type ] = [];
-
- // Check for a special event handler
- // Only use addEventListener/attachEvent if the special
- // events handler returns false
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
@@ -2698,10 +4829,14 @@
}
}
- // Add the function to the element's handler list
- handlers.push( handleObj );
-
- // Keep track of which events have been used, for event optimization
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
jQuery.event.global[ type ] = true;
}
@@ -2709,150 +4844,97 @@
elem = null;
},
- global: {},
-
// Detach an event or set of events from an element
- remove: function( elem, types, handler, pos ) {
- // don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
-
- if ( handler === false ) {
- handler = returnFalse;
- }
-
- var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
- elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
- events = elemData && elemData.events;
-
- if ( !elemData || !events ) {
- return;
- }
-
- // types is actually an event object here
- if ( types && types.type ) {
- handler = types.handler;
- types = types.type;
- }
-
- // Unbind all events for the element
- if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
- types = types || "";
-
- for ( type in events ) {
- jQuery.event.remove( elem, type + types );
- }
-
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
return;
}
- // Handle multiple events separated by a space
- // jQuery(...).unbind("mouseover mouseout", fn);
- types = types.split(" ");
-
- while ( (type = types[ i++ ]) ) {
- origType = type;
- handleObj = null;
- all = type.indexOf(".") < 0;
- namespaces = [];
-
- if ( !all ) {
- // Namespaced event handlers
- namespaces = type.split(".");
- type = namespaces.shift();
-
- namespace = new RegExp("(^|\\.)" +
- jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
- }
-
- eventType = events[ type ];
-
- if ( !eventType ) {
- continue;
- }
-
- if ( !handler ) {
- for ( j = 0; j < eventType.length; j++ ) {
- handleObj = eventType[ j ];
-
- if ( all || namespace.test( handleObj.namespace ) ) {
- jQuery.event.remove( elem, origType, handleObj.handler, j );
- eventType.splice( j--, 1 );
- }
- }
-
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( core_rnotwhite ) || [""];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
continue;
}
special = jQuery.event.special[ type ] || {};
-
- for ( j = pos || 0; j < eventType.length; j++ ) {
- handleObj = eventType[ j ];
-
- if ( handler.guid === handleObj.guid ) {
- // remove the given handler for the given type
- if ( all || namespace.test( handleObj.namespace ) ) {
- if ( pos == null ) {
- eventType.splice( j--, 1 );
- }
-
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
- }
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
}
-
- if ( pos != null ) {
- break;
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
}
}
}
- // remove generic event handler if no more handlers exist
- if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
- ret = null;
delete events[ type ];
}
}
// Remove the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
- var handle = elemData.handle;
- if ( handle ) {
- handle.elem = null;
- }
-
- delete elemData.events;
delete elemData.handle;
- if ( jQuery.isEmptyObject( elemData ) ) {
- jQuery.removeData( elem, undefined, true );
- }
- }
- },
-
- // Events that are safe to short-circuit if no handlers are attached.
- // Native DOM events should not be added, they may have inline handlers.
- customEvent: {
- "getData": true,
- "setData": true,
- "changeData": true
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
},
trigger: function( event, data, elem, onlyHandlers ) {
- // Event object or event type
- var type = event.type || event,
- namespaces = [],
- exclusive;
-
- if ( type.indexOf("!") >= 0 ) {
- // Exclusive events trigger only for the exact event (no namespaces)
- type = type.slice(0, -1);
- exclusive = true;
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = core_hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
}
if ( type.indexOf(".") >= 0 ) {
@@ -2861,261 +4943,396 @@
type = namespaces.shift();
namespaces.sort();
}
-
- if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
- // No jQuery handlers for this event type, and it can't have inline handlers
- return;
- }
-
- // Caller can pass in an Event, Object, or just an event type string
- event = typeof event === "object" ?
- // jQuery.Event object
- event[ jQuery.expando ] ? event :
- // Object literal
- new jQuery.Event( type, event ) :
- // Just the event type (string)
- new jQuery.Event( type );
-
- event.type = type;
- event.exclusive = exclusive;
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
event.namespace = namespaces.join(".");
- event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
-
- // triggerHandler() and global events don't bubble or run the default action
- if ( onlyHandlers || !elem ) {
- event.preventDefault();
- event.stopPropagation();
- }
-
- // Handle a global trigger
- if ( !elem ) {
- // TODO: Stop taunting the data cache; remove global events and always attach to document
- jQuery.each( jQuery.cache, function() {
- // internalKey variable is just used to make it easier to find
- // and potentially change this stuff later; currently it just
- // points to jQuery.expando
- var internalKey = jQuery.expando,
- internalCache = this[ internalKey ];
- if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
- jQuery.event.trigger( event, data, internalCache.handle.elem );
- }
- });
- return;
- }
-
- // Don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
// Clean up the event in case it is being reused
event.result = undefined;
- event.target = elem;
+ if ( !event.target ) {
+ event.target = elem;
+ }
// Clone any incoming data and prepend the event, creating the handler arg list
- data = data != null ? jQuery.makeArray( data ) : [];
- data.unshift( event );
-
- var cur = elem,
- // IE doesn't like method names with a colon (#3533, #8272)
- ontype = type.indexOf(":") < 0 ? "on" + type : "";
-
- // Fire event on the current element, then bubble up the DOM tree
- do {
- var handle = jQuery._data( cur, "handle" );
-
- event.currentTarget = cur;
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
}
- // Trigger an inline bound script
- if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
- event.result = false;
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
event.preventDefault();
}
-
- // Bubble up to document, then to window
- cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
- } while ( cur && !event.isPropagationStopped() );
+ }
+ event.type = type;
// If nobody prevented the default action, do it now
- if ( !event.isDefaultPrevented() ) {
- var old,
- special = jQuery.event.special[ type ] || {};
-
- if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
- !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
// Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction)() check here because IE6/7 fails that test.
- // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
- try {
- if ( ontype && elem[ type ] ) {
- // Don't re-trigger an onFOO event when we call its FOO() method
- old = elem[ ontype ];
-
- if ( old ) {
- elem[ ontype ] = null;
- }
-
- jQuery.event.triggered = type;
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
}
- } catch ( ieError ) {}
-
- if ( old ) {
- elem[ ontype ] = old;
- }
-
- jQuery.event.triggered = undefined;
- }
- }
-
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
return event.result;
},
- handle: function( event ) {
- event = jQuery.event.fix( event || window.event );
- // Snapshot the handlers list since a called handler may add/remove events.
- var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
- run_all = !event.exclusive && !event.namespace,
- args = Array.prototype.slice.call( arguments, 0 );
-
- // Use the fix-ed Event rather than the (read-only) native event
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = core_slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
args[0] = event;
- event.currentTarget = this;
-
- for ( var j = 0, l = handlers.length; j < l; j++ ) {
- var handleObj = handlers[ j ];
-
- // Triggered event must 1) be non-exclusive and have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event.
- if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
- // Pass in a reference to the handler function itself
- // So that we can later remove it
- event.handler = handleObj.handler;
- event.data = handleObj.data;
- event.handleObj = handleObj;
-
- var ret = handleObj.handler.apply( this, args );
-
- if ( ret !== undefined ) {
- event.result = ret;
- if ( ret === false ) {
- event.preventDefault();
- event.stopPropagation();
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
}
}
-
- if ( event.isImmediatePropagationStopped() ) {
- break;
- }
- }
- }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
return event.result;
},
- props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG <use> instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ /* jshint eqeqeq: false */
+ for ( ; cur != this; cur = cur.parentNode || this ) {
+ /* jshint eqeqeq: true */
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
fix: function( event ) {
if ( event[ jQuery.expando ] ) {
return event;
}
- // store a copy of the original event object
- // and "clone" to set read-only properties
- var originalEvent = event;
- event = jQuery.Event( originalEvent );
-
- for ( var i = this.props.length, prop; i; ) {
- prop = this.props[ --i ];
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
event[ prop ] = originalEvent[ prop ];
}
- // Fix target property, if necessary
+ // Support: IE<9
+ // Fix target property (#1925)
if ( !event.target ) {
- // Fixes #1925 where srcElement might not be defined either
- event.target = event.srcElement || document;
- }
-
- // check if target is a textnode (safari)
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Support: Chrome 23+, Safari?
+ // Target should not be a text node (#504, #13143)
if ( event.target.nodeType === 3 ) {
event.target = event.target.parentNode;
}
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && event.fromElement ) {
- event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
- }
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && event.clientX != null ) {
- var eventDocument = event.target.ownerDocument || document,
- doc = eventDocument.documentElement,
- body = eventDocument.body;
-
- event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
- event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
- }
-
- // Add which for key events
- if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
- event.which = event.charCode != null ? event.charCode : event.keyCode;
- }
-
- // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
- if ( !event.metaKey && event.ctrlKey ) {
- event.metaKey = event.ctrlKey;
- }
-
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && event.button !== undefined ) {
- event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
- }
-
- return event;
- },
-
- // Deprecated, use jQuery.guid instead
- guid: 1E8,
-
- // Deprecated, use jQuery.proxy instead
- proxy: jQuery.proxy,
+ // Support: IE<9
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var body, eventDoc, doc,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
special: {
- ready: {
- // Make sure the ready event is setup
- setup: jQuery.bindReady,
- teardown: jQuery.noop
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ try {
+ this.focus();
+ return false;
+ } catch ( e ) {
+ // Support: IE<9
+ // If we error on focus to hidden element (#1486, #12518),
+ // let .trigger() run the handlers
+ }
+ }
+ },
+ delegateType: "focusin"
},
-
- live: {
- add: function( handleObj ) {
- jQuery.event.add( this,
- liveConvert( handleObj.origType, handleObj.selector ),
- jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
},
-
- remove: function( handleObj ) {
- jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
}
},
beforeunload: {
- setup: function( data, namespaces, eventHandle ) {
- // We only want to do this special case on windows
- if ( jQuery.isWindow( this ) ) {
- this.onbeforeunload = eventHandle;
- }
- },
-
- teardown: function( namespaces, eventHandle ) {
- if ( this.onbeforeunload === eventHandle ) {
- this.onbeforeunload = null;
- }
- }
+ postDispatch: function( event ) {
+
+ // Even when returnValue equals to undefined Firefox will still show alert
+ if ( event.result !== undefined ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
}
}
};
@@ -3127,14 +5344,23 @@
}
} :
function( elem, type, handle ) {
+ var name = "on" + type;
+
if ( elem.detachEvent ) {
- elem.detachEvent( "on" + type, handle );
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === core_strundefined ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
}
};
jQuery.Event = function( src, props ) {
// Allow instantiation without the 'new' keyword
- if ( !this.preventDefault ) {
+ if ( !(this instanceof jQuery.Event) ) {
return new jQuery.Event( src, props );
}
@@ -3145,8 +5371,8 @@
// Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value.
- this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
- src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
// Event type
} else {
@@ -3158,274 +5384,191 @@
jQuery.extend( this, props );
}
- // timeStamp is buggy for some events on Firefox(#3843)
- // So we won't rely on the native value
- this.timeStamp = jQuery.now();
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
// Mark it as fixed
this[ jQuery.expando ] = true;
};
-function returnFalse() {
- return false;
-}
-function returnTrue() {
- return true;
-}
-
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
preventDefault: function() {
+ var e = this.originalEvent;
+
this.isDefaultPrevented = returnTrue;
-
- var e = this.originalEvent;
if ( !e ) {
return;
}
- // if preventDefault exists run it on the original event
+ // If preventDefault exists, run it on the original event
if ( e.preventDefault ) {
e.preventDefault();
- // otherwise set the returnValue property of the original event to false (IE)
+ // Support: IE
+ // Otherwise set the returnValue property of the original event to false
} else {
e.returnValue = false;
}
},
stopPropagation: function() {
+ var e = this.originalEvent;
+
this.isPropagationStopped = returnTrue;
-
- var e = this.originalEvent;
if ( !e ) {
return;
}
- // if stopPropagation exists run it on the original event
+ // If stopPropagation exists, run it on the original event
if ( e.stopPropagation ) {
e.stopPropagation();
}
- // otherwise set the cancelBubble property of the original event to true (IE)
+
+ // Support: IE
+ // Set the cancelBubble property of the original event to true
e.cancelBubble = true;
},
stopImmediatePropagation: function() {
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
- },
- isDefaultPrevented: returnFalse,
- isPropagationStopped: returnFalse,
- isImmediatePropagationStopped: returnFalse
+ }
};
-// Checks if an event happened on an element within another element
-// Used in jQuery.event.special.mouseenter and mouseleave handlers
-var withinElement = function( event ) {
-
- // Check if mouse(over|out) are still within the same parent element
- var related = event.relatedTarget,
- inside = false,
- eventType = event.type;
-
- event.type = event.data;
-
- if ( related !== this ) {
-
- if ( related ) {
- inside = jQuery.contains( this, related );
- }
-
- if ( !inside ) {
-
- jQuery.event.handle.apply( this, arguments );
-
- event.type = eventType;
- }
- }
-},
-
-// In case of event delegation, we only need to rename the event.type,
-// liveHandler will take care of the rest.
-delegate = function( event ) {
- event.type = event.data;
- jQuery.event.handle.apply( this, arguments );
-};
-
-// Create mouseenter and mouseleave events
+// Create mouseenter/leave events using mouseover/out and event-time checks
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout"
}, function( orig, fix ) {
jQuery.event.special[ orig ] = {
- setup: function( data ) {
- jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
- },
- teardown: function( data ) {
- jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
}
};
});
-// submit delegation
+// IE submit delegation
if ( !jQuery.support.submitBubbles ) {
jQuery.event.special.submit = {
- setup: function( data, namespaces ) {
- if ( !jQuery.nodeName( this, "form" ) ) {
- jQuery.event.add(this, "click.specialSubmit", function( e ) {
- // Avoid triggering error on non-existent type attribute in IE VML (#7071)
- var elem = e.target,
- type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : "";
-
- if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
- trigger( "submit", this, arguments );
- }
- });
-
- jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
- var elem = e.target,
- type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : "";
-
- if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
- trigger( "submit", this, arguments );
- }
- });
-
- } else {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
return false;
}
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "submitBubbles", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
},
- teardown: function( namespaces ) {
- jQuery.event.remove( this, ".specialSubmit" );
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
}
};
-
}
-// change delegation, happens here so we have bind.
+// IE change delegation and checkbox/radio fix
if ( !jQuery.support.changeBubbles ) {
- var changeFilters,
-
- getVal = function( elem ) {
- var type = jQuery.nodeName( elem, "input" ) ? elem.type : "",
- val = elem.value;
-
- if ( type === "radio" || type === "checkbox" ) {
- val = elem.checked;
-
- } else if ( type === "select-multiple" ) {
- val = elem.selectedIndex > -1 ?
- jQuery.map( elem.options, function( elem ) {
- return elem.selected;
- }).join("-") :
- "";
-
- } else if ( jQuery.nodeName( elem, "select" ) ) {
- val = elem.selectedIndex;
- }
-
- return val;
- },
-
- testChange = function testChange( e ) {
- var elem = e.target, data, val;
-
- if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
- return;
- }
-
- data = jQuery._data( elem, "_change_data" );
- val = getVal(elem);
-
- // the current data will be also retrieved by beforeactivate
- if ( e.type !== "focusout" || elem.type !== "radio" ) {
- jQuery._data( elem, "_change_data", val );
- }
-
- if ( data === undefined || val === data ) {
- return;
- }
-
- if ( data != null || val ) {
- e.type = "change";
- e.liveFired = undefined;
- jQuery.event.trigger( e, arguments[1], elem );
- }
- };
-
jQuery.event.special.change = {
- filters: {
- focusout: testChange,
-
- beforedeactivate: testChange,
-
- click: function( e ) {
- var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
-
- if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
- testChange.call( this, e );
- }
- },
-
- // Change has to be called before submit
- // Keydown will be called before keypress, which is used in submit-event delegation
- keydown: function( e ) {
- var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
-
- if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
- (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
- type === "select-multiple" ) {
- testChange.call( this, e );
- }
- },
-
- // Beforeactivate happens also before the previous element is blurred
- // with this event you can't trigger a change event, but you can store
- // information
- beforeactivate: function( e ) {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
var elem = e.target;
- jQuery._data( elem, "_change_data", getVal(elem) );
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "changeBubbles", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
}
},
- setup: function( data, namespaces ) {
- if ( this.type === "file" ) {
- return false;
- }
-
- for ( var type in changeFilters ) {
- jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
- }
-
- return rformElems.test( this.nodeName );
- },
-
- teardown: function( namespaces ) {
- jQuery.event.remove( this, ".specialChange" );
-
- return rformElems.test( this.nodeName );
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
}
};
-
- changeFilters = jQuery.event.special.change.filters;
-
- // Handle when the input is .focus()'d
- changeFilters.focus = changeFilters.beforeactivate;
-}
-
-function trigger( type, elem, args ) {
- // Piggyback on a donor event to simulate a different one.
- // Fake originalEvent to avoid donor's stopPropagation, but if the
- // simulated event prevents default then we do the same on the donor.
- // Don't pass args or remember liveFired; they apply to the donor event.
- var event = jQuery.extend( {}, args[ 0 ] );
- event.type = type;
- event.originalEvent = {};
- event.liveFired = undefined;
- jQuery.event.handle.call( elem, event );
- if ( event.isDefaultPrevented() ) {
- args[ 0 ].preventDefault();
- }
}
// Create "bubbling" focus and blur events
@@ -3433,7 +5576,10 @@
jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0;
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
jQuery.event.special[ fix ] = {
setup: function() {
@@ -3447,89 +5593,97 @@
}
}
};
-
- function handler( donor ) {
- // Donor event is always a native one; fix it and switch its type.
- // Let focusin/out handler cancel the donor focus/blur event.
- var e = jQuery.event.fix( donor );
- e.type = fix;
- e.originalEvent = {};
- jQuery.event.trigger( e, null, e.target );
- if ( e.isDefaultPrevented() ) {
- donor.preventDefault();
- }
- }
});
}
-jQuery.each(["bind", "one"], function( i, name ) {
- jQuery.fn[ name ] = function( type, data, fn ) {
- var handler;
-
- // Handle object literals
- if ( typeof type === "object" ) {
- for ( var key in type ) {
- this[ name ](key, data, type[key], fn);
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var type, origFn;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
}
return this;
}
- if ( arguments.length === 2 || data === false ) {
- fn = data;
- data = undefined;
- }
-
- if ( name === "one" ) {
- handler = function( event ) {
- jQuery( this ).unbind( event, handler );
- return fn.apply( this, arguments );
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
};
- handler.guid = fn.guid || jQuery.guid++;
- } else {
- handler = fn;
- }
-
- if ( type === "unload" && name !== "one" ) {
- this.one( type, data, fn );
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.add( this[i], type, handler, data );
- }
- }
-
- return this;
- };
-});
-
-jQuery.fn.extend({
- unbind: function( type, fn ) {
- // Handle object literals
- if ( typeof type === "object" && !type.preventDefault ) {
- for ( var key in type ) {
- this.unbind(key, type[key]);
- }
-
- } else {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- jQuery.event.remove( this[i], type, fn );
- }
- }
-
- return this;
- },
-
- delegate: function( selector, types, data, fn ) {
- return this.live( types, data, fn, selector );
- },
-
- undelegate: function( selector, types, fn ) {
- if ( arguments.length === 0 ) {
- return this.unbind( "live" );
-
- } else {
- return this.die( types, null, fn, selector );
- }
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
},
trigger: function( type, data ) {
@@ -3537,1664 +5691,16 @@
jQuery.event.trigger( type, data, this );
});
},
-
triggerHandler: function( type, data ) {
- if ( this[0] ) {
- return jQuery.event.trigger( type, data, this[0], true );
- }
- },
-
- toggle: function( fn ) {
- // Save reference to arguments for access in closure
- var args = arguments,
- guid = fn.guid || jQuery.guid++,
- i = 0,
- toggler = function( event ) {
- // Figure out which function to execute
- var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
- // Make sure that clicks stop
- event.preventDefault();
-
- // and execute the function
- return args[ lastToggle ].apply( this, arguments ) || false;
- };
-
- // link all the functions, so any of them can unbind this click handler
- toggler.guid = guid;
- while ( i < args.length ) {
- args[ i++ ].guid = guid;
- }
-
- return this.click( toggler );
- },
-
- hover: function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
- }
-});
-
-var liveMap = {
- focus: "focusin",
- blur: "focusout",
- mouseenter: "mouseover",
- mouseleave: "mouseout"
-};
-
-jQuery.each(["live", "die"], function( i, name ) {
- jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
- var type, i = 0, match, namespaces, preType,
- selector = origSelector || this.selector,
- context = origSelector ? this : jQuery( this.context );
-
- if ( typeof types === "object" && !types.preventDefault ) {
- for ( var key in types ) {
- context[ name ]( key, data, types[key], selector );
- }
-
- return this;
- }
-
- if ( name === "die" && !types &&
- origSelector && origSelector.charAt(0) === "." ) {
-
- context.unbind( origSelector );
-
- return this;
- }
-
- if ( data === false || jQuery.isFunction( data ) ) {
- fn = data || returnFalse;
- data = undefined;
- }
-
- types = (types || "").split(" ");
-
- while ( (type = types[ i++ ]) != null ) {
- match = rnamespaces.exec( type );
- namespaces = "";
-
- if ( match ) {
- namespaces = match[0];
- type = type.replace( rnamespaces, "" );
- }
-
- if ( type === "hover" ) {
- types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
- continue;
- }
-
- preType = type;
-
- if ( liveMap[ type ] ) {
- types.push( liveMap[ type ] + namespaces );
- type = type + namespaces;
-
- } else {
- type = (liveMap[ type ] || type) + namespaces;
- }
-
- if ( name === "live" ) {
- // bind live handler
- for ( var j = 0, l = context.length; j < l; j++ ) {
- jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
- { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
- }
-
- } else {
- // unbind live handler
- context.unbind( "live." + liveConvert( type, selector ), fn );
- }
- }
-
- return this;
- };
-});
-
-function liveHandler( event ) {
- var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
- elems = [],
- selectors = [],
- events = jQuery._data( this, "events" );
-
- // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
- if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
- return;
- }
-
- if ( event.namespace ) {
- namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
- }
-
- event.liveFired = this;
-
- var live = events.live.slice(0);
-
- for ( j = 0; j < live.length; j++ ) {
- handleObj = live[j];
-
- if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
- selectors.push( handleObj.selector );
-
- } else {
- live.splice( j--, 1 );
- }
- }
-
- match = jQuery( event.target ).closest( selectors, event.currentTarget );
-
- for ( i = 0, l = match.length; i < l; i++ ) {
- close = match[i];
-
- for ( j = 0; j < live.length; j++ ) {
- handleObj = live[j];
-
- if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
- elem = close.elem;
- related = null;
-
- // Those two events require additional checking
- if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
- event.type = handleObj.preType;
- related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
-
- // Make sure not to accidentally match a child element with the same selector
- if ( related && jQuery.contains( elem, related ) ) {
- related = elem;
- }
- }
-
- if ( !related || related !== elem ) {
- elems.push({ elem: elem, handleObj: handleObj, level: close.level });
- }
- }
- }
- }
-
- for ( i = 0, l = elems.length; i < l; i++ ) {
- match = elems[i];
-
- if ( maxLevel && match.level > maxLevel ) {
- break;
- }
-
- event.currentTarget = match.elem;
- event.data = match.handleObj.data;
- event.handleObj = match.handleObj;
-
- ret = match.handleObj.origHandler.apply( match.elem, arguments );
-
- if ( ret === false || event.isPropagationStopped() ) {
- maxLevel = match.level;
-
- if ( ret === false ) {
- stop = false;
- }
- if ( event.isImmediatePropagationStopped() ) {
- break;
- }
- }
- }
-
- return stop;
-}
-
-function liveConvert( type, selector ) {
- return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
-}
-
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
-
- // Handle event binding
- jQuery.fn[ name ] = function( data, fn ) {
- if ( fn == null ) {
- fn = data;
- data = null;
- }
-
- return arguments.length > 0 ?
- this.bind( name, data, fn ) :
- this.trigger( name );
- };
-
- if ( jQuery.attrFn ) {
- jQuery.attrFn[ name ] = true;
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
}
});
-
-
-
-/*!
- * Sizzle CSS Selector Engine
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- * More information: http://sizzlejs.com/
- */
-(function(){
-
-var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
- done = 0,
- toString = Object.prototype.toString,
- hasDuplicate = false,
- baseHasDuplicate = true,
- rBackslash = /\\/g,
- rNonWord = /\W/;
-
-// Here we check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
-// function. If that is the case, discard the hasDuplicate value.
-// Thus far that includes Google Chrome.
-[0, 0].sort(function() {
- baseHasDuplicate = false;
- return 0;
-});
-
-var Sizzle = function( selector, context, results, seed ) {
- results = results || [];
- context = context || document;
-
- var origContext = context;
-
- if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
- return [];
- }
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- var m, set, checkSet, extra, ret, cur, pop, i,
- prune = true,
- contextXML = Sizzle.isXML( context ),
- parts = [],
- soFar = selector;
-
- // Reset the position of the chunker regexp (start from head)
- do {
- chunker.exec( "" );
- m = chunker.exec( soFar );
-
- if ( m ) {
- soFar = m[3];
-
- parts.push( m[1] );
-
- if ( m[2] ) {
- extra = m[3];
- break;
- }
- }
- } while ( m );
-
- if ( parts.length > 1 && origPOS.exec( selector ) ) {
-
- if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
- set = posProcess( parts[0] + parts[1], context );
-
- } else {
- set = Expr.relative[ parts[0] ] ?
- [ context ] :
- Sizzle( parts.shift(), context );
-
- while ( parts.length ) {
- selector = parts.shift();
-
- if ( Expr.relative[ selector ] ) {
- selector += parts.shift();
- }
-
- set = posProcess( selector, set );
- }
- }
-
- } else {
- // Take a shortcut and set the context if the root selector is an ID
- // (but not if it'll be faster if the inner selector is an ID)
- if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
- Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
-
- ret = Sizzle.find( parts.shift(), context, contextXML );
- context = ret.expr ?
- Sizzle.filter( ret.expr, ret.set )[0] :
- ret.set[0];
- }
-
- if ( context ) {
- ret = seed ?
- { expr: parts.pop(), set: makeArray(seed) } :
- Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
-
- set = ret.expr ?
- Sizzle.filter( ret.expr, ret.set ) :
- ret.set;
-
- if ( parts.length > 0 ) {
- checkSet = makeArray( set );
-
- } else {
- prune = false;
- }
-
- while ( parts.length ) {
- cur = parts.pop();
- pop = cur;
-
- if ( !Expr.relative[ cur ] ) {
- cur = "";
- } else {
- pop = parts.pop();
- }
-
- if ( pop == null ) {
- pop = context;
- }
-
- Expr.relative[ cur ]( checkSet, pop, contextXML );
- }
-
- } else {
- checkSet = parts = [];
- }
- }
-
- if ( !checkSet ) {
- checkSet = set;
- }
-
- if ( !checkSet ) {
- Sizzle.error( cur || selector );
- }
-
- if ( toString.call(checkSet) === "[object Array]" ) {
- if ( !prune ) {
- results.push.apply( results, checkSet );
-
- } else if ( context && context.nodeType === 1 ) {
- for ( i = 0; checkSet[i] != null; i++ ) {
- if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
- results.push( set[i] );
- }
- }
-
- } else {
- for ( i = 0; checkSet[i] != null; i++ ) {
- if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
- results.push( set[i] );
- }
- }
- }
-
- } else {
- makeArray( checkSet, results );
- }
-
- if ( extra ) {
- Sizzle( extra, origContext, results, seed );
- Sizzle.uniqueSort( results );
- }
-
- return results;
-};
-
-Sizzle.uniqueSort = function( results ) {
- if ( sortOrder ) {
- hasDuplicate = baseHasDuplicate;
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- for ( var i = 1; i < results.length; i++ ) {
- if ( results[i] === results[ i - 1 ] ) {
- results.splice( i--, 1 );
- }
- }
- }
- }
-
- return results;
-};
-
-Sizzle.matches = function( expr, set ) {
- return Sizzle( expr, null, null, set );
-};
-
-Sizzle.matchesSelector = function( node, expr ) {
- return Sizzle( expr, null, null, [node] ).length > 0;
-};
-
-Sizzle.find = function( expr, context, isXML ) {
- var set;
-
- if ( !expr ) {
- return [];
- }
-
- for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
- var match,
- type = Expr.order[i];
-
- if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
- var left = match[1];
- match.splice( 1, 1 );
-
- if ( left.substr( left.length - 1 ) !== "\\" ) {
- match[1] = (match[1] || "").replace( rBackslash, "" );
- set = Expr.find[ type ]( match, context, isXML );
-
- if ( set != null ) {
- expr = expr.replace( Expr.match[ type ], "" );
- break;
- }
- }
- }
- }
-
- if ( !set ) {
- set = typeof context.getElementsByTagName !== "undefined" ?
- context.getElementsByTagName( "*" ) :
- [];
- }
-
- return { set: set, expr: expr };
-};
-
-Sizzle.filter = function( expr, set, inplace, not ) {
- var match, anyFound,
- old = expr,
- result = [],
- curLoop = set,
- isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
-
- while ( expr && set.length ) {
- for ( var type in Expr.filter ) {
- if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
- var found, item,
- filter = Expr.filter[ type ],
- left = match[1];
-
- anyFound = false;
-
- match.splice(1,1);
-
- if ( left.substr( left.length - 1 ) === "\\" ) {
- continue;
- }
-
- if ( curLoop === result ) {
- result = [];
- }
-
- if ( Expr.preFilter[ type ] ) {
- match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
-
- if ( !match ) {
- anyFound = found = true;
-
- } else if ( match === true ) {
- continue;
- }
- }
-
- if ( match ) {
- for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
- if ( item ) {
- found = filter( item, match, i, curLoop );
- var pass = not ^ !!found;
-
- if ( inplace && found != null ) {
- if ( pass ) {
- anyFound = true;
-
- } else {
- curLoop[i] = false;
- }
-
- } else if ( pass ) {
- result.push( item );
- anyFound = true;
- }
- }
- }
- }
-
- if ( found !== undefined ) {
- if ( !inplace ) {
- curLoop = result;
- }
-
- expr = expr.replace( Expr.match[ type ], "" );
-
- if ( !anyFound ) {
- return [];
- }
-
- break;
- }
- }
- }
-
- // Improper expression
- if ( expr === old ) {
- if ( anyFound == null ) {
- Sizzle.error( expr );
-
- } else {
- break;
- }
- }
-
- old = expr;
- }
-
- return curLoop;
-};
-
-Sizzle.error = function( msg ) {
- throw "Syntax error, unrecognized expression: " + msg;
-};
-
-var Expr = Sizzle.selectors = {
- order: [ "ID", "NAME", "TAG" ],
-
- match: {
- ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
- CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
- NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
- ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
- TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
- CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
- POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
- PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
- },
-
- leftMatch: {},
-
- attrMap: {
- "class": "className",
- "for": "htmlFor"
- },
-
- attrHandle: {
- href: function( elem ) {
- return elem.getAttribute( "href" );
- },
- type: function( elem ) {
- return elem.getAttribute( "type" );
- }
- },
-
- relative: {
- "+": function(checkSet, part){
- var isPartStr = typeof part === "string",
- isTag = isPartStr && !rNonWord.test( part ),
- isPartStrNotTag = isPartStr && !isTag;
-
- if ( isTag ) {
- part = part.toLowerCase();
- }
-
- for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
- if ( (elem = checkSet[i]) ) {
- while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
-
- checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
- elem || false :
- elem === part;
- }
- }
-
- if ( isPartStrNotTag ) {
- Sizzle.filter( part, checkSet, true );
- }
- },
-
- ">": function( checkSet, part ) {
- var elem,
- isPartStr = typeof part === "string",
- i = 0,
- l = checkSet.length;
-
- if ( isPartStr && !rNonWord.test( part ) ) {
- part = part.toLowerCase();
-
- for ( ; i < l; i++ ) {
- elem = checkSet[i];
-
- if ( elem ) {
- var parent = elem.parentNode;
- checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
- }
- }
-
- } else {
- for ( ; i < l; i++ ) {
- elem = checkSet[i];
-
- if ( elem ) {
- checkSet[i] = isPartStr ?
- elem.parentNode :
- elem.parentNode === part;
- }
- }
-
- if ( isPartStr ) {
- Sizzle.filter( part, checkSet, true );
- }
- }
- },
-
- "": function(checkSet, part, isXML){
- var nodeCheck,
- doneName = done++,
- checkFn = dirCheck;
-
- if ( typeof part === "string" && !rNonWord.test( part ) ) {
- part = part.toLowerCase();
- nodeCheck = part;
- checkFn = dirNodeCheck;
- }
-
- checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
- },
-
- "~": function( checkSet, part, isXML ) {
- var nodeCheck,
- doneName = done++,
- checkFn = dirCheck;
-
- if ( typeof part === "string" && !rNonWord.test( part ) ) {
- part = part.toLowerCase();
- nodeCheck = part;
- checkFn = dirNodeCheck;
- }
-
- checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
- }
- },
-
- find: {
- ID: function( match, context, isXML ) {
- if ( typeof context.getElementById !== "undefined" && !isXML ) {
- var m = context.getElementById(match[1]);
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [m] : [];
- }
- },
-
- NAME: function( match, context ) {
- if ( typeof context.getElementsByName !== "undefined" ) {
- var ret = [],
- results = context.getElementsByName( match[1] );
-
- for ( var i = 0, l = results.length; i < l; i++ ) {
- if ( results[i].getAttribute("name") === match[1] ) {
- ret.push( results[i] );
- }
- }
-
- return ret.length === 0 ? null : ret;
- }
- },
-
- TAG: function( match, context ) {
- if ( typeof context.getElementsByTagName !== "undefined" ) {
- return context.getElementsByTagName( match[1] );
- }
- }
- },
- preFilter: {
- CLASS: function( match, curLoop, inplace, result, not, isXML ) {
- match = " " + match[1].replace( rBackslash, "" ) + " ";
-
- if ( isXML ) {
- return match;
- }
-
- for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
- if ( elem ) {
- if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
- if ( !inplace ) {
- result.push( elem );
- }
-
- } else if ( inplace ) {
- curLoop[i] = false;
- }
- }
- }
-
- return false;
- },
-
- ID: function( match ) {
- return match[1].replace( rBackslash, "" );
- },
-
- TAG: function( match, curLoop ) {
- return match[1].replace( rBackslash, "" ).toLowerCase();
- },
-
- CHILD: function( match ) {
- if ( match[1] === "nth" ) {
- if ( !match[2] ) {
- Sizzle.error( match[0] );
- }
-
- match[2] = match[2].replace(/^\+|\s*/g, '');
-
- // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
- var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
- match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
- !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
-
- // calculate the numbers (first)n+(last) including if they are negative
- match[2] = (test[1] + (test[2] || 1)) - 0;
- match[3] = test[3] - 0;
- }
- else if ( match[2] ) {
- Sizzle.error( match[0] );
- }
-
- // TODO: Move to normal caching system
- match[0] = done++;
-
- return match;
- },
-
- ATTR: function( match, curLoop, inplace, result, not, isXML ) {
- var name = match[1] = match[1].replace( rBackslash, "" );
-
- if ( !isXML && Expr.attrMap[name] ) {
- match[1] = Expr.attrMap[name];
- }
-
- // Handle if an un-quoted value was used
- match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
-
- if ( match[2] === "~=" ) {
- match[4] = " " + match[4] + " ";
- }
-
- return match;
- },
-
- PSEUDO: function( match, curLoop, inplace, result, not ) {
- if ( match[1] === "not" ) {
- // If we're dealing with a complex expression, or a simple one
- if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
- match[3] = Sizzle(match[3], null, null, curLoop);
-
- } else {
- var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
-
- if ( !inplace ) {
- result.push.apply( result, ret );
- }
-
- return false;
- }
-
- } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
- return true;
- }
-
- return match;
- },
-
- POS: function( match ) {
- match.unshift( true );
-
- return match;
- }
- },
-
- filters: {
- enabled: function( elem ) {
- return elem.disabled === false && elem.type !== "hidden";
- },
-
- disabled: function( elem ) {
- return elem.disabled === true;
- },
-
- checked: function( elem ) {
- return elem.checked === true;
- },
-
- selected: function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
- if ( elem.parentNode ) {
- elem.parentNode.selectedIndex;
- }
-
- return elem.selected === true;
- },
-
- parent: function( elem ) {
- return !!elem.firstChild;
- },
-
- empty: function( elem ) {
- return !elem.firstChild;
- },
-
- has: function( elem, i, match ) {
- return !!Sizzle( match[3], elem ).length;
- },
-
- header: function( elem ) {
- return (/h\d/i).test( elem.nodeName );
- },
-
- text: function( elem ) {
- var attr = elem.getAttribute( "type" ), type = elem.type;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
- },
-
- radio: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
- },
-
- checkbox: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
- },
-
- file: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
- },
-
- password: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
- },
-
- submit: function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && "submit" === elem.type;
- },
-
- image: function( elem ) {
- return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
- },
-
- reset: function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && "reset" === elem.type;
- },
-
- button: function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && "button" === elem.type || name === "button";
- },
-
- input: function( elem ) {
- return (/input|select|textarea|button/i).test( elem.nodeName );
- },
-
- focus: function( elem ) {
- return elem === elem.ownerDocument.activeElement;
- }
- },
- setFilters: {
- first: function( elem, i ) {
- return i === 0;
- },
-
- last: function( elem, i, match, array ) {
- return i === array.length - 1;
- },
-
- even: function( elem, i ) {
- return i % 2 === 0;
- },
-
- odd: function( elem, i ) {
- return i % 2 === 1;
- },
-
- lt: function( elem, i, match ) {
- return i < match[3] - 0;
- },
-
- gt: function( elem, i, match ) {
- return i > match[3] - 0;
- },
-
- nth: function( elem, i, match ) {
- return match[3] - 0 === i;
- },
-
- eq: function( elem, i, match ) {
- return match[3] - 0 === i;
- }
- },
- filter: {
- PSEUDO: function( elem, match, i, array ) {
- var name = match[1],
- filter = Expr.filters[ name ];
-
- if ( filter ) {
- return filter( elem, i, match, array );
-
- } else if ( name === "contains" ) {
- return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
-
- } else if ( name === "not" ) {
- var not = match[3];
-
- for ( var j = 0, l = not.length; j < l; j++ ) {
- if ( not[j] === elem ) {
- return false;
- }
- }
-
- return true;
-
- } else {
- Sizzle.error( name );
- }
- },
-
- CHILD: function( elem, match ) {
- var type = match[1],
- node = elem;
-
- switch ( type ) {
- case "only":
- case "first":
- while ( (node = node.previousSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- if ( type === "first" ) {
- return true;
- }
-
- node = elem;
-
- case "last":
- while ( (node = node.nextSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- return true;
-
- case "nth":
- var first = match[2],
- last = match[3];
-
- if ( first === 1 && last === 0 ) {
- return true;
- }
-
- var doneName = match[0],
- parent = elem.parentNode;
-
- if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
- var count = 0;
-
- for ( node = parent.firstChild; node; node = node.nextSibling ) {
- if ( node.nodeType === 1 ) {
- node.nodeIndex = ++count;
- }
- }
-
- parent.sizcache = doneName;
- }
-
- var diff = elem.nodeIndex - last;
-
- if ( first === 0 ) {
- return diff === 0;
-
- } else {
- return ( diff % first === 0 && diff / first >= 0 );
- }
- }
- },
-
- ID: function( elem, match ) {
- return elem.nodeType === 1 && elem.getAttribute("id") === match;
- },
-
- TAG: function( elem, match ) {
- return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
- },
-
- CLASS: function( elem, match ) {
- return (" " + (elem.className || elem.getAttribute("class")) + " ")
- .indexOf( match ) > -1;
- },
-
- ATTR: function( elem, match ) {
- var name = match[1],
- result = Expr.attrHandle[ name ] ?
- Expr.attrHandle[ name ]( elem ) :
- elem[ name ] != null ?
- elem[ name ] :
- elem.getAttribute( name ),
- value = result + "",
- type = match[2],
- check = match[4];
-
- return result == null ?
- type === "!=" :
- type === "=" ?
- value === check :
- type === "*=" ?
- value.indexOf(check) >= 0 :
- type === "~=" ?
- (" " + value + " ").indexOf(check) >= 0 :
- !check ?
- value && result !== false :
- type === "!=" ?
- value !== check :
- type === "^=" ?
- value.indexOf(check) === 0 :
- type === "$=" ?
- value.substr(value.length - check.length) === check :
- type === "|=" ?
- value === check || value.substr(0, check.length + 1) === check + "-" :
- false;
- },
-
- POS: function( elem, match, i, array ) {
- var name = match[2],
- filter = Expr.setFilters[ name ];
-
- if ( filter ) {
- return filter( elem, i, match, array );
- }
- }
- }
-};
-
-var origPOS = Expr.match.POS,
- fescape = function(all, num){
- return "\\" + (num - 0 + 1);
- };
-
-for ( var type in Expr.match ) {
- Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
- Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
-}
-
-var makeArray = function( array, results ) {
- array = Array.prototype.slice.call( array, 0 );
-
- if ( results ) {
- results.push.apply( results, array );
- return results;
- }
-
- return array;
-};
-
-// Perform a simple check to determine if the browser is capable of
-// converting a NodeList to an array using builtin methods.
-// Also verifies that the returned array holds DOM nodes
-// (which is not the case in the Blackberry browser)
-try {
- Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
-
-// Provide a fallback method if it does not work
-} catch( e ) {
- makeArray = function( array, results ) {
- var i = 0,
- ret = results || [];
-
- if ( toString.call(array) === "[object Array]" ) {
- Array.prototype.push.apply( ret, array );
-
- } else {
- if ( typeof array.length === "number" ) {
- for ( var l = array.length; i < l; i++ ) {
- ret.push( array[i] );
- }
-
- } else {
- for ( ; array[i]; i++ ) {
- ret.push( array[i] );
- }
- }
- }
-
- return ret;
- };
-}
-
-var sortOrder, siblingCheck;
-
-if ( document.documentElement.compareDocumentPosition ) {
- sortOrder = function( a, b ) {
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
- return a.compareDocumentPosition ? -1 : 1;
- }
-
- return a.compareDocumentPosition(b) & 4 ? -1 : 1;
- };
-
-} else {
- sortOrder = function( a, b ) {
- // The nodes are identical, we can exit early
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Fallback to using sourceIndex (in IE) if it's available on both nodes
- } else if ( a.sourceIndex && b.sourceIndex ) {
- return a.sourceIndex - b.sourceIndex;
- }
-
- var al, bl,
- ap = [],
- bp = [],
- aup = a.parentNode,
- bup = b.parentNode,
- cur = aup;
-
- // If the nodes are siblings (or identical) we can do a quick check
- if ( aup === bup ) {
- return siblingCheck( a, b );
-
- // If no parents were found then the nodes are disconnected
- } else if ( !aup ) {
- return -1;
-
- } else if ( !bup ) {
- return 1;
- }
-
- // Otherwise they're somewhere else in the tree so we need
- // to build up a full list of the parentNodes for comparison
- while ( cur ) {
- ap.unshift( cur );
- cur = cur.parentNode;
- }
-
- cur = bup;
-
- while ( cur ) {
- bp.unshift( cur );
- cur = cur.parentNode;
- }
-
- al = ap.length;
- bl = bp.length;
-
- // Start walking down the tree looking for a discrepancy
- for ( var i = 0; i < al && i < bl; i++ ) {
- if ( ap[i] !== bp[i] ) {
- return siblingCheck( ap[i], bp[i] );
- }
- }
-
- // We ended someplace up the tree so do a sibling check
- return i === al ?
- siblingCheck( a, bp[i], -1 ) :
- siblingCheck( ap[i], b, 1 );
- };
-
- siblingCheck = function( a, b, ret ) {
- if ( a === b ) {
- return ret;
- }
-
- var cur = a.nextSibling;
-
- while ( cur ) {
- if ( cur === b ) {
- return -1;
- }
-
- cur = cur.nextSibling;
- }
-
- return 1;
- };
-}
-
-// Utility function for retreiving the text value of an array of DOM nodes
-Sizzle.getText = function( elems ) {
- var ret = "", elem;
-
- for ( var i = 0; elems[i]; i++ ) {
- elem = elems[i];
-
- // Get the text from text nodes and CDATA nodes
- if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
- ret += elem.nodeValue;
-
- // Traverse everything else, except comment nodes
- } else if ( elem.nodeType !== 8 ) {
- ret += Sizzle.getText( elem.childNodes );
- }
- }
-
- return ret;
-};
-
-// Check to see if the browser returns elements by name when
-// querying by getElementById (and provide a workaround)
-(function(){
- // We're going to inject a fake input element with a specified name
- var form = document.createElement("div"),
- id = "script" + (new Date()).getTime(),
- root = document.documentElement;
-
- form.innerHTML = "<a name='" + id + "'/>";
-
- // Inject it into the root element, check its status, and remove it quickly
- root.insertBefore( form, root.firstChild );
-
- // The workaround has to do additional checks after a getElementById
- // Which slows things down for other browsers (hence the branching)
- if ( document.getElementById( id ) ) {
- Expr.find.ID = function( match, context, isXML ) {
- if ( typeof context.getElementById !== "undefined" && !isXML ) {
- var m = context.getElementById(match[1]);
-
- return m ?
- m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
- [m] :
- undefined :
- [];
- }
- };
-
- Expr.filter.ID = function( elem, match ) {
- var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
-
- return elem.nodeType === 1 && node && node.nodeValue === match;
- };
- }
-
- root.removeChild( form );
-
- // release memory in IE
- root = form = null;
-})();
-
-(function(){
- // Check to see if the browser returns only elements
- // when doing getElementsByTagName("*")
-
- // Create a fake element
- var div = document.createElement("div");
- div.appendChild( document.createComment("") );
-
- // Make sure no comments are found
- if ( div.getElementsByTagName("*").length > 0 ) {
- Expr.find.TAG = function( match, context ) {
- var results = context.getElementsByTagName( match[1] );
-
- // Filter out possible comments
- if ( match[1] === "*" ) {
- var tmp = [];
-
- for ( var i = 0; results[i]; i++ ) {
- if ( results[i].nodeType === 1 ) {
- tmp.push( results[i] );
- }
- }
-
- results = tmp;
- }
-
- return results;
- };
- }
-
- // Check to see if an attribute returns normalized href attributes
- div.innerHTML = "<a href='#'></a>";
-
- if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
- div.firstChild.getAttribute("href") !== "#" ) {
-
- Expr.attrHandle.href = function( elem ) {
- return elem.getAttribute( "href", 2 );
- };
- }
-
- // release memory in IE
- div = null;
-})();
-
-if ( document.querySelectorAll ) {
- (function(){
- var oldSizzle = Sizzle,
- div = document.createElement("div"),
- id = "__sizzle__";
-
- div.innerHTML = "<p class='TEST'></p>";
-
- // Safari can't handle uppercase or unicode characters when
- // in quirks mode.
- if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
- return;
- }
-
- Sizzle = function( query, context, extra, seed ) {
- context = context || document;
-
- // Only use querySelectorAll on non-XML documents
- // (ID selectors don't work in non-HTML documents)
- if ( !seed && !Sizzle.isXML(context) ) {
- // See if we find a selector to speed up
- var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
-
- if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
- // Speed-up: Sizzle("TAG")
- if ( match[1] ) {
- return makeArray( context.getElementsByTagName( query ), extra );
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
- return makeArray( context.getElementsByClassName( match[2] ), extra );
- }
- }
-
- if ( context.nodeType === 9 ) {
- // Speed-up: Sizzle("body")
- // The body element only exists once, optimize finding it
- if ( query === "body" && context.body ) {
- return makeArray( [ context.body ], extra );
-
- // Speed-up: Sizzle("#ID")
- } else if ( match && match[3] ) {
- var elem = context.getElementById( match[3] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id === match[3] ) {
- return makeArray( [ elem ], extra );
- }
-
- } else {
- return makeArray( [], extra );
- }
- }
-
- try {
- return makeArray( context.querySelectorAll(query), extra );
- } catch(qsaError) {}
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- var oldContext = context,
- old = context.getAttribute( "id" ),
- nid = old || id,
- hasParent = context.parentNode,
- relativeHierarchySelector = /^\s*[+~]/.test( query );
-
- if ( !old ) {
- context.setAttribute( "id", nid );
- } else {
- nid = nid.replace( /'/g, "\\$&" );
- }
- if ( relativeHierarchySelector && hasParent ) {
- context = context.parentNode;
- }
-
- try {
- if ( !relativeHierarchySelector || hasParent ) {
- return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
- }
-
- } catch(pseudoError) {
- } finally {
- if ( !old ) {
- oldContext.removeAttribute( "id" );
- }
- }
- }
- }
-
- return oldSizzle(query, context, extra, seed);
- };
-
- for ( var prop in oldSizzle ) {
- Sizzle[ prop ] = oldSizzle[ prop ];
- }
-
- // release memory in IE
- div = null;
- })();
-}
-
-(function(){
- var html = document.documentElement,
- matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
-
- if ( matches ) {
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9 fails this)
- var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
- pseudoWorks = false;
-
- try {
- // This should fail with an exception
- // Gecko does not error, returns false instead
- matches.call( document.documentElement, "[test!='']:sizzle" );
-
- } catch( pseudoError ) {
- pseudoWorks = true;
- }
-
- Sizzle.matchesSelector = function( node, expr ) {
- // Make sure that attribute selectors are quoted
- expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
-
- if ( !Sizzle.isXML( node ) ) {
- try {
- if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
- var ret = matches.call( node, expr );
-
- // IE 9's matchesSelector returns false on disconnected nodes
- if ( ret || !disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9, so check for that
- node.document && node.document.nodeType !== 11 ) {
- return ret;
- }
- }
- } catch(e) {}
- }
-
- return Sizzle(expr, null, null, [node]).length > 0;
- };
- }
-})();
-
-(function(){
- var div = document.createElement("div");
-
- div.innerHTML = "<div class='test e'></div><div class='test'></div>";
-
- // Opera can't find a second classname (in 9.6)
- // Also, make sure that getElementsByClassName actually exists
- if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
- return;
- }
-
- // Safari caches class attributes, doesn't catch changes (in 3.2)
- div.lastChild.className = "e";
-
- if ( div.getElementsByClassName("e").length === 1 ) {
- return;
- }
-
- Expr.order.splice(1, 0, "CLASS");
- Expr.find.CLASS = function( match, context, isXML ) {
- if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
- return context.getElementsByClassName(match[1]);
- }
- };
-
- // release memory in IE
- div = null;
-})();
-
-function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
- var elem = checkSet[i];
-
- if ( elem ) {
- var match = false;
-
- elem = elem[dir];
-
- while ( elem ) {
- if ( elem.sizcache === doneName ) {
- match = checkSet[elem.sizset];
- break;
- }
-
- if ( elem.nodeType === 1 && !isXML ){
- elem.sizcache = doneName;
- elem.sizset = i;
- }
-
- if ( elem.nodeName.toLowerCase() === cur ) {
- match = elem;
- break;
- }
-
- elem = elem[dir];
- }
-
- checkSet[i] = match;
- }
- }
-}
-
-function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
- for ( var i = 0, l = checkSet.length; i < l; i++ ) {
- var elem = checkSet[i];
-
- if ( elem ) {
- var match = false;
-
- elem = elem[dir];
-
- while ( elem ) {
- if ( elem.sizcache === doneName ) {
- match = checkSet[elem.sizset];
- break;
- }
-
- if ( elem.nodeType === 1 ) {
- if ( !isXML ) {
- elem.sizcache = doneName;
- elem.sizset = i;
- }
-
- if ( typeof cur !== "string" ) {
- if ( elem === cur ) {
- match = true;
- break;
- }
-
- } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
- match = elem;
- break;
- }
- }
-
- elem = elem[dir];
- }
-
- checkSet[i] = match;
- }
- }
-}
-
-if ( document.documentElement.contains ) {
- Sizzle.contains = function( a, b ) {
- return a !== b && (a.contains ? a.contains(b) : true);
- };
-
-} else if ( document.documentElement.compareDocumentPosition ) {
- Sizzle.contains = function( a, b ) {
- return !!(a.compareDocumentPosition(b) & 16);
- };
-
-} else {
- Sizzle.contains = function() {
- return false;
- };
-}
-
-Sizzle.isXML = function( elem ) {
- // documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
- var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
-
- return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-var posProcess = function( selector, context ) {
- var match,
- tmpSet = [],
- later = "",
- root = context.nodeType ? [context] : context;
-
- // Position selectors must be done after the filter
- // And so must :not(positional) so we move all PSEUDOs to the end
- while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
- later += match[0];
- selector = selector.replace( Expr.match.PSEUDO, "" );
- }
-
- selector = Expr.relative[selector] ? selector + "*" : selector;
-
- for ( var i = 0, l = root.length; i < l; i++ ) {
- Sizzle( selector, root[i], tmpSet );
- }
-
- return Sizzle.filter( later, tmpSet );
-};
-
-// EXPOSE
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.filters;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})();
-
-
-var runtil = /Until$/,
- rparentsprev = /^(?:parents|prevUntil|prevAll)/,
- // Note: This RegExp should be improved, or likely pulled from Sizzle
- rmultiselector = /,/,
- isSimple = /^.[^:#\[\.,]*$/,
- slice = Array.prototype.slice,
- POS = jQuery.expr.match.POS,
+var isSimple = /^.[^:#\[\.,]*$/,
+ rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ rneedsContext = jQuery.expr.match.needsContext,
// methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
children: true,
@@ -5205,46 +5711,38 @@
jQuery.fn.extend({
find: function( selector ) {
- var self = this,
- i, l;
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
if ( typeof selector !== "string" ) {
- return jQuery( selector ).filter(function() {
- for ( i = 0, l = self.length; i < l; i++ ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( self[ i ], this ) ) {
return true;
}
}
- });
- }
-
- var ret = this.pushStack( "", "find", selector ),
- length, n, r;
-
- for ( i = 0, l = this.length; i < l; i++ ) {
- length = ret.length;
- jQuery.find( selector, this[i], ret );
-
- if ( i > 0 ) {
- // Make sure that the results are unique
- for ( n = length; n < ret.length; n++ ) {
- for ( r = 0; r < length; r++ ) {
- if ( ret[r] === ret[n] ) {
- ret.splice(n--, 1);
- break;
- }
- }
- }
- }
- }
-
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
return ret;
},
has: function( target ) {
- var targets = jQuery( target );
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
return this.filter(function() {
- for ( var i = 0, l = targets.length; i < l; i++ ) {
+ for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( this, targets[i] ) ) {
return true;
}
@@ -5253,81 +5751,52 @@
},
not: function( selector ) {
- return this.pushStack( winnow(this, selector, false), "not", selector);
+ return this.pushStack( winnow(this, selector || [], true) );
},
filter: function( selector ) {
- return this.pushStack( winnow(this, selector, true), "filter", selector );
+ return this.pushStack( winnow(this, selector || [], false) );
},
is: function( selector ) {
- return !!selector && ( typeof selector === "string" ?
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
},
closest: function( selectors, context ) {
- var ret = [], i, l, cur = this[0];
-
- // Array
- if ( jQuery.isArray( selectors ) ) {
- var match, selector,
- matches = {},
- level = 1;
-
- if ( cur && selectors.length ) {
- for ( i = 0, l = selectors.length; i < l; i++ ) {
- selector = selectors[i];
-
- if ( !matches[ selector ] ) {
- matches[ selector ] = POS.test( selector ) ?
- jQuery( selector, context || this.context ) :
- selector;
- }
- }
-
- while ( cur && cur.ownerDocument && cur !== context ) {
- for ( selector in matches ) {
- match = matches[ selector ];
-
- if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
- ret.push({ selector: selector, elem: cur, level: level });
- }
- }
-
- cur = cur.parentNode;
- level++;
- }
- }
-
- return ret;
- }
-
- // String
- var pos = POS.test( selectors ) || typeof selectors !== "string" ?
+ var cur,
+ i = 0,
+ l = this.length,
+ ret = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
jQuery( selectors, context || this.context ) :
0;
- for ( i = 0, l = this.length; i < l; i++ ) {
- cur = this[i];
-
- while ( cur ) {
- if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
- ret.push( cur );
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ cur = ret.push( cur );
break;
-
- } else {
- cur = cur.parentNode;
- if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
- break;
- }
- }
- }
- }
-
- ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
-
- return this.pushStack( ret, "closest", selectors );
+ }
+ }
+ }
+
+ return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
},
// Determine the position of an element within
@@ -5336,7 +5805,7 @@
// No argument, return index in parent
if ( !elem ) {
- return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
}
// index in selector
@@ -5356,20 +5825,22 @@
jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
all = jQuery.merge( this.get(), set );
- return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
- all :
- jQuery.unique( all ) );
- },
-
- andSelf: function() {
- return this.add( this.prevObject );
+ return this.pushStack( jQuery.unique(all) );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
}
});
-// A painfully simple check to see if an element is disconnected
-// from a document (should be improved, where feasible).
-function isDisconnected( node ) {
- return !node || !node.parentNode || node.parentNode.nodeType === 11;
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
}
jQuery.each({
@@ -5384,10 +5855,10 @@
return jQuery.dir( elem, "parentNode", until );
},
next: function( elem ) {
- return jQuery.nth( elem, 2, "nextSibling" );
+ return sibling( elem, "nextSibling" );
},
prev: function( elem ) {
- return jQuery.nth( elem, 2, "previousSibling" );
+ return sibling( elem, "previousSibling" );
},
nextAll: function( elem ) {
return jQuery.dir( elem, "nextSibling" );
@@ -5402,7 +5873,7 @@
return jQuery.dir( elem, "previousSibling", until );
},
siblings: function( elem ) {
- return jQuery.sibling( elem.parentNode.firstChild, elem );
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
},
children: function( elem ) {
return jQuery.sibling( elem.firstChild );
@@ -5410,18 +5881,13 @@
contents: function( elem ) {
return jQuery.nodeName( elem, "iframe" ) ?
elem.contentDocument || elem.contentWindow.document :
- jQuery.makeArray( elem.childNodes );
+ jQuery.merge( [], elem.childNodes );
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
- var ret = jQuery.map( this, fn, until ),
- // The variable 'args' was introduced in
- // https://github.com/jquery/jquery/commit/52a0238
- // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
- // http://code.google.com/p/v8/issues/detail?id=1050
- args = slice.call(arguments);
-
- if ( !runtil.test( name ) ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
selector = until;
}
@@ -5429,25 +5895,35 @@
ret = jQuery.filter( selector, ret );
}
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret, name, args.join(",") );
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ ret = jQuery.unique( ret );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+ }
+
+ return this.pushStack( ret );
};
});
jQuery.extend({
filter: function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
if ( not ) {
expr = ":not(" + expr + ")";
}
- return elems.length === 1 ?
- jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
- jQuery.find.matches(expr, elems);
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
},
dir: function( elem, dir, until ) {
@@ -5463,19 +5939,6 @@
return matched;
},
- nth: function( cur, result, dir, elem ) {
- result = result || 1;
- var num = 0;
-
- for ( ; cur; cur = cur[dir] ) {
- if ( cur.nodeType === 1 && ++num === result ) {
- break;
- }
- }
-
- return cur;
- },
-
sibling: function( n, elem ) {
var r = [];
@@ -5490,91 +5953,779 @@
});
// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-
- // Can't pass null or undefined to indexOf in Firefox 4
- // Set to 0 to skip string check
- qualifier = qualifier || 0;
-
+function winnow( elements, qualifier, not ) {
if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- var retVal = !!qualifier.call( elem, i, elem );
- return retVal === keep;
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
});
- } else if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem, i ) {
- return (elem === qualifier) === keep;
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
});
- } else if ( typeof qualifier === "string" ) {
- var filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
+ }
+
+ if ( typeof qualifier === "string" ) {
if ( isSimple.test( qualifier ) ) {
- return jQuery.filter(qualifier, filtered, !keep);
- } else {
- qualifier = jQuery.filter( qualifier, filtered );
- }
- }
-
- return jQuery.grep(elements, function( elem, i ) {
- return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
});
}
-
-
-
-
-var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
rleadingWhitespace = /^\s+/,
- rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
rtagName = /<([\w:]+)/,
rtbody = /<tbody/i,
rhtml = /<|&#?\w+;/,
- rnocache = /<(?:script|object|embed|option|style)/i,
+ rnoInnerhtml = /<(?:script|style|link)/i,
+ manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
// checked="checked" or checked
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
- rscriptType = /\/(java|ecma)script/i,
- rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
+ rscriptType = /^$|\/(?:java|ecma)script/i,
+ rscriptTypeMasked = /^true\/(.*)/,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
wrapMap = {
option: [ 1, "<select multiple='multiple'>", "</select>" ],
legend: [ 1, "<fieldset>", "</fieldset>" ],
+ area: [ 1, "<map>", "</map>" ],
+ param: [ 1, "<object>", "</object>" ],
thead: [ 1, "<table>", "</table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
- col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
- area: [ 1, "<map>", "</map>" ],
- _default: [ 0, "", "" ]
- };
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
-// IE can't serialize <link> and <script> tags normally
-if ( !jQuery.support.htmlSerialize ) {
- wrapMap._default = [ 1, "div<div>", "</div>" ];
-}
-
jQuery.fn.extend({
- text: function( text ) {
- if ( jQuery.isFunction(text) ) {
- return this.each(function(i) {
- var self = jQuery( this );
-
- self.text( text.call(this, i, self.text()) );
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+
+ // If this is a select, ensure that it displays empty (#12336)
+ // Support: IE<9
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+ elem.options.length = 0;
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var
+ // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
+ args = jQuery.map( this, function( elem ) {
+ return [ elem.nextSibling, elem.parentNode ];
+ }),
+ i = 0;
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ var next = args[ i++ ],
+ parent = args[ i++ ];
+
+ if ( parent ) {
+ // Don't use the snapshot next if it has moved (#13810)
+ if ( next && next.parentNode !== parent ) {
+ next = this.nextSibling;
+ }
+ jQuery( this ).remove();
+ parent.insertBefore( elem, next );
+ }
+ // Allow new content to include elements from the context set
+ }, true );
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return i ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback, allowIntersection ) {
+
+ // Flatten any nested arrays
+ args = core_concat.apply( [], args );
+
+ var first, node, hasScripts,
+ scripts, doc, fragment,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[0],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[0] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback, allowIntersection );
});
}
- if ( typeof text !== "object" && text !== undefined ) {
- return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
- }
-
- return jQuery.text( this );
- },
-
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[i], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Hope ajax is available...
+ jQuery._evalUrl( node.src );
+ } else {
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+ }
+ }
+
+ return this;
+ }
+});
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+ if ( match ) {
+ elem.type = match[1];
+ } else {
+ elem.removeAttribute("type");
+ }
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+ var nodeName, e, data;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
+ if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
+ data = jQuery._data( dest );
+
+ for ( e in data.events ) {
+ jQuery.removeEvent( dest, e, data.handle );
+ }
+
+ // Event data gets referenced instead of copied if the expando gets copied too
+ dest.removeAttribute( jQuery.expando );
+ }
+
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+ if ( nodeName === "script" && dest.text !== src.text ) {
+ disableScript( dest ).text = src.text;
+ restoreScript( dest );
+
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ } else if ( nodeName === "object" ) {
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.defaultSelected = dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone(true);
+ jQuery( insert[i] )[ original ]( elems );
+
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ core_push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( manipulation_rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var destElements, node, clone, i, srcElements,
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ // Fix all IE cloning issues
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ fixCloneNodeIssues( node, destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+ cloneCopyEvent( node, destElements[i] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ destElements = srcElements = node = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var j, elem, contains,
+ tmp, tag, tbody, wrap,
+ l = elems.length,
+
+ // Ensure a safe fragment
+ safe = createSafeFragment( context ),
+
+ nodes = [],
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || safe.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
+
+ // Descend through wrappers to the right content
+ j = wrap[0];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Manually add leading whitespace removed by IE
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !jQuery.support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var elem, type, id, data,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = jQuery.support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== core_strundefined ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ core_deletedIds.push( id );
+ }
+ }
+ }
+ }
+ },
+
+ _evalUrl: function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+ }
+});
+jQuery.fn.extend({
wrapAll: function( html ) {
if ( jQuery.isFunction( html ) ) {
return this.each(function(i) {
@@ -5625,8 +6776,10 @@
},
wrap: function( html ) {
- return this.each(function() {
- jQuery( this ).wrapAll( html );
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
});
},
@@ -5636,694 +6789,158 @@
jQuery( this ).replaceWith( this.childNodes );
}
}).end();
- },
-
- append: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 ) {
- this.appendChild( elem );
- }
- });
- },
-
- prepend: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 ) {
- this.insertBefore( elem, this.firstChild );
- }
- });
- },
-
- before: function() {
- if ( this[0] && this[0].parentNode ) {
- return this.domManip(arguments, false, function( elem ) {
- this.parentNode.insertBefore( elem, this );
- });
- } else if ( arguments.length ) {
- var set = jQuery(arguments[0]);
- set.push.apply( set, this.toArray() );
- return this.pushStack( set, "before", arguments );
- }
- },
-
- after: function() {
- if ( this[0] && this[0].parentNode ) {
- return this.domManip(arguments, false, function( elem ) {
- this.parentNode.insertBefore( elem, this.nextSibling );
- });
- } else if ( arguments.length ) {
- var set = this.pushStack( this, "after", arguments );
- set.push.apply( set, jQuery(arguments[0]).toArray() );
- return set;
- }
- },
-
- // keepData is for internal use only--do not document
- remove: function( selector, keepData ) {
- for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
- if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
- if ( !keepData && elem.nodeType === 1 ) {
- jQuery.cleanData( elem.getElementsByTagName("*") );
- jQuery.cleanData( [ elem ] );
- }
-
- if ( elem.parentNode ) {
- elem.parentNode.removeChild( elem );
- }
- }
- }
-
- return this;
- },
-
- empty: function() {
- for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
- // Remove element nodes and prevent memory leaks
- if ( elem.nodeType === 1 ) {
- jQuery.cleanData( elem.getElementsByTagName("*") );
- }
-
- // Remove any remaining nodes
- while ( elem.firstChild ) {
- elem.removeChild( elem.firstChild );
- }
- }
-
- return this;
- },
-
- clone: function( dataAndEvents, deepDataAndEvents ) {
- dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
- deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
-
- return this.map( function () {
- return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
- });
- },
-
- html: function( value ) {
- if ( value === undefined ) {
- return this[0] && this[0].nodeType === 1 ?
- this[0].innerHTML.replace(rinlinejQuery, "") :
- null;
-
- // See if we can take a shortcut and just use innerHTML
- } else if ( typeof value === "string" && !rnocache.test( value ) &&
- (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
- !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
-
- value = value.replace(rxhtmlTag, "<$1></$2>");
-
- try {
- for ( var i = 0, l = this.length; i < l; i++ ) {
- // Remove element nodes and prevent memory leaks
- if ( this[i].nodeType === 1 ) {
- jQuery.cleanData( this[i].getElementsByTagName("*") );
- this[i].innerHTML = value;
- }
- }
-
- // If using innerHTML throws an exception, use the fallback method
- } catch(e) {
- this.empty().append( value );
- }
-
- } else if ( jQuery.isFunction( value ) ) {
- this.each(function(i){
- var self = jQuery( this );
-
- self.html( value.call(this, i, self.html()) );
- });
-
- } else {
- this.empty().append( value );
- }
-
- return this;
- },
-
- replaceWith: function( value ) {
- if ( this[0] && this[0].parentNode ) {
- // Make sure that the elements are removed from the DOM before they are inserted
- // this can help fix replacing a parent with child elements
- if ( jQuery.isFunction( value ) ) {
- return this.each(function(i) {
- var self = jQuery(this), old = self.html();
- self.replaceWith( value.call( this, i, old ) );
- });
- }
-
- if ( typeof value !== "string" ) {
- value = jQuery( value ).detach();
- }
-
- return this.each(function() {
- var next = this.nextSibling,
- parent = this.parentNode;
-
- jQuery( this ).remove();
-
- if ( next ) {
- jQuery(next).before( value );
- } else {
- jQuery(parent).append( value );
- }
- });
- } else {
- return this.length ?
- this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
- this;
- }
- },
-
- detach: function( selector ) {
- return this.remove( selector, true );
- },
-
- domManip: function( args, table, callback ) {
- var results, first, fragment, parent,
- value = args[0],
- scripts = [];
-
- // We can't cloneNode fragments that contain checked, in WebKit
- if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
- return this.each(function() {
- jQuery(this).domManip( args, table, callback, true );
- });
- }
-
- if ( jQuery.isFunction(value) ) {
- return this.each(function(i) {
- var self = jQuery(this);
- args[0] = value.call(this, i, table ? self.html() : undefined);
- self.domManip( args, table, callback );
- });
- }
-
- if ( this[0] ) {
- parent = value && value.parentNode;
-
- // If we're in a fragment, just use that instead of building a new one
- if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
- results = { fragment: parent };
-
- } else {
- results = jQuery.buildFragment( args, this, scripts );
- }
-
- fragment = results.fragment;
-
- if ( fragment.childNodes.length === 1 ) {
- first = fragment = fragment.firstChild;
- } else {
- first = fragment.firstChild;
- }
-
- if ( first ) {
- table = table && jQuery.nodeName( first, "tr" );
-
- for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
- callback.call(
- table ?
- root(this[i], first) :
- this[i],
- // Make sure that we do not leak memory by inadvertently discarding
- // the original fragment (which might have attached data) instead of
- // using it; in addition, use the original fragment object for the last
- // item instead of first because it can end up being emptied incorrectly
- // in certain situations (Bug #8070).
- // Fragments from the fragment cache must always be cloned and never used
- // in place.
- results.cacheable || (l > 1 && i < lastIndex) ?
- jQuery.clone( fragment, true, true ) :
- fragment
- );
- }
- }
-
- if ( scripts.length ) {
- jQuery.each( scripts, evalScript );
- }
- }
-
- return this;
}
});
-
-function root( elem, cur ) {
- return jQuery.nodeName(elem, "table") ?
- (elem.getElementsByTagName("tbody")[0] ||
- elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
- elem;
-}
-
-function cloneCopyEvent( src, dest ) {
-
- if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
- return;
- }
-
- var internalKey = jQuery.expando,
- oldData = jQuery.data( src ),
- curData = jQuery.data( dest, oldData );
-
- // Switch to use the internal data object, if it exists, for the next
- // stage of data copying
- if ( (oldData = oldData[ internalKey ]) ) {
- var events = oldData.events;
- curData = curData[ internalKey ] = jQuery.extend({}, oldData);
-
- if ( events ) {
- delete curData.handle;
- curData.events = {};
-
- for ( var type in events ) {
- for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
- }
- }
- }
- }
-}
-
-function cloneFixAttributes( src, dest ) {
- var nodeName;
-
- // We do not need to do anything for non-Elements
- if ( dest.nodeType !== 1 ) {
- return;
- }
-
- // clearAttributes removes the attributes, which we don't want,
- // but also removes the attachEvent events, which we *do* want
- if ( dest.clearAttributes ) {
- dest.clearAttributes();
- }
-
- // mergeAttributes, in contrast, only merges back on the
- // original attributes, not the events
- if ( dest.mergeAttributes ) {
- dest.mergeAttributes( src );
- }
-
- nodeName = dest.nodeName.toLowerCase();
-
- // IE6-8 fail to clone children inside object elements that use
- // the proprietary classid attribute value (rather than the type
- // attribute) to identify the type of content to display
- if ( nodeName === "object" ) {
- dest.outerHTML = src.outerHTML;
-
- } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
- // IE6-8 fails to persist the checked state of a cloned checkbox
- // or radio button. Worse, IE6-7 fail to give the cloned element
- // a checked appearance if the defaultChecked value isn't also set
- if ( src.checked ) {
- dest.defaultChecked = dest.checked = src.checked;
- }
-
- // IE6-7 get confused and end up setting the value of a cloned
- // checkbox/radio button to an empty string instead of "on"
- if ( dest.value !== src.value ) {
- dest.value = src.value;
- }
-
- // IE6-8 fails to return the selected option to the default selected
- // state when cloning options
- } else if ( nodeName === "option" ) {
- dest.selected = src.defaultSelected;
-
- // IE6-8 fails to set the defaultValue to the correct value when
- // cloning other types of input fields
- } else if ( nodeName === "input" || nodeName === "textarea" ) {
- dest.defaultValue = src.defaultValue;
- }
-
- // Event data gets referenced instead of copied if the expando
- // gets copied too
- dest.removeAttribute( jQuery.expando );
+var iframe, getStyles, curCSS,
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+ rposition = /^(top|right|bottom|left)$/,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rmargin = /^margin/,
+ rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
+ rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
+ elemdisplay = { BODY: "block" },
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: 0,
+ fontWeight: 400
+ },
+
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
}
-jQuery.buildFragment = function( args, nodes, scripts ) {
- var fragment, cacheable, cacheresults, doc;
-
- // nodes may contain either an explicit document object,
- // a jQuery collection or context object.
- // If nodes[0] contains a valid object to assign to doc
- if ( nodes && nodes[0] ) {
- doc = nodes[0].ownerDocument || nodes[0];
- }
-
- // Ensure that an attr object doesn't incorrectly stand in as a document object
- // Chrome and Firefox seem to allow this to occur and will throw exception
- // Fixes #8950
- if ( !doc.createDocumentFragment ) {
- doc = document;
- }
-
- // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
- // Cloning options loses the selected state, so don't cache them
- // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
- // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
- if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
- args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
-
- cacheable = true;
-
- cacheresults = jQuery.fragments[ args[0] ];
- if ( cacheresults && cacheresults !== 1 ) {
- fragment = cacheresults;
- }
- }
-
- if ( !fragment ) {
- fragment = doc.createDocumentFragment();
- jQuery.clean( args, doc, fragment, scripts );
- }
-
- if ( cacheable ) {
- jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
- }
-
- return { fragment: fragment, cacheable: cacheable };
-};
-
-jQuery.fragments = {};
-
-jQuery.each({
- appendTo: "append",
- prependTo: "prepend",
- insertBefore: "before",
- insertAfter: "after",
- replaceAll: "replaceWith"
-}, function( name, original ) {
- jQuery.fn[ name ] = function( selector ) {
- var ret = [],
- insert = jQuery( selector ),
- parent = this.length === 1 && this[0].parentNode;
-
- if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
- insert[ original ]( this[0] );
- return this;
-
- } else {
- for ( var i = 0, l = insert.length; i < l; i++ ) {
- var elems = (i > 0 ? this.clone(true) : this).get();
- jQuery( insert[i] )[ original ]( elems );
- ret = ret.concat( elems );
- }
-
- return this.pushStack( ret, name, insert.selector );
- }
- };
-});
-
-function getAll( elem ) {
- if ( "getElementsByTagName" in elem ) {
- return elem.getElementsByTagName( "*" );
-
- } else if ( "querySelectorAll" in elem ) {
- return elem.querySelectorAll( "*" );
-
- } else {
- return [];
- }
-}
-
-// Used in clean, fixes the defaultChecked property
-function fixDefaultChecked( elem ) {
- if ( elem.type === "checkbox" || elem.type === "radio" ) {
- elem.defaultChecked = elem.checked;
- }
-}
-// Finds all inputs and passes them to fixDefaultChecked
-function findInputs( elem ) {
- if ( jQuery.nodeName( elem, "input" ) ) {
- fixDefaultChecked( elem );
- } else if ( "getElementsByTagName" in elem ) {
- jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
- }
+function isHidden( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
}
-jQuery.extend({
- clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var clone = elem.cloneNode(true),
- srcElements,
- destElements,
- i;
-
- if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
- (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
- // IE copies events bound via attachEvent when using cloneNode.
- // Calling detachEvent on the clone will also remove the events
- // from the original. In order to get around this, we use some
- // proprietary methods to clear the events. Thanks to MooTools
- // guys for this hotness.
-
- cloneFixAttributes( elem, clone );
-
- // Using Sizzle here is crazy slow, so we use getElementsByTagName
- // instead
- srcElements = getAll( elem );
- destElements = getAll( clone );
-
- // Weird iteration because IE will replace the length property
- // with an element if you are cloning the body and one of the
- // elements on the page has a name or id of "length"
- for ( i = 0; srcElements[i]; ++i ) {
- // Ensure that the destination node is not null; Fixes #9587
- if ( destElements[i] ) {
- cloneFixAttributes( srcElements[i], destElements[i] );
- }
- }
- }
-
- // Copy the events from the original to the clone
- if ( dataAndEvents ) {
- cloneCopyEvent( elem, clone );
-
- if ( deepDataAndEvents ) {
- srcElements = getAll( elem );
- destElements = getAll( clone );
-
- for ( i = 0; srcElements[i]; ++i ) {
- cloneCopyEvent( srcElements[i], destElements[i] );
- }
- }
- }
-
- srcElements = destElements = null;
-
- // Return the cloned set
- return clone;
- },
-
- clean: function( elems, context, fragment, scripts ) {
- var checkScriptType;
-
- context = context || document;
-
- // !context.createElement fails in IE with an error but returns typeof 'object'
- if ( typeof context.createElement === "undefined" ) {
- context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
- }
-
- var ret = [], j;
-
- for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
- if ( typeof elem === "number" ) {
- elem += "";
- }
-
- if ( !elem ) {
- continue;
- }
-
- // Convert html string into DOM nodes
- if ( typeof elem === "string" ) {
- if ( !rhtml.test( elem ) ) {
- elem = context.createTextNode( elem );
- } else {
- // Fix "XHTML"-style tags in all browsers
- elem = elem.replace(rxhtmlTag, "<$1></$2>");
-
- // Trim whitespace, otherwise indexOf won't work as expected
- var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
- wrap = wrapMap[ tag ] || wrapMap._default,
- depth = wrap[0],
- div = context.createElement("div");
-
- // Go to html and back, then peel off extra wrappers
- div.innerHTML = wrap[1] + elem + wrap[2];
-
- // Move to the right depth
- while ( depth-- ) {
- div = div.lastChild;
- }
-
- // Remove IE's autoinserted <tbody> from table fragments
- if ( !jQuery.support.tbody ) {
-
- // String was a <table>, *may* have spurious <tbody>
- var hasBody = rtbody.test(elem),
- tbody = tag === "table" && !hasBody ?
- div.firstChild && div.firstChild.childNodes :
-
- // String was a bare <thead> or <tfoot>
- wrap[1] === "<table>" && !hasBody ?
- div.childNodes :
- [];
-
- for ( j = tbody.length - 1; j >= 0 ; --j ) {
- if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
- tbody[ j ].parentNode.removeChild( tbody[ j ] );
- }
- }
- }
-
- // IE completely kills leading whitespace when innerHTML is used
- if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
- div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
- }
-
- elem = div.childNodes;
- }
- }
-
- // Resets defaultChecked for any radios and checkboxes
- // about to be appended to the DOM in IE 6/7 (#8060)
- var len;
- if ( !jQuery.support.appendChecked ) {
- if ( elem[0] && typeof (len = elem.length) === "number" ) {
- for ( j = 0; j < len; j++ ) {
- findInputs( elem[j] );
- }
- } else {
- findInputs( elem );
- }
- }
-
- if ( elem.nodeType ) {
- ret.push( elem );
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
+ }
+ } else {
+
+ if ( !values[ index ] ) {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ var len, styles,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
} else {
- ret = jQuery.merge( ret, elem );
- }
- }
-
- if ( fragment ) {
- checkScriptType = function( elem ) {
- return !elem.type || rscriptType.test( elem.type );
- };
- for ( i = 0; ret[i]; i++ ) {
- if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
- scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
-
- } else {
- if ( ret[i].nodeType === 1 ) {
- var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
-
- ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
- }
- fragment.appendChild( ret[i] );
- }
- }
- }
-
- return ret;
- },
-
- cleanData: function( elems ) {
- var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
- deleteExpando = jQuery.support.deleteExpando;
-
- for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
- if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
- continue;
- }
-
- id = elem[ jQuery.expando ];
-
- if ( id ) {
- data = cache[ id ] && cache[ id ][ internalKey ];
-
- if ( data && data.events ) {
- for ( var type in data.events ) {
- if ( special[ type ] ) {
- jQuery.event.remove( elem, type );
-
- // This is a shortcut to avoid jQuery.event.remove's overhead
- } else {
- jQuery.removeEvent( elem, type, data.handle );
- }
- }
-
- // Null the DOM reference to avoid IE6/7/8 leak (#7054)
- if ( data.handle ) {
- data.handle.elem = null;
- }
- }
-
- if ( deleteExpando ) {
- delete elem[ jQuery.expando ];
-
- } else if ( elem.removeAttribute ) {
- elem.removeAttribute( jQuery.expando );
- }
-
- delete cache[ id ];
- }
- }
+ jQuery( this ).hide();
+ }
+ });
}
});
-function evalScript( i, elem ) {
- if ( elem.src ) {
- jQuery.ajax({
- url: elem.src,
- async: false,
- dataType: "script"
- });
- } else {
- jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
- }
-
- if ( elem.parentNode ) {
- elem.parentNode.removeChild( elem );
- }
-}
-
-
-
-
-var ralpha = /alpha\([^)]*\)/i,
- ropacity = /opacity=([^)]*)/,
- // fixed for IE9, see #8346
- rupper = /([A-Z]|^ms)/g,
- rnumpx = /^-?\d+(?:px)?$/i,
- rnum = /^-?\d/,
- rrelNum = /^([\-+])=([\-+.\de]+)/,
-
- cssShow = { position: "absolute", visibility: "hidden", display: "block" },
- cssWidth = [ "Left", "Right" ],
- cssHeight = [ "Top", "Bottom" ],
- curCSS,
-
- getComputedStyle,
- currentStyle;
-
-jQuery.fn.css = function( name, value ) {
- // Setting 'undefined' is a no-op
- if ( arguments.length === 2 && value === undefined ) {
- return this;
- }
-
- return jQuery.access( this, name, value, true, function( elem, name, value ) {
- return value !== undefined ?
- jQuery.style( elem, name, value ) :
- jQuery.css( elem, name );
- });
-};
-
jQuery.extend({
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
@@ -6332,22 +6949,21 @@
get: function( elem, computed ) {
if ( computed ) {
// We should always get a number back from opacity
- var ret = curCSS( elem, "opacity", "opacity" );
+ var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
-
- } else {
- return elem.style.opacity;
- }
- }
- }
- },
-
- // Exclude the following css properties to add px
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
cssNumber: {
+ "columnCount": true,
"fillOpacity": true,
"fontWeight": true,
"lineHeight": true,
"opacity": true,
+ "order": true,
"orphans": true,
"widows": true,
"zIndex": true,
@@ -6369,10 +6985,15 @@
}
// Make sure that we're working with the right name
- var ret, type, origName = jQuery.camelCase( name ),
- style = elem.style, hooks = jQuery.cssHooks[ origName ];
-
- name = jQuery.cssProps[ origName ] || origName;
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// Check if we're setting a value
if ( value !== undefined ) {
@@ -6380,7 +7001,7 @@
// convert relative number strings (+= or -=) to relative numbers. #7345
if ( type === "string" && (ret = rrelNum.exec( value )) ) {
- value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
// Fixes bug #9237
type = "number";
}
@@ -6395,8 +7016,15 @@
value += "px";
}
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
// If a hook was provided, use that value, otherwise just set the specified value
- if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
// Fixes bug #5509
try {
@@ -6415,81 +7043,290 @@
}
},
- css: function( elem, name, extra ) {
- var ret, hooks;
+ css: function( elem, name, extra, styles ) {
+ var num, val, hooks,
+ origName = jQuery.camelCase( name );
// Make sure that we're working with the right name
- name = jQuery.camelCase( name );
- hooks = jQuery.cssHooks[ name ];
- name = jQuery.cssProps[ name ] || name;
-
- // cssFloat needs a special treatment
- if ( name === "cssFloat" ) {
- name = "float";
- }
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// If a hook was provided get the computed value from there
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
- return ret;
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
// Otherwise, if a way to get the computed value exists, use that
- } else if ( curCSS ) {
- return curCSS( elem, name );
- }
- },
-
- // A method for quickly swapping in/out CSS properties to get correct calculations
- swap: function( elem, options, callback ) {
- var old = {};
-
- // Remember the old values, and insert the new ones
- for ( var name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
-
- callback.call( elem );
-
- // Revert the old values
- for ( name in options ) {
- elem.style[ name ] = old[ name ];
- }
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
}
});
-// DEPRECATED, Use jQuery.css() instead
-jQuery.curCSS = jQuery.css;
-
-jQuery.each(["height", "width"], function( i, name ) {
+// NOTE: we've included the "window" in window.getComputedStyle
+// because jsdom on node.js will break without it.
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ return window.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var width, minWidth, maxWidth,
+ computed = _computed || getStyles( elem ),
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
+ style = elem.style;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret;
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, _computed ) {
+ var left, rs, rsLeft,
+ computed = _computed || getStyles( elem ),
+ ret = computed ? computed[ name ] : undefined,
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+// Try to determine the default display value of an element
+function css_defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+ // Use the already-created iframe if possible
+ iframe = ( iframe ||
+ jQuery("<iframe frameborder='0' width='0' height='0'/>")
+ .css( "cssText", "display:block !important" )
+ ).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
+ doc.write("<!doctype html><html><body>");
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+// Called ONLY from within css_defaultDisplay
+function actualDisplay( name, doc ) {
+ var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+ display = jQuery.css( elem[0], "display" );
+ elem.remove();
+ return display;
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
jQuery.cssHooks[ name ] = {
get: function( elem, computed, extra ) {
- var val;
-
if ( computed ) {
- if ( elem.offsetWidth !== 0 ) {
- return getWH( elem, name, extra );
- } else {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
jQuery.swap( elem, cssShow, function() {
- val = getWH( elem, name, extra );
- });
- }
-
- return val;
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
}
},
- set: function( elem, value ) {
- if ( rnumpx.test( value ) ) {
- // ignore negative width and height values #1599
- value = parseFloat( value );
-
- if ( value >= 0 ) {
- return value + "px";
- }
-
- } else {
- return value;
- }
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
}
};
});
@@ -6499,14 +7336,14 @@
get: function( elem, computed ) {
// IE uses filters for opacity
return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
- ( parseFloat( RegExp.$1 ) / 100 ) + "" :
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
computed ? "1" : "";
},
set: function( elem, value ) {
var style = elem.style,
currentStyle = elem.currentStyle,
- opacity = jQuery.isNaN( value ) ? "" : "alpha(opacity=" + value * 100 + ")",
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
filter = currentStyle && currentStyle.filter || style.filter || "";
// IE has trouble with opacity if it does not have layout
@@ -6514,15 +7351,18 @@
style.zoom = 1;
// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
- if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
// if "filter:" is present at all, clearType is disabled, we want to avoid this
// style.removeAttribute is IE Only, but so apparently is this code path...
style.removeAttribute( "filter" );
- // if there there is no filter style applied in a css rule, we are done
- if ( currentStyle && !currentStyle.filter ) {
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
return;
}
}
@@ -6535,138 +7375,49 @@
};
}
+// These hooks cannot be added until DOM ready because the support test
+// for it is not run until after DOM ready
jQuery(function() {
- // This hook cannot be added until DOM ready because the support test
- // for it is not run until after DOM ready
if ( !jQuery.support.reliableMarginRight ) {
jQuery.cssHooks.marginRight = {
get: function( elem, computed ) {
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- // Work around by temporarily setting element display to inline-block
- var ret;
- jQuery.swap( elem, { "display": "inline-block" }, function() {
- if ( computed ) {
- ret = curCSS( elem, "margin-right", "marginRight" );
- } else {
- ret = elem.style.marginRight;
- }
- });
- return ret;
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
}
};
}
+
+ // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+ // getComputedStyle returns percent when specified for top/left/bottom/right
+ // rather than make the css module depend on the offset module, we just check for it here
+ if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
+ jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ };
+ });
+ }
+
});
-if ( document.defaultView && document.defaultView.getComputedStyle ) {
- getComputedStyle = function( elem, name ) {
- var ret, defaultView, computedStyle;
-
- name = name.replace( rupper, "-$1" ).toLowerCase();
-
- if ( !(defaultView = elem.ownerDocument.defaultView) ) {
- return undefined;
- }
-
- if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
- ret = computedStyle.getPropertyValue( name );
- if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
- ret = jQuery.style( elem, name );
- }
- }
-
- return ret;
- };
-}
-
-if ( document.documentElement.currentStyle ) {
- currentStyle = function( elem, name ) {
- var left,
- ret = elem.currentStyle && elem.currentStyle[ name ],
- rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
- style = elem.style;
-
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
- // If we're not dealing with a regular pixel number
- // but a number that has a weird ending, we need to convert it to pixels
- if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
- // Remember the original values
- left = style.left;
-
- // Put in the new values to get a computed value out
- if ( rsLeft ) {
- elem.runtimeStyle.left = elem.currentStyle.left;
- }
- style.left = name === "fontSize" ? "1em" : (ret || 0);
- ret = style.pixelLeft + "px";
-
- // Revert the changed values
- style.left = left;
- if ( rsLeft ) {
- elem.runtimeStyle.left = rsLeft;
- }
- }
-
- return ret === "" ? "auto" : ret;
- };
-}
-
-curCSS = getComputedStyle || currentStyle;
-
-function getWH( elem, name, extra ) {
-
- // Start with offset property
- var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
- which = name === "width" ? cssWidth : cssHeight;
-
- if ( val > 0 ) {
- if ( extra !== "border" ) {
- jQuery.each( which, function() {
- if ( !extra ) {
- val -= parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
- }
- if ( extra === "margin" ) {
- val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
- } else {
- val -= parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
- }
- });
- }
-
- return val + "px";
- }
-
- // Fall back to computed then uncomputed css if necessary
- val = curCSS( elem, name, name );
- if ( val < 0 || val == null ) {
- val = elem.style[ name ] || 0;
- }
- // Normalize "", auto, and prepare for extra
- val = parseFloat( val ) || 0;
-
- // Add padding, border, margin
- if ( extra ) {
- jQuery.each( which, function() {
- val += parseFloat( jQuery.css( elem, "padding" + this ) ) || 0;
- if ( extra !== "padding" ) {
- val += parseFloat( jQuery.css( elem, "border" + this + "Width" ) ) || 0;
- }
- if ( extra === "margin" ) {
- val += parseFloat( jQuery.css( elem, extra + this ) ) || 0;
- }
- });
- }
-
- return val + "px";
-}
-
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.hidden = function( elem ) {
- var width = elem.offsetWidth,
- height = elem.offsetHeight;
-
- return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+ (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
};
jQuery.expr.filters.visible = function( elem ) {
@@ -6674,25 +7425,179 @@
};
}
-
-
-
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
var r20 = /%20/g,
rbracket = /\[\]$/,
rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function(){
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !manipulation_rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+//Serialize an array of form elements or a set of
+//key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+ ajax_nonce = jQuery.now(),
+
+ ajax_rquery = /\?/,
rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
- rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
// #7653, #8125, #8152: local protocol detection
- rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
rnoContent = /^(?:GET|HEAD)$/,
rprotocol = /^\/\//,
- rquery = /\?/,
- rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
- rselectTextarea = /^(?:select|textarea)/i,
- rspacesAjax = /\s+/,
- rts = /([?&])_=[^&]*/,
- rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+ rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
// Keep a copy of the old load method
_load = jQuery.fn.load,
@@ -6715,14 +7620,8 @@
*/
transports = {},
- // Document location
- ajaxLocation,
-
- // Document location segments
- ajaxLocParts,
-
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
- allTypes = ["*/"] + ["*"];
+ allTypes = "*/".concat("*");
// #8138, IE may throw an exception when accessing
// a field from window.location if document.domain has been set
@@ -6750,251 +7649,152 @@
dataTypeExpression = "*";
}
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
+
if ( jQuery.isFunction( func ) ) {
- var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
- i = 0,
- length = dataTypes.length,
- dataType,
- list,
- placeBefore;
-
// For each dataType in the dataTypeExpression
- for(; i < length; i++ ) {
- dataType = dataTypes[ i ];
- // We control if we're asked to add before
- // any existing element
- placeBefore = /^\+/.test( dataType );
- if ( placeBefore ) {
- dataType = dataType.substr( 1 ) || "*";
- }
- list = structure[ dataType ] = structure[ dataType ] || [];
- // then we add to the structure accordingly
- list[ placeBefore ? "unshift" : "push" ]( func );
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType[0] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
}
}
};
}
// Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
- dataType /* internal */, inspected /* internal */ ) {
-
- dataType = dataType || options.dataTypes[ 0 ];
- inspected = inspected || {};
-
- inspected[ dataType ] = true;
-
- var list = structure[ dataType ],
- i = 0,
- length = list ? list.length : 0,
- executeOnly = ( structure === prefilters ),
- selection;
-
- for(; i < length && ( executeOnly || !selection ); i++ ) {
- selection = list[ i ]( options, originalOptions, jqXHR );
- // If we got redirected to another dataType
- // we try there if executing only and not done already
- if ( typeof selection === "string" ) {
- if ( !executeOnly || inspected[ selection ] ) {
- selection = undefined;
- } else {
- options.dataTypes.unshift( selection );
- selection = inspectPrefiltersOrTransports(
- structure, options, originalOptions, jqXHR, selection, inspected );
- }
- }
- }
- // If we're only executing or nothing was selected
- // we try the catchall dataType if not done already
- if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
- selection = inspectPrefiltersOrTransports(
- structure, options, originalOptions, jqXHR, "*", inspected );
- }
- // unnecessary when only executing (prefilters)
- // but it'll be ignored by the caller in that case
- return selection;
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}
// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend( target, src ) {
- var key, deep,
+ var deep, key,
flatOptions = jQuery.ajaxSettings.flatOptions || {};
- for( key in src ) {
+
+ for ( key in src ) {
if ( src[ key ] !== undefined ) {
- ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
}
}
if ( deep ) {
jQuery.extend( true, target, deep );
}
+
+ return target;
}
-jQuery.fn.extend({
- load: function( url, params, callback ) {
- if ( typeof url !== "string" && _load ) {
- return _load.apply( this, arguments );
-
- // Don't do a request if no elements are being requested
- } else if ( !this.length ) {
- return this;
- }
-
- var off = url.indexOf( " " );
- if ( off >= 0 ) {
- var selector = url.slice( off, url.length );
- url = url.slice( 0, off );
- }
-
- // Default to a GET request
- var type = "GET";
-
- // If the second parameter was provided
- if ( params ) {
- // If it's a function
- if ( jQuery.isFunction( params ) ) {
- // We assume that it's the callback
- callback = params;
- params = undefined;
-
- // Otherwise, build a param string
- } else if ( typeof params === "object" ) {
- params = jQuery.param( params, jQuery.ajaxSettings.traditional );
- type = "POST";
- }
- }
-
- var self = this;
-
- // Request the remote document
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, response, type,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
jQuery.ajax({
url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
type: type,
dataType: "html",
- data: params,
- // Complete callback (responseText is used internally)
- complete: function( jqXHR, status, responseText ) {
- // Store the response as specified by the jqXHR object
- responseText = jqXHR.responseText;
- // If successful, inject the HTML into all the matched elements
- if ( jqXHR.isResolved() ) {
- // #4825: Get the actual response in case
- // a dataFilter is present in ajaxSettings
- jqXHR.done(function( r ) {
- responseText = r;
- });
- // See if a selector was specified
- self.html( selector ?
- // Create a dummy div to hold the results
- jQuery("<div>")
- // inject the contents of the document in, removing the scripts
- // to avoid any 'Permission Denied' errors in IE
- .append(responseText.replace(rscript, ""))
-
- // Locate the specified elements
- .find(selector) :
-
- // If not, just inject the full result
- responseText );
- }
-
- if ( callback ) {
- self.each( callback, [ responseText, status, jqXHR ] );
- }
- }
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
});
-
- return this;
- },
-
- serialize: function() {
- return jQuery.param( this.serializeArray() );
- },
-
- serializeArray: function() {
- return this.map(function(){
- return this.elements ? jQuery.makeArray( this.elements ) : this;
- })
- .filter(function(){
- return this.name && !this.disabled &&
- ( this.checked || rselectTextarea.test( this.nodeName ) ||
- rinput.test( this.type ) );
- })
- .map(function( i, elem ){
- var val = jQuery( this ).val();
-
- return val == null ?
- null :
- jQuery.isArray( val ) ?
- jQuery.map( val, function( val, i ){
- return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }) :
- { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }).get();
- }
-});
+ }
+
+ return this;
+};
// Attach a bunch of functions for handling common AJAX events
-jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
- jQuery.fn[ o ] = function( f ){
- return this.bind( o, f );
- };
-});
-
-jQuery.each( [ "get", "post" ], function( i, method ) {
- jQuery[ method ] = function( url, data, callback, type ) {
- // shift arguments if data argument was omitted
- if ( jQuery.isFunction( data ) ) {
- type = type || callback;
- callback = data;
- data = undefined;
- }
-
- return jQuery.ajax({
- type: method,
- url: url,
- data: data,
- success: callback,
- dataType: type
- });
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
+ jQuery.fn[ type ] = function( fn ){
+ return this.on( type, fn );
};
});
jQuery.extend({
- getScript: function( url, callback ) {
- return jQuery.get( url, undefined, callback, "script" );
- },
-
- getJSON: function( url, data, callback ) {
- return jQuery.get( url, data, callback, "json" );
- },
-
- // Creates a full fledged settings object into target
- // with both ajaxSettings and settings fields.
- // If target is omitted, writes into ajaxSettings.
- ajaxSetup: function( target, settings ) {
- if ( settings ) {
- // Building a settings object
- ajaxExtend( target, jQuery.ajaxSettings );
- } else {
- // Extending ajaxSettings
- settings = target;
- target = jQuery.ajaxSettings;
- }
- ajaxExtend( target, settings );
- return target;
- },
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
ajaxSettings: {
url: ajaxLocation,
+ type: "GET",
isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
global: true,
- type: "GET",
- contentType: "application/x-www-form-urlencoded",
processData: true,
async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
/*
timeout: 0,
data: null,
@@ -7002,16 +7802,17 @@
username: null,
password: null,
cache: null,
+ throws: false,
traditional: false,
headers: {},
*/
accepts: {
- xml: "application/xml, text/xml",
- html: "text/html",
+ "*": allTypes,
text: "text/plain",
- json: "application/json, text/javascript",
- "*": allTypes
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
},
contents: {
@@ -7022,16 +7823,16 @@
responseFields: {
xml: "responseXML",
- text: "responseText"
+ text: "responseText",
+ json: "responseJSON"
},
- // List of data converters
- // 1) key format is "source_type destination_type" (a single space in-between)
- // 2) the catchall symbol "*" can be used for source_type
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
converters: {
// Convert anything to text
- "* text": window.String,
+ "* text": String,
// Text to html (true = no transformation)
"text html": true,
@@ -7048,9 +7849,22 @@
// and when you create one that shouldn't be
// deep extended (see ajaxExtend)
flatOptions: {
- context: true,
- url: true
- }
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
},
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
@@ -7068,74 +7882,75 @@
// Force options to be an object
options = options || {};
- var // Create the final options object
+ var // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // Create the final options object
s = jQuery.ajaxSetup( {}, options ),
// Callbacks context
callbackContext = s.context || s,
- // Context for global events
- // It's the callbackContext if one was provided in the options
- // and if it's a DOM node or a jQuery collection
- globalEventContext = callbackContext !== s &&
- ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
- jQuery( callbackContext ) : jQuery.event,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
// Deferreds
deferred = jQuery.Deferred(),
- completeDeferred = jQuery._Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
// Status-dependent callbacks
statusCode = s.statusCode || {},
- // ifModified key
- ifModifiedKey,
// Headers (they are sent all at once)
requestHeaders = {},
requestHeadersNames = {},
- // Response headers
- responseHeadersString,
- responseHeaders,
- // transport
- transport,
- // timeout handle
- timeoutTimer,
- // Cross-domain detection vars
- parts,
// The jqXHR state
state = 0,
- // To know if global events are to be dispatched
- fireGlobals,
- // Loop variable
- i,
+ // Default abort message
+ strAbort = "canceled",
// Fake xhr
jqXHR = {
-
readyState: 0,
- // Caches the header
- setRequestHeader: function( name, value ) {
- if ( !state ) {
- var lname = name.toLowerCase();
- name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
- requestHeaders[ name ] = value;
- }
- return this;
- },
-
- // Raw string
- getAllResponseHeaders: function() {
- return state === 2 ? responseHeadersString : null;
- },
-
// Builds headers hashtable if needed
getResponseHeader: function( key ) {
var match;
if ( state === 2 ) {
if ( !responseHeaders ) {
responseHeaders = {};
- while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
}
}
match = responseHeaders[ key.toLowerCase() ];
}
- return match === undefined ? null : match;
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
},
// Overrides response content-type header
@@ -7146,21 +7961,194 @@
return this;
},
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
// Cancel the request
abort: function( statusText ) {
- statusText = statusText || "abort";
+ var finalText = statusText || strAbort;
if ( transport ) {
- transport.abort( statusText );
+ transport.abort( finalText );
}
- done( 0, statusText );
+ done( 0, finalText );
return this;
}
};
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
// Callback for when everything is done
- // It is defined here because jslint complains if it is declared
- // at the end of the function (which would be more logical and readable)
function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
// Called once
if ( state === 2 ) {
@@ -7185,52 +8173,52 @@
// Set readyState
jqXHR.readyState = status > 0 ? 4 : 0;
- var isSuccess,
- success,
- error,
- statusText = nativeStatusText,
- response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
- lastModified,
- etag;
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
// If successful, handle type chaining
- if ( status >= 200 && status < 300 || status === 304 ) {
+ if ( isSuccess ) {
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
-
- if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
- jQuery.lastModified[ ifModifiedKey ] = lastModified;
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
}
- if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
- jQuery.etag[ ifModifiedKey ] = etag;
- }
- }
-
- // If not modified
- if ( status === 304 ) {
-
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
statusText = "notmodified";
- isSuccess = true;
-
- // If we have data
+
+ // If we have data, let's convert it
} else {
-
- try {
- success = ajaxConvert( s, response );
- statusText = "success";
- isSuccess = true;
- } catch(e) {
- // We have a parsererror
- statusText = "parsererror";
- error = e;
- }
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
}
} else {
// We extract error from statusText
// then normalize statusText and status for non-aborts
error = statusText;
- if( !statusText || status ) {
+ if ( status || !statusText ) {
statusText = "error";
if ( status < 0 ) {
status = 0;
@@ -7240,7 +8228,7 @@
// Set data for the fake xhr object
jqXHR.status = status;
- jqXHR.statusText = "" + ( nativeStatusText || statusText );
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
// Success/Error
if ( isSuccess ) {
@@ -7254,185 +8242,18 @@
statusCode = undefined;
if ( fireGlobals ) {
- globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
- [ jqXHR, s, isSuccess ? success : error ] );
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
}
// Complete
- completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
- jQuery.event.trigger( "ajaxStop" );
- }
- }
- }
-
- // Attach deferreds
- deferred.promise( jqXHR );
- jqXHR.success = jqXHR.done;
- jqXHR.error = jqXHR.fail;
- jqXHR.complete = completeDeferred.done;
-
- // Status-dependent callbacks
- jqXHR.statusCode = function( map ) {
- if ( map ) {
- var tmp;
- if ( state < 2 ) {
- for( tmp in map ) {
- statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
- }
- } else {
- tmp = map[ jqXHR.status ];
- jqXHR.then( tmp, tmp );
- }
- }
- return this;
- };
-
- // Remove hash character (#7531: and string promotion)
- // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
- // We also use the url parameter if available
- s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
- // Extract dataTypes list
- s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
-
- // Determine if a cross-domain request is in order
- if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() );
- s.crossDomain = !!( parts &&
- ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
- ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
- ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
- );
- }
-
- // Convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" ) {
- s.data = jQuery.param( s.data, s.traditional );
- }
-
- // Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
- // If request was aborted inside a prefiler, stop there
- if ( state === 2 ) {
- return false;
- }
-
- // We can fire global events as of now if asked to
- fireGlobals = s.global;
-
- // Uppercase the type
- s.type = s.type.toUpperCase();
-
- // Determine if request has content
- s.hasContent = !rnoContent.test( s.type );
-
- // Watch for a new set of requests
- if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger( "ajaxStart" );
- }
-
- // More options handling for requests with no content
- if ( !s.hasContent ) {
-
- // If data is available, append data to url
- if ( s.data ) {
- s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
- // #9682: remove data so that it's not used in an eventual retry
- delete s.data;
- }
-
- // Get ifModifiedKey before adding the anti-cache parameter
- ifModifiedKey = s.url;
-
- // Add anti-cache in url if needed
- if ( s.cache === false ) {
-
- var ts = jQuery.now(),
- // try replacing _= if it is there
- ret = s.url.replace( rts, "$1_=" + ts );
-
- // if nothing was replaced, add timestamp to the end
- s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
- }
- }
-
- // Set the correct header, if data is being sent
- if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
- jqXHR.setRequestHeader( "Content-Type", s.contentType );
- }
-
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
- ifModifiedKey = ifModifiedKey || s.url;
- if ( jQuery.lastModified[ ifModifiedKey ] ) {
- jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
- }
- if ( jQuery.etag[ ifModifiedKey ] ) {
- jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
- }
- }
-
- // Set the Accepts header for the server, depending on the dataType
- jqXHR.setRequestHeader(
- "Accept",
- s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
- s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
- s.accepts[ "*" ]
- );
-
- // Check for headers option
- for ( i in s.headers ) {
- jqXHR.setRequestHeader( i, s.headers[ i ] );
- }
-
- // Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
- // Abort if not done already
- jqXHR.abort();
- return false;
-
- }
-
- // Install callbacks on deferreds
- for ( i in { success: 1, error: 1, complete: 1 } ) {
- jqXHR[ i ]( s[ i ] );
- }
-
- // Get transport
- transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-
- // If no transport, we auto-abort
- if ( !transport ) {
- done( -1, "No Transport" );
- } else {
- jqXHR.readyState = 1;
- // Send global event
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
- }
- // Timeout
- if ( s.async && s.timeout > 0 ) {
- timeoutTimer = setTimeout( function(){
- jqXHR.abort( "timeout" );
- }, s.timeout );
- }
-
- try {
- state = 1;
- transport.send( requestHeaders, done );
- } catch (e) {
- // Propagate exception as error if not done
- if ( state < 2 ) {
- done( -1, e );
- // Simply rethrow otherwise
- } else {
- jQuery.error( e );
+ jQuery.event.trigger("ajaxStop");
}
}
}
@@ -7440,113 +8261,48 @@
return jqXHR;
},
- // Serialize an array of form elements or a set of
- // key/values into a query string
- param: function( a, traditional ) {
- var s = [],
- add = function( key, value ) {
- // If value is a function, invoke it and return its value
- value = jQuery.isFunction( value ) ? value() : value;
- s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
- };
-
- // Set traditional to true for jQuery <= 1.3.2 behavior.
- if ( traditional === undefined ) {
- traditional = jQuery.ajaxSettings.traditional;
- }
-
- // If an array was passed in, assume that it is an array of form elements.
- if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
- // Serialize the form elements
- jQuery.each( a, function() {
- add( this.name, this.value );
- });
-
- } else {
- // If traditional, encode the "old" way (the way 1.3.2 or older
- // did it), otherwise encode params recursively.
- for ( var prefix in a ) {
- buildParams( prefix, a[ prefix ], traditional, add );
- }
- }
-
- // Return the resulting serialization
- return s.join( "&" ).replace( r20, "+" );
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
}
});
-function buildParams( prefix, obj, traditional, add ) {
- if ( jQuery.isArray( obj ) ) {
- // Serialize array item.
- jQuery.each( obj, function( i, v ) {
- if ( traditional || rbracket.test( prefix ) ) {
- // Treat each array item as a scalar.
- add( prefix, v );
-
- } else {
- // If array item is non-scalar (array or object), encode its
- // numeric index to resolve deserialization ambiguity issues.
- // Note that rack (as of 1.0.0) can't currently deserialize
- // nested arrays properly, and attempting to do so may cause
- // a server error. Possible fixes are to modify rack's
- // deserialization algorithm or to provide an option or flag
- // to force array serialization to be shallow.
- buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
- }
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
});
-
- } else if ( !traditional && obj != null && typeof obj === "object" ) {
- // Serialize object item.
- for ( var name in obj ) {
- buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
- }
-
- } else {
- // Serialize scalar item.
- add( prefix, obj );
- }
-}
-
-// This is still on the jQuery object... for now
-// Want to move this to jQuery.ajax some day
-jQuery.extend({
-
- // Counter for holding the number of active queries
- active: 0,
-
- // Last-Modified header cache for next request
- lastModified: {},
- etag: {}
-
+ };
});
/* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
* - finds the right dataType (mediates between content-type and expected dataType)
* - returns the corresponding response
*/
function ajaxHandleResponses( s, jqXHR, responses ) {
-
- var contents = s.contents,
- dataTypes = s.dataTypes,
- responseFields = s.responseFields,
- ct,
- type,
- finalDataType,
- firstDataType;
-
- // Fill responseXXX fields
- for( type in responseFields ) {
- if ( type in responses ) {
- jqXHR[ responseFields[type] ] = responses[ type ];
- }
- }
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
// Remove auto dataType and get content-type in the process
while( dataTypes[ 0 ] === "*" ) {
dataTypes.shift();
if ( ct === undefined ) {
- ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
}
}
@@ -7589,180 +8345,106 @@
}
}
-// Chain conversions given the request and the original response
-function ajaxConvert( s, response ) {
-
- // Apply the dataFilter if provided
- if ( s.dataFilter ) {
- response = s.dataFilter( response, s.dataType );
- }
-
- var dataTypes = s.dataTypes,
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
converters = {},
- i,
- key,
- length = dataTypes.length,
- tmp,
- // Current and previous dataTypes
- current = dataTypes[ 0 ],
- prev,
- // Conversion expression
- conversion,
- // Conversion function
- conv,
- // Conversion functions (transitive conversion)
- conv1,
- conv2;
-
- // For each dataType in the chain
- for( i = 1; i < length; i++ ) {
-
- // Create converters map
- // with lowercased keys
- if ( i === 1 ) {
- for( key in s.converters ) {
- if( typeof key === "string" ) {
- converters[ key.toLowerCase() ] = s.converters[ key ];
- }
- }
- }
-
- // Get the dataTypes
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
prev = current;
- current = dataTypes[ i ];
-
- // If current is auto dataType, update it to prev
- if( current === "*" ) {
- current = prev;
- // If no auto and dataTypes are actually different
- } else if ( prev !== "*" && prev !== current ) {
-
- // Get the converter
- conversion = prev + " " + current;
- conv = converters[ conversion ] || converters[ "* " + current ];
-
- // If there is no direct converter, search transitively
- if ( !conv ) {
- conv2 = undefined;
- for( conv1 in converters ) {
- tmp = conv1.split( " " );
- if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
- conv2 = converters[ tmp[1] + " " + current ];
- if ( conv2 ) {
- conv1 = converters[ conv1 ];
- if ( conv1 === true ) {
- conv = conv2;
- } else if ( conv2 === true ) {
- conv = conv1;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
}
- break;
}
}
}
- }
- // If we found no converter, dispatch an error
- if ( !( conv || conv2 ) ) {
- jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
- }
- // If found converter is not an equivalence
- if ( conv !== true ) {
- // Convert with 1 or 2 converters accordingly
- response = conv ? conv( response ) : conv2( conv1(response) );
- }
- }
- }
- return response;
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
}
-
-
-
-
-var jsc = jQuery.now(),
- jsre = /(\=)\?(&|$)|\?\?/i;
-
-// Default jsonp settings
-jQuery.ajaxSetup({
- jsonp: "callback",
- jsonpCallback: function() {
- return jQuery.expando + "_" + ( jsc++ );
- }
-});
-
-// Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
-
- var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
- ( typeof s.data === "string" );
-
- if ( s.dataTypes[ 0 ] === "jsonp" ||
- s.jsonp !== false && ( jsre.test( s.url ) ||
- inspectData && jsre.test( s.data ) ) ) {
-
- var responseContainer,
- jsonpCallback = s.jsonpCallback =
- jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
- previous = window[ jsonpCallback ],
- url = s.url,
- data = s.data,
- replace = "$1" + jsonpCallback + "$2";
-
- if ( s.jsonp !== false ) {
- url = url.replace( jsre, replace );
- if ( s.url === url ) {
- if ( inspectData ) {
- data = data.replace( jsre, replace );
- }
- if ( s.data === data ) {
- // Add callback manually
- url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
- }
- }
- }
-
- s.url = url;
- s.data = data;
-
- // Install callback
- window[ jsonpCallback ] = function( response ) {
- responseContainer = [ response ];
- };
-
- // Clean-up function
- jqXHR.always(function() {
- // Set callback back to previous value
- window[ jsonpCallback ] = previous;
- // Call if it was a function and we have a response
- if ( responseContainer && jQuery.isFunction( previous ) ) {
- window[ jsonpCallback ]( responseContainer[ 0 ] );
- }
- });
-
- // Use data converter to retrieve json after script execution
- s.converters["script json"] = function() {
- if ( !responseContainer ) {
- jQuery.error( jsonpCallback + " was not called" );
- }
- return responseContainer[ 0 ];
- };
-
- // force json dataType
- s.dataTypes[ 0 ] = "json";
-
- // Delegate to script
- return "script";
- }
-});
-
-
-
-
// Install script dataType
jQuery.ajaxSetup({
accepts: {
script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
},
contents: {
- script: /javascript|ecmascript/
+ script: /(?:java|ecma)script/
},
converters: {
"text script": function( text ) {
@@ -7790,15 +8472,15 @@
if ( s.crossDomain ) {
var script,
- head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+ head = document.head || jQuery("head")[0] || document.documentElement;
return {
send: function( _, callback ) {
- script = document.createElement( "script" );
-
- script.async = "async";
+ script = document.createElement("script");
+
+ script.async = true;
if ( s.scriptCharset ) {
script.charset = s.scriptCharset;
@@ -7815,12 +8497,12 @@
script.onload = script.onreadystatechange = null;
// Remove the script
- if ( head && script.parentNode ) {
- head.removeChild( script );
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
}
// Dereference the script
- script = undefined;
+ script = null;
// Callback if not abort
if ( !isAbort ) {
@@ -7828,32 +8510,110 @@
}
}
};
- // Use insertBefore instead of appendChild to circumvent an IE6 bug.
- // This arises when a base node is used (#2709 and #4378).
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
head.insertBefore( script, head.firstChild );
},
abort: function() {
if ( script ) {
- script.onload( 0, 1 );
+ script.onload( undefined, true );
}
}
};
}
});
-
-
-
-
-var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
- xhrOnUnloadAbort = window.ActiveXObject ? function() {
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+var xhrCallbacks, xhrSupported,
+ xhrId = 0,
+ // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject && function() {
// Abort all pending requests
- for ( var key in xhrCallbacks ) {
- xhrCallbacks[ key ]( 0, 1 );
- }
- } : false,
- xhrId = 0,
- xhrCallbacks;
+ var key;
+ for ( key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ };
// Functions to create xhrs
function createStandardXHR() {
@@ -7864,7 +8624,7 @@
function createActiveXHR() {
try {
- return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ return new window.ActiveXObject("Microsoft.XMLHTTP");
} catch( e ) {}
}
@@ -7884,15 +8644,12 @@
createStandardXHR;
// Determine support properties
-(function( xhr ) {
- jQuery.extend( jQuery.support, {
- ajax: !!xhr,
- cors: !!xhr && ( "withCredentials" in xhr )
- });
-})( jQuery.ajaxSettings.xhr() );
+xhrSupported = jQuery.ajaxSettings.xhr();
+jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = jQuery.support.ajax = !!xhrSupported;
// Create transport if the browser can provide an xhr
-if ( jQuery.support.ajax ) {
+if ( xhrSupported ) {
jQuery.ajaxTransport(function( s ) {
// Cross domain only allowed if supported through XMLHttpRequest
@@ -7904,9 +8661,8 @@
send: function( headers, complete ) {
// Get a new xhr
- var xhr = s.xhr(),
- handle,
- i;
+ var handle, i,
+ xhr = s.xhr();
// Open the socket
// Passing null username, generates a login popup on Opera (#2865)
@@ -7934,7 +8690,7 @@
// (it can always be set on a per-request basis or even using ajaxSetup)
// For same-domain requests, won't change header if already provided.
if ( !s.crossDomain && !headers["X-Requested-With"] ) {
- headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ headers["X-Requested-With"] = "XMLHttpRequest";
}
// Need an extra try/catch for cross domain requests in Firefox 3
@@ -7942,7 +8698,7 @@
for ( i in headers ) {
xhr.setRequestHeader( i, headers[ i ] );
}
- } catch( _ ) {}
+ } catch( err ) {}
// Do send the request
// This may raise an exception which is actually
@@ -7951,15 +8707,10 @@
// Listener
callback = function( _, isAbort ) {
-
- var status,
- statusText,
- responseHeaders,
- responses,
- xml;
+ var status, responseHeaders, statusText, responses;
// Firefox throws exceptions when accessing properties
- // of an xhr when a network error occured
+ // of an xhr when a network error occurred
// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
try {
@@ -7984,16 +8735,15 @@
xhr.abort();
}
} else {
+ responses = {};
status = xhr.status;
responseHeaders = xhr.getAllResponseHeaders();
- responses = {};
- xml = xhr.responseXML;
-
- // Construct response list
- if ( xml && xml.documentElement /* #4958 */ ) {
- responses.xml = xml;
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
}
- responses.text = xhr.responseText;
// Firefox throws an exception when accessing
// statusText for faulty cross-domain requests
@@ -8029,11 +8779,13 @@
}
};
- // if we're in sync mode or it's in cache
- // and has been retrieved directly (IE6 & IE7)
- // we need to manually fire the callback
- if ( !s.async || xhr.readyState === 4 ) {
+ if ( !s.async ) {
+ // if we're in sync mode we fire the callback
callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
} else {
handle = ++xhrId;
if ( xhrOnUnloadAbort ) {
@@ -8052,320 +8804,636 @@
abort: function() {
if ( callback ) {
- callback(0,1);
+ callback( undefined, true );
}
}
};
}
});
}
-
-
-
-
-var elemdisplay = {},
- iframe, iframeDoc,
+var fxNow, timerId,
rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
- timerId,
- fxAttrs = [
- // height animations
- [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
- // width animations
- [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
- // opacity animations
- [ "opacity" ]
- ],
- fxNow;
-
-jQuery.fn.extend({
- show: function( speed, easing, callback ) {
- var elem, display;
-
- if ( speed || speed === 0 ) {
- return this.animate( genFx("show", 3), speed, easing, callback);
-
- } else {
- for ( var i = 0, j = this.length; i < j; i++ ) {
- elem = this[i];
-
- if ( elem.style ) {
- display = elem.style.display;
-
- // Reset the inline display of this element to learn if it is
- // being hidden by cascaded rules or not
- if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
- display = elem.style.display = "";
- }
-
- // Set elements which have been overridden with display: none
- // in a stylesheet to whatever the default browser style is
- // for such an element
- if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
- jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
- }
- }
- }
-
- // Set the display of most of the elements in a second loop
- // to avoid the constant reflow
- for ( i = 0; i < j; i++ ) {
- elem = this[i];
-
- if ( elem.style ) {
- display = elem.style.display;
-
- if ( display === "" || display === "none" ) {
- elem.style.display = jQuery._data(elem, "olddisplay") || "";
- }
- }
- }
-
- return this;
- }
- },
-
- hide: function( speed, easing, callback ) {
- if ( speed || speed === 0 ) {
- return this.animate( genFx("hide", 3), speed, easing, callback);
-
- } else {
- for ( var i = 0, j = this.length; i < j; i++ ) {
- if ( this[i].style ) {
- var display = jQuery.css( this[i], "display" );
-
- if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
- jQuery._data( this[i], "olddisplay", display );
- }
- }
- }
-
- // Set the display of the elements in a second loop
- // to avoid the constant reflow
- for ( i = 0; i < j; i++ ) {
- if ( this[i].style ) {
- this[i].style.display = "none";
- }
- }
-
- return this;
- }
- },
-
- // Save the old toggle function
- _toggle: jQuery.fn.toggle,
-
- toggle: function( fn, fn2, callback ) {
- var bool = typeof fn === "boolean";
-
- if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
- this._toggle.apply( this, arguments );
-
- } else if ( fn == null || bool ) {
- this.each(function() {
- var state = bool ? fn : jQuery(this).is(":hidden");
- jQuery(this)[ state ? "show" : "hide" ]();
- });
-
- } else {
- this.animate(genFx("toggle", 3), fn, fn2, callback);
- }
-
- return this;
- },
-
- fadeTo: function( speed, to, easing, callback ) {
- return this.filter(":hidden").css("opacity", 0).show().end()
- .animate({opacity: to}, speed, easing, callback);
- },
-
- animate: function( prop, speed, easing, callback ) {
- var optall = jQuery.speed(speed, easing, callback);
-
- if ( jQuery.isEmptyObject( prop ) ) {
- return this.each( optall.complete, [ false ] );
- }
-
- // Do not change referenced properties as per-property easing will be lost
- prop = jQuery.extend( {}, prop );
-
- return this[ optall.queue === false ? "each" : "queue" ](function() {
- // XXX 'this' does not always have a nodeName when running the
- // test suite
-
- if ( optall.queue === false ) {
- jQuery._mark( this );
- }
-
- var opt = jQuery.extend( {}, optall ),
- isElement = this.nodeType === 1,
- hidden = isElement && jQuery(this).is(":hidden"),
- name, val, p,
- display, e,
- parts, start, end, unit;
-
- // will store per property easing and be used to determine when an animation is complete
- opt.animatedProperties = {};
-
- for ( p in prop ) {
-
- // property name normalization
- name = jQuery.camelCase( p );
- if ( p !== name ) {
- prop[ name ] = prop[ p ];
- delete prop[ p ];
- }
-
- val = prop[ name ];
-
- // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
- if ( jQuery.isArray( val ) ) {
- opt.animatedProperties[ name ] = val[ 1 ];
- val = prop[ name ] = val[ 0 ];
- } else {
- opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
- }
-
- if ( val === "hide" && hidden || val === "show" && !hidden ) {
- return opt.complete.call( this );
- }
-
- if ( isElement && ( name === "height" || name === "width" ) ) {
- // Make sure that nothing sneaks out
- // Record all 3 overflow attributes because IE does not
- // change the overflow attribute when overflowX and
- // overflowY are set to the same value
- opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
-
- // Set display property to inline-block for height/width
- // animations on inline elements that are having width/height
- // animated
- if ( jQuery.css( this, "display" ) === "inline" &&
- jQuery.css( this, "float" ) === "none" ) {
- if ( !jQuery.support.inlineBlockNeedsLayout ) {
- this.style.display = "inline-block";
-
- } else {
- display = defaultDisplay( this.nodeName );
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( display === "inline" ) {
- this.style.display = "inline-block";
-
- } else {
- this.style.display = "inline";
- this.style.zoom = 1;
- }
- }
- }
- }
- }
-
- if ( opt.overflow != null ) {
- this.style.overflow = "hidden";
- }
-
- for ( p in prop ) {
- e = new jQuery.fx( this, opt, p );
- val = prop[ p ];
-
- if ( rfxtypes.test(val) ) {
- e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();
-
- } else {
- parts = rfxnum.exec( val );
- start = e.cur();
-
- if ( parts ) {
- end = parseFloat( parts[2] );
- unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
-
- // We need to compute starting value
- if ( unit !== "px" ) {
- jQuery.style( this, p, (end || 1) + unit);
- start = ((end || 1) / e.cur()) * start;
- jQuery.style( this, p, start + unit);
- }
-
- // If a +=/-= token was provided, we're doing a relative animation
- if ( parts[1] ) {
- end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
- }
-
- e.custom( start, end, unit );
-
- } else {
- e.custom( start, val, "" );
- }
- }
- }
-
- // For JS strict compliance
- return true;
- });
- },
-
- stop: function( clearQueue, gotoEnd ) {
- if ( clearQueue ) {
- this.queue([]);
- }
-
- this.each(function() {
- var timers = jQuery.timers,
- i = timers.length;
- // clear marker counters if we know they won't be
- if ( !gotoEnd ) {
- jQuery._unmark( true, this );
- }
- while ( i-- ) {
- if ( timers[i].elem === this ) {
- if (gotoEnd) {
- // force the next step to be the last
- timers[i](true);
- }
-
- timers.splice(i, 1);
- }
- }
- });
-
- // start the next in the queue if the last step wasn't forced
- if ( !gotoEnd ) {
- this.dequeue();
- }
-
- return this;
- }
-
-});
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ }]
+ };
// Animations created synchronously will run synchronously
function createFxNow() {
- setTimeout( clearFxNow, 0 );
+ setTimeout(function() {
+ fxNow = undefined;
+ });
return ( fxNow = jQuery.now() );
}
-function clearFxNow() {
- fxNow = undefined;
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
}
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = jQuery._data( elem, "fxshow" );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( elem, "display" ) === "inline" &&
+ jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
+ style.display = "inline-block";
+
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !jQuery.support.shrinkWrapBlocks ) {
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+ continue;
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = jQuery._data( elem, "fxshow", {} );
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+ }
+}
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
// Generate parameters to create a standard animation
-function genFx( type, num ) {
- var obj = {};
-
- jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
- obj[ this ] = type;
- });
-
- return obj;
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth? 1 : 0;
+ for( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
}
// Generate shortcuts for custom animations
jQuery.each({
- slideDown: genFx("show", 1),
- slideUp: genFx("hide", 1),
- slideToggle: genFx("toggle", 1),
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
@@ -8375,237 +9443,98 @@
};
});
-jQuery.extend({
- speed: function( speed, easing, fn ) {
- var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
- complete: fn || !fn && easing ||
- jQuery.isFunction( speed ) && speed,
- duration: speed,
- easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
- };
-
- opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
-
- // Queueing
- opt.old = opt.complete;
- opt.complete = function( noUnmark ) {
- if ( jQuery.isFunction( opt.old ) ) {
- opt.old.call( this );
- }
-
- if ( opt.queue !== false ) {
- jQuery.dequeue( this );
- } else if ( noUnmark !== false ) {
- jQuery._unmark( this );
- }
- };
-
- return opt;
- },
-
- easing: {
- linear: function( p, n, firstNum, diff ) {
- return firstNum + diff * p;
- },
- swing: function( p, n, firstNum, diff ) {
- return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
- }
- },
-
- timers: [],
-
- fx: function( elem, options, prop ) {
- this.options = options;
- this.elem = elem;
- this.prop = prop;
-
- options.orig = options.orig || {};
- }
-
-});
-
-jQuery.fx.prototype = {
- // Simple function for setting a style value
- update: function() {
- if ( this.options.step ) {
- this.options.step.call( this.elem, this.now, this );
- }
-
- (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
- },
-
- // Get the current size
- cur: function() {
- if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
- return this.elem[ this.prop ];
- }
-
- var parsed,
- r = jQuery.css( this.elem, this.prop );
- // Empty strings, null, undefined and "auto" are converted to 0,
- // complex values such as "rotate(1rad)" are returned as is,
- // simple values such as "10px" are parsed to Float.
- return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
- },
-
- // Start an animation from one number to another
- custom: function( from, to, unit ) {
- var self = this,
- fx = jQuery.fx;
-
- this.startTime = fxNow || createFxNow();
- this.start = from;
- this.end = to;
- this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
- this.now = this.start;
- this.pos = this.state = 0;
-
- function t( gotoEnd ) {
- return self.step(gotoEnd);
- }
-
- t.elem = this.elem;
-
- if ( t() && jQuery.timers.push(t) && !timerId ) {
- timerId = setInterval( fx.tick, fx.interval );
- }
- },
-
- // Simple 'show' function
- show: function() {
- // Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
- this.options.show = true;
-
- // Begin the animation
- // Make sure that we start at a small width/height to avoid any
- // flash of content
- this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
-
- // Start by showing the element
- jQuery( this.elem ).show();
- },
-
- // Simple 'hide' function
- hide: function() {
- // Remember where we started, so that we can go back to it later
- this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
- this.options.hide = true;
-
- // Begin the animation
- this.custom(this.cur(), 0);
- },
-
- // Each step of an animation
- step: function( gotoEnd ) {
- var t = fxNow || createFxNow(),
- done = true,
- elem = this.elem,
- options = this.options,
- i, n;
-
- if ( gotoEnd || t >= options.duration + this.startTime ) {
- this.now = this.end;
- this.pos = this.state = 1;
- this.update();
-
- options.animatedProperties[ this.prop ] = true;
-
- for ( i in options.animatedProperties ) {
- if ( options.animatedProperties[i] !== true ) {
- done = false;
- }
- }
-
- if ( done ) {
- // Reset the overflow
- if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
-
- jQuery.each( [ "", "X", "Y" ], function (index, value) {
- elem.style[ "overflow" + value ] = options.overflow[index];
- });
- }
-
- // Hide the element if the "hide" operation was done
- if ( options.hide ) {
- jQuery(elem).hide();
- }
-
- // Reset the properties, if the item has been hidden or shown
- if ( options.hide || options.show ) {
- for ( var p in options.animatedProperties ) {
- jQuery.style( elem, p, options.orig[p] );
- }
- }
-
- // Execute the complete function
- options.complete.call( elem );
- }
-
- return false;
-
- } else {
- // classical easing cannot be used with an Infinity duration
- if ( options.duration == Infinity ) {
- this.now = t;
- } else {
- n = t - this.startTime;
- this.state = n / options.duration;
-
- // Perform the easing function, defaults to swing
- this.pos = jQuery.easing[ options.animatedProperties[ this.prop ] ]( this.state, n, 0, 1, options.duration );
- this.now = this.start + ((this.end - this.start) * this.pos);
- }
- // Perform the next step of the animation
- this.update();
- }
-
- return true;
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p*Math.PI ) / 2;
}
};
-jQuery.extend( jQuery.fx, {
- tick: function() {
- for ( var timers = jQuery.timers, i = 0 ; i < timers.length ; ++i ) {
- if ( !timers[i]() ) {
- timers.splice(i--, 1);
- }
- }
-
- if ( !timers.length ) {
- jQuery.fx.stop();
- }
- },
-
- interval: 13,
-
- stop: function() {
- clearInterval( timerId );
- timerId = null;
- },
-
- speeds: {
- slow: 600,
- fast: 200,
- // Default speed
- _default: 400
- },
-
- step: {
- opacity: function( fx ) {
- jQuery.style( fx.elem, "opacity", fx.now );
- },
-
- _default: function( fx ) {
- if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
- fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
- } else {
- fx.elem[ fx.prop ] = fx.now;
- }
- }
- }
-});
+jQuery.timers = [];
+jQuery.fx = Tween.prototype.init;
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ if ( timer() && jQuery.timers.push( timer ) ) {
+ jQuery.fx.start();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
if ( jQuery.expr && jQuery.expr.filters ) {
jQuery.expr.filters.animated = function( elem ) {
@@ -8614,224 +9543,44 @@
}).length;
};
}
-
-// Try to restore the default display value of an element
-function defaultDisplay( nodeName ) {
-
- if ( !elemdisplay[ nodeName ] ) {
-
- var body = document.body,
- elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
- display = elem.css( "display" );
-
- elem.remove();
-
- // If the simple way fails,
- // get element's real default display by attaching it to a temp iframe
- if ( display === "none" || display === "" ) {
- // No iframe to use yet, so create it
- if ( !iframe ) {
- iframe = document.createElement( "iframe" );
- iframe.frameBorder = iframe.width = iframe.height = 0;
- }
-
- body.appendChild( iframe );
-
- // Create a cacheable copy of the iframe document on first call.
- // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
- // document to it; WebKit & Firefox won't allow reusing the iframe document.
- if ( !iframeDoc || !iframe.createElement ) {
- iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
- iframeDoc.write( ( document.compatMode === "CSS1Compat" ? "<!doctype html>" : "" ) + "<html><body>" );
- iframeDoc.close();
- }
-
- elem = iframeDoc.createElement( nodeName );
-
- iframeDoc.body.appendChild( elem );
-
- display = jQuery.css( elem, "display" );
-
- body.removeChild( iframe );
- }
-
- // Store the correct default display
- elemdisplay[ nodeName ] = display;
- }
-
- return elemdisplay[ nodeName ];
-}
-
-
-
-
-var rtable = /^t(?:able|d|h)$/i,
- rroot = /^(?:body|html)$/i;
-
-if ( "getBoundingClientRect" in document.documentElement ) {
- jQuery.fn.offset = function( options ) {
- var elem = this[0], box;
-
- if ( options ) {
- return this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- if ( !elem || !elem.ownerDocument ) {
- return null;
- }
-
- if ( elem === elem.ownerDocument.body ) {
- return jQuery.offset.bodyOffset( elem );
- }
-
- try {
- box = elem.getBoundingClientRect();
- } catch(e) {}
-
- var doc = elem.ownerDocument,
- docElem = doc.documentElement;
-
- // Make sure we're not dealing with a disconnected DOM node
- if ( !box || !jQuery.contains( docElem, elem ) ) {
- return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
- }
-
- var body = doc.body,
- win = getWindow(doc),
- clientTop = docElem.clientTop || body.clientTop || 0,
- clientLeft = docElem.clientLeft || body.clientLeft || 0,
- scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
- scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
- top = box.top + scrollTop - clientTop,
- left = box.left + scrollLeft - clientLeft;
-
- return { top: top, left: left };
- };
-
-} else {
- jQuery.fn.offset = function( options ) {
- var elem = this[0];
-
- if ( options ) {
- return this.each(function( i ) {
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
jQuery.offset.setOffset( this, options, i );
});
- }
-
- if ( !elem || !elem.ownerDocument ) {
- return null;
- }
-
- if ( elem === elem.ownerDocument.body ) {
- return jQuery.offset.bodyOffset( elem );
- }
-
- jQuery.offset.initialize();
-
- var computedStyle,
- offsetParent = elem.offsetParent,
- prevOffsetParent = elem,
- doc = elem.ownerDocument,
- docElem = doc.documentElement,
- body = doc.body,
- defaultView = doc.defaultView,
- prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
- top = elem.offsetTop,
- left = elem.offsetLeft;
-
- while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
- if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
- break;
- }
-
- computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
- top -= elem.scrollTop;
- left -= elem.scrollLeft;
-
- if ( elem === offsetParent ) {
- top += elem.offsetTop;
- left += elem.offsetLeft;
-
- if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
- top += parseFloat( computedStyle.borderTopWidth ) || 0;
- left += parseFloat( computedStyle.borderLeftWidth ) || 0;
- }
-
- prevOffsetParent = offsetParent;
- offsetParent = elem.offsetParent;
- }
-
- if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
- top += parseFloat( computedStyle.borderTopWidth ) || 0;
- left += parseFloat( computedStyle.borderLeftWidth ) || 0;
- }
-
- prevComputedStyle = computedStyle;
- }
-
- if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
- top += body.offsetTop;
- left += body.offsetLeft;
- }
-
- if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
- top += Math.max( docElem.scrollTop, body.scrollTop );
- left += Math.max( docElem.scrollLeft, body.scrollLeft );
- }
-
- return { top: top, left: left };
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
};
-}
+};
jQuery.offset = {
- initialize: function() {
- var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
- html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
-
- jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
-
- container.innerHTML = html;
- body.insertBefore( container, body.firstChild );
- innerDiv = container.firstChild;
- checkDiv = innerDiv.firstChild;
- td = innerDiv.nextSibling.firstChild.firstChild;
-
- this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
- this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
-
- checkDiv.style.position = "fixed";
- checkDiv.style.top = "20px";
-
- // safari subtracts parent border width here which is 5px
- this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
- checkDiv.style.position = checkDiv.style.top = "";
-
- innerDiv.style.overflow = "hidden";
- innerDiv.style.position = "relative";
-
- this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
-
- this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
-
- body.removeChild( container );
- jQuery.offset.initialize = jQuery.noop;
- },
-
- bodyOffset: function( body ) {
- var top = body.offsetTop,
- left = body.offsetLeft;
-
- jQuery.offset.initialize();
-
- if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
- top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
- left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
- }
-
- return { top: top, left: left };
- },
setOffset: function( elem, options, i ) {
var position = jQuery.css( elem, "position" );
@@ -8845,7 +9594,7 @@
curOffset = curElem.offset(),
curCSSTop = jQuery.css( elem, "top" ),
curCSSLeft = jQuery.css( elem, "left" ),
- calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
props = {}, curPosition = {}, curTop, curLeft;
// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
@@ -8862,11 +9611,11 @@
options = options.call( elem, i, curOffset );
}
- if (options.top != null) {
- props.top = (options.top - curOffset.top) + curTop;
- }
- if (options.left != null) {
- props.left = (options.left - curOffset.left) + curLeft;
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
}
if ( "using" in options ) {
@@ -8879,86 +9628,80 @@
jQuery.fn.extend({
+
position: function() {
- if ( !this[0] ) {
- return null;
- }
-
- var elem = this[0],
-
- // Get *real* offsetParent
- offsetParent = this.offsetParent(),
-
- // Get correct offsets
- offset = this.offset(),
- parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
-
- // Subtract element margins
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
- offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
- offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
-
- // Add offsetParent borders
- parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
- parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
-
- // Subtract the two offsets
return {
- top: offset.top - parentOffset.top,
- left: offset.left - parentOffset.left
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
};
},
offsetParent: function() {
return this.map(function() {
- var offsetParent = this.offsetParent || document.body;
- while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+ var offsetParent = this.offsetParent || docElem;
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
offsetParent = offsetParent.offsetParent;
}
- return offsetParent;
+ return offsetParent || docElem;
});
}
});
// Create scrollLeft and scrollTop methods
-jQuery.each( ["Left", "Top"], function( i, name ) {
- var method = "scroll" + name;
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
jQuery.fn[ method ] = function( val ) {
- var elem, win;
-
- if ( val === undefined ) {
- elem = this[ 0 ];
-
- if ( !elem ) {
- return null;
- }
-
- win = getWindow( elem );
-
- // Return the scroll offset
- return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
- jQuery.support.boxModel && win.document.documentElement[ method ] ||
- win.document.body[ method ] :
- elem[ method ];
- }
-
- // Set the scroll offset
- return this.each(function() {
- win = getWindow( this );
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
if ( win ) {
win.scrollTo(
- !i ? val : jQuery( win ).scrollLeft(),
- i ? val : jQuery( win ).scrollTop()
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
);
} else {
- this[ method ] = val;
- }
- });
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
};
});
@@ -8969,78 +9712,78 @@
elem.defaultView || elem.parentWindow :
false;
}
-
-
-
-
-// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
-jQuery.each([ "Height", "Width" ], function( i, name ) {
-
- var type = name.toLowerCase();
-
- // innerHeight and innerWidth
- jQuery.fn[ "inner" + name ] = function() {
- var elem = this[0];
- return elem && elem.style ?
- parseFloat( jQuery.css( elem, type, "padding" ) ) :
- null;
- };
-
- // outerHeight and outerWidth
- jQuery.fn[ "outer" + name ] = function( margin ) {
- var elem = this[0];
- return elem && elem.style ?
- parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
- null;
- };
-
- jQuery.fn[ type ] = function( size ) {
- // Get window width or height
- var elem = this[0];
- if ( !elem ) {
- return size == null ? null : this;
- }
-
- if ( jQuery.isFunction( size ) ) {
- return this.each(function( i ) {
- var self = jQuery( this );
- self[ type ]( size.call( this, i, self[ type ]() ) );
- });
- }
-
- if ( jQuery.isWindow( elem ) ) {
- // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
- // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
- var docElemProp = elem.document.documentElement[ "client" + name ],
- body = elem.document.body;
- return elem.document.compatMode === "CSS1Compat" && docElemProp ||
- body && body[ "client" + name ] || docElemProp;
-
- // Get document width or height
- } else if ( elem.nodeType === 9 ) {
- // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
- return Math.max(
- elem.documentElement["client" + name],
- elem.body["scroll" + name], elem.documentElement["scroll" + name],
- elem.body["offset" + name], elem.documentElement["offset" + name]
- );
-
- // Get or set width or height on the element
- } else if ( size === undefined ) {
- var orig = jQuery.css( elem, type ),
- ret = parseFloat( orig );
-
- return jQuery.isNaN( ret ) ? orig : ret;
-
- // Set the width or height on the element (default to pixels if value is unitless)
- } else {
- return this.css( type, typeof size === "string" ? size : size + "px" );
- }
- };
-
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
});
-
-
-// Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
-})(window);
+// Limit scope pollution from any deprecated API
+// (function() {
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+// })();
+if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+ // Expose jQuery as module.exports in loaders that implement the Node
+ // module pattern (including browserify). Do not create the global, since
+ // the user will be storing it themselves locally, and globals are frowned
+ // upon in the Node module world.
+ module.exports = jQuery;
+} else {
+ // Otherwise expose jQuery to the global object as usual
+ window.jQuery = window.$ = jQuery;
+
+ // Register as a named AMD module, since jQuery can be concatenated with other
+ // files that may use define, but not via a proper concatenation script that
+ // understands anonymous AMD modules. A named AMD is safest and most robust
+ // way to register. Lowercase jquery is used because AMD module names are
+ // derived from file names, and jQuery is normally delivered in a lowercase
+ // file name. Do this after creating the global so that if an AMD module wants
+ // to call noConflict to hide this version of jQuery, it will work.
+ if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function () { return jQuery; } );
+ }
+}
+
+})( window );
--- a/web/data/jquery.ui.css Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/jquery.ui.css Mon Jan 13 13:47:47 2014 +0100
@@ -1,104 +1,971 @@
-/*
- * jQuery UI CSS Framework @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- */
-
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
/* Layout helpers
----------------------------------*/
-.ui-helper-hidden { display: none; }
-.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
-.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
-.ui-helper-clearfix { display: inline-block; }
-/* required comment for clearfix to work in Opera \*/
-* html .ui-helper-clearfix { height:1%; }
-.ui-helper-clearfix { display:block; }
-/* end clearfix */
-.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+.ui-helper-hidden {
+ display: none;
+}
+.ui-helper-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.ui-helper-reset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ line-height: 1.3;
+ text-decoration: none;
+ font-size: 100%;
+ list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+ content: "";
+ display: table;
+ border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+ clear: both;
+}
+.ui-helper-clearfix {
+ min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ position: absolute;
+ opacity: 0;
+ filter:Alpha(Opacity=0);
+}
+
+.ui-front {
+ z-index: 100;
+}
/* Interaction Cues
----------------------------------*/
-.ui-state-disabled { cursor: default !important; }
+.ui-state-disabled {
+ cursor: default !important;
+}
/* Icons
----------------------------------*/
/* states and images */
-.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+.ui-icon {
+ display: block;
+ text-indent: -99999px;
+ overflow: hidden;
+ background-repeat: no-repeat;
+}
/* Misc visuals
----------------------------------*/
/* Overlays */
-.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+.ui-widget-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.ui-accordion .ui-accordion-header {
+ display: block;
+ cursor: pointer;
+ position: relative;
+ margin-top: 2px;
+ padding: .5em .5em .5em .7em;
+ min-height: 0; /* support: IE7 */
+}
+.ui-accordion .ui-accordion-icons {
+ padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-noicons {
+ padding-left: .7em;
+}
+.ui-accordion .ui-accordion-icons .ui-accordion-icons {
+ padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+ position: absolute;
+ left: .5em;
+ top: 50%;
+ margin-top: -8px;
+}
+.ui-accordion .ui-accordion-content {
+ padding: 1em 2.2em;
+ border-top: 0;
+ overflow: auto;
+}
+
+.ui-autocomplete {
+ position: absolute;
+ top: 0;
+ left: 0;
+ cursor: default;
+}
+
+.ui-button {
+ display: inline-block;
+ position: relative;
+ padding: 0;
+ line-height: normal;
+ margin-right: .1em;
+ cursor: pointer;
+ vertical-align: middle;
+ text-align: center;
+ overflow: visible; /* removes extra width in IE */
+}
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+ text-decoration: none;
+}
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+ width: 2.2em;
+}
+/* button elements seem to need a little more width */
+button.ui-button-icon-only {
+ width: 2.4em;
+}
+.ui-button-icons-only {
+ width: 3.4em;
+}
+button.ui-button-icons-only {
+ width: 3.7em;
+}
+
+/* button text element */
+.ui-button .ui-button-text {
+ display: block;
+ line-height: normal;
+}
+.ui-button-text-only .ui-button-text {
+ padding: .4em 1em;
+}
+.ui-button-icon-only .ui-button-text,
+.ui-button-icons-only .ui-button-text {
+ padding: .4em;
+ text-indent: -9999999px;
+}
+.ui-button-text-icon-primary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+ padding: .4em 1em .4em 2.1em;
+}
+.ui-button-text-icon-secondary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+ padding: .4em 2.1em .4em 1em;
+}
+.ui-button-text-icons .ui-button-text {
+ padding-left: 2.1em;
+ padding-right: 2.1em;
+}
+/* no icon support for input elements, provide padding by default */
+input.ui-button {
+ padding: .4em 1em;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon,
+.ui-button-text-icon-primary .ui-icon,
+.ui-button-text-icon-secondary .ui-icon,
+.ui-button-text-icons .ui-icon,
+.ui-button-icons-only .ui-icon {
+ position: absolute;
+ top: 50%;
+ margin-top: -8px;
+}
+.ui-button-icon-only .ui-icon {
+ left: 50%;
+ margin-left: -8px;
+}
+.ui-button-text-icon-primary .ui-button-icon-primary,
+.ui-button-text-icons .ui-button-icon-primary,
+.ui-button-icons-only .ui-button-icon-primary {
+ left: .5em;
+}
+.ui-button-text-icon-secondary .ui-button-icon-secondary,
+.ui-button-text-icons .ui-button-icon-secondary,
+.ui-button-icons-only .ui-button-icon-secondary {
+ right: .5em;
+}
+
+/* button sets */
+.ui-buttonset {
+ margin-right: 7px;
+}
+.ui-buttonset .ui-button {
+ margin-left: 0;
+ margin-right: -.3em;
+}
+
+/* workarounds */
+/* reset extra padding in Firefox, see h5bp.com/l */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+.ui-datepicker {
+ width: 17em;
+ padding: .2em .2em 0;
+ display: none;
+}
+.ui-datepicker .ui-datepicker-header {
+ position: relative;
+ padding: .2em 0;
+}
+.ui-datepicker .ui-datepicker-prev,
+.ui-datepicker .ui-datepicker-next {
+ position: absolute;
+ top: 2px;
+ width: 1.8em;
+ height: 1.8em;
+}
+.ui-datepicker .ui-datepicker-prev-hover,
+.ui-datepicker .ui-datepicker-next-hover {
+ top: 1px;
+}
+.ui-datepicker .ui-datepicker-prev {
+ left: 2px;
+}
+.ui-datepicker .ui-datepicker-next {
+ right: 2px;
+}
+.ui-datepicker .ui-datepicker-prev-hover {
+ left: 1px;
+}
+.ui-datepicker .ui-datepicker-next-hover {
+ right: 1px;
+}
+.ui-datepicker .ui-datepicker-prev span,
+.ui-datepicker .ui-datepicker-next span {
+ display: block;
+ position: absolute;
+ left: 50%;
+ margin-left: -8px;
+ top: 50%;
+ margin-top: -8px;
+}
+.ui-datepicker .ui-datepicker-title {
+ margin: 0 2.3em;
+ line-height: 1.8em;
+ text-align: center;
+}
+.ui-datepicker .ui-datepicker-title select {
+ font-size: 1em;
+ margin: 1px 0;
+}
+.ui-datepicker select.ui-datepicker-month-year {
+ width: 100%;
+}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+ width: 49%;
+}
+.ui-datepicker table {
+ width: 100%;
+ font-size: .9em;
+ border-collapse: collapse;
+ margin: 0 0 .4em;
+}
+.ui-datepicker th {
+ padding: .7em .3em;
+ text-align: center;
+ font-weight: bold;
+ border: 0;
+}
+.ui-datepicker td {
+ border: 0;
+ padding: 1px;
+}
+.ui-datepicker td span,
+.ui-datepicker td a {
+ display: block;
+ padding: .2em;
+ text-align: right;
+ text-decoration: none;
+}
+.ui-datepicker .ui-datepicker-buttonpane {
+ background-image: none;
+ margin: .7em 0 0 0;
+ padding: 0 .2em;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 0;
+}
+.ui-datepicker .ui-datepicker-buttonpane button {
+ float: right;
+ margin: .5em .2em .4em;
+ cursor: pointer;
+ padding: .2em .6em .3em .6em;
+ width: auto;
+ overflow: visible;
+}
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
+ float: left;
+}
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi {
+ width: auto;
+}
+.ui-datepicker-multi .ui-datepicker-group {
+ float: left;
+}
+.ui-datepicker-multi .ui-datepicker-group table {
+ width: 95%;
+ margin: 0 auto .4em;
+}
+.ui-datepicker-multi-2 .ui-datepicker-group {
+ width: 50%;
+}
+.ui-datepicker-multi-3 .ui-datepicker-group {
+ width: 33.3%;
+}
+.ui-datepicker-multi-4 .ui-datepicker-group {
+ width: 25%;
+}
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
+ border-left-width: 0;
+}
+.ui-datepicker-multi .ui-datepicker-buttonpane {
+ clear: left;
+}
+.ui-datepicker-row-break {
+ clear: both;
+ width: 100%;
+ font-size: 0;
+}
+
+/* RTL support */
+.ui-datepicker-rtl {
+ direction: rtl;
+}
+.ui-datepicker-rtl .ui-datepicker-prev {
+ right: 2px;
+ left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next {
+ left: 2px;
+ right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-prev:hover {
+ right: 1px;
+ left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next:hover {
+ left: 1px;
+ right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane {
+ clear: right;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button {
+ float: left;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
+.ui-datepicker-rtl .ui-datepicker-group {
+ float: right;
+}
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
+ border-right-width: 0;
+ border-left-width: 1px;
+}
-/*
- * jQuery UI CSS Framework @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Theming/API
- *
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
- */
+.ui-dialog {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: .2em;
+ outline: 0;
+}
+.ui-dialog .ui-dialog-titlebar {
+ padding: .4em 1em;
+ position: relative;
+}
+.ui-dialog .ui-dialog-title {
+ float: left;
+ margin: .1em 0;
+ white-space: nowrap;
+ width: 90%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.ui-dialog .ui-dialog-titlebar-close {
+ position: absolute;
+ right: .3em;
+ top: 50%;
+ width: 21px;
+ margin: -10px 0 0 0;
+ padding: 1px;
+ height: 20px;
+}
+.ui-dialog .ui-dialog-content {
+ position: relative;
+ border: 0;
+ padding: .5em 1em;
+ background: none;
+ overflow: auto;
+}
+.ui-dialog .ui-dialog-buttonpane {
+ text-align: left;
+ border-width: 1px 0 0 0;
+ background-image: none;
+ margin-top: .5em;
+ padding: .3em 1em .5em .4em;
+}
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+ float: right;
+}
+.ui-dialog .ui-dialog-buttonpane button {
+ margin: .5em .4em .5em 0;
+ cursor: pointer;
+}
+.ui-dialog .ui-resizable-se {
+ width: 12px;
+ height: 12px;
+ right: -5px;
+ bottom: -5px;
+ background-position: 16px 16px;
+}
+.ui-draggable .ui-dialog-titlebar {
+ cursor: move;
+}
+
+.ui-menu {
+ list-style: none;
+ padding: 2px;
+ margin: 0;
+ display: block;
+ outline: none;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+ position: absolute;
+}
+.ui-menu .ui-menu-item {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ /* support: IE10, see #8844 */
+ list-style-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
+}
+.ui-menu .ui-menu-divider {
+ margin: 5px -2px 5px -2px;
+ height: 0;
+ font-size: 0;
+ line-height: 0;
+ border-width: 1px 0 0 0;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration: none;
+ display: block;
+ padding: 2px .4em;
+ line-height: 1.5;
+ min-height: 0; /* support: IE7 */
+ font-weight: normal;
+}
+.ui-menu .ui-menu-item a.ui-state-focus,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+}
+
+.ui-menu .ui-state-disabled {
+ font-weight: normal;
+ margin: .4em 0 .2em;
+ line-height: 1.5;
+}
+.ui-menu .ui-state-disabled a {
+ cursor: default;
+}
+
+/* icon support */
+.ui-menu-icons {
+ position: relative;
+}
+.ui-menu-icons .ui-menu-item a {
+ position: relative;
+ padding-left: 2em;
+}
+
+/* left-aligned */
+.ui-menu .ui-icon {
+ position: absolute;
+ top: .2em;
+ left: .2em;
+}
+
+/* right-aligned */
+.ui-menu .ui-menu-icon {
+ position: static;
+ float: right;
+}
+
+.ui-progressbar {
+ height: 2em;
+ text-align: left;
+ overflow: hidden;
+}
+.ui-progressbar .ui-progressbar-value {
+ margin: -1px;
+ height: 100%;
+}
+.ui-progressbar .ui-progressbar-overlay {
+ background: url("images/animated-overlay.gif");
+ height: 100%;
+ filter: alpha(opacity=25);
+ opacity: 0.25;
+}
+.ui-progressbar-indeterminate .ui-progressbar-value {
+ background-image: none;
+}
+.ui-resizable {
+ position: relative;
+}
+.ui-resizable-handle {
+ position: absolute;
+ font-size: 0.1px;
+ display: block;
+}
+.ui-resizable-disabled .ui-resizable-handle,
+.ui-resizable-autohide .ui-resizable-handle {
+ display: none;
+}
+.ui-resizable-n {
+ cursor: n-resize;
+ height: 7px;
+ width: 100%;
+ top: -5px;
+ left: 0;
+}
+.ui-resizable-s {
+ cursor: s-resize;
+ height: 7px;
+ width: 100%;
+ bottom: -5px;
+ left: 0;
+}
+.ui-resizable-e {
+ cursor: e-resize;
+ width: 7px;
+ right: -5px;
+ top: 0;
+ height: 100%;
+}
+.ui-resizable-w {
+ cursor: w-resize;
+ width: 7px;
+ left: -5px;
+ top: 0;
+ height: 100%;
+}
+.ui-resizable-se {
+ cursor: se-resize;
+ width: 12px;
+ height: 12px;
+ right: 1px;
+ bottom: 1px;
+}
+.ui-resizable-sw {
+ cursor: sw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ bottom: -5px;
+}
+.ui-resizable-nw {
+ cursor: nw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ top: -5px;
+}
+.ui-resizable-ne {
+ cursor: ne-resize;
+ width: 9px;
+ height: 9px;
+ right: -5px;
+ top: -5px;
+}
+
+.ui-selectable-helper {
+ position: absolute;
+ z-index: 100;
+ border: 1px dotted black;
+}
+
+.ui-slider {
+ position: relative;
+ text-align: left;
+}
+.ui-slider .ui-slider-handle {
+ position: absolute;
+ z-index: 2;
+ width: 1.2em;
+ height: 1.2em;
+ cursor: default;
+}
+.ui-slider .ui-slider-range {
+ position: absolute;
+ z-index: 1;
+ font-size: .7em;
+ display: block;
+ border: 0;
+ background-position: 0 0;
+}
+
+/* For IE8 - See #6727 */
+.ui-slider.ui-state-disabled .ui-slider-handle,
+.ui-slider.ui-state-disabled .ui-slider-range {
+ filter: inherit;
+}
+
+.ui-slider-horizontal {
+ height: .8em;
+}
+.ui-slider-horizontal .ui-slider-handle {
+ top: -.3em;
+ margin-left: -.6em;
+}
+.ui-slider-horizontal .ui-slider-range {
+ top: 0;
+ height: 100%;
+}
+.ui-slider-horizontal .ui-slider-range-min {
+ left: 0;
+}
+.ui-slider-horizontal .ui-slider-range-max {
+ right: 0;
+}
+
+.ui-slider-vertical {
+ width: .8em;
+ height: 100px;
+}
+.ui-slider-vertical .ui-slider-handle {
+ left: -.3em;
+ margin-left: 0;
+ margin-bottom: -.6em;
+}
+.ui-slider-vertical .ui-slider-range {
+ left: 0;
+ width: 100%;
+}
+.ui-slider-vertical .ui-slider-range-min {
+ bottom: 0;
+}
+.ui-slider-vertical .ui-slider-range-max {
+ top: 0;
+}
+
+.ui-spinner {
+ position: relative;
+ display: inline-block;
+ overflow: hidden;
+ padding: 0;
+ vertical-align: middle;
+}
+.ui-spinner-input {
+ border: none;
+ background: none;
+ color: inherit;
+ padding: 0;
+ margin: .2em 0;
+ vertical-align: middle;
+ margin-left: .4em;
+ margin-right: 22px;
+}
+.ui-spinner-button {
+ width: 16px;
+ height: 50%;
+ font-size: .5em;
+ padding: 0;
+ margin: 0;
+ text-align: center;
+ position: absolute;
+ cursor: default;
+ display: block;
+ overflow: hidden;
+ right: 0;
+}
+/* more specificity required here to overide default borders */
+.ui-spinner a.ui-spinner-button {
+ border-top: none;
+ border-bottom: none;
+ border-right: none;
+}
+/* vertical centre icon */
+.ui-spinner .ui-icon {
+ position: absolute;
+ margin-top: -8px;
+ top: 50%;
+ left: 0;
+}
+.ui-spinner-up {
+ top: 0;
+}
+.ui-spinner-down {
+ bottom: 0;
+}
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+ /* need to fix icons sprite */
+ background-position: -65px -16px;
+}
+
+.ui-tabs {
+ position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+ padding: .2em;
+}
+.ui-tabs .ui-tabs-nav {
+ margin: 0;
+ padding: .2em .2em 0;
+}
+.ui-tabs .ui-tabs-nav li {
+ list-style: none;
+ float: left;
+ position: relative;
+ top: 0;
+ margin: 1px .2em 0 0;
+ border-bottom-width: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+.ui-tabs .ui-tabs-nav li a {
+ float: left;
+ padding: .5em 1em;
+ text-decoration: none;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+ margin-bottom: -1px;
+ padding-bottom: 1px;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active a,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled a,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading a {
+ cursor: text;
+}
+.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a {
+ cursor: pointer;
+}
+.ui-tabs .ui-tabs-panel {
+ display: block;
+ border-width: 0;
+ padding: 1em 1.4em;
+ background: none;
+}
+
+.ui-tooltip {
+ padding: 8px;
+ position: absolute;
+ z-index: 9999;
+ max-width: 300px;
+ -webkit-box-shadow: 0 0 5px #aaa;
+ box-shadow: 0 0 5px #aaa;
+}
+body .ui-tooltip {
+ border-width: 2px;
+}
/* Component containers
----------------------------------*/
-.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
-.ui-widget .ui-widget { font-size: 1em; }
-.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
-.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
-.ui-widget-content a { color: #333333; }
-.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
-.ui-widget-header a { color: #ffffff; }
+.ui-widget {
+ font-family: Verdana,Arial,sans-serif/*{ffDefault}*/;
+ font-size: 1.1em/*{fsDefault}*/;
+}
+.ui-widget .ui-widget {
+ font-size: 1em;
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+ font-family: Verdana,Arial,sans-serif/*{ffDefault}*/;
+ font-size: 1em;
+}
+.ui-widget-content {
+ border: 1px solid #aaaaaa/*{borderColorContent}*/;
+ background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/;
+ color: #222222/*{fcContent}*/;
+}
+.ui-widget-content a {
+ color: #222222/*{fcContent}*/;
+}
+.ui-widget-header {
+ border: 1px solid #aaaaaa/*{borderColorHeader}*/;
+ background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/;
+ color: #222222/*{fcHeader}*/;
+ font-weight: bold;
+}
+.ui-widget-header a {
+ color: #222222/*{fcHeader}*/;
+}
/* Interaction states
----------------------------------*/
-.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
-.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
-.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
-.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
-.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
-.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
-.ui-widget :active { outline: none; }
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default {
+ border: 1px solid #d3d3d3/*{borderColorDefault}*/;
+ background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/;
+ font-weight: normal/*{fwDefault}*/;
+ color: #555555/*{fcDefault}*/;
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited {
+ color: #555555/*{fcDefault}*/;
+ text-decoration: none;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus {
+ border: 1px solid #999999/*{borderColorHover}*/;
+ background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/;
+ font-weight: normal/*{fwDefault}*/;
+ color: #212121/*{fcHover}*/;
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited {
+ color: #212121/*{fcHover}*/;
+ text-decoration: none;
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active {
+ border: 1px solid #aaaaaa/*{borderColorActive}*/;
+ background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/;
+ font-weight: normal/*{fwDefault}*/;
+ color: #212121/*{fcActive}*/;
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+ color: #212121/*{fcActive}*/;
+ text-decoration: none;
+}
/* Interaction Cues
----------------------------------*/
-.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
-.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
-.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
-.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
-.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
-.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
-.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
-.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+ border: 1px solid #fcefa1/*{borderColorHighlight}*/;
+ background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/;
+ color: #363636/*{fcHighlight}*/;
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+ color: #363636/*{fcHighlight}*/;
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+ border: 1px solid #cd0a0a/*{borderColorError}*/;
+ background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/;
+ color: #cd0a0a/*{fcError}*/;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+ color: #cd0a0a/*{fcError}*/;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+ color: #cd0a0a/*{fcError}*/;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+ font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+ opacity: .7;
+ filter:Alpha(Opacity=70);
+ font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+ opacity: .35;
+ filter:Alpha(Opacity=35);
+ background-image: none;
+}
+.ui-state-disabled .ui-icon {
+ filter:Alpha(Opacity=35); /* For IE8 - See #6059 */
+}
/* Icons
----------------------------------*/
/* states and images */
-.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
-.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
-.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
-.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
-.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
-.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
-.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
+.ui-icon {
+ width: 16px;
+ height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+ background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/;
+}
+.ui-widget-header .ui-icon {
+ background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/;
+}
+.ui-state-default .ui-icon {
+ background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/;
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon {
+ background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/;
+}
+.ui-state-active .ui-icon {
+ background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/;
+}
+.ui-state-highlight .ui-icon {
+ background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/;
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+ background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/;
+}
/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
@@ -225,8 +1092,8 @@
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
-.ui-icon-radio-off { background-position: -96px -144px; }
-.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
@@ -280,293 +1147,42 @@
----------------------------------*/
/* Corner radius */
-.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
-.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
-.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
-.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
-.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
-.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
-.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
-.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
-.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+ border-top-left-radius: 4px/*{cornerRadius}*/;
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+ border-top-right-radius: 4px/*{cornerRadius}*/;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+ border-bottom-left-radius: 4px/*{cornerRadius}*/;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+ border-bottom-right-radius: 4px/*{cornerRadius}*/;
+}
/* Overlays */
-.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
-.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
- * jQuery UI Resizable @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizable#theming
- */
-.ui-resizable { position: relative;}
-.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
-.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
-.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
-.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
-.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
-.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
-.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
-.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
-.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
-.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
- * jQuery UI Selectable @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectable#theming
- */
-.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
-/*
- * jQuery UI Accordion @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion#theming
- */
-/* IE/Win - Fix animation bug - #4615 */
-.ui-accordion { width: 100%; }
-.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
-.ui-accordion .ui-accordion-li-fix { display: inline; }
-.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
-.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
-.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
-.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
-.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
-.ui-accordion .ui-accordion-content-active { display: block; }/*
- * jQuery UI Autocomplete @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete#theming
- */
-.ui-autocomplete { position: absolute; cursor: default; }
-
-/* workarounds */
-* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
-
-/*
- * jQuery UI Menu @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Menu#theming
- */
-.ui-menu {
- list-style:none;
- padding: 2px;
- margin: 0;
- display:block;
- float: left;
-}
-.ui-menu .ui-menu {
- margin-top: -3px;
-}
-.ui-menu .ui-menu-item {
- margin:0;
- padding: 0;
- zoom: 1;
- float: left;
- clear: left;
- width: 100%;
-}
-.ui-menu .ui-menu-item a {
- text-decoration:none;
- display:block;
- padding:.2em .4em;
- line-height:1.5;
- zoom:1;
-}
-.ui-menu .ui-menu-item a.ui-state-hover,
-.ui-menu .ui-menu-item a.ui-state-active {
- font-weight: normal;
- margin: -1px;
+.ui-widget-overlay {
+ background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/;
+ opacity: .3/*{opacityOverlay}*/;
+ filter: Alpha(Opacity=30)/*{opacityFilterOverlay}*/;
}
-/*
- * jQuery UI Button @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button#theming
- */
-.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
-.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
-button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
-.ui-button-icons-only { width: 3.4em; }
-button.ui-button-icons-only { width: 3.7em; }
-
-/*button text element */
-.ui-button .ui-button-text { display: block; line-height: 1.4; }
-.ui-button-text-only .ui-button-text { padding: .4em 1em; }
-.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
-.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
-.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
-.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
-/* no icon support for input elements, provide padding by default */
-input.ui-button { padding: .4em 1em; }
-
-/*button icon element(s) */
-.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
-.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
-.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
-.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
-
-/*button sets*/
-.ui-buttonset { margin-right: 7px; }
-.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
-
-/* workarounds */
-button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
-/*
- * jQuery UI Dialog @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Dialog#theming
- */
-.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
-.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; }
-.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; }
-.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
-.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
-.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
-.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
-.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
-.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
-.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
-.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
-.ui-draggable .ui-dialog-titlebar { cursor: move; }
-/*
- * jQuery UI Slider @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider#theming
- */
-.ui-slider { position: relative; text-align: left; }
-.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
-.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
-
-.ui-slider-horizontal { height: .8em; }
-.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
-.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
-.ui-slider-horizontal .ui-slider-range-min { left: 0; }
-.ui-slider-horizontal .ui-slider-range-max { right: 0; }
-
-.ui-slider-vertical { width: .8em; height: 100px; }
-.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
-.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
-.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
-.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
- * jQuery UI Tabs @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs#theming
- */
-.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
-.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
-.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
-.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
-.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
-.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
-.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
-.ui-tabs .ui-tabs-hide { display: none !important; }
-/*
- * jQuery UI Datepicker @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker#theming
- */
-.ui-datepicker { width: 17em; padding: .2em .2em 0; }
-.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
-.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
-.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
-.ui-datepicker .ui-datepicker-prev { left:2px; }
-.ui-datepicker .ui-datepicker-next { right:2px; }
-.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
-.ui-datepicker .ui-datepicker-next-hover { right:1px; }
-.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
-.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
-.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
-.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
-.ui-datepicker select.ui-datepicker-month,
-.ui-datepicker select.ui-datepicker-year { width: 49%;}
-.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
-.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
-.ui-datepicker td { border: 0; padding: 1px; }
-.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
-.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
-.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
-.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
-
-/* with multiple calendars */
-.ui-datepicker.ui-datepicker-multi { width:auto; }
-.ui-datepicker-multi .ui-datepicker-group { float:left; }
-.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
-.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
-.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
-.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
-.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
-.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
-.ui-datepicker-row-break { clear:both; width:100%; }
-
-/* RTL support */
-.ui-datepicker-rtl { direction: rtl; }
-.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
-.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
-.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group { float:right; }
-.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
-
-/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
-.ui-datepicker-cover {
- display: none; /*sorry for IE5*/
- display/**/: block; /*sorry for IE5*/
- position: absolute; /*must have*/
- z-index: -1; /*must have*/
- filter: mask(); /*must have*/
- top: -4px; /*must have*/
- left: -4px; /*must have*/
- width: 200px; /*must have*/
- height: 200px; /*must have*/
-}/*
- * jQuery UI Progressbar @VERSION
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar#theming
- */
-.ui-progressbar { height:2em; text-align: left; }
-.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file
+.ui-widget-shadow {
+ margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/;
+ padding: 8px/*{thicknessShadow}*/;
+ background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/;
+ opacity: .3/*{opacityShadow}*/;
+ filter: Alpha(Opacity=30)/*{opacityFilterShadow}*/;
+ border-radius: 8px/*{cornerRadiusShadow}*/;
+}
--- a/web/data/jquery.ui.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/jquery.ui.js Mon Jan 13 13:47:47 2014 +0100
@@ -1,778 +1,15003 @@
-/*!
- * jQuery UI 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI
- */
-(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.5",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,
-NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,
-"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");
-if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"));if(!isNaN(b)&&b!=0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind("mousedown.ui-disableSelection selectstart.ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,
-"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c.style(this,h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c.style(this,
-h,d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});
-c(function(){var a=document.createElement("div"),b=document.body;c.extend(a.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.appendChild(a).offsetHeight===100;b.removeChild(a).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&b[e][1].apply(a.element,
-d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
-;/*!
- * jQuery UI Widget 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Widget
- */
-(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
-a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)===
-"_")return h;e?this.each(function(){var g=b.data(this,a);if(!g)throw"cannot call methods on "+a+" prior to initialization; attempted to call method '"+d+"'";if(!b.isFunction(g[d]))throw"no such method '"+d+"' for "+a+" widget instance";var i=g[d].apply(g,f);if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",
-widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+
-"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}b.each(d,function(f,h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",
-false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
-;/*!
- * jQuery UI Mouse 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Mouse
- *
- * Depends:
- * jquery.ui.widget.js
- */
-(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(a._preventClickEvent){a._preventClickEvent=false;b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&
-this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();
-return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);c.browser.safari||a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&
-this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
-;/*
- * jQuery UI Position 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Position
- */
-(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.scrollTo&&d.document){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j=
-{top:b.of.pageY,left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/
-2;if(b.at[1]==="bottom")j.top+=k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+parseInt(c.curCSS(this,"marginRight",true))||0,w=m+q+parseInt(c.curCSS(this,"marginBottom",true))||0,i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]===
-"center")i.top-=m/2;i.left=parseInt(i.left);i.top=parseInt(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();
-b.left=d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];
-b.left+=a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=
-c(b),g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
-;/*
- * jQuery UI Draggable 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Draggables
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.mouse.js
- * jquery.ui.widget.js
- */
-(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
-"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
-this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-
-this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();
-d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||
-this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if(!this.element[0]||!this.element[0].parentNode)return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&this.options.revert.call(this.element,
-b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==
-a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||
-0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
-this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-
-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment==
-"parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&
-a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),
-10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
-this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():
-f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+
-this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+
-Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-
-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=
-this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.5"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");
-if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;
-c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=
-1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;
-this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=
-this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","iframeFix",{start:function(){var a=
-d(this).data("draggable").options;d(a.iframeFix===true?"iframe":a.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;
-if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!=
-"HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-
-b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-
-c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,
-width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=c.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&
-o<l+e){if(f.snapMode!="inner"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left}var t=
-p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&
-(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),
-10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
-;/*
- * jQuery UI Droppable 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Droppables
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- * jquery.ui.mouse.js
- * jquery.ui.draggable.js
- */
-(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
-a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
-this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
-this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
-d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
-a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.5"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
-switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=
-i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
-"none";if(c[f].visible){c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight};e=="mousedown"&&c[f]._activate.call(c[f],b)}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
-a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=
-d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);
-;/*
- * jQuery UI Resizable 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Resizables
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.mouse.js
- * jquery.ui.widget.js
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function( $, undefined ) {
+
+var uuid = 0,
+ runiqueId = /^ui-id-\d+$/;
+
+// $.ui might exist from components with no dependencies, e.g., $.ui.position
+$.ui = $.ui || {};
+
+$.extend( $.ui, {
+ version: "1.10.3",
+
+ keyCode: {
+ BACKSPACE: 8,
+ COMMA: 188,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ LEFT: 37,
+ NUMPAD_ADD: 107,
+ NUMPAD_DECIMAL: 110,
+ NUMPAD_DIVIDE: 111,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_SUBTRACT: 109,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38
+ }
+});
+
+// plugins
+$.fn.extend({
+ focus: (function( orig ) {
+ return function( delay, fn ) {
+ return typeof delay === "number" ?
+ this.each(function() {
+ var elem = this;
+ setTimeout(function() {
+ $( elem ).focus();
+ if ( fn ) {
+ fn.call( elem );
+ }
+ }, delay );
+ }) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.focus ),
+
+ scrollParent: function() {
+ var scrollParent;
+ if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
+ scrollParent = this.parents().filter(function() {
+ return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ } else {
+ scrollParent = this.parents().filter(function() {
+ return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
+ }).eq(0);
+ }
+
+ return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
+ },
+
+ zIndex: function( zIndex ) {
+ if ( zIndex !== undefined ) {
+ return this.css( "zIndex", zIndex );
+ }
+
+ if ( this.length ) {
+ var elem = $( this[ 0 ] ), position, value;
+ while ( elem.length && elem[ 0 ] !== document ) {
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
+ // This makes behavior of this function consistent across browsers
+ // WebKit always returns auto if the element is positioned
+ position = elem.css( "position" );
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+ // IE returns 0 when zIndex is not specified
+ // other browsers return a string
+ // we ignore the case of nested elements with an explicit value of 0
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+ value = parseInt( elem.css( "zIndex" ), 10 );
+ if ( !isNaN( value ) && value !== 0 ) {
+ return value;
+ }
+ }
+ elem = elem.parent();
+ }
+ }
+
+ return 0;
+ },
+
+ uniqueId: function() {
+ return this.each(function() {
+ if ( !this.id ) {
+ this.id = "ui-id-" + (++uuid);
+ }
+ });
+ },
+
+ removeUniqueId: function() {
+ return this.each(function() {
+ if ( runiqueId.test( this.id ) ) {
+ $( this ).removeAttr( "id" );
+ }
+ });
+ }
+});
+
+// selectors
+function focusable( element, isTabIndexNotNaN ) {
+ var map, mapName, img,
+ nodeName = element.nodeName.toLowerCase();
+ if ( "area" === nodeName ) {
+ map = element.parentNode;
+ mapName = map.name;
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+ return false;
+ }
+ img = $( "img[usemap=#" + mapName + "]" )[0];
+ return !!img && visible( img );
+ }
+ return ( /input|select|textarea|button|object/.test( nodeName ) ?
+ !element.disabled :
+ "a" === nodeName ?
+ element.href || isTabIndexNotNaN :
+ isTabIndexNotNaN) &&
+ // the element and all of its ancestors must be visible
+ visible( element );
+}
+
+function visible( element ) {
+ return $.expr.filters.visible( element ) &&
+ !$( element ).parents().addBack().filter(function() {
+ return $.css( this, "visibility" ) === "hidden";
+ }).length;
+}
+
+$.extend( $.expr[ ":" ], {
+ data: $.expr.createPseudo ?
+ $.expr.createPseudo(function( dataName ) {
+ return function( elem ) {
+ return !!$.data( elem, dataName );
+ };
+ }) :
+ // support: jQuery <1.8
+ function( elem, i, match ) {
+ return !!$.data( elem, match[ 3 ] );
+ },
+
+ focusable: function( element ) {
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
+ },
+
+ tabbable: function( element ) {
+ var tabIndex = $.attr( element, "tabindex" ),
+ isTabIndexNaN = isNaN( tabIndex );
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
+ }
+});
+
+// support: jQuery <1.8
+if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
+ $.each( [ "Width", "Height" ], function( i, name ) {
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+ type = name.toLowerCase(),
+ orig = {
+ innerWidth: $.fn.innerWidth,
+ innerHeight: $.fn.innerHeight,
+ outerWidth: $.fn.outerWidth,
+ outerHeight: $.fn.outerHeight
+ };
+
+ function reduce( elem, size, border, margin ) {
+ $.each( side, function() {
+ size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
+ if ( border ) {
+ size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
+ }
+ if ( margin ) {
+ size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
+ }
+ });
+ return size;
+ }
+
+ $.fn[ "inner" + name ] = function( size ) {
+ if ( size === undefined ) {
+ return orig[ "inner" + name ].call( this );
+ }
+
+ return this.each(function() {
+ $( this ).css( type, reduce( this, size ) + "px" );
+ });
+ };
+
+ $.fn[ "outer" + name] = function( size, margin ) {
+ if ( typeof size !== "number" ) {
+ return orig[ "outer" + name ].call( this, size );
+ }
+
+ return this.each(function() {
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
+ });
+ };
+ });
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
+if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
+ $.fn.removeData = (function( removeData ) {
+ return function( key ) {
+ if ( arguments.length ) {
+ return removeData.call( this, $.camelCase( key ) );
+ } else {
+ return removeData.call( this );
+ }
+ };
+ })( $.fn.removeData );
+}
+
+
+
+
+
+// deprecated
+$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
+
+$.support.selectstart = "onselectstart" in document.createElement( "div" );
+$.fn.extend({
+ disableSelection: function() {
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
+ ".ui-disableSelection", function( event ) {
+ event.preventDefault();
+ });
+ },
+
+ enableSelection: function() {
+ return this.unbind( ".ui-disableSelection" );
+ }
+});
+
+$.extend( $.ui, {
+ // $.ui.plugin is deprecated. Use $.widget() extensions instead.
+ plugin: {
+ add: function( module, option, set ) {
+ var i,
+ proto = $.ui[ module ].prototype;
+ for ( i in set ) {
+ proto.plugins[ i ] = proto.plugins[ i ] || [];
+ proto.plugins[ i ].push( [ option, set[ i ] ] );
+ }
+ },
+ call: function( instance, name, args ) {
+ var i,
+ set = instance.plugins[ name ];
+ if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
+ return;
+ }
+
+ for ( i = 0; i < set.length; i++ ) {
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
+ set[ i ][ 1 ].apply( instance.element, args );
+ }
+ }
+ }
+ },
+
+ // only used by resizable
+ hasScroll: function( el, a ) {
+
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
+ if ( $( el ).css( "overflow" ) === "hidden") {
+ return false;
+ }
+
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+ has = false;
+
+ if ( el[ scroll ] > 0 ) {
+ return true;
+ }
+
+ // TODO: determine which cases actually cause this to happen
+ // if the element doesn't have the scroll set, see if it's possible to
+ // set the scroll
+ el[ scroll ] = 1;
+ has = ( el[ scroll ] > 0 );
+ el[ scroll ] = 0;
+ return has;
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+var uuid = 0,
+ slice = Array.prototype.slice,
+ _cleanData = $.cleanData;
+$.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+};
+
+$.widget = function( name, base, prototype ) {
+ var fullName, existingConstructor, constructor, basePrototype,
+ // proxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ proxiedPrototype = {},
+ namespace = name.split( "." )[ 0 ];
+
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+ // extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+ // copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+ // track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ });
+
+ basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = (function() {
+ var _super = function() {
+ return base.prototype[ prop ].apply( this, arguments );
+ },
+ _superApply = function( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ };
+ return function() {
+ var __super = this._super,
+ __superApply = this._superApply,
+ returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ })();
+ });
+ constructor.prototype = $.widget.extend( basePrototype, {
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ });
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+ });
+ // remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+};
+
+$.widget.extend = function( target ) {
+ var input = slice.call( arguments, 1 ),
+ inputIndex = 0,
+ inputLength = input.length,
+ key,
+ value;
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+};
+
+$.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.widget.extend.apply( null, [ options ].concat(args) ) :
+ options;
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var methodValue,
+ instance = $.data( this, fullName );
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+ if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+ }
+ methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ // 1.9 BC for #7810
+ // TODO remove dual storage
+ .removeData( this.widgetName )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( value === undefined ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( value === undefined ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
+ .attr( "aria-disabled", value );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ // accept selectors, DOM elements
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^(\w+)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+var mouseHandled = false;
+$( document ).mouseup( function() {
+ mouseHandled = false;
+});
+
+$.widget("ui.mouse", {
+ version: "1.10.3",
+ options: {
+ cancel: "input,textarea,button,select,option",
+ distance: 1,
+ delay: 0
+ },
+ _mouseInit: function() {
+ var that = this;
+
+ this.element
+ .bind("mousedown."+this.widgetName, function(event) {
+ return that._mouseDown(event);
+ })
+ .bind("click."+this.widgetName, function(event) {
+ if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, that.widgetName + ".preventClickEvent");
+ event.stopImmediatePropagation();
+ return false;
+ }
+ });
+
+ this.started = false;
+ },
+
+ // TODO: make sure destroying one instance of mouse doesn't mess with
+ // other instances of mouse
+ _mouseDestroy: function() {
+ this.element.unbind("."+this.widgetName);
+ if ( this._mouseMoveDelegate ) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+ }
+ },
+
+ _mouseDown: function(event) {
+ // don't let more than one widget handle mouseStart
+ if( mouseHandled ) { return; }
+
+ // we may have missed mouseup (out of window)
+ (this._mouseStarted && this._mouseUp(event));
+
+ this._mouseDownEvent = event;
+
+ var that = this,
+ btnIsLeft = (event.which === 1),
+ // event.target.nodeName works around a bug in IE 8 with
+ // disabled inputs (#7620)
+ elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+ return true;
+ }
+
+ this.mouseDelayMet = !this.options.delay;
+ if (!this.mouseDelayMet) {
+ this._mouseDelayTimer = setTimeout(function() {
+ that.mouseDelayMet = true;
+ }, this.options.delay);
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted = (this._mouseStart(event) !== false);
+ if (!this._mouseStarted) {
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // Click event may never have fired (Gecko & Opera)
+ if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+ $.removeData(event.target, this.widgetName + ".preventClickEvent");
+ }
+
+ // these delegates are required to keep context
+ this._mouseMoveDelegate = function(event) {
+ return that._mouseMove(event);
+ };
+ this._mouseUpDelegate = function(event) {
+ return that._mouseUp(event);
+ };
+ $(document)
+ .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ event.preventDefault();
+
+ mouseHandled = true;
+ return true;
+ },
+
+ _mouseMove: function(event) {
+ // IE mouseup check - mouseup happened when mouse was out of window
+ if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
+ return this._mouseUp(event);
+ }
+
+ if (this._mouseStarted) {
+ this._mouseDrag(event);
+ return event.preventDefault();
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted =
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+ }
+
+ return !this._mouseStarted;
+ },
+
+ _mouseUp: function(event) {
+ $(document)
+ .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
+ .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
+
+ if (this._mouseStarted) {
+ this._mouseStarted = false;
+
+ if (event.target === this._mouseDownEvent.target) {
+ $.data(event.target, this.widgetName + ".preventClickEvent", true);
+ }
+
+ this._mouseStop(event);
+ }
+
+ return false;
+ },
+
+ _mouseDistanceMet: function(event) {
+ return (Math.max(
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
+ ) >= this.options.distance
+ );
+ },
+
+ _mouseDelayMet: function(/* event */) {
+ return this.mouseDelayMet;
+ },
+
+ // These are placeholder methods, to be overriden by extending plugin
+ _mouseStart: function(/* event */) {},
+ _mouseDrag: function(/* event */) {},
+ _mouseStop: function(/* event */) {},
+ _mouseCapture: function(/* event */) { return true; }
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget("ui.draggable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "drag",
+ options: {
+ addClasses: true,
+ appendTo: "parent",
+ axis: false,
+ connectToSortable: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ iframeFix: false,
+ opacity: false,
+ refreshPositions: false,
+ revert: false,
+ revertDuration: 500,
+ scope: "default",
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ snap: false,
+ snapMode: "both",
+ snapTolerance: 20,
+ stack: false,
+ zIndex: false,
+
+ // callbacks
+ drag: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
+ this.element[0].style.position = "relative";
+ }
+ if (this.options.addClasses){
+ this.element.addClass("ui-draggable");
+ }
+ if (this.options.disabled){
+ this.element.addClass("ui-draggable-disabled");
+ }
+
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function(event) {
+
+ var o = this.options;
+
+ // among others, prevent a drag on a resizable-handle
+ if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
+ return false;
+ }
+
+ //Quit if we're not on a valid handle
+ this.handle = this._getHandle(event);
+ if (!this.handle) {
+ return false;
+ }
+
+ $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
+ $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
+ .css({
+ width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+ position: "absolute", opacity: "0.001", zIndex: 1000
+ })
+ .css($(this).offset())
+ .appendTo("body");
+ });
+
+ return true;
+
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options;
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ this.helper.addClass("ui-draggable-dragging");
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ //If ddmanager is used for droppables, set the global draggable
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Store the helper's css position
+ this.cssPosition = this.helper.css( "position" );
+ this.scrollParent = this.helper.scrollParent();
+ this.offsetParent = this.helper.offsetParent();
+ this.offsetParentCssPosition = this.offsetParent.css( "position" );
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.positionAbs = this.element.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ //Reset scroll cache
+ this.offset.scroll = false;
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ //Generate the original position
+ this.originalPosition = this.position = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Set a containment if given in the options
+ this._setContainment();
+
+ //Trigger event + callbacks
+ if(this._trigger("start", event) === false) {
+ this._clear();
+ return false;
+ }
+
+ //Recache the helper size
+ this._cacheHelperProportions();
+
+ //Prepare the droppable offsets
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+
+ this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+ if ( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStart(this, event);
+ }
+
+ return true;
+ },
+
+ _mouseDrag: function(event, noPropagation) {
+ // reset any necessary cached properties (see #5009)
+ if ( this.offsetParentCssPosition === "fixed" ) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Call plugins and callbacks and use the resulting position if something is returned
+ if (!noPropagation) {
+ var ui = this._uiHash();
+ if(this._trigger("drag", event, ui) === false) {
+ this._mouseUp({});
+ return false;
+ }
+ this.position = ui.position;
+ }
+
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ //If we are using droppables, inform the manager about the drop
+ var that = this,
+ dropped = false;
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ dropped = $.ui.ddmanager.drop(this, event);
+ }
+
+ //if a drop comes from outside (a sortable)
+ if(this.dropped) {
+ dropped = this.dropped;
+ this.dropped = false;
+ }
+
+ //if the original element is no longer in the DOM don't bother to continue (see #8269)
+ if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
+ return false;
+ }
+
+ if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+ $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+ if(that._trigger("stop", event) !== false) {
+ that._clear();
+ }
+ });
+ } else {
+ if(this._trigger("stop", event) !== false) {
+ this._clear();
+ }
+ }
+
+ return false;
+ },
+
+ _mouseUp: function(event) {
+ //Remove frame helpers
+ $("div.ui-draggable-iframeFix").each(function() {
+ this.parentNode.removeChild(this);
+ });
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+ if( $.ui.ddmanager ) {
+ $.ui.ddmanager.dragStop(this, event);
+ }
+
+ return $.ui.mouse.prototype._mouseUp.call(this, event);
+ },
+
+ cancel: function() {
+
+ if(this.helper.is(".ui-draggable-dragging")) {
+ this._mouseUp({});
+ } else {
+ this._clear();
+ }
+
+ return this;
+
+ },
+
+ _getHandle: function(event) {
+ return this.options.handle ?
+ !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
+ true;
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
+
+ if(!helper.parents("body").length) {
+ helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
+ }
+
+ if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
+ helper.css("position", "absolute");
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+ //Get the offsetParent and cache its position
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ //This needs to be actually done for all browsers, since pageX/pageY includes this information
+ //Ugly IE fix
+ if((this.offsetParent[0] === document.body) ||
+ (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.element.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.element.css("marginLeft"),10) || 0),
+ top: (parseInt(this.element.css("marginTop"),10) || 0),
+ right: (parseInt(this.element.css("marginRight"),10) || 0),
+ bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var over, c, ce,
+ o = this.options;
+
+ if ( !o.containment ) {
+ this.containment = null;
+ return;
+ }
+
+ if ( o.containment === "window" ) {
+ this.containment = [
+ $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+ $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+ $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
+ $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment === "document") {
+ this.containment = [
+ 0,
+ 0,
+ $( document ).width() - this.helperProportions.width - this.margins.left,
+ ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+ ];
+ return;
+ }
+
+ if ( o.containment.constructor === Array ) {
+ this.containment = o.containment;
+ return;
+ }
+
+ if ( o.containment === "parent" ) {
+ o.containment = this.helper[ 0 ].parentNode;
+ }
+
+ c = $( o.containment );
+ ce = c[ 0 ];
+
+ if( !ce ) {
+ return;
+ }
+
+ over = c.css( "overflow" ) !== "hidden";
+
+ this.containment = [
+ ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
+ ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
+ ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
+ ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
+ ];
+ this.relative_container = c;
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var containment, co, top, left,
+ o = this.options,
+ scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
+ pageX = event.pageX,
+ pageY = event.pageY;
+
+ //Cache the scroll
+ if (!this.offset.scroll) {
+ this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ // If we are not dragging yet, we won't check for options
+ if ( this.originalPosition ) {
+ if ( this.containment ) {
+ if ( this.relative_container ){
+ co = this.relative_container.offset();
+ containment = [
+ this.containment[ 0 ] + co.left,
+ this.containment[ 1 ] + co.top,
+ this.containment[ 2 ] + co.left,
+ this.containment[ 3 ] + co.top
+ ];
+ }
+ else {
+ containment = this.containment;
+ }
+
+ if(event.pageX - this.offset.click.left < containment[0]) {
+ pageX = containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < containment[1]) {
+ pageY = containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > containment[2]) {
+ pageX = containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > containment[3]) {
+ pageY = containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+ top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+ pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+ pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
+ )
+ };
+
+ },
+
+ _clear: function() {
+ this.helper.removeClass("ui-draggable-dragging");
+ if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
+ this.helper.remove();
+ }
+ this.helper = null;
+ this.cancelHelperRemoval = false;
+ },
+
+ // From now on bulk stuff - mainly helpers
+
+ _trigger: function(type, event, ui) {
+ ui = ui || this._uiHash();
+ $.ui.plugin.call(this, type, [event, ui]);
+ //The absolute position has to be recalculated after plugins
+ if(type === "drag") {
+ this.positionAbs = this._convertPositionTo("absolute");
+ }
+ return $.Widget.prototype._trigger.call(this, type, event, ui);
+ },
+
+ plugins: {},
+
+ _uiHash: function() {
+ return {
+ helper: this.helper,
+ position: this.position,
+ originalPosition: this.originalPosition,
+ offset: this.positionAbs
+ };
+ }
+
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), o = inst.options,
+ uiSortable = $.extend({}, ui, { item: inst.element });
+ inst.sortables = [];
+ $(o.connectToSortable).each(function() {
+ var sortable = $.data(this, "ui-sortable");
+ if (sortable && !sortable.options.disabled) {
+ inst.sortables.push({
+ instance: sortable,
+ shouldRevert: sortable.options.revert
+ });
+ sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
+ sortable._trigger("activate", event, uiSortable);
+ }
+ });
+
+ },
+ stop: function(event, ui) {
+
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+ var inst = $(this).data("ui-draggable"),
+ uiSortable = $.extend({}, ui, { item: inst.element });
+
+ $.each(inst.sortables, function() {
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+
+ //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
+ if(this.shouldRevert) {
+ this.instance.options.revert = this.shouldRevert;
+ }
+
+ //Trigger the stop of the sortable
+ this.instance._mouseStop(event);
+
+ this.instance.options.helper = this.instance.options._helper;
+
+ //If the helper has been the original item, restore properties in the sortable
+ if(inst.options.helper === "original") {
+ this.instance.currentItem.css({ top: "auto", left: "auto" });
+ }
+
+ } else {
+ this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
+ this.instance._trigger("deactivate", event, uiSortable);
+ }
+
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("ui-draggable"), that = this;
+
+ $.each(inst.sortables, function() {
+
+ var innermostIntersecting = false,
+ thisSortable = this;
+
+ //Copy over some variables to allow calling the sortable's native _intersectsWith
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+
+ if(this.instance._intersectsWith(this.instance.containerCache)) {
+ innermostIntersecting = true;
+ $.each(inst.sortables, function () {
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+ if (this !== thisSortable &&
+ this.instance._intersectsWith(this.instance.containerCache) &&
+ $.contains(thisSortable.instance.element[0], this.instance.element[0])
+ ) {
+ innermostIntersecting = false;
+ }
+ return innermostIntersecting;
+ });
+ }
+
+
+ if(innermostIntersecting) {
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+ if(!this.instance.isOver) {
+
+ this.instance.isOver = 1;
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+ this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
+ this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
+ this.instance.options.helper = function() { return ui.helper[0]; };
+
+ event.target = this.instance.currentItem[0];
+ this.instance._mouseCapture(event, true);
+ this.instance._mouseStart(event, true, true);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+ this.instance.offset.click.top = inst.offset.click.top;
+ this.instance.offset.click.left = inst.offset.click.left;
+ this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
+ this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
+
+ inst._trigger("toSortable", event);
+ inst.dropped = this.instance.element; //draggable revert needs that
+ //hack so receive/update callbacks work (mostly)
+ inst.currentItem = inst.element;
+ this.instance.fromOutside = inst;
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+ if(this.instance.currentItem) {
+ this.instance._mouseDrag(event);
+ }
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+ this.instance.cancelHelperRemoval = true;
+
+ //Prevent reverting on this forced stop
+ this.instance.options.revert = false;
+
+ // The out event needs to be triggered independently
+ this.instance._trigger("out", event, this.instance._uiHash(this.instance));
+
+ this.instance._mouseStop(event, true);
+ this.instance.options.helper = this.instance.options._helper;
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+ this.instance.currentItem.remove();
+ if(this.instance.placeholder) {
+ this.instance.placeholder.remove();
+ }
+
+ inst._trigger("fromSortable", event);
+ inst.dropped = false; //draggable revert needs that
+ }
+
+ }
+
+ });
+
+ }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+ start: function() {
+ var t = $("body"), o = $(this).data("ui-draggable").options;
+ if (t.css("cursor")) {
+ o._cursor = t.css("cursor");
+ }
+ t.css("cursor", o.cursor);
+ },
+ stop: function() {
+ var o = $(this).data("ui-draggable").options;
+ if (o._cursor) {
+ $("body").css("cursor", o._cursor);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("opacity")) {
+ o._opacity = t.css("opacity");
+ }
+ t.css("opacity", o.opacity);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._opacity) {
+ $(ui.helper).css("opacity", o._opacity);
+ }
+ }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+ start: function() {
+ var i = $(this).data("ui-draggable");
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+ i.overflowOffset = i.scrollParent.offset();
+ }
+ },
+ drag: function( event ) {
+
+ var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
+
+ if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
+
+ if(!o.axis || o.axis !== "x") {
+ if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+ }
+
+ } else {
+
+ if(!o.axis || o.axis !== "x") {
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+ }
+
+ if(!o.axis || o.axis !== "y") {
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(i, event);
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+ start: function() {
+
+ var i = $(this).data("ui-draggable"),
+ o = i.options;
+
+ i.snapElements = [];
+
+ $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
+ var $t = $(this),
+ $o = $t.offset();
+ if(this !== i.element[0]) {
+ i.snapElements.push({
+ item: this,
+ width: $t.outerWidth(), height: $t.outerHeight(),
+ top: $o.top, left: $o.left
+ });
+ }
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var ts, bs, ls, rs, l, r, t, b, i, first,
+ inst = $(this).data("ui-draggable"),
+ o = inst.options,
+ d = o.snapTolerance,
+ x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+ y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+ for (i = inst.snapElements.length - 1; i >= 0; i--){
+
+ l = inst.snapElements[i].left;
+ r = l + inst.snapElements[i].width;
+ t = inst.snapElements[i].top;
+ b = t + inst.snapElements[i].height;
+
+ if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
+ if(inst.snapElements[i].snapping) {
+ (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = false;
+ continue;
+ }
+
+ if(o.snapMode !== "inner") {
+ ts = Math.abs(t - y2) <= d;
+ bs = Math.abs(b - y1) <= d;
+ ls = Math.abs(l - x2) <= d;
+ rs = Math.abs(r - x1) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
+ }
+ }
+
+ first = (ts || bs || ls || rs);
+
+ if(o.snapMode !== "outer") {
+ ts = Math.abs(t - y1) <= d;
+ bs = Math.abs(b - y2) <= d;
+ ls = Math.abs(l - x1) <= d;
+ rs = Math.abs(r - x2) <= d;
+ if(ts) {
+ ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
+ }
+ if(bs) {
+ ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ }
+ if(ls) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
+ }
+ if(rs) {
+ ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
+ }
+ }
+
+ if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
+ (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ }
+ inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+ }
+
+ }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+ start: function() {
+ var min,
+ o = this.data("ui-draggable").options,
+ group = $.makeArray($(o.stack)).sort(function(a,b) {
+ return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
+ });
+
+ if (!group.length) { return; }
+
+ min = parseInt($(group[0]).css("zIndex"), 10) || 0;
+ $(group).each(function(i) {
+ $(this).css("zIndex", min + i);
+ });
+ this.css("zIndex", (min + group.length));
+ }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("ui-draggable").options;
+ if(t.css("zIndex")) {
+ o._zIndex = t.css("zIndex");
+ }
+ t.css("zIndex", o.zIndex);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("ui-draggable").options;
+ if(o._zIndex) {
+ $(ui.helper).css("zIndex", o._zIndex);
+ }
+ }
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+$.widget("ui.droppable", {
+ version: "1.10.3",
+ widgetEventPrefix: "drop",
+ options: {
+ accept: "*",
+ activeClass: false,
+ addClasses: true,
+ greedy: false,
+ hoverClass: false,
+ scope: "default",
+ tolerance: "intersect",
+
+ // callbacks
+ activate: null,
+ deactivate: null,
+ drop: null,
+ out: null,
+ over: null
+ },
+ _create: function() {
+
+ var o = this.options,
+ accept = o.accept;
+
+ this.isover = false;
+ this.isout = true;
+
+ this.accept = $.isFunction(accept) ? accept : function(d) {
+ return d.is(accept);
+ };
+
+ //Store the droppable's proportions
+ this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
+
+ // Add the reference and positions to the manager
+ $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
+ $.ui.ddmanager.droppables[o.scope].push(this);
+
+ (o.addClasses && this.element.addClass("ui-droppable"));
+
+ },
+
+ _destroy: function() {
+ var i = 0,
+ drop = $.ui.ddmanager.droppables[this.options.scope];
+
+ for ( ; i < drop.length; i++ ) {
+ if ( drop[i] === this ) {
+ drop.splice(i, 1);
+ }
+ }
+
+ this.element.removeClass("ui-droppable ui-droppable-disabled");
+ },
+
+ _setOption: function(key, value) {
+
+ if(key === "accept") {
+ this.accept = $.isFunction(value) ? value : function(d) {
+ return d.is(value);
+ };
+ }
+ $.Widget.prototype._setOption.apply(this, arguments);
+ },
+
+ _activate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.addClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("activate", event, this.ui(draggable));
+ }
+ },
+
+ _deactivate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(draggable){
+ this._trigger("deactivate", event, this.ui(draggable));
+ }
+ },
+
+ _over: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.addClass(this.options.hoverClass);
+ }
+ this._trigger("over", event, this.ui(draggable));
+ }
+
+ },
+
+ _out: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return;
+ }
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("out", event, this.ui(draggable));
+ }
+
+ },
+
+ _drop: function(event,custom) {
+
+ var draggable = custom || $.ui.ddmanager.current,
+ childrenIntersection = false;
+
+ // Bail if draggable and droppable are same element
+ if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
+ return false;
+ }
+
+ this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
+ var inst = $.data(this, "ui-droppable");
+ if(
+ inst.options.greedy &&
+ !inst.options.disabled &&
+ inst.options.scope === draggable.options.scope &&
+ inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
+ $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
+ ) { childrenIntersection = true; return false; }
+ });
+ if(childrenIntersection) {
+ return false;
+ }
+
+ if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.activeClass) {
+ this.element.removeClass(this.options.activeClass);
+ }
+ if(this.options.hoverClass) {
+ this.element.removeClass(this.options.hoverClass);
+ }
+ this._trigger("drop", event, this.ui(draggable));
+ return this.element;
+ }
+
+ return false;
+
+ },
+
+ ui: function(c) {
+ return {
+ draggable: (c.currentItem || c.element),
+ helper: c.helper,
+ position: c.position,
+ offset: c.positionAbs
+ };
+ }
+
+});
+
+$.ui.intersect = function(draggable, droppable, toleranceMode) {
+
+ if (!droppable.offset) {
+ return false;
+ }
+
+ var draggableLeft, draggableTop,
+ x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
+ y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,
+ l = droppable.offset.left, r = l + droppable.proportions.width,
+ t = droppable.offset.top, b = t + droppable.proportions.height;
+
+ switch (toleranceMode) {
+ case "fit":
+ return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
+ case "intersect":
+ return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
+ x2 - (draggable.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
+ y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
+ case "pointer":
+ draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
+ draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
+ return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );
+ case "touch":
+ return (
+ (y1 >= t && y1 <= b) || // Top edge touching
+ (y2 >= t && y2 <= b) || // Bottom edge touching
+ (y1 < t && y2 > b) // Surrounded vertically
+ ) && (
+ (x1 >= l && x1 <= r) || // Left edge touching
+ (x2 >= l && x2 <= r) || // Right edge touching
+ (x1 < l && x2 > r) // Surrounded horizontally
+ );
+ default:
+ return false;
+ }
+
+};
+
+/*
+ This manager tracks offsets of draggables and droppables
+*/
+$.ui.ddmanager = {
+ current: null,
+ droppables: { "default": [] },
+ prepareOffsets: function(t, event) {
+
+ var i, j,
+ m = $.ui.ddmanager.droppables[t.options.scope] || [],
+ type = event ? event.type : null, // workaround for #2317
+ list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
+
+ droppablesLoop: for (i = 0; i < m.length; i++) {
+
+ //No disabled and non-accepted
+ if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
+ continue;
+ }
+
+ // Filter out elements in the current dragged item
+ for (j=0; j < list.length; j++) {
+ if(list[j] === m[i].element[0]) {
+ m[i].proportions.height = 0;
+ continue droppablesLoop;
+ }
+ }
+
+ m[i].visible = m[i].element.css("display") !== "none";
+ if(!m[i].visible) {
+ continue;
+ }
+
+ //Activate the droppable if used directly from draggables
+ if(type === "mousedown") {
+ m[i]._activate.call(m[i], event);
+ }
+
+ m[i].offset = m[i].element.offset();
+ m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
+
+ }
+
+ },
+ drop: function(draggable, event) {
+
+ var dropped = false;
+ // Create a copy of the droppables in case the list changes during the drop (#9116)
+ $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
+
+ if(!this.options) {
+ return;
+ }
+ if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
+ dropped = this._drop.call(this, event) || dropped;
+ }
+
+ if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ this.isout = true;
+ this.isover = false;
+ this._deactivate.call(this, event);
+ }
+
+ });
+ return dropped;
+
+ },
+ dragStart: function( draggable, event ) {
+ //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
+ draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ });
+ },
+ drag: function(draggable, event) {
+
+ //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
+ if(draggable.options.refreshPositions) {
+ $.ui.ddmanager.prepareOffsets(draggable, event);
+ }
+
+ //Run through all droppables and check their positions based on specific tolerance options
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
+
+ if(this.options.disabled || this.greedyChild || !this.visible) {
+ return;
+ }
+
+ var parentInstance, scope, parent,
+ intersects = $.ui.intersect(draggable, this, this.options.tolerance),
+ c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
+ if(!c) {
+ return;
+ }
+
+ if (this.options.greedy) {
+ // find droppable parents with same scope
+ scope = this.options.scope;
+ parent = this.element.parents(":data(ui-droppable)").filter(function () {
+ return $.data(this, "ui-droppable").options.scope === scope;
+ });
+
+ if (parent.length) {
+ parentInstance = $.data(parent[0], "ui-droppable");
+ parentInstance.greedyChild = (c === "isover");
+ }
+ }
+
+ // we just moved into a greedy child
+ if (parentInstance && c === "isover") {
+ parentInstance.isover = false;
+ parentInstance.isout = true;
+ parentInstance._out.call(parentInstance, event);
+ }
+
+ this[c] = true;
+ this[c === "isout" ? "isover" : "isout"] = false;
+ this[c === "isover" ? "_over" : "_out"].call(this, event);
+
+ // we just moved out of a greedy child
+ if (parentInstance && c === "isout") {
+ parentInstance.isout = false;
+ parentInstance.isover = true;
+ parentInstance._over.call(parentInstance, event);
+ }
+ });
+
+ },
+ dragStop: function( draggable, event ) {
+ draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
+ //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
+ if( !draggable.options.refreshPositions ) {
+ $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+ }
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+function num(v) {
+ return parseInt(v, 10) || 0;
+}
+
+function isNumber(value) {
+ return !isNaN(parseInt(value, 10));
+}
+
+$.widget("ui.resizable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "resize",
+ options: {
+ alsoResize: false,
+ animate: false,
+ animateDuration: "slow",
+ animateEasing: "swing",
+ aspectRatio: false,
+ autoHide: false,
+ containment: false,
+ ghost: false,
+ grid: false,
+ handles: "e,s,se",
+ helper: false,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 10,
+ minWidth: 10,
+ // See #7960
+ zIndex: 90,
+
+ // callbacks
+ resize: null,
+ start: null,
+ stop: null
+ },
+ _create: function() {
+
+ var n, i, handle, axis, hname,
+ that = this,
+ o = this.options;
+ this.element.addClass("ui-resizable");
+
+ $.extend(this, {
+ _aspectRatio: !!(o.aspectRatio),
+ aspectRatio: o.aspectRatio,
+ originalElement: this.element,
+ _proportionallyResizeElements: [],
+ _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
+ });
+
+ //Wrap the element if it cannot hold child nodes
+ if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ this.element.wrap(
+ $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
+ position: this.element.css("position"),
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight(),
+ top: this.element.css("top"),
+ left: this.element.css("left")
+ })
+ );
+
+ //Overwrite the original this.element
+ this.element = this.element.parent().data(
+ "ui-resizable", this.element.data("ui-resizable")
+ );
+
+ this.elementIsWrapper = true;
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
+ this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
+
+ //Prevent Safari textarea resize
+ this.originalResizeStyle = this.originalElement.css("resize");
+ this.originalElement.css("resize", "none");
+
+ //Push the actual element to our proportionallyResize internal array
+ this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
+
+ // avoid IE jump (hard set the margin)
+ this.originalElement.css({ margin: this.originalElement.css("margin") });
+
+ // fix handlers offset
+ this._proportionallyResize();
+
+ }
+
+ this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
+ if(this.handles.constructor === String) {
+
+ if ( this.handles === "all") {
+ this.handles = "n,e,s,w,se,sw,ne,nw";
+ }
+
+ n = this.handles.split(",");
+ this.handles = {};
+
+ for(i = 0; i < n.length; i++) {
+
+ handle = $.trim(n[i]);
+ hname = "ui-resizable-"+handle;
+ axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
+
+ // Apply zIndex to all handles - see #7960
+ axis.css({ zIndex: o.zIndex });
+
+ //TODO : What's going on here?
+ if ("se" === handle) {
+ axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
+ }
+
+ //Insert into internal handles object and append to element
+ this.handles[handle] = ".ui-resizable-"+handle;
+ this.element.append(axis);
+ }
+
+ }
+
+ this._renderAxis = function(target) {
+
+ var i, axis, padPos, padWrapper;
+
+ target = target || this.element;
+
+ for(i in this.handles) {
+
+ if(this.handles[i].constructor === String) {
+ this.handles[i] = $(this.handles[i], this.element).show();
+ }
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
+ if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
+
+ axis = $(this.handles[i], this.element);
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ padPos = [ "padding",
+ /ne|nw|n/.test(i) ? "Top" :
+ /se|sw|s/.test(i) ? "Bottom" :
+ /^e$/.test(i) ? "Right" : "Left" ].join("");
+
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+
+ }
+
+ //TODO: What's that good for? There's not anything to be executed left
+ if(!$(this.handles[i]).length) {
+ continue;
+ }
+ }
+ };
+
+ //TODO: make renderAxis a prototype function
+ this._renderAxis(this.element);
+
+ this._handles = $(".ui-resizable-handle", this.element)
+ .disableSelection();
+
+ //Matching axis name
+ this._handles.mouseover(function() {
+ if (!that.resizing) {
+ if (this.className) {
+ axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ }
+ //Axis, default = se
+ that.axis = axis && axis[1] ? axis[1] : "se";
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autoHide) {
+ this._handles.hide();
+ $(this.element)
+ .addClass("ui-resizable-autohide")
+ .mouseenter(function() {
+ if (o.disabled) {
+ return;
+ }
+ $(this).removeClass("ui-resizable-autohide");
+ that._handles.show();
+ })
+ .mouseleave(function(){
+ if (o.disabled) {
+ return;
+ }
+ if (!that.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ that._handles.hide();
+ }
+ });
+ }
+
+ //Initialize the mouse interaction
+ this._mouseInit();
+
+ },
+
+ _destroy: function() {
+
+ this._mouseDestroy();
+
+ var wrapper,
+ _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
+ .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
+ };
+
+ //TODO: Unwrap at same DOM position
+ if (this.elementIsWrapper) {
+ _destroy(this.element);
+ wrapper = this.element;
+ this.originalElement.css({
+ position: wrapper.css("position"),
+ width: wrapper.outerWidth(),
+ height: wrapper.outerHeight(),
+ top: wrapper.css("top"),
+ left: wrapper.css("left")
+ }).insertAfter( wrapper );
+ wrapper.remove();
+ }
+
+ this.originalElement.css("resize", this.originalResizeStyle);
+ _destroy(this.originalElement);
+
+ return this;
+ },
+
+ _mouseCapture: function(event) {
+ var i, handle,
+ capture = false;
+
+ for (i in this.handles) {
+ handle = $(this.handles[i])[0];
+ if (handle === event.target || $.contains(handle, event.target)) {
+ capture = true;
+ }
+ }
+
+ return !this.options.disabled && capture;
+ },
+
+ _mouseStart: function(event) {
+
+ var curleft, curtop, cursor,
+ o = this.options,
+ iniPos = this.element.position(),
+ el = this.element;
+
+ this.resizing = true;
+
+ // bugfix for http://dev.jquery.com/ticket/1749
+ if ( (/absolute/).test( el.css("position") ) ) {
+ el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
+ } else if (el.is(".ui-draggable")) {
+ el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
+ }
+
+ this._renderProxy();
+
+ curleft = num(this.helper.css("left"));
+ curtop = num(this.helper.css("top"));
+
+ if (o.containment) {
+ curleft += $(o.containment).scrollLeft() || 0;
+ curtop += $(o.containment).scrollTop() || 0;
+ }
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
+ this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+ //Aspect Ratio
+ this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
+
+ cursor = $(".ui-resizable-" + this.axis).css("cursor");
+ $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
+
+ el.addClass("ui-resizable-resizing");
+ this._propagate("start", event);
+ return true;
+ },
+
+ _mouseDrag: function(event) {
+
+ //Increase performance, avoid regex
+ var data,
+ el = this.helper, props = {},
+ smp = this.originalMousePosition,
+ a = this.axis,
+ prevTop = this.position.top,
+ prevLeft = this.position.left,
+ prevWidth = this.size.width,
+ prevHeight = this.size.height,
+ dx = (event.pageX-smp.left)||0,
+ dy = (event.pageY-smp.top)||0,
+ trigger = this._change[a];
+
+ if (!trigger) {
+ return false;
+ }
+
+ // Calculate the attrs that will be change
+ data = trigger.apply(this, [event, dx, dy]);
+
+ // Put this in the mouseDrag handler since the user can start pressing shift while resizing
+ this._updateVirtualBoundaries(event.shiftKey);
+ if (this._aspectRatio || event.shiftKey) {
+ data = this._updateRatio(data, event);
+ }
+
+ data = this._respectSize(data, event);
+
+ this._updateCache(data);
+
+ // plugins callbacks need to be called first
+ this._propagate("resize", event);
+
+ if (this.position.top !== prevTop) {
+ props.top = this.position.top + "px";
+ }
+ if (this.position.left !== prevLeft) {
+ props.left = this.position.left + "px";
+ }
+ if (this.size.width !== prevWidth) {
+ props.width = this.size.width + "px";
+ }
+ if (this.size.height !== prevHeight) {
+ props.height = this.size.height + "px";
+ }
+ el.css(props);
+
+ if (!this._helper && this._proportionallyResizeElements.length) {
+ this._proportionallyResize();
+ }
+
+ // Call the user callback if the element was resized
+ if ( ! $.isEmptyObject(props) ) {
+ this._trigger("resize", event, this.ui());
+ }
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ this.resizing = false;
+ var pr, ista, soffseth, soffsetw, s, left, top,
+ o = this.options, that = this;
+
+ if(this._helper) {
+
+ pr = this._proportionallyResizeElements;
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName);
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
+ soffsetw = ista ? 0 : that.sizeDiff.width;
+
+ s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ if (!o.animate) {
+ this.element.css($.extend(s, { top: top, left: left }));
+ }
+
+ that.helper.height(that.size.height);
+ that.helper.width(that.size.width);
+
+ if (this._helper && !o.animate) {
+ this._proportionallyResize();
+ }
+ }
+
+ $("body").css("cursor", "auto");
+
+ this.element.removeClass("ui-resizable-resizing");
+
+ this._propagate("stop", event);
+
+ if (this._helper) {
+ this.helper.remove();
+ }
+
+ return false;
+
+ },
+
+ _updateVirtualBoundaries: function(forceAspectRatio) {
+ var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
+ o = this.options;
+
+ b = {
+ minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
+ maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
+ minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
+ maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
+ };
+
+ if(this._aspectRatio || forceAspectRatio) {
+ // We want to create an enclosing box whose aspect ration is the requested one
+ // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
+ pMinWidth = b.minHeight * this.aspectRatio;
+ pMinHeight = b.minWidth / this.aspectRatio;
+ pMaxWidth = b.maxHeight * this.aspectRatio;
+ pMaxHeight = b.maxWidth / this.aspectRatio;
+
+ if(pMinWidth > b.minWidth) {
+ b.minWidth = pMinWidth;
+ }
+ if(pMinHeight > b.minHeight) {
+ b.minHeight = pMinHeight;
+ }
+ if(pMaxWidth < b.maxWidth) {
+ b.maxWidth = pMaxWidth;
+ }
+ if(pMaxHeight < b.maxHeight) {
+ b.maxHeight = pMaxHeight;
+ }
+ }
+ this._vBoundaries = b;
+ },
+
+ _updateCache: function(data) {
+ this.offset = this.helper.offset();
+ if (isNumber(data.left)) {
+ this.position.left = data.left;
+ }
+ if (isNumber(data.top)) {
+ this.position.top = data.top;
+ }
+ if (isNumber(data.height)) {
+ this.size.height = data.height;
+ }
+ if (isNumber(data.width)) {
+ this.size.width = data.width;
+ }
+ },
+
+ _updateRatio: function( data ) {
+
+ var cpos = this.position,
+ csize = this.size,
+ a = this.axis;
+
+ if (isNumber(data.height)) {
+ data.width = (data.height * this.aspectRatio);
+ } else if (isNumber(data.width)) {
+ data.height = (data.width / this.aspectRatio);
+ }
+
+ if (a === "sw") {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a === "nw") {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function( data ) {
+
+ var o = this._vBoundaries,
+ a = this.axis,
+ ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
+ isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
+ dw = this.originalPosition.left + this.originalSize.width,
+ dh = this.position.top + this.size.height,
+ cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+ if (isminw) {
+ data.width = o.minWidth;
+ }
+ if (isminh) {
+ data.height = o.minHeight;
+ }
+ if (ismaxw) {
+ data.width = o.maxWidth;
+ }
+ if (ismaxh) {
+ data.height = o.maxHeight;
+ }
+
+ if (isminw && cw) {
+ data.left = dw - o.minWidth;
+ }
+ if (ismaxw && cw) {
+ data.left = dw - o.maxWidth;
+ }
+ if (isminh && ch) {
+ data.top = dh - o.minHeight;
+ }
+ if (ismaxh && ch) {
+ data.top = dh - o.maxHeight;
+ }
+
+ // fixing jump error on top/left - bug #2330
+ if (!data.width && !data.height && !data.left && data.top) {
+ data.top = null;
+ } else if (!data.width && !data.height && !data.top && data.left) {
+ data.left = null;
+ }
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+
+ if (!this._proportionallyResizeElements.length) {
+ return;
+ }
+
+ var i, j, borders, paddings, prel,
+ element = this.helper || this.element;
+
+ for ( i=0; i < this._proportionallyResizeElements.length; i++) {
+
+ prel = this._proportionallyResizeElements[i];
+
+ if (!this.borderDif) {
+ this.borderDif = [];
+ borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
+ paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
+
+ for ( j = 0; j < borders.length; j++ ) {
+ this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
+ }
+ }
+
+ prel.css({
+ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
+ width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
+ });
+
+ }
+
+ },
+
+ _renderProxy: function() {
+
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(this._helper) {
+
+ this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
+
+ this.helper.addClass(this._helper).css({
+ width: this.element.outerWidth() - 1,
+ height: this.element.outerHeight() - 1,
+ position: "absolute",
+ left: this.elementOffset.left +"px",
+ top: this.elementOffset.top +"px",
+ zIndex: ++o.zIndex //TODO: Don't modify option
+ });
+
+ this.helper
+ .appendTo("body")
+ .disableSelection();
+
+ } else {
+ this.helper = this.element;
+ }
+
+ },
+
+ _change: {
+ e: function(event, dx) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(event, dx) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(event, dx, dy) {
+ var cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(event, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ sw: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ },
+ ne: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ nw: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ }
+ },
+
+ _propagate: function(n, event) {
+ $.ui.plugin.call(this, n, [event, this.ui()]);
+ (n !== "resize" && this._trigger(n, event, this.ui()));
+ },
+
+ plugins: {},
+
+ ui: function() {
+ return {
+ originalElement: this.originalElement,
+ element: this.element,
+ helper: this.helper,
+ position: this.position,
+ size: this.size,
+ originalSize: this.originalSize,
+ originalPosition: this.originalPosition
+ };
+ }
+
+});
+
+/*
+ * Resizable Extensions
*/
-(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
-_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
-top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
-this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
-nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
-String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
-this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
-if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
-d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
-this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
-this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
-b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
-f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
-b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
-a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
-k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),
-c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
-this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
-a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
-arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,
-{version:"1.8.5"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
-function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
-(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
-false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
-b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
-"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
-f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
-a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
-a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
-e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
-height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
-d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
-;/*
- * jQuery UI Selectable 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Selectables
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.mouse.js
- * jquery.ui.widget.js
- */
-(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),
-selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,
-c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",
-c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=
-this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");
-a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&
-!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d=
-e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.5"})})(jQuery);
-;/*
- * jQuery UI Sortable 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Sortables
+
+$.ui.plugin.add("resizable", "animate", {
+
+ stop: function( event ) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ pr = that._proportionallyResizeElements,
+ ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
+ soffsetw = ista ? 0 : that.sizeDiff.width,
+ style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
+ left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
+ top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
+
+ that.element.animate(
+ $.extend(style, top && left ? { top: top, left: left } : {}), {
+ duration: o.animateDuration,
+ easing: o.animateEasing,
+ step: function() {
+
+ var data = {
+ width: parseInt(that.element.css("width"), 10),
+ height: parseInt(that.element.css("height"), 10),
+ top: parseInt(that.element.css("top"), 10),
+ left: parseInt(that.element.css("left"), 10)
+ };
+
+ if (pr && pr.length) {
+ $(pr[0]).css({ width: data.width, height: data.height });
+ }
+
+ // propagating resize, and updating values for each animation step
+ that._updateCache(data);
+ that._propagate("resize", event);
+
+ }
+ }
+ );
+ }
+
+});
+
+$.ui.plugin.add("resizable", "containment", {
+
+ start: function() {
+ var element, p, co, ch, cw, width, height,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ el = that.element,
+ oc = o.containment,
+ ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
+
+ if (!ce) {
+ return;
+ }
+
+ that.containerElement = $(ce);
+
+ if (/document/.test(oc) || oc === document) {
+ that.containerOffset = { left: 0, top: 0 };
+ that.containerPosition = { left: 0, top: 0 };
+
+ that.parentData = {
+ element: $(document), left: 0, top: 0,
+ width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else {
+ element = $(ce);
+ p = [];
+ $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
+
+ that.containerOffset = element.offset();
+ that.containerPosition = element.position();
+ that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
+
+ co = that.containerOffset;
+ ch = that.containerSize.height;
+ cw = that.containerSize.width;
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
+ height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ that.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function( event ) {
+ var woset, hoset, isParent, isOffsetRelative,
+ that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset, cp = that.position,
+ pRatio = that._aspectRatio || event.shiftKey,
+ cop = { top:0, left:0 }, ce = that.containerElement;
+
+ if (ce[0] !== document && (/static/).test(ce.css("position"))) {
+ cop = co;
+ }
+
+ if (cp.left < (that._helper ? co.left : 0)) {
+ that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ that.position.left = o.helper ? co.left : 0;
+ }
+
+ if (cp.top < (that._helper ? co.top : 0)) {
+ that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ that.position.top = that._helper ? co.top : 0;
+ }
+
+ that.offset.left = that.parentData.left+that.position.left;
+ that.offset.top = that.parentData.top+that.position.top;
+
+ woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
+ hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
+
+ isParent = that.containerElement.get(0) === that.element.parent().get(0);
+ isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
+
+ if(isParent && isOffsetRelative) {
+ woset -= that.parentData.left;
+ }
+
+ if (woset + that.size.width >= that.parentData.width) {
+ that.size.width = that.parentData.width - woset;
+ if (pRatio) {
+ that.size.height = that.size.width / that.aspectRatio;
+ }
+ }
+
+ if (hoset + that.size.height >= that.parentData.height) {
+ that.size.height = that.parentData.height - hoset;
+ if (pRatio) {
+ that.size.width = that.size.height * that.aspectRatio;
+ }
+ }
+ },
+
+ stop: function(){
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ co = that.containerOffset,
+ cop = that.containerPosition,
+ ce = that.containerElement,
+ helper = $(that.helper),
+ ho = helper.offset(),
+ w = helper.outerWidth() - that.sizeDiff.width,
+ h = helper.outerHeight() - that.sizeDiff.height;
+
+ if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+ }
+
+ }
+});
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+ start: function () {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ _store = function (exp) {
+ $(exp).each(function() {
+ var el = $(this);
+ el.data("ui-resizable-alsoresize", {
+ width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
+ left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
+ });
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
+ if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
+ else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
+ }else{
+ _store(o.alsoResize);
+ }
+ },
+
+ resize: function (event, ui) {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ os = that.originalSize,
+ op = that.originalPosition,
+ delta = {
+ height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
+ top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
+ },
+
+ _alsoResize = function (exp, c) {
+ $(exp).each(function() {
+ var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
+ css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
+
+ $.each(css, function (i, prop) {
+ var sum = (start[prop]||0) + (delta[prop]||0);
+ if (sum && sum >= 0) {
+ style[prop] = sum || null;
+ }
+ });
+
+ el.css(style);
+ });
+ };
+
+ if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
+ $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
+ }else{
+ _alsoResize(o.alsoResize);
+ }
+ },
+
+ stop: function () {
+ $(this).removeData("resizable-alsoresize");
+ }
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+ start: function() {
+
+ var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
+
+ that.ghost = that.originalElement.clone();
+ that.ghost
+ .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
+ .addClass("ui-resizable-ghost")
+ .addClass(typeof o.ghost === "string" ? o.ghost : "");
+
+ that.ghost.appendTo(that.helper);
+
+ },
+
+ resize: function(){
+ var that = $(this).data("ui-resizable");
+ if (that.ghost) {
+ that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
+ }
+ },
+
+ stop: function() {
+ var that = $(this).data("ui-resizable");
+ if (that.ghost && that.helper) {
+ that.helper.get(0).removeChild(that.ghost.get(0));
+ }
+ }
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+ resize: function() {
+ var that = $(this).data("ui-resizable"),
+ o = that.options,
+ cs = that.size,
+ os = that.originalSize,
+ op = that.originalPosition,
+ a = that.axis,
+ grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
+ gridX = (grid[0]||1),
+ gridY = (grid[1]||1),
+ ox = Math.round((cs.width - os.width) / gridX) * gridX,
+ oy = Math.round((cs.height - os.height) / gridY) * gridY,
+ newWidth = os.width + ox,
+ newHeight = os.height + oy,
+ isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
+ isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
+ isMinWidth = o.minWidth && (o.minWidth > newWidth),
+ isMinHeight = o.minHeight && (o.minHeight > newHeight);
+
+ o.grid = grid;
+
+ if (isMinWidth) {
+ newWidth = newWidth + gridX;
+ }
+ if (isMinHeight) {
+ newHeight = newHeight + gridY;
+ }
+ if (isMaxWidth) {
+ newWidth = newWidth - gridX;
+ }
+ if (isMaxHeight) {
+ newHeight = newHeight - gridY;
+ }
+
+ if (/^(se|s|e)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ } else if (/^(ne)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ } else if (/^(sw)$/.test(a)) {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.left = op.left - ox;
+ } else {
+ that.size.width = newWidth;
+ that.size.height = newHeight;
+ that.position.top = op.top - oy;
+ that.position.left = op.left - ox;
+ }
+ }
+
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget("ui.selectable", $.ui.mouse, {
+ version: "1.10.3",
+ options: {
+ appendTo: "body",
+ autoRefresh: true,
+ distance: 0,
+ filter: "*",
+ tolerance: "touch",
+
+ // callbacks
+ selected: null,
+ selecting: null,
+ start: null,
+ stop: null,
+ unselected: null,
+ unselecting: null
+ },
+ _create: function() {
+ var selectees,
+ that = this;
+
+ this.element.addClass("ui-selectable");
+
+ this.dragged = false;
+
+ // cache selectee children based on filter
+ this.refresh = function() {
+ selectees = $(that.options.filter, that.element[0]);
+ selectees.addClass("ui-selectee");
+ selectees.each(function() {
+ var $this = $(this),
+ pos = $this.offset();
+ $.data(this, "selectable-item", {
+ element: this,
+ $element: $this,
+ left: pos.left,
+ top: pos.top,
+ right: pos.left + $this.outerWidth(),
+ bottom: pos.top + $this.outerHeight(),
+ startselected: false,
+ selected: $this.hasClass("ui-selected"),
+ selecting: $this.hasClass("ui-selecting"),
+ unselecting: $this.hasClass("ui-unselecting")
+ });
+ });
+ };
+ this.refresh();
+
+ this.selectees = selectees.addClass("ui-selectee");
+
+ this._mouseInit();
+
+ this.helper = $("<div class='ui-selectable-helper'></div>");
+ },
+
+ _destroy: function() {
+ this.selectees
+ .removeClass("ui-selectee")
+ .removeData("selectable-item");
+ this.element
+ .removeClass("ui-selectable ui-selectable-disabled");
+ this._mouseDestroy();
+ },
+
+ _mouseStart: function(event) {
+ var that = this,
+ options = this.options;
+
+ this.opos = [event.pageX, event.pageY];
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ this.selectees = $(options.filter, this.element[0]);
+
+ this._trigger("start", event);
+
+ $(options.appendTo).append(this.helper);
+ // position helper (lasso)
+ this.helper.css({
+ "left": event.pageX,
+ "top": event.pageY,
+ "width": 0,
+ "height": 0
+ });
+
+ if (options.autoRefresh) {
+ this.refresh();
+ }
+
+ this.selectees.filter(".ui-selected").each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.startselected = true;
+ if (!event.metaKey && !event.ctrlKey) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ });
+
+ $(event.target).parents().addBack().each(function() {
+ var doSelect,
+ selectee = $.data(this, "selectable-item");
+ if (selectee) {
+ doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
+ selectee.$element
+ .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
+ .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
+ selectee.unselecting = !doSelect;
+ selectee.selecting = doSelect;
+ selectee.selected = doSelect;
+ // selectable (UN)SELECTING callback
+ if (doSelect) {
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ } else {
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ return false;
+ }
+ });
+
+ },
+
+ _mouseDrag: function(event) {
+
+ this.dragged = true;
+
+ if (this.options.disabled) {
+ return;
+ }
+
+ var tmp,
+ that = this,
+ options = this.options,
+ x1 = this.opos[0],
+ y1 = this.opos[1],
+ x2 = event.pageX,
+ y2 = event.pageY;
+
+ if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
+ if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
+ this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
+
+ this.selectees.each(function() {
+ var selectee = $.data(this, "selectable-item"),
+ hit = false;
+
+ //prevent helper from being selected if appendTo: selectable
+ if (!selectee || selectee.element === that.element[0]) {
+ return;
+ }
+
+ if (options.tolerance === "touch") {
+ hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
+ } else if (options.tolerance === "fit") {
+ hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
+ }
+
+ if (hit) {
+ // SELECT
+ if (selectee.selected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+ }
+ if (selectee.unselecting) {
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ }
+ if (!selectee.selecting) {
+ selectee.$element.addClass("ui-selecting");
+ selectee.selecting = true;
+ // selectable SELECTING callback
+ that._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ }
+ } else {
+ // UNSELECT
+ if (selectee.selecting) {
+ if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ selectee.$element.addClass("ui-selected");
+ selectee.selected = true;
+ } else {
+ selectee.$element.removeClass("ui-selecting");
+ selectee.selecting = false;
+ if (selectee.startselected) {
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ }
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ if (selectee.selected) {
+ if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
+ selectee.$element.removeClass("ui-selected");
+ selectee.selected = false;
+
+ selectee.$element.addClass("ui-unselecting");
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ that._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ }
+ });
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+ var that = this;
+
+ this.dragged = false;
+
+ $(".ui-unselecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-unselecting");
+ selectee.unselecting = false;
+ selectee.startselected = false;
+ that._trigger("unselected", event, {
+ unselected: selectee.element
+ });
+ });
+ $(".ui-selecting", this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
+ selectee.selecting = false;
+ selectee.selected = true;
+ selectee.startselected = true;
+ that._trigger("selected", event, {
+ selected: selectee.element
+ });
+ });
+ this._trigger("stop", event);
+
+ this.helper.remove();
+
+ return false;
+ }
+
+});
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+/*jshint loopfunc: true */
+
+function isOverAxis( x, reference, size ) {
+ return ( x > reference ) && ( x < ( reference + size ) );
+}
+
+function isFloating(item) {
+ return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+}
+
+$.widget("ui.sortable", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "sort",
+ ready: false,
+ options: {
+ appendTo: "parent",
+ axis: false,
+ connectWith: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ dropOnEmpty: true,
+ forcePlaceholderSize: false,
+ forceHelperSize: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ items: "> *",
+ opacity: false,
+ placeholder: false,
+ revert: false,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ tolerance: "intersect",
+ zIndex: 1000,
+
+ // callbacks
+ activate: null,
+ beforeStop: null,
+ change: null,
+ deactivate: null,
+ out: null,
+ over: null,
+ receive: null,
+ remove: null,
+ sort: null,
+ start: null,
+ stop: null,
+ update: null
+ },
+ _create: function() {
+
+ var o = this.options;
+ this.containerCache = {};
+ this.element.addClass("ui-sortable");
+
+ //Get the items
+ this.refresh();
+
+ //Let's determine if the items are being displayed horizontally
+ this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
+
+ //Let's determine the parent's offset
+ this.offset = this.element.offset();
+
+ //Initialize mouse events for interaction
+ this._mouseInit();
+
+ //We're ready to go
+ this.ready = true;
+
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass("ui-sortable ui-sortable-disabled");
+ this._mouseDestroy();
+
+ for ( var i = this.items.length - 1; i >= 0; i-- ) {
+ this.items[i].item.removeData(this.widgetName + "-item");
+ }
+
+ return this;
+ },
+
+ _setOption: function(key, value){
+ if ( key === "disabled" ) {
+ this.options[ key ] = value;
+
+ this.widget().toggleClass( "ui-sortable-disabled", !!value );
+ } else {
+ // Don't call widget base _setOption for disable as it adds ui-state-disabled class
+ $.Widget.prototype._setOption.apply(this, arguments);
+ }
+ },
+
+ _mouseCapture: function(event, overrideHandle) {
+ var currentItem = null,
+ validHandle = false,
+ that = this;
+
+ if (this.reverting) {
+ return false;
+ }
+
+ if(this.options.disabled || this.options.type === "static") {
+ return false;
+ }
+
+ //We have to refresh the items data once first
+ this._refreshItems(event);
+
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
+ $(event.target).parents().each(function() {
+ if($.data(this, that.widgetName + "-item") === that) {
+ currentItem = $(this);
+ return false;
+ }
+ });
+ if($.data(event.target, that.widgetName + "-item") === that) {
+ currentItem = $(event.target);
+ }
+
+ if(!currentItem) {
+ return false;
+ }
+ if(this.options.handle && !overrideHandle) {
+ $(this.options.handle, currentItem).find("*").addBack().each(function() {
+ if(this === event.target) {
+ validHandle = true;
+ }
+ });
+ if(!validHandle) {
+ return false;
+ }
+ }
+
+ this.currentItem = currentItem;
+ this._removeCurrentsFromItems();
+ return true;
+
+ },
+
+ _mouseStart: function(event, overrideHandle, noActivation) {
+
+ var i, body,
+ o = this.options;
+
+ this.currentContainer = this;
+
+ //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+ this.refreshPositions();
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Get the next scrolling parent
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.currentItem.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ // Only after we got the offset, we can change the helper's position to absolute
+ // TODO: Still need to figure out a way to make relative sorting possible
+ this.helper.css("position", "absolute");
+ this.cssPosition = this.helper.css("position");
+
+ //Generate the original position
+ this.originalPosition = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Cache the former DOM position
+ this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+ //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.currentItem.hide();
+ }
+
+ //Create the placeholder
+ this._createPlaceholder();
+
+ //Set a containment if given in the options
+ if(o.containment) {
+ this._setContainment();
+ }
+
+ if( o.cursor && o.cursor !== "auto" ) { // cursor option
+ body = this.document.find( "body" );
+
+ // support: IE
+ this.storedCursor = body.css( "cursor" );
+ body.css( "cursor", o.cursor );
+
+ this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
+ }
+
+ if(o.opacity) { // opacity option
+ if (this.helper.css("opacity")) {
+ this._storedOpacity = this.helper.css("opacity");
+ }
+ this.helper.css("opacity", o.opacity);
+ }
+
+ if(o.zIndex) { // zIndex option
+ if (this.helper.css("zIndex")) {
+ this._storedZIndex = this.helper.css("zIndex");
+ }
+ this.helper.css("zIndex", o.zIndex);
+ }
+
+ //Prepare scrolling
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+ this.overflowOffset = this.scrollParent.offset();
+ }
+
+ //Call callbacks
+ this._trigger("start", event, this._uiHash());
+
+ //Recache the helper size
+ if(!this._preserveHelperProportions) {
+ this._cacheHelperProportions();
+ }
+
+
+ //Post "activate" events to possible containers
+ if( !noActivation ) {
+ for ( i = this.containers.length - 1; i >= 0; i-- ) {
+ this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+ }
+ }
+
+ //Prepare possible droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.current = this;
+ }
+
+ if ($.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+ this.dragging = true;
+
+ this.helper.addClass("ui-sortable-helper");
+ this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+ return true;
+
+ },
+
+ _mouseDrag: function(event) {
+ var i, item, itemElement, intersection,
+ o = this.options,
+ scrolled = false;
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ if (!this.lastPositionAbs) {
+ this.lastPositionAbs = this.positionAbs;
+ }
+
+ //Do scrolling
+ if(this.options.scroll) {
+ if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+ } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+ } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+
+ } else {
+
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+ }
+
+ //Regenerate the absolute position used for position checks
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Set the helper position
+ if(!this.options.axis || this.options.axis !== "y") {
+ this.helper[0].style.left = this.position.left+"px";
+ }
+ if(!this.options.axis || this.options.axis !== "x") {
+ this.helper[0].style.top = this.position.top+"px";
+ }
+
+ //Rearrange
+ for (i = this.items.length - 1; i >= 0; i--) {
+
+ //Cache variables and intersection, continue if no intersection
+ item = this.items[i];
+ itemElement = item.item[0];
+ intersection = this._intersectsWithPointer(item);
+ if (!intersection) {
+ continue;
+ }
+
+ // Only put the placeholder inside the current Container, skip all
+ // items form other containers. This works because when moving
+ // an item from one container to another the
+ // currentContainer is switched before the placeholder is moved.
+ //
+ // Without this moving items in "sub-sortables" can cause the placeholder to jitter
+ // beetween the outer and inner container.
+ if (item.instance !== this.currentContainer) {
+ continue;
+ }
+
+ // cannot intersect with itself
+ // no useless actions that have been done before
+ // no action if the item moved is the parent of the item checked
+ if (itemElement !== this.currentItem[0] &&
+ this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+ !$.contains(this.placeholder[0], itemElement) &&
+ (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
+ ) {
+
+ this.direction = intersection === 1 ? "down" : "up";
+
+ if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+ this._rearrange(event, item);
+ } else {
+ break;
+ }
+
+ this._trigger("change", event, this._uiHash());
+ break;
+ }
+ }
+
+ //Post events to containers
+ this._contactContainers(event);
+
+ //Interconnect with droppables
+ if($.ui.ddmanager) {
+ $.ui.ddmanager.drag(this, event);
+ }
+
+ //Call callbacks
+ this._trigger("sort", event, this._uiHash());
+
+ this.lastPositionAbs = this.positionAbs;
+ return false;
+
+ },
+
+ _mouseStop: function(event, noPropagation) {
+
+ if(!event) {
+ return;
+ }
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour) {
+ $.ui.ddmanager.drop(this, event);
+ }
+
+ if(this.options.revert) {
+ var that = this,
+ cur = this.placeholder.offset(),
+ axis = this.options.axis,
+ animation = {};
+
+ if ( !axis || axis === "x" ) {
+ animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
+ }
+ if ( !axis || axis === "y" ) {
+ animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
+ }
+ this.reverting = true;
+ $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
+ that._clear(event);
+ });
+ } else {
+ this._clear(event, noPropagation);
+ }
+
+ return false;
+
+ },
+
+ cancel: function() {
+
+ if(this.dragging) {
+
+ this._mouseUp({ target: null });
+
+ if(this.options.helper === "original") {
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ //Post deactivating events to containers
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ this.containers[i]._trigger("deactivate", null, this._uiHash(this));
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", null, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ if (this.placeholder) {
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ if(this.placeholder[0].parentNode) {
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+ }
+ if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+ this.helper.remove();
+ }
+
+ $.extend(this, {
+ helper: null,
+ dragging: false,
+ reverting: false,
+ _noFinalSort: null
+ });
+
+ if(this.domPosition.prev) {
+ $(this.domPosition.prev).after(this.currentItem);
+ } else {
+ $(this.domPosition.parent).prepend(this.currentItem);
+ }
+ }
+
+ return this;
+
+ },
+
+ serialize: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ str = [];
+ o = o || {};
+
+ $(items).each(function() {
+ var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+ if (res) {
+ str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+ }
+ });
+
+ if(!str.length && o.key) {
+ str.push(o.key + "=");
+ }
+
+ return str.join("&");
+
+ },
+
+ toArray: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected),
+ ret = [];
+
+ o = o || {};
+
+ items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
+ return ret;
+
+ },
+
+ /* Be careful with the following core functions */
+ _intersectsWith: function(item) {
+
+ var x1 = this.positionAbs.left,
+ x2 = x1 + this.helperProportions.width,
+ y1 = this.positionAbs.top,
+ y2 = y1 + this.helperProportions.height,
+ l = item.left,
+ r = l + item.width,
+ t = item.top,
+ b = t + item.height,
+ dyClick = this.offset.click.top,
+ dxClick = this.offset.click.left,
+ isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+ isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+ isOverElement = isOverElementHeight && isOverElementWidth;
+
+ if ( this.options.tolerance === "pointer" ||
+ this.options.forcePointerForContainers ||
+ (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
+ ) {
+ return isOverElement;
+ } else {
+
+ return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+ x2 - (this.helperProportions.width / 2) < r && // Left Half
+ t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+ y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+ }
+ },
+
+ _intersectsWithPointer: function(item) {
+
+ var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+ isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+ isOverElement = isOverElementHeight && isOverElementWidth,
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (!isOverElement) {
+ return false;
+ }
+
+ return this.floating ?
+ ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+ : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
+
+ },
+
+ _intersectsWithSides: function(item) {
+
+ var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+ isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (this.floating && horizontalDirection) {
+ return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
+ } else {
+ return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
+ }
+
+ },
+
+ _getDragVerticalDirection: function() {
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
+ return delta !== 0 && (delta > 0 ? "down" : "up");
+ },
+
+ _getDragHorizontalDirection: function() {
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
+ return delta !== 0 && (delta > 0 ? "right" : "left");
+ },
+
+ refresh: function(event) {
+ this._refreshItems(event);
+ this.refreshPositions();
+ return this;
+ },
+
+ _connectWith: function() {
+ var options = this.options;
+ return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
+ },
+
+ _getItemsAsjQuery: function(connected) {
+
+ var i, j, cur, inst,
+ items = [],
+ queries = [],
+ connectWith = this._connectWith();
+
+ if(connectWith && connected) {
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for ( j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
+ }
+ }
+ }
+ }
+
+ queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+ for (i = queries.length - 1; i >= 0; i--){
+ queries[i][0].each(function() {
+ items.push(this);
+ });
+ }
+
+ return $(items);
+
+ },
+
+ _removeCurrentsFromItems: function() {
+
+ var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+ this.items = $.grep(this.items, function (item) {
+ for (var j=0; j < list.length; j++) {
+ if(list[j] === item.item[0]) {
+ return false;
+ }
+ }
+ return true;
+ });
+
+ },
+
+ _refreshItems: function(event) {
+
+ this.items = [];
+ this.containers = [this];
+
+ var i, j, cur, inst, targetData, _queries, item, queriesLength,
+ items = this.items,
+ queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+ connectWith = this._connectWith();
+
+ if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+ for (i = connectWith.length - 1; i >= 0; i--){
+ cur = $(connectWith[i]);
+ for (j = cur.length - 1; j >= 0; j--){
+ inst = $.data(cur[j], this.widgetFullName);
+ if(inst && inst !== this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+ this.containers.push(inst);
+ }
+ }
+ }
+ }
+
+ for (i = queries.length - 1; i >= 0; i--) {
+ targetData = queries[i][1];
+ _queries = queries[i][0];
+
+ for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+ item = $(_queries[j]);
+
+ item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
+
+ items.push({
+ item: item,
+ instance: targetData,
+ width: 0, height: 0,
+ left: 0, top: 0
+ });
+ }
+ }
+
+ },
+
+ refreshPositions: function(fast) {
+
+ //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+ if(this.offsetParent && this.helper) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ var i, item, t, p;
+
+ for (i = this.items.length - 1; i >= 0; i--){
+ item = this.items[i];
+
+ //We ignore calculating positions of all connected containers when we're not over them
+ if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
+ continue;
+ }
+
+ t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+ if (!fast) {
+ item.width = t.outerWidth();
+ item.height = t.outerHeight();
+ }
+
+ p = t.offset();
+ item.left = p.left;
+ item.top = p.top;
+ }
+
+ if(this.options.custom && this.options.custom.refreshContainers) {
+ this.options.custom.refreshContainers.call(this);
+ } else {
+ for (i = this.containers.length - 1; i >= 0; i--){
+ p = this.containers[i].element.offset();
+ this.containers[i].containerCache.left = p.left;
+ this.containers[i].containerCache.top = p.top;
+ this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+ this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+ }
+ }
+
+ return this;
+ },
+
+ _createPlaceholder: function(that) {
+ that = that || this;
+ var className,
+ o = that.options;
+
+ if(!o.placeholder || o.placeholder.constructor === String) {
+ className = o.placeholder;
+ o.placeholder = {
+ element: function() {
+
+ var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+ element = $( "<" + nodeName + ">", that.document[0] )
+ .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+ .removeClass("ui-sortable-helper");
+
+ if ( nodeName === "tr" ) {
+ that.currentItem.children().each(function() {
+ $( "<td> </td>", that.document[0] )
+ .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+ .appendTo( element );
+ });
+ } else if ( nodeName === "img" ) {
+ element.attr( "src", that.currentItem.attr( "src" ) );
+ }
+
+ if ( !className ) {
+ element.css( "visibility", "hidden" );
+ }
+
+ return element;
+ },
+ update: function(container, p) {
+
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+ if(className && !o.forcePlaceholderSize) {
+ return;
+ }
+
+ //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+ if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+ if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
+ }
+ };
+ }
+
+ //Create the placeholder
+ that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
+
+ //Append it after the actual current item
+ that.currentItem.after(that.placeholder);
+
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+ o.placeholder.update(that, that.placeholder);
+
+ },
+
+ _contactContainers: function(event) {
+ var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
+ innermostContainer = null,
+ innermostIndex = null;
+
+ // get innermost container that intersects with item
+ for (i = this.containers.length - 1; i >= 0; i--) {
+
+ // never consider a container that's located within the item itself
+ if($.contains(this.currentItem[0], this.containers[i].element[0])) {
+ continue;
+ }
+
+ if(this._intersectsWith(this.containers[i].containerCache)) {
+
+ // if we've already found a container and it's more "inner" than this, then continue
+ if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
+ continue;
+ }
+
+ innermostContainer = this.containers[i];
+ innermostIndex = i;
+
+ } else {
+ // container doesn't intersect. trigger "out" event if necessary
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", event, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ // if no intersecting containers found, return
+ if(!innermostContainer) {
+ return;
+ }
+
+ // move the item into the container if it's not there already
+ if(this.containers.length === 1) {
+ if (!this.containers[innermostIndex].containerCache.over) {
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+ } else {
+
+ //When entering a new container, we will find the item with the least distance and append our item near it
+ dist = 10000;
+ itemWithLeastDistance = null;
+ floating = innermostContainer.floating || isFloating(this.currentItem);
+ posProperty = floating ? "left" : "top";
+ sizeProperty = floating ? "width" : "height";
+ base = this.positionAbs[posProperty] + this.offset.click[posProperty];
+ for (j = this.items.length - 1; j >= 0; j--) {
+ if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+ continue;
+ }
+ if(this.items[j].item[0] === this.currentItem[0]) {
+ continue;
+ }
+ if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
+ continue;
+ }
+ cur = this.items[j].item.offset()[posProperty];
+ nearBottom = false;
+ if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
+ nearBottom = true;
+ cur += this.items[j][sizeProperty];
+ }
+
+ if(Math.abs(cur - base) < dist) {
+ dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
+ this.direction = nearBottom ? "up": "down";
+ }
+ }
+
+ //Check if dropOnEmpty is enabled
+ if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
+ return;
+ }
+
+ if(this.currentContainer === this.containers[innermostIndex]) {
+ return;
+ }
+
+ itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+ this._trigger("change", event, this._uiHash());
+ this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+ this.currentContainer = this.containers[innermostIndex];
+
+ //Update the placeholder
+ this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options,
+ helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+ //Add the helper to the DOM if that didn't happen already
+ if(!helper.parents("body").length) {
+ $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+ }
+
+ if(helper[0] === this.currentItem[0]) {
+ this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+ }
+
+ if(!helper[0].style.width || o.forceHelperSize) {
+ helper.width(this.currentItem.width());
+ }
+ if(!helper[0].style.height || o.forceHelperSize) {
+ helper.height(this.currentItem.height());
+ }
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj === "string") {
+ obj = obj.split(" ");
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ("left" in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ("right" in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ("top" in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ("bottom" in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ // This needs to be actually done for all browsers, since pageX/pageY includes this information
+ // with an ugly IE fix
+ if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+ po = { top: 0, left: 0 };
+ }
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition === "relative") {
+ var p = this.currentItem.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+ top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var ce, co, over,
+ o = this.options;
+ if(o.containment === "parent") {
+ o.containment = this.helper[0].parentNode;
+ }
+ if(o.containment === "document" || o.containment === "window") {
+ this.containment = [
+ 0 - this.offset.relative.left - this.offset.parent.left,
+ 0 - this.offset.relative.top - this.offset.parent.top,
+ $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
+ ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ if(!(/^(document|window|parent)$/).test(o.containment)) {
+ ce = $(o.containment)[0];
+ co = $(o.containment).offset();
+ over = ($(ce).css("overflow") !== "hidden");
+
+ this.containment = [
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+ co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+ co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) {
+ pos = this.position;
+ }
+ var mod = d === "absolute" ? 1 : -1,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+ scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top + // The absolute mouse position
+ this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left + // The absolute mouse position
+ this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var top, left,
+ o = this.options,
+ pageX = event.pageX,
+ pageY = event.pageY,
+ scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ // This is another very weird special case that only happens for relative elements:
+ // 1. If the css position is relative
+ // 2. and the scroll parent is the document or similar to the offset parent
+ // we have to refresh the relative offset during the scroll so there are no jumps
+ if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
+ this.offset.relative = this._getRelativeOffset();
+ }
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+ if(this.containment) {
+ if(event.pageX - this.offset.click.left < this.containment[0]) {
+ pageX = this.containment[0] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top < this.containment[1]) {
+ pageY = this.containment[1] + this.offset.click.top;
+ }
+ if(event.pageX - this.offset.click.left > this.containment[2]) {
+ pageX = this.containment[2] + this.offset.click.left;
+ }
+ if(event.pageY - this.offset.click.top > this.containment[3]) {
+ pageY = this.containment[3] + this.offset.click.top;
+ }
+ }
+
+ if(o.grid) {
+ top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+ pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+ pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY - // The absolute mouse position
+ this.offset.click.top - // Click offset (relative to the element)
+ this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX - // The absolute mouse position
+ this.offset.click.left - // Click offset (relative to the element)
+ this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
+ this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
+ ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _rearrange: function(event, i, a, hardRefresh) {
+
+ a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
+
+ //Various things done here to improve the performance:
+ // 1. we create a setTimeout, that calls refreshPositions
+ // 2. on the instance, we have a counter variable, that get's higher after every append
+ // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+ // 4. this lets only the last addition to the timeout stack through
+ this.counter = this.counter ? ++this.counter : 1;
+ var counter = this.counter;
+
+ this._delay(function() {
+ if(counter === this.counter) {
+ this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+ }
+ });
+
+ },
+
+ _clear: function(event, noPropagation) {
+
+ this.reverting = false;
+ // We delay all events that have to be triggered to after the point where the placeholder has been removed and
+ // everything else normalized again
+ var i,
+ delayedTriggers = [];
+
+ // We first have to update the dom position of the actual currentItem
+ // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+ if(!this._noFinalSort && this.currentItem.parent().length) {
+ this.placeholder.before(this.currentItem);
+ }
+ this._noFinalSort = null;
+
+ if(this.helper[0] === this.currentItem[0]) {
+ for(i in this._storedCSS) {
+ if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+ this._storedCSS[i] = "";
+ }
+ }
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ if(this.fromOutside && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+ }
+ if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+ }
+
+ // Check if the items Container has Changed and trigger appropriate
+ // events.
+ if (this !== this.currentContainer) {
+ if(!noPropagation) {
+ delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
+ }
+ }
+
+
+ //Post events to containers
+ for (i = this.containers.length - 1; i >= 0; i--){
+ if(!noPropagation) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ }
+ if(this.containers[i].containerCache.over) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ //Do what was originally in plugins
+ if ( this.storedCursor ) {
+ this.document.find( "body" ).css( "cursor", this.storedCursor );
+ this.storedStylesheet.remove();
+ }
+ if(this._storedOpacity) {
+ this.helper.css("opacity", this._storedOpacity);
+ }
+ if(this._storedZIndex) {
+ this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+ }
+
+ this.dragging = false;
+ if(this.cancelHelperRemoval) {
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return false;
+ }
+
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ }
+
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+ if(this.helper[0] !== this.currentItem[0]) {
+ this.helper.remove();
+ }
+ this.helper = null;
+
+ if(!noPropagation) {
+ for (i=0; i < delayedTriggers.length; i++) {
+ delayedTriggers[i].call(this, event);
+ } //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return true;
+
+ },
+
+ _trigger: function() {
+ if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+ this.cancel();
+ }
+ },
+
+ _uiHash: function(_inst) {
+ var inst = _inst || this;
+ return {
+ helper: inst.helper,
+ placeholder: inst.placeholder || $([]),
+ position: inst.position,
+ originalPosition: inst.originalPosition,
+ offset: inst.positionAbs,
+ item: inst.currentItem,
+ sender: _inst ? _inst.element : null
+ };
+ }
+
+});
+
+})(jQuery);
+
+(function($, undefined) {
+
+var dataSpace = "ui-effects-";
+
+$.effects = {
+ effect: {}
+};
+
+/*!
+ * jQuery Color Animations v2.1.2
+ * https://github.com/jquery/jquery-color
*
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.mouse.js
- * jquery.ui.widget.js
- */
-(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
-this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,
-arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
-c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
-{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
-if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
-a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
-if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+
-this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+
-b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+
-"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
-c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
-document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp();this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",
-null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):
-d(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||
-"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+
-this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?
-2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},
-_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=
-this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=
-this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");
-if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=
-0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=
-this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},
-update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=
-null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));
-this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,
-null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||
-d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a==
-"string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition==
-"absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition==
-"relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},
-_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-
-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),
-10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?
-this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=
-this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])f=this.containment[0]+
-this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?
-g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():
-e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==
-f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",
-f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",
-g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=
-0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
-this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});
-d.extend(d.ui.sortable,{version:"1.8.5"})})(jQuery);
-;/*
- * jQuery UI Accordion 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Accordion
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- */
-(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
-a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
-if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var f=d.closest(".ui-accordion-header");a.active=f.length?f:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",function(g){return a._keydown(g)}).next().attr("role",
-"tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(g){a._clickHandler.call(a,g,this);g.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);
-this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex");
-this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
-b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,f=this.headers.index(a.target),g=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:g=this.headers[(f+1)%d];break;case b.LEFT:case b.UP:g=this.headers[(f-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
-a.preventDefault()}if(g){c(a.target).attr("tabIndex",-1);c(g).attr("tabIndex",0);g.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
-c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
-if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);
-a.next().addClass("ui-accordion-content-active")}h=a.next();f=this.active.next();g={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):h,oldContent:f};d=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(h,f,g,b,d)}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
-this.active.next().addClass("ui-accordion-content-active");var f=this.active.next(),g={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:f},h=this.active=c([]);this._toggle(h,f,g)}},_toggle:function(a,b,d,f,g){var h=this,e=h.options;h.toShow=a;h.toHide=b;h.data=d;var j=function(){if(h)return h._completed.apply(h,arguments)};h._trigger("changestart",null,h.data);h.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&f?{toShow:c([]),toHide:b,complete:j,
-down:g,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:g,autoHeight:e.autoHeight||e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;f=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!f[k]&&!c.easing[k])k="slide";f[k]||(f[k]=function(l){this.slide(l,{easing:k,duration:i||700})});
-f[k](d)}else{if(e.collapsible&&f)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.5",animations:{slide:function(a,
-b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),f=0,g={},h={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){h[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);g[i]={value:j[1],
-unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(h,{step:function(j,i){if(i.prop=="height")f=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=f*g[i.prop].value+g[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide",
-paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
-;/*
- * jQuery UI Autocomplete 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Autocomplete
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- * jquery.ui.position.js
- */
-(function(e){e.widget("ui.autocomplete",{options:{appendTo:"body",delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},_create:function(){var a=this,b=this.element[0].ownerDocument;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!a.options.disabled){var d=e.ui.keyCode;switch(c.keyCode){case d.PAGE_UP:a._move("previousPage",
-c);break;case d.PAGE_DOWN:a._move("nextPage",c);break;case d.UP:a._move("previous",c);c.preventDefault();break;case d.DOWN:a._move("next",c);c.preventDefault();break;case d.ENTER:case d.NUMPAD_ENTER:a.menu.element.is(":visible")&&c.preventDefault();case d.TAB:if(!a.menu.active)return;a.menu.select(c);break;case d.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);
-break}}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=e("<ul></ul>").addClass("ui-autocomplete").appendTo(e(this.options.appendTo||"body",b)[0]).mousedown(function(c){var d=a.menu.element[0];
-c.target===d&&setTimeout(function(){e(document).one("mousedown",function(f){f.target!==a.element[0]&&f.target!==d&&!e.ui.contains(d,f.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,d){d=d.item.data("item.autocomplete");false!==a._trigger("focus",null,{item:d})&&/^key/.test(c.originalEvent.type)&&a.element.val(d.value)},selected:function(c,d){d=d.item.data("item.autocomplete");var f=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();
-a.previous=f}if(false!==a._trigger("select",c,{item:d})){a.term=d.value;a.element.val(d.value)}a.close(c);a.selectedItem=d},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");e.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");
-this.menu.element.remove();e.Widget.prototype.destroy.call(this)},_setOption:function(a,b){e.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(e(b||"body",this.element[0].ownerDocument)[0])},_initSource:function(){var a=this,b,c;if(e.isArray(this.options.source)){b=this.options.source;this.source=function(d,f){f(e.ui.autocomplete.filter(b,d.term))}}else if(typeof this.options.source==="string"){c=this.options.source;this.source=
-function(d,f){a.xhr&&a.xhr.abort();a.xhr=e.getJSON(c,d,function(g,i,h){h===a.xhr&&f(g);a.xhr=null})}}else this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search")!==false)return this._search(a)},_search:function(a){this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(a.length){a=
-this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this._trigger("close",a);this.menu.element.hide();this.menu.deactivate()}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return e.map(a,function(b){if(typeof b===
-"string")return{label:b,value:b};return e.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1),c;this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();this.menu.element.show().position(e.extend({of:this.element},this.options.position));a=b.width("").outerWidth();c=this.element.outerWidth();b.outerWidth(Math.max(a,c))},_renderMenu:function(a,b){var c=this;e.each(b,function(d,f){c._renderItem(a,f)})},
-_renderItem:function(a,b){return e("<li></li>").data("item.autocomplete",b).append(e("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});e.extend(e.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},
-filter:function(a,b){var c=new RegExp(e.ui.autocomplete.escapeRegex(b),"i");return e.grep(a,function(d){return c.test(d.label||d.value||d)})}})})(jQuery);
-(function(e){e.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(b){if(e(b.target).closest(".ui-menu-item a").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
--1).mouseenter(function(b){a.activate(b,e(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.attr("scrollTop"),f=this.element.height();if(c<0)this.element.attr("scrollTop",d+c);else c>=f&&this.element.attr("scrollTop",d+c-f+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:b})},
-deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0);
-a.length?this.activate(c,a):this.activate(c,this.element.children(b))}else this.activate(c,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||this.last())this.activate(a,this.element.children(":first"));else{var b=this.active.offset().top,c=this.element.height(),d=this.element.children("li").filter(function(){var f=e(this).offset().top-b-c+e(this).height();return f<10&&f>-10});d.length||(d=this.element.children(":last"));this.activate(a,d)}else this.activate(a,this.element.children(!this.active||
-this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(":last"));else{var b=this.active.offset().top,c=this.element.height();result=this.element.children("li").filter(function(){var d=e(this).offset().top-b+c-e(this).height();return d<10&&d>-10});result.length||(result=this.element.children(":first"));this.activate(a,result)}else this.activate(a,this.element.children(!this.active||this.first()?":last":":first"))},
-hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})})(jQuery);
-;/*
- * jQuery UI Button 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Button
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- */
-(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return e};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",
-i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",e="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",
-function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(e)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");
-b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");
-g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",
-c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("label[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var b=this.element.is(":checked");b&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=
-this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||
-this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
-true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),
-c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary");
-this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{_create:function(){this.element.addClass("ui-buttonset");this._init()},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(":button, :submit, :reset, :checkbox, :radio, a, :data(button)").filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":visible").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end().end()},
-destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);
-;/*
- * jQuery UI Dialog 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
* http://jquery.org/license
*
- * http://docs.jquery.com/UI/Dialog
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- * jquery.ui.button.js
- * jquery.ui.draggable.js
- * jquery.ui.mouse.js
- * jquery.ui.position.js
- * jquery.ui.resizable.js
- */
-(function(c,j){c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",of:window,collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");
-if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",f=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog",
-"aria-labelledby":f}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var e=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);
-return false}).appendTo(e);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",f).html(d).prependTo(e);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;e.find("*").add(e).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&
-g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");
-b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0])d=Math.max(d,c(this).css("z-index"))});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,f=d.options;if(f.modal&&!a||!f.stack&&!f.modal)return d._trigger("focus",b);if(f.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=
-f.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;d.next().length&&d.appendTo("body");a._size();a._position(b.position);d.show(b.show);
-a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(f){if(f.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),e=g.filter(":first");g=g.filter(":last");if(f.target===g[0]&&!f.shiftKey){e.focus(1);return false}else if(f.target===e[0]&&f.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,
-f=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(f);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(e,h){h=c.isFunction(h)?{click:h,text:e}:h;e=c("<button></button>",h).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&e.button()});f.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(e){return{position:e.position,
-offset:e.offset}}var b=this,d=b.options,f=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(e,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",e,a(h))},drag:function(e,h){b._trigger("drag",e,a(h))},stop:function(e,h){d.position=[h.position.left-f.scrollLeft(),h.position.top-f.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);
-b._trigger("dragStop",e,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}a=a===j?this.options.resizable:a;var d=this,f=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:d._minHeight(),
-handles:a,start:function(e,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",e,b(h))},resize:function(e,h){d._trigger("resize",e,b(h))},stop:function(e,h){c(this).removeClass("ui-dialog-resizing");f.height=c(this).height();f.width=c(this).width();d._trigger("resizeStop",e,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,
-a.height)},_position:function(a){var b=[],d=[0,0],f;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,e){if(+b[g]===b[g]){d[g]=b[g];b[g]=e}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(f=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(a);
-f||this.uiDialog.hide()},_setOption:function(a,b){var d=this,f=d.uiDialog,g=f.is(":data(resizable)"),e=false;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);e=true;break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":f.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case "draggable":b?
-d._makeDraggable():f.draggable("destroy");break;case "height":e=true;break;case "maxHeight":g&&f.resizable("option","maxHeight",b);e=true;break;case "maxWidth":g&&f.resizable("option","maxWidth",b);e=true;break;case "minHeight":g&&f.resizable("option","minHeight",b);e=true;break;case "minWidth":g&&f.resizable("option","minWidth",b);e=true;break;case "position":d._position(b);break;case "resizable":g&&!b&&f.resizable("destroy");g&&typeof b==="string"&&f.resizable("option","handles",b);!g&&b!==false&&
-d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break;case "width":e=true;break}c.Widget.prototype._setOption.apply(d,arguments);e&&d._size()},_size:function(){var a=this.options,b;this.element.css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();this.element.css(a.height==="auto"?{minHeight:Math.max(a.minHeight-b,0),height:c.support.minHeight?"auto":Math.max(a.minHeight-
-b,0)}:{minHeight:0,height:Math.max(a.height-b,0)}).show();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.5",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),
-function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=
-(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){this.oldInstances.push(this.instances.splice(c.inArray(a,this.instances),1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var b=0;c.each(this.instances,function(){b=Math.max(b,this.css("z-index"))});this.maxZ=b},height:function(){var a,
-b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<
-b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
-;/*
- * jQuery UI Slider 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Slider
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.mouse.js
- * jquery.ui.widget.js
- */
-(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var a=this,b=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");b.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");
-this.range=d([]);if(b.range){if(b.range===true){this.range=d("<div></div>");if(!b.values)b.values=[this._valueMin(),this._valueMin()];if(b.values.length&&b.values.length!==2)b.values=[b.values[0],b.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(b.range==="min"||b.range==="max")this.range.addClass("ui-slider-range-"+b.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");
-if(b.values&&b.values.length)for(;d(".ui-slider-handle",this.element).length<b.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();
-else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!a.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
-false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");h=a._start(c,f);if(h===false)return}break}i=a.options.step;h=a.options.values&&a.options.values.length?(g=a.values(f)):(g=a.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=a._valueMin();break;case d.ui.keyCode.END:g=a._valueMax();break;case d.ui.keyCode.PAGE_UP:g=a._trimAlignValue(h+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=a._trimAlignValue(h-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===
-a._valueMax())return;g=a._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===a._valueMin())return;g=a._trimAlignValue(h-i);break}a._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(c,e);a._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
-this._mouseDestroy();return this},_mouseCapture:function(a){var b=this.options,c,e,f,h,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(b.range===true&&this.values(1)===b.min){g+=1;f=d(this.handles[g])}if(this._start(a,
-g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();b=f.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-f.width()/2,top:a.pageY-b.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b=
-this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b=
-this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);
-c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var e;if(this.options.values&&this.options.values.length){e=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>e||b===1&&c<e))c=e;if(c!==this.values(b)){e=this.values();e[b]=c;a=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e});this.values(b?0:1);a!==false&&this.values(b,c,true)}}else if(c!==this.value()){a=this._trigger("slide",a,{handle:this.handles[b],value:c});
-a!==false&&this.value(c)}},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=
-this._trimAlignValue(a);this._refreshValue();this._change(null,0)}return this._value()},values:function(a,b){var c,e,f;if(arguments.length>1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(a):this.value();
-else return this._values()},_setOption:function(a,b){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(a){case "disabled":if(b){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
-this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a)},_values:function(a){var b,c;if(arguments.length){b=this.options.values[a];
-return b=this._trimAlignValue(b)}else{b=this.options.values.slice();for(c=0;c<b.length;c+=1)b[c]=this._trimAlignValue(b[c]);return b}},_trimAlignValue:function(a){if(a<this._valueMin())return this._valueMin();if(a>this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=a%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a=
-this.options.range,b=this.options,c=this,e=!this._animateOff?b.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},b.animate);if(k===1)c.range[e?"animate":"css"]({width:f-
-g+"%"},{queue:false,duration:b.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},b.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:b.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},
-b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.5"})})(jQuery);
-;/*
- * jQuery UI Tabs 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Tabs
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
+ * Date: Wed Jan 16 08:47:09 2013 -0600
*/
-(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(a,e){if(a=="selected")this.options.collapsible&&
-e==this.options.selected||this.select(e);else{this.options[a]=e;this._tabify()}},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var a=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[a].concat(d.makeArray(arguments)))},_ui:function(a,e){return{tab:a,panel:e,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var a=
-d(this);a.html(a.data("label.tabs")).removeData("label.tabs")})},_tabify:function(a){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var b=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||
-(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))b.panels=b.panels.add(b._sanitizeSelector(i));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=b._tabId(f);f.href="#"+i;f=d("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(b.panels[g-1]||b.list);f.data("destroy.tabs",true)}b.panels=b.panels.add(f)}else c.disabled.push(g)});if(a){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
-this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(b._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=
-this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return b.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
-if(c.selected>=0&&this.anchors.length){this.panels.eq(c.selected).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");b.element.queue("tabs",function(){b._trigger("show",null,b._ui(b.anchors[c.selected],b.panels[c.selected]))});this.load(c.selected)}d(window).bind("unload",function(){b.lis.add(b.anchors).unbind(".tabs");b.lis=b.anchors=b.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));this.element[c.collapsible?"addClass":
-"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);a=0;for(var j;j=this.lis[a];a++)d(j)[d.inArray(a,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+g)};this.lis.bind("mouseover.tabs",
-function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",function(){e(f,o);b._trigger("show",
-null,b._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");b._trigger("show",null,b._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){b.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);b.element.dequeue("tabs")})}:function(g,f){b.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");b.element.dequeue("tabs")};this.anchors.bind(c.event+".tabs",
-function(){var g=this,f=d(g).closest("li"),i=b.panels.filter(":not(.ui-tabs-hide)"),l=d(b._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||b.panels.filter(":animated").length||b._trigger("select",null,b._ui(this,l[0]))===false){this.blur();return false}c.selected=b.anchors.index(this);b.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=-1;c.cookie&&b._cookie(c.selected,c.cookie);b.element.queue("tabs",
-function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&b._cookie(c.selected,c.cookie);b.element.queue("tabs",function(){r(g,l)});b.load(b.anchors.index(this));this.blur();return false}c.cookie&&b._cookie(c.selected,c.cookie);if(l.length){i.length&&b.element.queue("tabs",function(){s(g,i)});b.element.queue("tabs",function(){r(g,l)});b.load(b.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",
-function(){return false})},_getIndex:function(a){if(typeof a=="string")a=this.anchors.index(this.anchors.filter("[href$="+a+"]"));return a},destroy:function(){var a=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=d.data(this,"href.tabs");if(e)this.href=
-e;var b=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){b.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});a.cookie&&this._cookie(null,a.cookie);return this},add:function(a,e,b){if(b===p)b=this.anchors.length;
-var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,a).replace(/#\{label\}/g,e));a=!a.indexOf("#")?a.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=d("#"+a);j.length||(j=d(h.panelTemplate).attr("id",a).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(b>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[b]);
-j.insertBefore(this.panels[b])}h.disabled=d.map(h.disabled,function(k){return k>=b?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[b],this.panels[b]));return this},remove:function(a){a=this._getIndex(a);var e=this.options,b=this.lis.eq(a).remove(),c=this.panels.eq(a).remove();
-if(b.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(a+(a+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=a}),function(h){return h>=a?--h:h});this._tabify();this._trigger("remove",null,this._ui(b.find("a")[0],c[0]));return this},enable:function(a){a=this._getIndex(a);var e=this.options;if(d.inArray(a,e.disabled)!=-1){this.lis.eq(a).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(b){return b!=a});this._trigger("enable",null,
-this._ui(this.anchors[a],this.panels[a]));return this}},disable:function(a){a=this._getIndex(a);var e=this.options;if(a!=e.selected){this.lis.eq(a).addClass("ui-state-disabled");e.disabled.push(a);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))}return this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;this.anchors.eq(a).trigger(this.options.event+".tabs");return this},
-load:function(a){a=this._getIndex(a);var e=this,b=this.options,c=this.anchors.eq(a)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(a).addClass("ui-state-processing");if(b.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(b.spinner)}this.xhr=d.ajax(d.extend({},b.ajaxOptions,{url:h,success:function(k,n){d(e._sanitizeSelector(c.hash)).html(k);e._cleanup();b.cache&&d.data(c,"cache.tabs",
-true);e._trigger("load",null,e._ui(e.anchors[a],e.panels[a]));try{b.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[a],e.panels[a]));try{b.ajaxOptions.error(k,n,a,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},url:function(a,
-e){this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.5"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(a,e){var b=this,c=this.options,h=b._rotate||(b._rotate=function(j){clearTimeout(b.rotation);b.rotation=setTimeout(function(){var k=c.selected;b.select(++k<b.anchors.length?k:0)},a);j&&j.stopPropagation()});e=b._unrotate||(b._unrotate=!e?function(j){j.clientX&&b.rotate(null)}:
-function(){t=c.selected;h()});if(a){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(b.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);
-;/*
- * jQuery UI Datepicker 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Datepicker
- *
- * Depends:
- * jquery.ui.core.js
- */
-(function(d,G){function L(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
-"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
-"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
-minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>')}function E(a,b){d.extend(a,
-b);for(var c in b)if(b[c]==null||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.5"}});var y=(new Date).getTime();d.extend(L.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=
-f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},
-_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&
-b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==
-""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,
-c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),
-true);this._updateDatepicker(b);this._updateAlternate(b)}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{});b=b&&b.constructor==
-Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);
-d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},
-_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=
-d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;
-for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&
-this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&
-!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass,b.dpDiv).add(d("td."+d.datepicker._currentClass,b.dpDiv));c[0]?d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();
-return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||
-a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,
-a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));
-var c=String.fromCharCode(a.charCode==G?a.keyCode:a.charCode);return a.ctrlKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||
-a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);
-d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&
-d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=d.datepicker._getBorders(b.dpDiv);b.dpDiv.find("iframe.ui-datepicker-cover").css({left:-i[0],top:-i[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,
-h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a)).find("iframe.ui-datepicker-cover").css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){d(this).removeClass("ui-state-hover");
-this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).addClass("ui-datepicker-prev-hover");
-this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);var e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");
-a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus()},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),
-k=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>k&&k>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];
-a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():
-"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&
-!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;
-b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=
-this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=
-d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,
-"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b==
-"object"?b.toString():b+"";if(b=="")return null;for(var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff,f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,k=c=-1,l=-1,u=-1,j=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"?4:p=="o"?
-3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,w,H){p=o(p)?H:w;for(w=0;w<p.length;w++)if(b.substr(s,p[w].length).toLowerCase()==p[w].toLowerCase()){s+=p[w].length;return w+1}throw"Unknown name at position "+s;},r=function(){if(b.charAt(s)!=a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(j)if(a.charAt(z)=="'"&&!o("'"))j=false;else r();else switch(a.charAt(z)){case "d":l=m("d");
-break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":k=m("m");break;case "M":k=n("M",i,g);break;case "y":c=m("y");break;case "@":var v=new Date(m("@"));c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "!":v=new Date((m("!")-this._ticksTo1970)/1E4);c=v.getFullYear();k=v.getMonth()+1;l=v.getDate();break;case "'":if(o("'"))r();else j=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>
--1){k=1;l=u;do{e=this._getDaysInMonth(c,k-1);if(l<=e)break;k++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,k-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=k||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*
-60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=j+1<a.length&&a.charAt(j+1)==o)&&j++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},k=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var j=0;j<a.length;j++)if(u)if(a.charAt(j)==
-"'"&&!i("'"))u=false;else l+=a.charAt(j);else switch(a.charAt(j)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=k("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=k("M",b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+=
-"'";else u=true;break;default:l+=a.charAt(j)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+="0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==G?a.settings[b]:this._defaults[b]},
-_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,
-this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,k=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,j=u.exec(h);j;){switch(j[2]||"d"){case "d":case "D":g+=
-parseInt(j[1],10);break;case "w":case "W":g+=parseInt(j[1],10)*7;break;case "m":case "M":l+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break;case "y":case "Y":k+=parseInt(j[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(k,l));break}j=u.exec(h)}return new Date(k,l,g)};if(b=(b=b==null?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):b)&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},
-_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?
-"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),k=
-this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),j=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=j&&n<j?j:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,
-"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-k,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+k+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+
-n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+k,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+k+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+
-(c?"w":"e")+'">'+r+"</span></a>";k=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;k=!h?k:this.formatDate(k,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+
-y+".datepicker._gotoToday('#"+a.id+"');\">"+k+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;k=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),w=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var M=this._getDefaultDate(a),I="",C=0;C<i[0];C++){for(var N=
-"",D=0;D<i[1];D++){var J=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&C==0?c?
-f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,j,o,C>0||D>0,z,v)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var A=k?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=(t+h)%7;A+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=A+"</tr></thead><tbody>";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,
-A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<A;O++){x+="<tr>";var P=!k?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var F=p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,K=B&&!H||!F[0]||j&&q<j||o&&q>o;P+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(B?" ui-datepicker-other-month":"")+(q.getTime()==J.getTime()&&g==a.selectedMonth&&
-a._keyEvent||M.getTime()==q.getTime()&&M.getTime()==J.getTime()?" "+this._dayOverClass:"")+(K?" "+this._unselectableClass+" ui-state-disabled":"")+(B&&!w?"":" "+F[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!B||w)&&F[2]?' title="'+F[2]+'"':"")+(K?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(B&&!w?" ":K?'<span class="ui-state-default">'+q.getDate()+
-"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==J.getTime()?" ui-state-active":"")+(B?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=P+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&D==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");N+=x}I+=N}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':
-"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var k=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),j='<div class="ui-datepicker-title">',o="";if(h||!k)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+
-a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(j+=o+(h||!(k&&l)?" ":""));if(h||!l)j+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,
-i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(j+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)j+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";j+="</select>"}j+=this._get(a,"yearSuffix");if(u)j+=(h||!(k&&l)?" ":"")+o;j+="</div>";return j},_adjustInstDate:function(a,b,c){var e=
-a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,
-"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);
-c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,
-"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=
-function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
-return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new L;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.5";window["DP_jQuery_"+y]=d})(jQuery);
-;/*
- * jQuery UI Progressbar 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Progressbar
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- */
-(function(b,c){b.widget("ui.progressbar",{options:{value:0},min:0,max:100,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
-this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===c)return this._value();this._setOption("value",a);return this},_setOption:function(a,d){if(a==="value"){this.options.value=d;this._refreshValue();this._trigger("change")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.max,Math.max(this.min,a))},_refreshValue:function(){var a=this.value();this.valueDiv.toggleClass("ui-corner-right",
-a===this.max).width(a+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.5"})})(jQuery);
-;/*
- * jQuery UI Effects 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/
+(function( jQuery, undefined ) {
+
+ var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
+
+ // plusequals test for += 100 -= 100
+ rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
+ // a set of RE's that can match strings and generate color tuples.
+ stringParsers = [{
+ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ],
+ execResult[ 3 ],
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ] * 2.55,
+ execResult[ 2 ] * 2.55,
+ execResult[ 3 ] * 2.55,
+ execResult[ 4 ]
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ // this regex ignores A-F because it's compared against an already lowercased string
+ re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
+ parse: function( execResult ) {
+ return [
+ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
+ parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
+ parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
+ ];
+ }
+ }, {
+ re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+ space: "hsla",
+ parse: function( execResult ) {
+ return [
+ execResult[ 1 ],
+ execResult[ 2 ] / 100,
+ execResult[ 3 ] / 100,
+ execResult[ 4 ]
+ ];
+ }
+ }],
+
+ // jQuery.Color( )
+ color = jQuery.Color = function( color, green, blue, alpha ) {
+ return new jQuery.Color.fn.parse( color, green, blue, alpha );
+ },
+ spaces = {
+ rgba: {
+ props: {
+ red: {
+ idx: 0,
+ type: "byte"
+ },
+ green: {
+ idx: 1,
+ type: "byte"
+ },
+ blue: {
+ idx: 2,
+ type: "byte"
+ }
+ }
+ },
+
+ hsla: {
+ props: {
+ hue: {
+ idx: 0,
+ type: "degrees"
+ },
+ saturation: {
+ idx: 1,
+ type: "percent"
+ },
+ lightness: {
+ idx: 2,
+ type: "percent"
+ }
+ }
+ }
+ },
+ propTypes = {
+ "byte": {
+ floor: true,
+ max: 255
+ },
+ "percent": {
+ max: 1
+ },
+ "degrees": {
+ mod: 360,
+ floor: true
+ }
+ },
+ support = color.support = {},
+
+ // element for support tests
+ supportElem = jQuery( "<p>" )[ 0 ],
+
+ // colors = jQuery.Color.names
+ colors,
+
+ // local aliases of functions called often
+ each = jQuery.each;
+
+// determine rgba support immediately
+supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
+support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
+
+// define cache name and alpha properties
+// for rgba and hsla spaces
+each( spaces, function( spaceName, space ) {
+ space.cache = "_" + spaceName;
+ space.props.alpha = {
+ idx: 3,
+ type: "percent",
+ def: 1
+ };
+});
+
+function clamp( value, prop, allowEmpty ) {
+ var type = propTypes[ prop.type ] || {};
+
+ if ( value == null ) {
+ return (allowEmpty || !prop.def) ? null : prop.def;
+ }
+
+ // ~~ is an short way of doing floor for positive numbers
+ value = type.floor ? ~~value : parseFloat( value );
+
+ // IE will pass in empty strings as value for alpha,
+ // which will hit this case
+ if ( isNaN( value ) ) {
+ return prop.def;
+ }
+
+ if ( type.mod ) {
+ // we add mod before modding to make sure that negatives values
+ // get converted properly: -10 -> 350
+ return (value + type.mod) % type.mod;
+ }
+
+ // for now all property types without mod have min and max
+ return 0 > value ? 0 : type.max < value ? type.max : value;
+}
+
+function stringParse( string ) {
+ var inst = color(),
+ rgba = inst._rgba = [];
+
+ string = string.toLowerCase();
+
+ each( stringParsers, function( i, parser ) {
+ var parsed,
+ match = parser.re.exec( string ),
+ values = match && parser.parse( match ),
+ spaceName = parser.space || "rgba";
+
+ if ( values ) {
+ parsed = inst[ spaceName ]( values );
+
+ // if this was an rgba parse the assignment might happen twice
+ // oh well....
+ inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
+ rgba = inst._rgba = parsed._rgba;
+
+ // exit each( stringParsers ) here because we matched
+ return false;
+ }
+ });
+
+ // Found a stringParser that handled it
+ if ( rgba.length ) {
+
+ // if this came from a parsed string, force "transparent" when alpha is 0
+ // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
+ if ( rgba.join() === "0,0,0,0" ) {
+ jQuery.extend( rgba, colors.transparent );
+ }
+ return inst;
+ }
+
+ // named colors
+ return colors[ string ];
+}
+
+color.fn = jQuery.extend( color.prototype, {
+ parse: function( red, green, blue, alpha ) {
+ if ( red === undefined ) {
+ this._rgba = [ null, null, null, null ];
+ return this;
+ }
+ if ( red.jquery || red.nodeType ) {
+ red = jQuery( red ).css( green );
+ green = undefined;
+ }
+
+ var inst = this,
+ type = jQuery.type( red ),
+ rgba = this._rgba = [];
+
+ // more than 1 argument specified - assume ( red, green, blue, alpha )
+ if ( green !== undefined ) {
+ red = [ red, green, blue, alpha ];
+ type = "array";
+ }
+
+ if ( type === "string" ) {
+ return this.parse( stringParse( red ) || colors._default );
+ }
+
+ if ( type === "array" ) {
+ each( spaces.rgba.props, function( key, prop ) {
+ rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
+ });
+ return this;
+ }
+
+ if ( type === "object" ) {
+ if ( red instanceof color ) {
+ each( spaces, function( spaceName, space ) {
+ if ( red[ space.cache ] ) {
+ inst[ space.cache ] = red[ space.cache ].slice();
+ }
+ });
+ } else {
+ each( spaces, function( spaceName, space ) {
+ var cache = space.cache;
+ each( space.props, function( key, prop ) {
+
+ // if the cache doesn't exist, and we know how to convert
+ if ( !inst[ cache ] && space.to ) {
+
+ // if the value was null, we don't need to copy it
+ // if the key was alpha, we don't need to copy it either
+ if ( key === "alpha" || red[ key ] == null ) {
+ return;
+ }
+ inst[ cache ] = space.to( inst._rgba );
+ }
+
+ // this is the only case where we allow nulls for ALL properties.
+ // call clamp with alwaysAllowEmpty
+ inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
+ });
+
+ // everything defined but alpha?
+ if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
+ // use the default of 1
+ inst[ cache ][ 3 ] = 1;
+ if ( space.from ) {
+ inst._rgba = space.from( inst[ cache ] );
+ }
+ }
+ });
+ }
+ return this;
+ }
+ },
+ is: function( compare ) {
+ var is = color( compare ),
+ same = true,
+ inst = this;
+
+ each( spaces, function( _, space ) {
+ var localCache,
+ isCache = is[ space.cache ];
+ if (isCache) {
+ localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
+ each( space.props, function( _, prop ) {
+ if ( isCache[ prop.idx ] != null ) {
+ same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
+ return same;
+ }
+ });
+ }
+ return same;
+ });
+ return same;
+ },
+ _space: function() {
+ var used = [],
+ inst = this;
+ each( spaces, function( spaceName, space ) {
+ if ( inst[ space.cache ] ) {
+ used.push( spaceName );
+ }
+ });
+ return used.pop();
+ },
+ transition: function( other, distance ) {
+ var end = color( other ),
+ spaceName = end._space(),
+ space = spaces[ spaceName ],
+ startColor = this.alpha() === 0 ? color( "transparent" ) : this,
+ start = startColor[ space.cache ] || space.to( startColor._rgba ),
+ result = start.slice();
+
+ end = end[ space.cache ];
+ each( space.props, function( key, prop ) {
+ var index = prop.idx,
+ startValue = start[ index ],
+ endValue = end[ index ],
+ type = propTypes[ prop.type ] || {};
+
+ // if null, don't override start value
+ if ( endValue === null ) {
+ return;
+ }
+ // if null - use end
+ if ( startValue === null ) {
+ result[ index ] = endValue;
+ } else {
+ if ( type.mod ) {
+ if ( endValue - startValue > type.mod / 2 ) {
+ startValue += type.mod;
+ } else if ( startValue - endValue > type.mod / 2 ) {
+ startValue -= type.mod;
+ }
+ }
+ result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
+ }
+ });
+ return this[ spaceName ]( result );
+ },
+ blend: function( opaque ) {
+ // if we are already opaque - return ourself
+ if ( this._rgba[ 3 ] === 1 ) {
+ return this;
+ }
+
+ var rgb = this._rgba.slice(),
+ a = rgb.pop(),
+ blend = color( opaque )._rgba;
+
+ return color( jQuery.map( rgb, function( v, i ) {
+ return ( 1 - a ) * blend[ i ] + a * v;
+ }));
+ },
+ toRgbaString: function() {
+ var prefix = "rgba(",
+ rgba = jQuery.map( this._rgba, function( v, i ) {
+ return v == null ? ( i > 2 ? 1 : 0 ) : v;
+ });
+
+ if ( rgba[ 3 ] === 1 ) {
+ rgba.pop();
+ prefix = "rgb(";
+ }
+
+ return prefix + rgba.join() + ")";
+ },
+ toHslaString: function() {
+ var prefix = "hsla(",
+ hsla = jQuery.map( this.hsla(), function( v, i ) {
+ if ( v == null ) {
+ v = i > 2 ? 1 : 0;
+ }
+
+ // catch 1 and 2
+ if ( i && i < 3 ) {
+ v = Math.round( v * 100 ) + "%";
+ }
+ return v;
+ });
+
+ if ( hsla[ 3 ] === 1 ) {
+ hsla.pop();
+ prefix = "hsl(";
+ }
+ return prefix + hsla.join() + ")";
+ },
+ toHexString: function( includeAlpha ) {
+ var rgba = this._rgba.slice(),
+ alpha = rgba.pop();
+
+ if ( includeAlpha ) {
+ rgba.push( ~~( alpha * 255 ) );
+ }
+
+ return "#" + jQuery.map( rgba, function( v ) {
+
+ // default to 0 when nulls exist
+ v = ( v || 0 ).toString( 16 );
+ return v.length === 1 ? "0" + v : v;
+ }).join("");
+ },
+ toString: function() {
+ return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
+ }
+});
+color.fn.parse.prototype = color.fn;
+
+// hsla conversions adapted from:
+// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
+
+function hue2rgb( p, q, h ) {
+ h = ( h + 1 ) % 1;
+ if ( h * 6 < 1 ) {
+ return p + (q - p) * h * 6;
+ }
+ if ( h * 2 < 1) {
+ return q;
+ }
+ if ( h * 3 < 2 ) {
+ return p + (q - p) * ((2/3) - h) * 6;
+ }
+ return p;
+}
+
+spaces.hsla.to = function ( rgba ) {
+ if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
+ return [ null, null, null, rgba[ 3 ] ];
+ }
+ var r = rgba[ 0 ] / 255,
+ g = rgba[ 1 ] / 255,
+ b = rgba[ 2 ] / 255,
+ a = rgba[ 3 ],
+ max = Math.max( r, g, b ),
+ min = Math.min( r, g, b ),
+ diff = max - min,
+ add = max + min,
+ l = add * 0.5,
+ h, s;
+
+ if ( min === max ) {
+ h = 0;
+ } else if ( r === max ) {
+ h = ( 60 * ( g - b ) / diff ) + 360;
+ } else if ( g === max ) {
+ h = ( 60 * ( b - r ) / diff ) + 120;
+ } else {
+ h = ( 60 * ( r - g ) / diff ) + 240;
+ }
+
+ // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
+ // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
+ if ( diff === 0 ) {
+ s = 0;
+ } else if ( l <= 0.5 ) {
+ s = diff / add;
+ } else {
+ s = diff / ( 2 - add );
+ }
+ return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
+};
+
+spaces.hsla.from = function ( hsla ) {
+ if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
+ return [ null, null, null, hsla[ 3 ] ];
+ }
+ var h = hsla[ 0 ] / 360,
+ s = hsla[ 1 ],
+ l = hsla[ 2 ],
+ a = hsla[ 3 ],
+ q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
+ p = 2 * l - q;
+
+ return [
+ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
+ Math.round( hue2rgb( p, q, h ) * 255 ),
+ Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
+ a
+ ];
+};
+
+
+each( spaces, function( spaceName, space ) {
+ var props = space.props,
+ cache = space.cache,
+ to = space.to,
+ from = space.from;
+
+ // makes rgba() and hsla()
+ color.fn[ spaceName ] = function( value ) {
+
+ // generate a cache for this space if it doesn't exist
+ if ( to && !this[ cache ] ) {
+ this[ cache ] = to( this._rgba );
+ }
+ if ( value === undefined ) {
+ return this[ cache ].slice();
+ }
+
+ var ret,
+ type = jQuery.type( value ),
+ arr = ( type === "array" || type === "object" ) ? value : arguments,
+ local = this[ cache ].slice();
+
+ each( props, function( key, prop ) {
+ var val = arr[ type === "object" ? key : prop.idx ];
+ if ( val == null ) {
+ val = local[ prop.idx ];
+ }
+ local[ prop.idx ] = clamp( val, prop );
+ });
+
+ if ( from ) {
+ ret = color( from( local ) );
+ ret[ cache ] = local;
+ return ret;
+ } else {
+ return color( local );
+ }
+ };
+
+ // makes red() green() blue() alpha() hue() saturation() lightness()
+ each( props, function( key, prop ) {
+ // alpha is included in more than one space
+ if ( color.fn[ key ] ) {
+ return;
+ }
+ color.fn[ key ] = function( value ) {
+ var vtype = jQuery.type( value ),
+ fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
+ local = this[ fn ](),
+ cur = local[ prop.idx ],
+ match;
+
+ if ( vtype === "undefined" ) {
+ return cur;
+ }
+
+ if ( vtype === "function" ) {
+ value = value.call( this, cur );
+ vtype = jQuery.type( value );
+ }
+ if ( value == null && prop.empty ) {
+ return this;
+ }
+ if ( vtype === "string" ) {
+ match = rplusequals.exec( value );
+ if ( match ) {
+ value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
+ }
+ }
+ local[ prop.idx ] = value;
+ return this[ fn ]( local );
+ };
+ });
+});
+
+// add cssHook and .fx.step function for each named hook.
+// accept a space separated string of properties
+color.hook = function( hook ) {
+ var hooks = hook.split( " " );
+ each( hooks, function( i, hook ) {
+ jQuery.cssHooks[ hook ] = {
+ set: function( elem, value ) {
+ var parsed, curElem,
+ backgroundColor = "";
+
+ if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
+ value = color( parsed || value );
+ if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
+ curElem = hook === "backgroundColor" ? elem.parentNode : elem;
+ while (
+ (backgroundColor === "" || backgroundColor === "transparent") &&
+ curElem && curElem.style
+ ) {
+ try {
+ backgroundColor = jQuery.css( curElem, "backgroundColor" );
+ curElem = curElem.parentNode;
+ } catch ( e ) {
+ }
+ }
+
+ value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
+ backgroundColor :
+ "_default" );
+ }
+
+ value = value.toRgbaString();
+ }
+ try {
+ elem.style[ hook ] = value;
+ } catch( e ) {
+ // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
+ }
+ }
+ };
+ jQuery.fx.step[ hook ] = function( fx ) {
+ if ( !fx.colorInit ) {
+ fx.start = color( fx.elem, hook );
+ fx.end = color( fx.end );
+ fx.colorInit = true;
+ }
+ jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
+ };
+ });
+
+};
+
+color.hook( stepHooks );
+
+jQuery.cssHooks.borderColor = {
+ expand: function( value ) {
+ var expanded = {};
+
+ each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
+ expanded[ "border" + part + "Color" ] = value;
+ });
+ return expanded;
+ }
+};
+
+// Basic color names only.
+// Usage of any of the other color names requires adding yourself or including
+// jquery.color.svg-names.js.
+colors = jQuery.Color.names = {
+ // 4.1. Basic color keywords
+ aqua: "#00ffff",
+ black: "#000000",
+ blue: "#0000ff",
+ fuchsia: "#ff00ff",
+ gray: "#808080",
+ green: "#008000",
+ lime: "#00ff00",
+ maroon: "#800000",
+ navy: "#000080",
+ olive: "#808000",
+ purple: "#800080",
+ red: "#ff0000",
+ silver: "#c0c0c0",
+ teal: "#008080",
+ white: "#ffffff",
+ yellow: "#ffff00",
+
+ // 4.2.3. "transparent" color keyword
+ transparent: [ null, null, null, 0 ],
+
+ _default: "#ffffff"
+};
+
+})( jQuery );
+
+
+/******************************************************************************/
+/****************************** CLASS ANIMATIONS ******************************/
+/******************************************************************************/
+(function() {
+
+var classAnimationActions = [ "add", "remove", "toggle" ],
+ shorthandStyles = {
+ border: 1,
+ borderBottom: 1,
+ borderColor: 1,
+ borderLeft: 1,
+ borderRight: 1,
+ borderTop: 1,
+ borderWidth: 1,
+ margin: 1,
+ padding: 1
+ };
+
+$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
+ $.fx.step[ prop ] = function( fx ) {
+ if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
+ jQuery.style( fx.elem, prop, fx.end );
+ fx.setAttr = true;
+ }
+ };
+});
+
+function getElementStyles( elem ) {
+ var key, len,
+ style = elem.ownerDocument.defaultView ?
+ elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
+ elem.currentStyle,
+ styles = {};
+
+ if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
+ len = style.length;
+ while ( len-- ) {
+ key = style[ len ];
+ if ( typeof style[ key ] === "string" ) {
+ styles[ $.camelCase( key ) ] = style[ key ];
+ }
+ }
+ // support: Opera, IE <9
+ } else {
+ for ( key in style ) {
+ if ( typeof style[ key ] === "string" ) {
+ styles[ key ] = style[ key ];
+ }
+ }
+ }
+
+ return styles;
+}
+
+
+function styleDifference( oldStyle, newStyle ) {
+ var diff = {},
+ name, value;
+
+ for ( name in newStyle ) {
+ value = newStyle[ name ];
+ if ( oldStyle[ name ] !== value ) {
+ if ( !shorthandStyles[ name ] ) {
+ if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
+ diff[ name ] = value;
+ }
+ }
+ }
+ }
+
+ return diff;
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+ $.fn.addBack = function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ };
+}
+
+$.effects.animateClass = function( value, duration, easing, callback ) {
+ var o = $.speed( duration, easing, callback );
+
+ return this.queue( function() {
+ var animated = $( this ),
+ baseClass = animated.attr( "class" ) || "",
+ applyClassChange,
+ allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
+
+ // map the animated objects to store the original styles.
+ allAnimations = allAnimations.map(function() {
+ var el = $( this );
+ return {
+ el: el,
+ start: getElementStyles( this )
+ };
+ });
+
+ // apply class change
+ applyClassChange = function() {
+ $.each( classAnimationActions, function(i, action) {
+ if ( value[ action ] ) {
+ animated[ action + "Class" ]( value[ action ] );
+ }
+ });
+ };
+ applyClassChange();
+
+ // map all animated objects again - calculate new styles and diff
+ allAnimations = allAnimations.map(function() {
+ this.end = getElementStyles( this.el[ 0 ] );
+ this.diff = styleDifference( this.start, this.end );
+ return this;
+ });
+
+ // apply original class
+ animated.attr( "class", baseClass );
+
+ // map all animated objects again - this time collecting a promise
+ allAnimations = allAnimations.map(function() {
+ var styleInfo = this,
+ dfd = $.Deferred(),
+ opts = $.extend({}, o, {
+ queue: false,
+ complete: function() {
+ dfd.resolve( styleInfo );
+ }
+ });
+
+ this.el.animate( this.diff, opts );
+ return dfd.promise();
+ });
+
+ // once all animations have completed:
+ $.when.apply( $, allAnimations.get() ).done(function() {
+
+ // set the final class
+ applyClassChange();
+
+ // for each animated element,
+ // clear all css properties that were animated
+ $.each( arguments, function() {
+ var el = this.el;
+ $.each( this.diff, function(key) {
+ el.css( key, "" );
+ });
+ });
+
+ // this is guarnteed to be there if you use jQuery.speed()
+ // it also handles dequeuing the next anim...
+ o.complete.call( animated[ 0 ] );
+ });
+ });
+};
+
+$.fn.extend({
+ addClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return speed ?
+ $.effects.animateClass.call( this,
+ { add: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.addClass ),
+
+ removeClass: (function( orig ) {
+ return function( classNames, speed, easing, callback ) {
+ return arguments.length > 1 ?
+ $.effects.animateClass.call( this,
+ { remove: classNames }, speed, easing, callback ) :
+ orig.apply( this, arguments );
+ };
+ })( $.fn.removeClass ),
+
+ toggleClass: (function( orig ) {
+ return function( classNames, force, speed, easing, callback ) {
+ if ( typeof force === "boolean" || force === undefined ) {
+ if ( !speed ) {
+ // without speed parameter
+ return orig.apply( this, arguments );
+ } else {
+ return $.effects.animateClass.call( this,
+ (force ? { add: classNames } : { remove: classNames }),
+ speed, easing, callback );
+ }
+ } else {
+ // without force parameter
+ return $.effects.animateClass.call( this,
+ { toggle: classNames }, force, speed, easing );
+ }
+ };
+ })( $.fn.toggleClass ),
+
+ switchClass: function( remove, add, speed, easing, callback) {
+ return $.effects.animateClass.call( this, {
+ add: add,
+ remove: remove
+ }, speed, easing, callback );
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EFFECTS **********************************/
+/******************************************************************************/
+
+(function() {
+
+$.extend( $.effects, {
+ version: "1.10.3",
+
+ // Saves a set of properties in a data storage
+ save: function( element, set ) {
+ for( var i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+ }
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function( element, set ) {
+ var val, i;
+ for( i=0; i < set.length; i++ ) {
+ if ( set[ i ] !== null ) {
+ val = element.data( dataSpace + set[ i ] );
+ // support: jQuery 1.6.2
+ // http://bugs.jquery.com/ticket/9917
+ // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
+ // We can't differentiate between "" and 0 here, so we just assume
+ // empty string since it's likely to be a more common value...
+ if ( val === undefined ) {
+ val = "";
+ }
+ element.css( set[ i ], val );
+ }
+ }
+ },
+
+ setMode: function( el, mode ) {
+ if (mode === "toggle") {
+ mode = el.is( ":hidden" ) ? "show" : "hide";
+ }
+ return mode;
+ },
+
+ // Translates a [top,left] array into a baseline value
+ // this should be a little more flexible in the future to handle a string & hash
+ getBaseline: function( origin, original ) {
+ var y, x;
+ switch ( origin[ 0 ] ) {
+ case "top": y = 0; break;
+ case "middle": y = 0.5; break;
+ case "bottom": y = 1; break;
+ default: y = origin[ 0 ] / original.height;
+ }
+ switch ( origin[ 1 ] ) {
+ case "left": x = 0; break;
+ case "center": x = 0.5; break;
+ case "right": x = 1; break;
+ default: x = origin[ 1 ] / original.width;
+ }
+ return {
+ x: x,
+ y: y
+ };
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function( element ) {
+
+ // if the element is already wrapped, return it
+ if ( element.parent().is( ".ui-effects-wrapper" )) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth(true),
+ height: element.outerHeight(true),
+ "float": element.css( "float" )
+ },
+ wrapper = $( "<div></div>" )
+ .addClass( "ui-effects-wrapper" )
+ .css({
+ fontSize: "100%",
+ background: "transparent",
+ border: "none",
+ margin: 0,
+ padding: 0
+ }),
+ // Store the size in case width/height are defined in % - Fixes #5245
+ size = {
+ width: element.width(),
+ height: element.height()
+ },
+ active = document.activeElement;
+
+ // support: Firefox
+ // Firefox incorrectly exposes anonymous content
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
+ try {
+ active.id;
+ } catch( e ) {
+ active = document.body;
+ }
+
+ element.wrap( wrapper );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if ( element.css( "position" ) === "static" ) {
+ wrapper.css({ position: "relative" });
+ element.css({ position: "relative" });
+ } else {
+ $.extend( props, {
+ position: element.css( "position" ),
+ zIndex: element.css( "z-index" )
+ });
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+ props[ pos ] = element.css( pos );
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+ props[ pos ] = "auto";
+ }
+ });
+ element.css({
+ position: "relative",
+ top: 0,
+ left: 0,
+ right: "auto",
+ bottom: "auto"
+ });
+ }
+ element.css(size);
+
+ return wrapper.css( props ).show();
+ },
+
+ removeWrapper: function( element ) {
+ var active = document.activeElement;
+
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ element.parent().replaceWith( element );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ }
+
+
+ return element;
+ },
+
+ setTransition: function( element, list, factor, value ) {
+ value = value || {};
+ $.each( list, function( i, x ) {
+ var unit = element.cssUnit( x );
+ if ( unit[ 0 ] > 0 ) {
+ value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
+ }
+ });
+ return value;
+ }
+});
+
+// return an effect options object for the given parameters:
+function _normalizeArguments( effect, options, speed, callback ) {
+
+ // allow passing all options as the first parameter
+ if ( $.isPlainObject( effect ) ) {
+ options = effect;
+ effect = effect.effect;
+ }
+
+ // convert to an object
+ effect = { effect: effect };
+
+ // catch (effect, null, ...)
+ if ( options == null ) {
+ options = {};
+ }
+
+ // catch (effect, callback)
+ if ( $.isFunction( options ) ) {
+ callback = options;
+ speed = null;
+ options = {};
+ }
+
+ // catch (effect, speed, ?)
+ if ( typeof options === "number" || $.fx.speeds[ options ] ) {
+ callback = speed;
+ speed = options;
+ options = {};
+ }
+
+ // catch (effect, options, callback)
+ if ( $.isFunction( speed ) ) {
+ callback = speed;
+ speed = null;
+ }
+
+ // add options to effect
+ if ( options ) {
+ $.extend( effect, options );
+ }
+
+ speed = speed || options.duration;
+ effect.duration = $.fx.off ? 0 :
+ typeof speed === "number" ? speed :
+ speed in $.fx.speeds ? $.fx.speeds[ speed ] :
+ $.fx.speeds._default;
+
+ effect.complete = callback || options.complete;
+
+ return effect;
+}
+
+function standardAnimationOption( option ) {
+ // Valid standard speeds (nothing, number, named speed)
+ if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
+ return true;
+ }
+
+ // Invalid strings - treat as "normal" speed
+ if ( typeof option === "string" && !$.effects.effect[ option ] ) {
+ return true;
+ }
+
+ // Complete callback
+ if ( $.isFunction( option ) ) {
+ return true;
+ }
+
+ // Options hash (but not naming an effect)
+ if ( typeof option === "object" && !option.effect ) {
+ return true;
+ }
+
+ // Didn't match any standard API
+ return false;
+}
+
+$.fn.extend({
+ effect: function( /* effect, options, speed, callback */ ) {
+ var args = _normalizeArguments.apply( this, arguments ),
+ mode = args.mode,
+ queue = args.queue,
+ effectMethod = $.effects.effect[ args.effect ];
+
+ if ( $.fx.off || !effectMethod ) {
+ // delegate to the original method (e.g., .show()) if possible
+ if ( mode ) {
+ return this[ mode ]( args.duration, args.complete );
+ } else {
+ return this.each( function() {
+ if ( args.complete ) {
+ args.complete.call( this );
+ }
+ });
+ }
+ }
+
+ function run( next ) {
+ var elem = $( this ),
+ complete = args.complete,
+ mode = args.mode;
+
+ function done() {
+ if ( $.isFunction( complete ) ) {
+ complete.call( elem[0] );
+ }
+ if ( $.isFunction( next ) ) {
+ next();
+ }
+ }
+
+ // If the element already has the correct final state, delegate to
+ // the core methods so the internal tracking of "olddisplay" works.
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+ elem[ mode ]();
+ done();
+ } else {
+ effectMethod.call( elem[0], args, done );
+ }
+ }
+
+ return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+ },
+
+ show: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "show";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.show ),
+
+ hide: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "hide";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.hide ),
+
+ toggle: (function( orig ) {
+ return function( option ) {
+ if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
+ return orig.apply( this, arguments );
+ } else {
+ var args = _normalizeArguments.apply( this, arguments );
+ args.mode = "toggle";
+ return this.effect.call( this, args );
+ }
+ };
+ })( $.fn.toggle ),
+
+ // helper functions
+ cssUnit: function(key) {
+ var style = this.css( key ),
+ val = [];
+
+ $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
+ if ( style.indexOf( unit ) > 0 ) {
+ val = [ parseFloat( style ), unit ];
+ }
+ });
+ return val;
+ }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EASING ***********************************/
+/******************************************************************************/
+
+(function() {
+
+// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
+
+var baseEasings = {};
+
+$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
+ baseEasings[ name ] = function( p ) {
+ return Math.pow( p, i + 2 );
+ };
+});
+
+$.extend( baseEasings, {
+ Sine: function ( p ) {
+ return 1 - Math.cos( p * Math.PI / 2 );
+ },
+ Circ: function ( p ) {
+ return 1 - Math.sqrt( 1 - p * p );
+ },
+ Elastic: function( p ) {
+ return p === 0 || p === 1 ? p :
+ -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
+ },
+ Back: function( p ) {
+ return p * p * ( 3 * p - 2 );
+ },
+ Bounce: function ( p ) {
+ var pow2,
+ bounce = 4;
+
+ while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
+ return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
+ }
+});
+
+$.each( baseEasings, function( name, easeIn ) {
+ $.easing[ "easeIn" + name ] = easeIn;
+ $.easing[ "easeOut" + name ] = function( p ) {
+ return 1 - easeIn( 1 - p );
+ };
+ $.easing[ "easeInOut" + name ] = function( p ) {
+ return p < 0.5 ?
+ easeIn( p * 2 ) / 2 :
+ 1 - easeIn( p * -2 + 2 ) / 2;
+ };
+});
+
+})();
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+var uid = 0,
+ hideProps = {},
+ showProps = {};
+
+hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
+ hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
+showProps.height = showProps.paddingTop = showProps.paddingBottom =
+ showProps.borderTopWidth = showProps.borderBottomWidth = "show";
+
+$.widget( "ui.accordion", {
+ version: "1.10.3",
+ options: {
+ active: 0,
+ animate: {},
+ collapsible: false,
+ event: "click",
+ header: "> li > :first-child,> :not(li):even",
+ heightStyle: "auto",
+ icons: {
+ activeHeader: "ui-icon-triangle-1-s",
+ header: "ui-icon-triangle-1-e"
+ },
+
+ // callbacks
+ activate: null,
+ beforeActivate: null
+ },
+
+ _create: function() {
+ var options = this.options;
+ this.prevShow = this.prevHide = $();
+ this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
+ // ARIA
+ .attr( "role", "tablist" );
+
+ // don't allow collapsible: false and active: false / null
+ if ( !options.collapsible && (options.active === false || options.active == null) ) {
+ options.active = 0;
+ }
+
+ this._processPanels();
+ // handle negative values
+ if ( options.active < 0 ) {
+ options.active += this.headers.length;
+ }
+ this._refresh();
+ },
+
+ _getCreateEventData: function() {
+ return {
+ header: this.active,
+ panel: !this.active.length ? $() : this.active.next(),
+ content: !this.active.length ? $() : this.active.next()
+ };
+ },
+
+ _createIcons: function() {
+ var icons = this.options.icons;
+ if ( icons ) {
+ $( "<span>" )
+ .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
+ .prependTo( this.headers );
+ this.active.children( ".ui-accordion-header-icon" )
+ .removeClass( icons.header )
+ .addClass( icons.activeHeader );
+ this.headers.addClass( "ui-accordion-icons" );
+ }
+ },
+
+ _destroyIcons: function() {
+ this.headers
+ .removeClass( "ui-accordion-icons" )
+ .children( ".ui-accordion-header-icon" )
+ .remove();
+ },
+
+ _destroy: function() {
+ var contents;
+
+ // clean up main element
+ this.element
+ .removeClass( "ui-accordion ui-widget ui-helper-reset" )
+ .removeAttr( "role" );
+
+ // clean up headers
+ this.headers
+ .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-controls" )
+ .removeAttr( "tabIndex" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ this._destroyIcons();
+
+ // clean up content panels
+ contents = this.headers.next()
+ .css( "display", "" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-labelledby" )
+ .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
+ .each(function() {
+ if ( /^ui-accordion/.test( this.id ) ) {
+ this.removeAttribute( "id" );
+ }
+ });
+ if ( this.options.heightStyle !== "content" ) {
+ contents.css( "height", "" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "event" ) {
+ if ( this.options.event ) {
+ this._off( this.headers, this.options.event );
+ }
+ this._setupEvents( value );
+ }
+
+ this._super( key, value );
+
+ // setting collapsible: false while collapsed; open first panel
+ if ( key === "collapsible" && !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+
+ if ( key === "icons" ) {
+ this._destroyIcons();
+ if ( value ) {
+ this._createIcons();
+ }
+ }
+
+ // #5332 - opacity doesn't cascade to positioned elements in IE
+ // so we need to add the disabled class to the headers and panels
+ if ( key === "disabled" ) {
+ this.headers.add( this.headers.next() )
+ .toggleClass( "ui-state-disabled", !!value );
+ }
+ },
+
+ _keydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ if ( event.altKey || event.ctrlKey ) {
+ return;
+ }
+
+ var keyCode = $.ui.keyCode,
+ length = this.headers.length,
+ currentIndex = this.headers.index( event.target ),
+ toFocus = false;
+
+ switch ( event.keyCode ) {
+ case keyCode.RIGHT:
+ case keyCode.DOWN:
+ toFocus = this.headers[ ( currentIndex + 1 ) % length ];
+ break;
+ case keyCode.LEFT:
+ case keyCode.UP:
+ toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
+ break;
+ case keyCode.SPACE:
+ case keyCode.ENTER:
+ this._eventHandler( event );
+ break;
+ case keyCode.HOME:
+ toFocus = this.headers[ 0 ];
+ break;
+ case keyCode.END:
+ toFocus = this.headers[ length - 1 ];
+ break;
+ }
+
+ if ( toFocus ) {
+ $( event.target ).attr( "tabIndex", -1 );
+ $( toFocus ).attr( "tabIndex", 0 );
+ toFocus.focus();
+ event.preventDefault();
+ }
+ },
+
+ _panelKeyDown : function( event ) {
+ if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
+ $( event.currentTarget ).prev().focus();
+ }
+ },
+
+ refresh: function() {
+ var options = this.options;
+ this._processPanels();
+
+ // was collapsed or no panel
+ if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
+ options.active = false;
+ this.active = $();
+ // active false only when collapsible is true
+ } else if ( options.active === false ) {
+ this._activate( 0 );
+ // was active, but active panel is gone
+ } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining panel are disabled
+ if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous panel
+ } else {
+ this._activate( Math.max( 0, options.active - 1 ) );
+ }
+ // was active, active panel still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.headers.index( this.active );
+ }
+
+ this._destroyIcons();
+
+ this._refresh();
+ },
+
+ _processPanels: function() {
+ this.headers = this.element.find( this.options.header )
+ .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
+
+ this.headers.next()
+ .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
+ .filter(":not(.ui-accordion-content-active)")
+ .hide();
+ },
+
+ _refresh: function() {
+ var maxHeight,
+ options = this.options,
+ heightStyle = options.heightStyle,
+ parent = this.element.parent(),
+ accordionId = this.accordionId = "ui-accordion-" +
+ (this.element.attr( "id" ) || ++uid);
+
+ this.active = this._findActive( options.active )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
+ .removeClass( "ui-corner-all" );
+ this.active.next()
+ .addClass( "ui-accordion-content-active" )
+ .show();
+
+ this.headers
+ .attr( "role", "tab" )
+ .each(function( i ) {
+ var header = $( this ),
+ headerId = header.attr( "id" ),
+ panel = header.next(),
+ panelId = panel.attr( "id" );
+ if ( !headerId ) {
+ headerId = accordionId + "-header-" + i;
+ header.attr( "id", headerId );
+ }
+ if ( !panelId ) {
+ panelId = accordionId + "-panel-" + i;
+ panel.attr( "id", panelId );
+ }
+ header.attr( "aria-controls", panelId );
+ panel.attr( "aria-labelledby", headerId );
+ })
+ .next()
+ .attr( "role", "tabpanel" );
+
+ this.headers
+ .not( this.active )
+ .attr({
+ "aria-selected": "false",
+ tabIndex: -1
+ })
+ .next()
+ .attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ })
+ .hide();
+
+ // make sure at least one header is in the tab order
+ if ( !this.active.length ) {
+ this.headers.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active.attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ })
+ .next()
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ }
+
+ this._createIcons();
+
+ this._setupEvents( options.event );
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.headers.each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.headers.next()
+ .each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.headers.next()
+ .each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
+ })
+ .height( maxHeight );
+ }
+ },
+
+ _activate: function( index ) {
+ var active = this._findActive( index )[ 0 ];
+
+ // trying to activate the already active panel
+ if ( active === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the currently active header
+ active = active || this.active[ 0 ];
+
+ this._eventHandler({
+ target: active,
+ currentTarget: active,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( selector ) {
+ return typeof selector === "number" ? this.headers.eq( selector ) : $();
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ keydown: "_keydown"
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.headers.add( this.headers.next() ) );
+ this._on( this.headers, events );
+ this._on( this.headers.next(), { keydown: "_panelKeyDown" });
+ this._hoverable( this.headers );
+ this._focusable( this.headers );
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ clicked = $( event.currentTarget ),
+ clickedIsActive = clicked[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : clicked.next(),
+ toHide = active.next(),
+ eventData = {
+ oldHeader: active,
+ oldPanel: toHide,
+ newHeader: collapsing ? $() : clicked,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if (
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.headers.index( clicked );
+
+ // when the call to ._toggle() comes after the class changes
+ // it causes a very odd bug in IE 8 (see #6720)
+ this.active = clickedIsActive ? $() : clicked;
+ this._toggle( eventData );
+
+ // switch classes
+ // corner classes on the previously active header stay after the animation
+ active.removeClass( "ui-accordion-header-active ui-state-active" );
+ if ( options.icons ) {
+ active.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.activeHeader )
+ .addClass( options.icons.header );
+ }
+
+ if ( !clickedIsActive ) {
+ clicked
+ .removeClass( "ui-corner-all" )
+ .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
+ if ( options.icons ) {
+ clicked.children( ".ui-accordion-header-icon" )
+ .removeClass( options.icons.header )
+ .addClass( options.icons.activeHeader );
+ }
+
+ clicked
+ .next()
+ .addClass( "ui-accordion-content-active" );
+ }
+ },
+
+ _toggle: function( data ) {
+ var toShow = data.newPanel,
+ toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
+
+ // handle activating a panel during the animation for another activation
+ this.prevShow.add( this.prevHide ).stop( true, true );
+ this.prevShow = toShow;
+ this.prevHide = toHide;
+
+ if ( this.options.animate ) {
+ this._animate( toShow, toHide, data );
+ } else {
+ toHide.hide();
+ toShow.show();
+ this._toggleComplete( data );
+ }
+
+ toHide.attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+ toHide.prev().attr( "aria-selected", "false" );
+ // if we're switching panels, remove the old header from the tab order
+ // if we're opening from collapsed state, remove the previous header from the tab order
+ // if we're collapsing, then keep the collapsing header in the tab order
+ if ( toShow.length && toHide.length ) {
+ toHide.prev().attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.headers.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ })
+ .prev()
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ },
+
+ _animate: function( toShow, toHide, data ) {
+ var total, easing, duration,
+ that = this,
+ adjust = 0,
+ down = toShow.length &&
+ ( !toHide.length || ( toShow.index() < toHide.index() ) ),
+ animate = this.options.animate || {},
+ options = down && animate.down || animate,
+ complete = function() {
+ that._toggleComplete( data );
+ };
+
+ if ( typeof options === "number" ) {
+ duration = options;
+ }
+ if ( typeof options === "string" ) {
+ easing = options;
+ }
+ // fall back from options to animation in case of partial down settings
+ easing = easing || options.easing || animate.easing;
+ duration = duration || options.duration || animate.duration;
+
+ if ( !toHide.length ) {
+ return toShow.animate( showProps, duration, easing, complete );
+ }
+ if ( !toShow.length ) {
+ return toHide.animate( hideProps, duration, easing, complete );
+ }
+
+ total = toShow.show().outerHeight();
+ toHide.animate( hideProps, {
+ duration: duration,
+ easing: easing,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ }
+ });
+ toShow
+ .hide()
+ .animate( showProps, {
+ duration: duration,
+ easing: easing,
+ complete: complete,
+ step: function( now, fx ) {
+ fx.now = Math.round( now );
+ if ( fx.prop !== "height" ) {
+ adjust += fx.now;
+ } else if ( that.options.heightStyle !== "content" ) {
+ fx.now = Math.round( total - toHide.outerHeight() - adjust );
+ adjust = 0;
+ }
+ }
+ });
+ },
+
+ _toggleComplete: function( data ) {
+ var toHide = data.oldPanel;
+
+ toHide
+ .removeClass( "ui-accordion-content-active" )
+ .prev()
+ .removeClass( "ui-corner-top" )
+ .addClass( "ui-corner-all" );
+
+ // Work around for rendering bug in IE (#5421)
+ if ( toHide.length ) {
+ toHide.parent()[0].className = toHide.parent()[0].className;
+ }
+
+ this._trigger( "activate", null, data );
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// used to prevent race conditions with remote data sources
+var requestIndex = 0;
+
+$.widget( "ui.autocomplete", {
+ version: "1.10.3",
+ defaultElement: "<input>",
+ options: {
+ appendTo: null,
+ autoFocus: false,
+ delay: 300,
+ minLength: 1,
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ source: null,
+
+ // callbacks
+ change: null,
+ close: null,
+ focus: null,
+ open: null,
+ response: null,
+ search: null,
+ select: null
+ },
+
+ pending: 0,
+
+ _create: function() {
+ // Some browsers only repeat keydown events, not keypress events,
+ // so we use the suppressKeyPress flag to determine if we've already
+ // handled the keydown event. #7269
+ // Unfortunately the code for & in keypress is the same as the up arrow,
+ // so we use the suppressKeyPressRepeat flag to avoid handling keypress
+ // events when we know the keydown event was used to modify the
+ // search term. #7799
+ var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
+ nodeName = this.element[0].nodeName.toLowerCase(),
+ isTextarea = nodeName === "textarea",
+ isInput = nodeName === "input";
+
+ this.isMultiLine =
+ // Textareas are always multi-line
+ isTextarea ? true :
+ // Inputs are always single-line, even if inside a contentEditable element
+ // IE also treats inputs as contentEditable
+ isInput ? false :
+ // All other element types are determined by whether or not they're contentEditable
+ this.element.prop( "isContentEditable" );
+
+ this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
+ this.isNewMenu = true;
+
+ this.element
+ .addClass( "ui-autocomplete-input" )
+ .attr( "autocomplete", "off" );
+
+ this._on( this.element, {
+ keydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ if ( this.element.prop( "readOnly" ) ) {
+ suppressKeyPress = true;
+ suppressInput = true;
+ suppressKeyPressRepeat = true;
+ return;
+ }
+
+ suppressKeyPress = false;
+ suppressInput = false;
+ suppressKeyPressRepeat = false;
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ suppressKeyPress = true;
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ suppressKeyPress = true;
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ suppressKeyPress = true;
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ suppressKeyPress = true;
+ this._keyEvent( "next", event );
+ break;
+ case keyCode.ENTER:
+ case keyCode.NUMPAD_ENTER:
+ // when menu is open and has focus
+ if ( this.menu.active ) {
+ // #6055 - Opera still allows the keypress to occur
+ // which causes forms to submit
+ suppressKeyPress = true;
+ event.preventDefault();
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.TAB:
+ if ( this.menu.active ) {
+ this.menu.select( event );
+ }
+ break;
+ case keyCode.ESCAPE:
+ if ( this.menu.element.is( ":visible" ) ) {
+ this._value( this.term );
+ this.close( event );
+ // Different browsers have different default behavior for escape
+ // Single press can mean undo or clear
+ // Double press in IE means clear the whole form
+ event.preventDefault();
+ }
+ break;
+ default:
+ suppressKeyPressRepeat = true;
+ // search timeout should be triggered before the input value is changed
+ this._searchTimeout( event );
+ break;
+ }
+ },
+ keypress: function( event ) {
+ if ( suppressKeyPress ) {
+ suppressKeyPress = false;
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ event.preventDefault();
+ }
+ return;
+ }
+ if ( suppressKeyPressRepeat ) {
+ return;
+ }
+
+ // replicate some key handlers to allow them to repeat in Firefox and Opera
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ this._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ this._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ this._keyEvent( "previous", event );
+ break;
+ case keyCode.DOWN:
+ this._keyEvent( "next", event );
+ break;
+ }
+ },
+ input: function( event ) {
+ if ( suppressInput ) {
+ suppressInput = false;
+ event.preventDefault();
+ return;
+ }
+ this._searchTimeout( event );
+ },
+ focus: function() {
+ this.selectedItem = null;
+ this.previous = this._value();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ clearTimeout( this.searching );
+ this.close( event );
+ this._change( event );
+ }
+ });
+
+ this._initSource();
+ this.menu = $( "<ul>" )
+ .addClass( "ui-autocomplete ui-front" )
+ .appendTo( this._appendTo() )
+ .menu({
+ // disable ARIA support, the live region takes care of that
+ role: null
+ })
+ .hide()
+ .data( "ui-menu" );
+
+ this._on( this.menu.element, {
+ mousedown: function( event ) {
+ // prevent moving focus out of the text field
+ event.preventDefault();
+
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ });
+
+ // clicking on the scrollbar causes focus to shift to the body
+ // but we can't detect a mouseup or a click immediately afterward
+ // so we have to track the next mousedown and close the menu if
+ // the user clicks somewhere outside of the autocomplete
+ var menuElement = this.menu.element[ 0 ];
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+ this._delay(function() {
+ var that = this;
+ this.document.one( "mousedown", function( event ) {
+ if ( event.target !== that.element[ 0 ] &&
+ event.target !== menuElement &&
+ !$.contains( menuElement, event.target ) ) {
+ that.close();
+ }
+ });
+ });
+ }
+ },
+ menufocus: function( event, ui ) {
+ // support: Firefox
+ // Prevent accidental activation of menu items in Firefox (#7024 #9118)
+ if ( this.isNewMenu ) {
+ this.isNewMenu = false;
+ if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
+ this.menu.blur();
+
+ this.document.one( "mousemove", function() {
+ $( event.target ).trigger( event.originalEvent );
+ });
+
+ return;
+ }
+ }
+
+ var item = ui.item.data( "ui-autocomplete-item" );
+ if ( false !== this._trigger( "focus", event, { item: item } ) ) {
+ // use value to match what will end up in the input, if it was a key event
+ if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
+ this._value( item.value );
+ }
+ } else {
+ // Normally the input is populated with the item's value as the
+ // menu is navigated, causing screen readers to notice a change and
+ // announce the item. Since the focus event was canceled, this doesn't
+ // happen, so we update the live region so that screen readers can
+ // still notice the change and announce it.
+ this.liveRegion.text( item.value );
+ }
+ },
+ menuselect: function( event, ui ) {
+ var item = ui.item.data( "ui-autocomplete-item" ),
+ previous = this.previous;
+
+ // only trigger when focus was lost (click on menu)
+ if ( this.element[0] !== this.document[0].activeElement ) {
+ this.element.focus();
+ this.previous = previous;
+ // #6109 - IE triggers two focus events and the second
+ // is asynchronous, so we need to reset the previous
+ // term synchronously and asynchronously :-(
+ this._delay(function() {
+ this.previous = previous;
+ this.selectedItem = item;
+ });
+ }
+
+ if ( false !== this._trigger( "select", event, { item: item } ) ) {
+ this._value( item.value );
+ }
+ // reset the term after the select event
+ // this allows custom select handling to work properly
+ this.term = this._value();
+
+ this.close( event );
+ this.selectedItem = item;
+ }
+ });
+
+ this.liveRegion = $( "<span>", {
+ role: "status",
+ "aria-live": "polite"
+ })
+ .addClass( "ui-helper-hidden-accessible" )
+ .insertBefore( this.element );
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _destroy: function() {
+ clearTimeout( this.searching );
+ this.element
+ .removeClass( "ui-autocomplete-input" )
+ .removeAttr( "autocomplete" );
+ this.menu.element.remove();
+ this.liveRegion.remove();
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "source" ) {
+ this._initSource();
+ }
+ if ( key === "appendTo" ) {
+ this.menu.element.appendTo( this._appendTo() );
+ }
+ if ( key === "disabled" && value && this.xhr ) {
+ this.xhr.abort();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+
+ if ( element ) {
+ element = element.jquery || element.nodeType ?
+ $( element ) :
+ this.document.find( element ).eq( 0 );
+ }
+
+ if ( !element ) {
+ element = this.element.closest( ".ui-front" );
+ }
+
+ if ( !element.length ) {
+ element = this.document[0].body;
+ }
+
+ return element;
+ },
+
+ _initSource: function() {
+ var array, url,
+ that = this;
+ if ( $.isArray(this.options.source) ) {
+ array = this.options.source;
+ this.source = function( request, response ) {
+ response( $.ui.autocomplete.filter( array, request.term ) );
+ };
+ } else if ( typeof this.options.source === "string" ) {
+ url = this.options.source;
+ this.source = function( request, response ) {
+ if ( that.xhr ) {
+ that.xhr.abort();
+ }
+ that.xhr = $.ajax({
+ url: url,
+ data: request,
+ dataType: "json",
+ success: function( data ) {
+ response( data );
+ },
+ error: function() {
+ response( [] );
+ }
+ });
+ };
+ } else {
+ this.source = this.options.source;
+ }
+ },
+
+ _searchTimeout: function( event ) {
+ clearTimeout( this.searching );
+ this.searching = this._delay(function() {
+ // only search if the value has changed
+ if ( this.term !== this._value() ) {
+ this.selectedItem = null;
+ this.search( null, event );
+ }
+ }, this.options.delay );
+ },
+
+ search: function( value, event ) {
+ value = value != null ? value : this._value();
+
+ // always save the actual value, not the one passed as an argument
+ this.term = this._value();
+
+ if ( value.length < this.options.minLength ) {
+ return this.close( event );
+ }
+
+ if ( this._trigger( "search", event ) === false ) {
+ return;
+ }
+
+ return this._search( value );
+ },
+
+ _search: function( value ) {
+ this.pending++;
+ this.element.addClass( "ui-autocomplete-loading" );
+ this.cancelSearch = false;
+
+ this.source( { term: value }, this._response() );
+ },
+
+ _response: function() {
+ var that = this,
+ index = ++requestIndex;
+
+ return function( content ) {
+ if ( index === requestIndex ) {
+ that.__response( content );
+ }
+
+ that.pending--;
+ if ( !that.pending ) {
+ that.element.removeClass( "ui-autocomplete-loading" );
+ }
+ };
+ },
+
+ __response: function( content ) {
+ if ( content ) {
+ content = this._normalize( content );
+ }
+ this._trigger( "response", null, { content: content } );
+ if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
+ this._suggest( content );
+ this._trigger( "open" );
+ } else {
+ // use ._close() instead of .close() so we don't cancel future searches
+ this._close();
+ }
+ },
+
+ close: function( event ) {
+ this.cancelSearch = true;
+ this._close( event );
+ },
+
+ _close: function( event ) {
+ if ( this.menu.element.is( ":visible" ) ) {
+ this.menu.element.hide();
+ this.menu.blur();
+ this.isNewMenu = true;
+ this._trigger( "close", event );
+ }
+ },
+
+ _change: function( event ) {
+ if ( this.previous !== this._value() ) {
+ this._trigger( "change", event, { item: this.selectedItem } );
+ }
+ },
+
+ _normalize: function( items ) {
+ // assume all items have the right format when the first item is complete
+ if ( items.length && items[0].label && items[0].value ) {
+ return items;
+ }
+ return $.map( items, function( item ) {
+ if ( typeof item === "string" ) {
+ return {
+ label: item,
+ value: item
+ };
+ }
+ return $.extend({
+ label: item.label || item.value,
+ value: item.value || item.label
+ }, item );
+ });
+ },
+
+ _suggest: function( items ) {
+ var ul = this.menu.element.empty();
+ this._renderMenu( ul, items );
+ this.isNewMenu = true;
+ this.menu.refresh();
+
+ // size and position menu
+ ul.show();
+ this._resizeMenu();
+ ul.position( $.extend({
+ of: this.element
+ }, this.options.position ));
+
+ if ( this.options.autoFocus ) {
+ this.menu.next();
+ }
+ },
+
+ _resizeMenu: function() {
+ var ul = this.menu.element;
+ ul.outerWidth( Math.max(
+ // Firefox wraps long text (possibly a rounding bug)
+ // so we add 1px to avoid the wrapping (#7513)
+ ul.width( "" ).outerWidth() + 1,
+ this.element.outerWidth()
+ ) );
+ },
+
+ _renderMenu: function( ul, items ) {
+ var that = this;
+ $.each( items, function( index, item ) {
+ that._renderItemData( ul, item );
+ });
+ },
+
+ _renderItemData: function( ul, item ) {
+ return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
+ },
+
+ _renderItem: function( ul, item ) {
+ return $( "<li>" )
+ .append( $( "<a>" ).text( item.label ) )
+ .appendTo( ul );
+ },
+
+ _move: function( direction, event ) {
+ if ( !this.menu.element.is( ":visible" ) ) {
+ this.search( null, event );
+ return;
+ }
+ if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
+ this.menu.isLastItem() && /^next/.test( direction ) ) {
+ this._value( this.term );
+ this.menu.blur();
+ return;
+ }
+ this.menu[ direction ]( event );
+ },
+
+ widget: function() {
+ return this.menu.element;
+ },
+
+ _value: function() {
+ return this.valueMethod.apply( this.element, arguments );
+ },
+
+ _keyEvent: function( keyEvent, event ) {
+ if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+ this._move( keyEvent, event );
+
+ // prevents moving cursor to beginning/end of the text field in some browsers
+ event.preventDefault();
+ }
+ }
+});
+
+$.extend( $.ui.autocomplete, {
+ escapeRegex: function( value ) {
+ return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+ },
+ filter: function(array, term) {
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+ return $.grep( array, function(value) {
+ return matcher.test( value.label || value.value || value );
+ });
+ }
+});
+
+
+// live region extension, adding a `messages` option
+// NOTE: This is an experimental API. We are still investigating
+// a full solution for string manipulation and internationalization.
+$.widget( "ui.autocomplete", $.ui.autocomplete, {
+ options: {
+ messages: {
+ noResults: "No search results.",
+ results: function( amount ) {
+ return amount + ( amount > 1 ? " results are" : " result is" ) +
+ " available, use up and down arrow keys to navigate.";
+ }
+ }
+ },
+
+ __response: function( content ) {
+ var message;
+ this._superApply( arguments );
+ if ( this.options.disabled || this.cancelSearch ) {
+ return;
+ }
+ if ( content && content.length ) {
+ message = this.options.messages.results( content.length );
+ } else {
+ message = this.options.messages.noResults;
+ }
+ this.liveRegion.text( message );
+ }
+});
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+var lastActive, startXPos, startYPos, clickDragged,
+ baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
+ stateClasses = "ui-state-hover ui-state-active ",
+ typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
+ formResetHandler = function() {
+ var form = $( this );
+ setTimeout(function() {
+ form.find( ":ui-button" ).button( "refresh" );
+ }, 1 );
+ },
+ radioGroup = function( radio ) {
+ var name = radio.name,
+ form = radio.form,
+ radios = $( [] );
+ if ( name ) {
+ name = name.replace( /'/g, "\\'" );
+ if ( form ) {
+ radios = $( form ).find( "[name='" + name + "']" );
+ } else {
+ radios = $( "[name='" + name + "']", radio.ownerDocument )
+ .filter(function() {
+ return !this.form;
+ });
+ }
+ }
+ return radios;
+ };
+
+$.widget( "ui.button", {
+ version: "1.10.3",
+ defaultElement: "<button>",
+ options: {
+ disabled: null,
+ text: true,
+ label: null,
+ icons: {
+ primary: null,
+ secondary: null
+ }
+ },
+ _create: function() {
+ this.element.closest( "form" )
+ .unbind( "reset" + this.eventNamespace )
+ .bind( "reset" + this.eventNamespace, formResetHandler );
+
+ if ( typeof this.options.disabled !== "boolean" ) {
+ this.options.disabled = !!this.element.prop( "disabled" );
+ } else {
+ this.element.prop( "disabled", this.options.disabled );
+ }
+
+ this._determineButtonType();
+ this.hasTitle = !!this.buttonElement.attr( "title" );
+
+ var that = this,
+ options = this.options,
+ toggleButton = this.type === "checkbox" || this.type === "radio",
+ activeClass = !toggleButton ? "ui-state-active" : "",
+ focusClass = "ui-state-focus";
+
+ if ( options.label === null ) {
+ options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
+ }
+
+ this._hoverable( this.buttonElement );
+
+ this.buttonElement
+ .addClass( baseClasses )
+ .attr( "role", "button" )
+ .bind( "mouseenter" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( this === lastActive ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ .bind( "mouseleave" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).removeClass( activeClass );
+ })
+ .bind( "click" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ });
+
+ this.element
+ .bind( "focus" + this.eventNamespace, function() {
+ // no need to check disabled, focus won't be triggered anyway
+ that.buttonElement.addClass( focusClass );
+ })
+ .bind( "blur" + this.eventNamespace, function() {
+ that.buttonElement.removeClass( focusClass );
+ });
+
+ if ( toggleButton ) {
+ this.element.bind( "change" + this.eventNamespace, function() {
+ if ( clickDragged ) {
+ return;
+ }
+ that.refresh();
+ });
+ // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
+ // prevents issue where button state changes but checkbox/radio checked state
+ // does not in Firefox (see ticket #6970)
+ this.buttonElement
+ .bind( "mousedown" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ clickDragged = false;
+ startXPos = event.pageX;
+ startYPos = event.pageY;
+ })
+ .bind( "mouseup" + this.eventNamespace, function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
+ clickDragged = true;
+ }
+ });
+ }
+
+ if ( this.type === "checkbox" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ });
+ } else if ( this.type === "radio" ) {
+ this.buttonElement.bind( "click" + this.eventNamespace, function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ that.buttonElement.attr( "aria-pressed", "true" );
+
+ var radio = that.element[ 0 ];
+ radioGroup( radio )
+ .not( radio )
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ });
+ } else {
+ this.buttonElement
+ .bind( "mousedown" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ lastActive = this;
+ that.document.one( "mouseup", function() {
+ lastActive = null;
+ });
+ })
+ .bind( "mouseup" + this.eventNamespace, function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).removeClass( "ui-state-active" );
+ })
+ .bind( "keydown" + this.eventNamespace, function(event) {
+ if ( options.disabled ) {
+ return false;
+ }
+ if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ // see #8559, we bind to blur here in case the button element loses
+ // focus between keydown and keyup, it would be left in an "active" state
+ .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
+ $( this ).removeClass( "ui-state-active" );
+ });
+
+ if ( this.buttonElement.is("a") ) {
+ this.buttonElement.keyup(function(event) {
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
+ // TODO pass through original event correctly (just as 2nd argument doesn't work)
+ $( this ).click();
+ }
+ });
+ }
+ }
+
+ // TODO: pull out $.Widget's handling for the disabled option into
+ // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
+ // be overridden by individual plugins
+ this._setOption( "disabled", options.disabled );
+ this._resetButton();
+ },
+
+ _determineButtonType: function() {
+ var ancestor, labelSelector, checked;
+
+ if ( this.element.is("[type=checkbox]") ) {
+ this.type = "checkbox";
+ } else if ( this.element.is("[type=radio]") ) {
+ this.type = "radio";
+ } else if ( this.element.is("input") ) {
+ this.type = "input";
+ } else {
+ this.type = "button";
+ }
+
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ // we don't search against the document in case the element
+ // is disconnected from the DOM
+ ancestor = this.element.parents().last();
+ labelSelector = "label[for='" + this.element.attr("id") + "']";
+ this.buttonElement = ancestor.find( labelSelector );
+ if ( !this.buttonElement.length ) {
+ ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
+ this.buttonElement = ancestor.filter( labelSelector );
+ if ( !this.buttonElement.length ) {
+ this.buttonElement = ancestor.find( labelSelector );
+ }
+ }
+ this.element.addClass( "ui-helper-hidden-accessible" );
+
+ checked = this.element.is( ":checked" );
+ if ( checked ) {
+ this.buttonElement.addClass( "ui-state-active" );
+ }
+ this.buttonElement.prop( "aria-pressed", checked );
+ } else {
+ this.buttonElement = this.element;
+ }
+ },
+
+ widget: function() {
+ return this.buttonElement;
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-helper-hidden-accessible" );
+ this.buttonElement
+ .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
+ .removeAttr( "role" )
+ .removeAttr( "aria-pressed" )
+ .html( this.buttonElement.find(".ui-button-text").html() );
+
+ if ( !this.hasTitle ) {
+ this.buttonElement.removeAttr( "title" );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ this._super( key, value );
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.prop( "disabled", true );
+ } else {
+ this.element.prop( "disabled", false );
+ }
+ return;
+ }
+ this._resetButton();
+ },
+
+ refresh: function() {
+ //See #8237 & #8828
+ var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOption( "disabled", isDisabled );
+ }
+ if ( this.type === "radio" ) {
+ radioGroup( this.element[0] ).each(function() {
+ if ( $( this ).is( ":checked" ) ) {
+ $( this ).button( "widget" )
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ $( this ).button( "widget" )
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ });
+ } else if ( this.type === "checkbox" ) {
+ if ( this.element.is( ":checked" ) ) {
+ this.buttonElement
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ this.buttonElement
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ }
+ },
+
+ _resetButton: function() {
+ if ( this.type === "input" ) {
+ if ( this.options.label ) {
+ this.element.val( this.options.label );
+ }
+ return;
+ }
+ var buttonElement = this.buttonElement.removeClass( typeClasses ),
+ buttonText = $( "<span></span>", this.document[0] )
+ .addClass( "ui-button-text" )
+ .html( this.options.label )
+ .appendTo( buttonElement.empty() )
+ .text(),
+ icons = this.options.icons,
+ multipleIcons = icons.primary && icons.secondary,
+ buttonClasses = [];
+
+ if ( icons.primary || icons.secondary ) {
+ if ( this.options.text ) {
+ buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
+ }
+
+ if ( icons.primary ) {
+ buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
+ }
+
+ if ( icons.secondary ) {
+ buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
+ }
+
+ if ( !this.options.text ) {
+ buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
+
+ if ( !this.hasTitle ) {
+ buttonElement.attr( "title", $.trim( buttonText ) );
+ }
+ }
+ } else {
+ buttonClasses.push( "ui-button-text-only" );
+ }
+ buttonElement.addClass( buttonClasses.join( " " ) );
+ }
+});
+
+$.widget( "ui.buttonset", {
+ version: "1.10.3",
+ options: {
+ items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
+ },
+
+ _create: function() {
+ this.element.addClass( "ui-buttonset" );
+ },
+
+ _init: function() {
+ this.refresh();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "disabled" ) {
+ this.buttons.button( "option", key, value );
+ }
+
+ this._super( key, value );
+ },
+
+ refresh: function() {
+ var rtl = this.element.css( "direction" ) === "rtl";
+
+ this.buttons = this.element.find( this.options.items )
+ .filter( ":ui-button" )
+ .button( "refresh" )
+ .end()
+ .not( ":ui-button" )
+ .button()
+ .end()
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
+ .filter( ":first" )
+ .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
+ .end()
+ .filter( ":last" )
+ .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
+ .end()
+ .end();
+ },
+
+ _destroy: function() {
+ this.element.removeClass( "ui-buttonset" );
+ this.buttons
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-left ui-corner-right" )
+ .end()
+ .button( "destroy" );
+ }
+});
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+$.extend($.ui, { datepicker: { version: "1.10.3" } });
+
+var PROP_NAME = "datepicker",
+ instActive;
+
+/* Date picker manager.
+ Use the singleton instance of this class, $.datepicker, to interact with the date picker.
+ Settings for (groups of) date pickers are maintained in an instance object,
+ allowing multiple different settings on the same page. */
+
+function Datepicker() {
+ this._curInst = null; // The current instance in use
+ this._keyEvent = false; // If the last event was a key event
+ this._disabledInputs = []; // List of date picker inputs that have been disabled
+ this._datepickerShowing = false; // True if the popup picker is showing , false if not
+ this._inDialog = false; // True if showing within a "dialog", false if not
+ this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
+ this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
+ this._appendClass = "ui-datepicker-append"; // The name of the append marker class
+ this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
+ this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
+ this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
+ this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
+ this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
+ this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[""] = { // Default regional settings
+ closeText: "Done", // Display text for close link
+ prevText: "Prev", // Display text for previous month link
+ nextText: "Next", // Display text for next month link
+ currentText: "Today", // Display text for current month link
+ monthNames: ["January","February","March","April","May","June",
+ "July","August","September","October","November","December"], // Names of months for drop-down and formatting
+ monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
+ dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
+ dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
+ dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
+ weekHeader: "Wk", // Column header for week of the year
+ dateFormat: "mm/dd/yy", // See format options on parseDate
+ firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
+ isRTL: false, // True if right-to-left language, false if left-to-right
+ showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+ yearSuffix: "" // Additional text to append to the year in the month headers
+ };
+ this._defaults = { // Global defaults for all the date picker instances
+ showOn: "focus", // "focus" for popup on focus,
+ // "button" for trigger button, or "both" for either
+ showAnim: "fadeIn", // Name of jQuery animation for popup
+ showOptions: {}, // Options for enhanced animations
+ defaultDate: null, // Used when field is blank: actual date,
+ // +/-number for offset from today, null for today
+ appendText: "", // Display text following the input box, e.g. showing the format
+ buttonText: "...", // Text for trigger button
+ buttonImage: "", // URL for trigger button image
+ buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
+ hideIfNoPrevNext: false, // True to hide next/previous month links
+ // if not applicable, false to just disable them
+ navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
+ gotoCurrent: false, // True if today link goes back to current selection instead
+ changeMonth: false, // True if month can be selected directly, false if only prev/next
+ changeYear: false, // True if year can be selected directly, false if only prev/next
+ yearRange: "c-10:c+10", // Range of years to display in drop-down,
+ // either relative to today's year (-nn:+nn), relative to currently displayed year
+ // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
+ showOtherMonths: false, // True to show dates in other months, false to leave blank
+ selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
+ showWeek: false, // True to show week of the year, false to not show it
+ calculateWeek: this.iso8601Week, // How to calculate the week of the year,
+ // takes a Date and returns the number of the week for it
+ shortYearCutoff: "+10", // Short year values < this are in the current century,
+ // > this are in the previous century,
+ // string value starting with "+" for current year + value
+ minDate: null, // The earliest selectable date, or null for no limit
+ maxDate: null, // The latest selectable date, or null for no limit
+ duration: "fast", // Duration of display/closure
+ beforeShowDay: null, // Function that takes a date and returns an array with
+ // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
+ // [2] = cell title (optional), e.g. $.datepicker.noWeekends
+ beforeShow: null, // Function that takes an input field and
+ // returns a set of custom settings for the date picker
+ onSelect: null, // Define a callback function when a date is selected
+ onChangeMonthYear: null, // Define a callback function when the month or year is changed
+ onClose: null, // Define a callback function when the datepicker is closed
+ numberOfMonths: 1, // Number of months to show at a time
+ showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
+ stepMonths: 1, // Number of months to step back/forward
+ stepBigMonths: 12, // Number of months to step back/forward for the big links
+ altField: "", // Selector for an alternate field to store selected dates into
+ altFormat: "", // The date format to use for the alternate field
+ constrainInput: true, // The input is constrained by the current date format
+ showButtonPanel: false, // True to show button panel, false to not show it
+ autoSize: false, // True to size the input for the date format, false to leave as is
+ disabled: false // The initial disabled state
+ };
+ $.extend(this._defaults, this.regional[""]);
+ this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
+}
+
+$.extend(Datepicker.prototype, {
+ /* Class name added to elements to indicate already configured with a date picker. */
+ markerClassName: "hasDatepicker",
+
+ //Keep track of the maximum number of rows displayed (see #7043)
+ maxRows: 4,
+
+ // TODO rename to "widget" when switching to widget factory
+ _widgetDatepicker: function() {
+ return this.dpDiv;
+ },
+
+ /* Override the default settings for all instances of the date picker.
+ * @param settings object - the new settings to use as defaults (anonymous object)
+ * @return the manager object
+ */
+ setDefaults: function(settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /* Attach the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param settings object - the new settings to use for this date picker instance (anonymous)
+ */
+ _attachDatepicker: function(target, settings) {
+ var nodeName, inline, inst;
+ nodeName = target.nodeName.toLowerCase();
+ inline = (nodeName === "div" || nodeName === "span");
+ if (!target.id) {
+ this.uuid += 1;
+ target.id = "dp" + this.uuid;
+ }
+ inst = this._newInst($(target), inline);
+ inst.settings = $.extend({}, settings || {});
+ if (nodeName === "input") {
+ this._connectDatepicker(target, inst);
+ } else if (inline) {
+ this._inlineDatepicker(target, inst);
+ }
+ },
+
+ /* Create a new instance object. */
+ _newInst: function(target, inline) {
+ var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
+ return {id: id, input: target, // associated target
+ selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
+ drawMonth: 0, drawYear: 0, // month being drawn
+ inline: inline, // is datepicker inline or not
+ dpDiv: (!inline ? this.dpDiv : // presentation div
+ bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
+ },
+
+ /* Attach the date picker to an input field. */
+ _connectDatepicker: function(target, inst) {
+ var input = $(target);
+ inst.append = $([]);
+ inst.trigger = $([]);
+ if (input.hasClass(this.markerClassName)) {
+ return;
+ }
+ this._attachments(input, inst);
+ input.addClass(this.markerClassName).keydown(this._doKeyDown).
+ keypress(this._doKeyPress).keyup(this._doKeyUp);
+ this._autoSize(inst);
+ $.data(target, PROP_NAME, inst);
+ //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ },
+
+ /* Make attachments based on settings. */
+ _attachments: function(input, inst) {
+ var showOn, buttonText, buttonImage,
+ appendText = this._get(inst, "appendText"),
+ isRTL = this._get(inst, "isRTL");
+
+ if (inst.append) {
+ inst.append.remove();
+ }
+ if (appendText) {
+ inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
+ input[isRTL ? "before" : "after"](inst.append);
+ }
+
+ input.unbind("focus", this._showDatepicker);
+
+ if (inst.trigger) {
+ inst.trigger.remove();
+ }
+
+ showOn = this._get(inst, "showOn");
+ if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
+ input.focus(this._showDatepicker);
+ }
+ if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
+ buttonText = this._get(inst, "buttonText");
+ buttonImage = this._get(inst, "buttonImage");
+ inst.trigger = $(this._get(inst, "buttonImageOnly") ?
+ $("<img/>").addClass(this._triggerClass).
+ attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
+ $("<button type='button'></button>").addClass(this._triggerClass).
+ html(!buttonImage ? buttonText : $("<img/>").attr(
+ { src:buttonImage, alt:buttonText, title:buttonText })));
+ input[isRTL ? "before" : "after"](inst.trigger);
+ inst.trigger.click(function() {
+ if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
+ $.datepicker._hideDatepicker();
+ } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
+ $.datepicker._hideDatepicker();
+ $.datepicker._showDatepicker(input[0]);
+ } else {
+ $.datepicker._showDatepicker(input[0]);
+ }
+ return false;
+ });
+ }
+ },
+
+ /* Apply the maximum length for the date format. */
+ _autoSize: function(inst) {
+ if (this._get(inst, "autoSize") && !inst.inline) {
+ var findMax, max, maxI, i,
+ date = new Date(2009, 12 - 1, 20), // Ensure double digits
+ dateFormat = this._get(inst, "dateFormat");
+
+ if (dateFormat.match(/[DM]/)) {
+ findMax = function(names) {
+ max = 0;
+ maxI = 0;
+ for (i = 0; i < names.length; i++) {
+ if (names[i].length > max) {
+ max = names[i].length;
+ maxI = i;
+ }
+ }
+ return maxI;
+ };
+ date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
+ "monthNames" : "monthNamesShort"))));
+ date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
+ "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
+ }
+ inst.input.attr("size", this._formatDate(inst, date).length);
+ }
+ },
+
+ /* Attach an inline date picker to a div. */
+ _inlineDatepicker: function(target, inst) {
+ var divSpan = $(target);
+ if (divSpan.hasClass(this.markerClassName)) {
+ return;
+ }
+ divSpan.addClass(this.markerClassName).append(inst.dpDiv);
+ $.data(target, PROP_NAME, inst);
+ this._setDate(inst, this._getDefaultDate(inst), true);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
+ // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
+ inst.dpDiv.css( "display", "block" );
+ },
+
+ /* Pop-up the date picker in a "dialog" box.
+ * @param input element - ignored
+ * @param date string or Date - the initial date to display
+ * @param onSelect function - the function to call when a date is selected
+ * @param settings object - update the dialog date picker instance's settings (anonymous object)
+ * @param pos int[2] - coordinates for the dialog's position within the screen or
+ * event - with x/y coordinates or
+ * leave empty for default (screen centre)
+ * @return the manager object
+ */
+ _dialogDatepicker: function(input, date, onSelect, settings, pos) {
+ var id, browserWidth, browserHeight, scrollX, scrollY,
+ inst = this._dialogInst; // internal instance
+
+ if (!inst) {
+ this.uuid += 1;
+ id = "dp" + this.uuid;
+ this._dialogInput = $("<input type='text' id='" + id +
+ "' style='position: absolute; top: -100px; width: 0px;'/>");
+ this._dialogInput.keydown(this._doKeyDown);
+ $("body").append(this._dialogInput);
+ inst = this._dialogInst = this._newInst(this._dialogInput, false);
+ inst.settings = {};
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ }
+ extendRemove(inst.settings, settings || {});
+ date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
+ this._dialogInput.val(date);
+
+ this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+ if (!this._pos) {
+ browserWidth = document.documentElement.clientWidth;
+ browserHeight = document.documentElement.clientHeight;
+ scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+ scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+ this._pos = // should use actual width/height below
+ [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
+ }
+
+ // move input on screen for focus, but hidden behind dialog
+ this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
+ inst.settings.onSelect = onSelect;
+ this._inDialog = true;
+ this.dpDiv.addClass(this._dialogClass);
+ this._showDatepicker(this._dialogInput[0]);
+ if ($.blockUI) {
+ $.blockUI(this.dpDiv);
+ }
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ return this;
+ },
+
+ /* Detach a datepicker from its control.
+ * @param target element - the target input field or division or span
+ */
+ _destroyDatepicker: function(target) {
+ var nodeName,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ $.removeData(target, PROP_NAME);
+ if (nodeName === "input") {
+ inst.append.remove();
+ inst.trigger.remove();
+ $target.removeClass(this.markerClassName).
+ unbind("focus", this._showDatepicker).
+ unbind("keydown", this._doKeyDown).
+ unbind("keypress", this._doKeyPress).
+ unbind("keyup", this._doKeyUp);
+ } else if (nodeName === "div" || nodeName === "span") {
+ $target.removeClass(this.markerClassName).empty();
+ }
+ },
+
+ /* Enable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _enableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = false;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = false; }).end().
+ filter("img").css({opacity: "1.0", cursor: ""});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().removeClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", false);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ },
+
+ /* Disable the date picker to a jQuery selection.
+ * @param target element - the target input field or division or span
+ */
+ _disableDatepicker: function(target) {
+ var nodeName, inline,
+ $target = $(target),
+ inst = $.data(target, PROP_NAME);
+
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+
+ nodeName = target.nodeName.toLowerCase();
+ if (nodeName === "input") {
+ target.disabled = true;
+ inst.trigger.filter("button").
+ each(function() { this.disabled = true; }).end().
+ filter("img").css({opacity: "0.5", cursor: "default"});
+ } else if (nodeName === "div" || nodeName === "span") {
+ inline = $target.children("." + this._inlineClass);
+ inline.children().addClass("ui-state-disabled");
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ prop("disabled", true);
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value === target ? null : value); }); // delete entry
+ this._disabledInputs[this._disabledInputs.length] = target;
+ },
+
+ /* Is the first field in a jQuery collection disabled as a datepicker?
+ * @param target element - the target input field or division or span
+ * @return boolean - true if disabled, false if enabled
+ */
+ _isDisabledDatepicker: function(target) {
+ if (!target) {
+ return false;
+ }
+ for (var i = 0; i < this._disabledInputs.length; i++) {
+ if (this._disabledInputs[i] === target) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /* Retrieve the instance data for the target control.
+ * @param target element - the target input field or division or span
+ * @return object - the associated instance data
+ * @throws error if a jQuery problem getting data
+ */
+ _getInst: function(target) {
+ try {
+ return $.data(target, PROP_NAME);
+ }
+ catch (err) {
+ throw "Missing instance data for this datepicker";
+ }
+ },
+
+ /* Update or retrieve the settings for a date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ * @param name object - the new settings to update or
+ * string - the name of the setting to change or retrieve,
+ * when retrieving also "all" for all instance settings or
+ * "defaults" for all global defaults
+ * @param value any - the new value for the setting
+ * (omit if above is an object or to retrieve a value)
+ */
+ _optionDatepicker: function(target, name, value) {
+ var settings, date, minDate, maxDate,
+ inst = this._getInst(target);
+
+ if (arguments.length === 2 && typeof name === "string") {
+ return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
+ (inst ? (name === "all" ? $.extend({}, inst.settings) :
+ this._get(inst, name)) : null));
+ }
+
+ settings = name || {};
+ if (typeof name === "string") {
+ settings = {};
+ settings[name] = value;
+ }
+
+ if (inst) {
+ if (this._curInst === inst) {
+ this._hideDatepicker();
+ }
+
+ date = this._getDateDatepicker(target, true);
+ minDate = this._getMinMaxDate(inst, "min");
+ maxDate = this._getMinMaxDate(inst, "max");
+ extendRemove(inst.settings, settings);
+ // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
+ if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
+ inst.settings.minDate = this._formatDate(inst, minDate);
+ }
+ if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
+ inst.settings.maxDate = this._formatDate(inst, maxDate);
+ }
+ if ( "disabled" in settings ) {
+ if ( settings.disabled ) {
+ this._disableDatepicker(target);
+ } else {
+ this._enableDatepicker(target);
+ }
+ }
+ this._attachments($(target), inst);
+ this._autoSize(inst);
+ this._setDate(inst, date);
+ this._updateAlternate(inst);
+ this._updateDatepicker(inst);
+ }
+ },
+
+ // change method deprecated
+ _changeDatepicker: function(target, name, value) {
+ this._optionDatepicker(target, name, value);
+ },
+
+ /* Redraw the date picker attached to an input field or division.
+ * @param target element - the target input field or division or span
+ */
+ _refreshDatepicker: function(target) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._updateDatepicker(inst);
+ }
+ },
+
+ /* Set the dates for a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param date Date - the new date
+ */
+ _setDateDatepicker: function(target, date) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._setDate(inst, date);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ }
+ },
+
+ /* Get the date(s) for the first entry in a jQuery selection.
+ * @param target element - the target input field or division or span
+ * @param noDefault boolean - true if no default date is to be used
+ * @return Date - the current date
+ */
+ _getDateDatepicker: function(target, noDefault) {
+ var inst = this._getInst(target);
+ if (inst && !inst.inline) {
+ this._setDateFromField(inst, noDefault);
+ }
+ return (inst ? this._getDate(inst) : null);
+ },
+
+ /* Handle keystrokes. */
+ _doKeyDown: function(event) {
+ var onSelect, dateStr, sel,
+ inst = $.datepicker._getInst(event.target),
+ handled = true,
+ isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
+
+ inst._keyEvent = true;
+ if ($.datepicker._datepickerShowing) {
+ switch (event.keyCode) {
+ case 9: $.datepicker._hideDatepicker();
+ handled = false;
+ break; // hide on tab out
+ case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
+ $.datepicker._currentClass + ")", inst.dpDiv);
+ if (sel[0]) {
+ $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+ }
+
+ onSelect = $.datepicker._get(inst, "onSelect");
+ if (onSelect) {
+ dateStr = $.datepicker._formatDate(inst);
+
+ // trigger custom callback
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
+ } else {
+ $.datepicker._hideDatepicker();
+ }
+
+ return false; // don't submit the form
+ case 27: $.datepicker._hideDatepicker();
+ break; // hide on escape
+ case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ break; // previous month/year on page up/+ ctrl
+ case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ break; // next month/year on page down/+ ctrl
+ case 35: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._clearDate(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // clear on ctrl or command +end
+ case 36: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._gotoToday(event.target);
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // current on ctrl or command +home
+ case 37: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // -1 day on ctrl or command +left
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, "stepBigMonths") :
+ -$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +left on Mac
+ break;
+ case 38: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, -7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // -1 week on ctrl or command +up
+ case 39: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ // +1 day on ctrl or command +right
+ if (event.originalEvent.altKey) {
+ $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, "stepBigMonths") :
+ +$.datepicker._get(inst, "stepMonths")), "M");
+ }
+ // next month/year on alt +right
+ break;
+ case 40: if (event.ctrlKey || event.metaKey) {
+ $.datepicker._adjustDate(event.target, +7, "D");
+ }
+ handled = event.ctrlKey || event.metaKey;
+ break; // +1 week on ctrl or command +down
+ default: handled = false;
+ }
+ } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
+ $.datepicker._showDatepicker(this);
+ } else {
+ handled = false;
+ }
+
+ if (handled) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ },
+
+ /* Filter entered characters - based on date format. */
+ _doKeyPress: function(event) {
+ var chars, chr,
+ inst = $.datepicker._getInst(event.target);
+
+ if ($.datepicker._get(inst, "constrainInput")) {
+ chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
+ chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
+ return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
+ }
+ },
+
+ /* Synchronise manual entry and field/alternate field. */
+ _doKeyUp: function(event) {
+ var date,
+ inst = $.datepicker._getInst(event.target);
+
+ if (inst.input.val() !== inst.lastVal) {
+ try {
+ date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ (inst.input ? inst.input.val() : null),
+ $.datepicker._getFormatConfig(inst));
+
+ if (date) { // only if valid
+ $.datepicker._setDateFromField(inst);
+ $.datepicker._updateAlternate(inst);
+ $.datepicker._updateDatepicker(inst);
+ }
+ }
+ catch (err) {
+ }
+ }
+ return true;
+ },
+
+ /* Pop-up the date picker for a given input field.
+ * If false returned from beforeShow event handler do not show.
+ * @param input element - the input field attached to the date picker or
+ * event - if triggered by focus
+ */
+ _showDatepicker: function(input) {
+ input = input.target || input;
+ if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
+ input = $("input", input.parentNode)[0];
+ }
+
+ if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
+ return;
+ }
+
+ var inst, beforeShow, beforeShowSettings, isFixed,
+ offset, showAnim, duration;
+
+ inst = $.datepicker._getInst(input);
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
+ $.datepicker._curInst.dpDiv.stop(true, true);
+ if ( inst && $.datepicker._datepickerShowing ) {
+ $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
+ }
+ }
+
+ beforeShow = $.datepicker._get(inst, "beforeShow");
+ beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
+ if(beforeShowSettings === false){
+ return;
+ }
+ extendRemove(inst.settings, beforeShowSettings);
+
+ inst.lastVal = null;
+ $.datepicker._lastInput = input;
+ $.datepicker._setDateFromField(inst);
+
+ if ($.datepicker._inDialog) { // hide cursor
+ input.value = "";
+ }
+ if (!$.datepicker._pos) { // position below input
+ $.datepicker._pos = $.datepicker._findPos(input);
+ $.datepicker._pos[1] += input.offsetHeight; // add the height
+ }
+
+ isFixed = false;
+ $(input).parents().each(function() {
+ isFixed |= $(this).css("position") === "fixed";
+ return !isFixed;
+ });
+
+ offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
+ $.datepicker._pos = null;
+ //to avoid flashes on Firefox
+ inst.dpDiv.empty();
+ // determine sizing offscreen
+ inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
+ $.datepicker._updateDatepicker(inst);
+ // fix width for dynamic number of date pickers
+ // and adjust position before showing
+ offset = $.datepicker._checkOffset(inst, offset, isFixed);
+ inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
+ "static" : (isFixed ? "fixed" : "absolute")), display: "none",
+ left: offset.left + "px", top: offset.top + "px"});
+
+ if (!inst.inline) {
+ showAnim = $.datepicker._get(inst, "showAnim");
+ duration = $.datepicker._get(inst, "duration");
+ inst.dpDiv.zIndex($(input).zIndex()+1);
+ $.datepicker._datepickerShowing = true;
+
+ if ( $.effects && $.effects.effect[ showAnim ] ) {
+ inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
+ } else {
+ inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
+ }
+
+ if ( $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ $.datepicker._curInst = inst;
+ }
+ },
+
+ /* Generate the date picker content. */
+ _updateDatepicker: function(inst) {
+ this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
+ instActive = inst; // for delegate hover events
+ inst.dpDiv.empty().append(this._generateHTML(inst));
+ this._attachHandlers(inst);
+ inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
+
+ var origyearshtml,
+ numMonths = this._getNumberOfMonths(inst),
+ cols = numMonths[1],
+ width = 17;
+
+ inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
+ if (cols > 1) {
+ inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
+ }
+ inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
+ "Class"]("ui-datepicker-multi");
+ inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
+ "Class"]("ui-datepicker-rtl");
+
+ if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
+ inst.input.focus();
+ }
+
+ // deffered render of the years select (to avoid flashes on Firefox)
+ if( inst.yearshtml ){
+ origyearshtml = inst.yearshtml;
+ setTimeout(function(){
+ //assure that inst.yearshtml didn't change.
+ if( origyearshtml === inst.yearshtml && inst.yearshtml ){
+ inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
+ }
+ origyearshtml = inst.yearshtml = null;
+ }, 0);
+ }
+ },
+
+ // #6694 - don't focus the input if it's already focused
+ // this breaks the change event in IE
+ // Support: IE and jQuery <1.9
+ _shouldFocusInput: function( inst ) {
+ return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
+ },
+
+ /* Check positioning to remain on screen. */
+ _checkOffset: function(inst, offset, isFixed) {
+ var dpWidth = inst.dpDiv.outerWidth(),
+ dpHeight = inst.dpDiv.outerHeight(),
+ inputWidth = inst.input ? inst.input.outerWidth() : 0,
+ inputHeight = inst.input ? inst.input.outerHeight() : 0,
+ viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
+ viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
+
+ offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
+ offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
+ offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
+
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
+ offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
+ offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+ Math.abs(dpHeight + inputHeight) : 0);
+
+ return offset;
+ },
+
+ /* Find an object's position on the screen. */
+ _findPos: function(obj) {
+ var position,
+ inst = this._getInst(obj),
+ isRTL = this._get(inst, "isRTL");
+
+ while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
+ obj = obj[isRTL ? "previousSibling" : "nextSibling"];
+ }
+
+ position = $(obj).offset();
+ return [position.left, position.top];
+ },
+
+ /* Hide the date picker from view.
+ * @param input element - the input field attached to the date picker
+ */
+ _hideDatepicker: function(input) {
+ var showAnim, duration, postProcess, onClose,
+ inst = this._curInst;
+
+ if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
+ return;
+ }
+
+ if (this._datepickerShowing) {
+ showAnim = this._get(inst, "showAnim");
+ duration = this._get(inst, "duration");
+ postProcess = function() {
+ $.datepicker._tidyDialog(inst);
+ };
+
+ // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
+ if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
+ inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
+ } else {
+ inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
+ (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
+ }
+
+ if (!showAnim) {
+ postProcess();
+ }
+ this._datepickerShowing = false;
+
+ onClose = this._get(inst, "onClose");
+ if (onClose) {
+ onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
+ }
+
+ this._lastInput = null;
+ if (this._inDialog) {
+ this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
+ if ($.blockUI) {
+ $.unblockUI();
+ $("body").append(this.dpDiv);
+ }
+ }
+ this._inDialog = false;
+ }
+ },
+
+ /* Tidy up after a dialog display. */
+ _tidyDialog: function(inst) {
+ inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
+ },
+
+ /* Close date picker if clicked elsewhere. */
+ _checkExternalClick: function(event) {
+ if (!$.datepicker._curInst) {
+ return;
+ }
+
+ var $target = $(event.target),
+ inst = $.datepicker._getInst($target[0]);
+
+ if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
+ $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
+ !$target.hasClass($.datepicker.markerClassName) &&
+ !$target.closest("." + $.datepicker._triggerClass).length &&
+ $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
+ ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
+ $.datepicker._hideDatepicker();
+ }
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustDate: function(id, offset, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+ this._adjustInstDate(inst, offset +
+ (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
+ period);
+ this._updateDatepicker(inst);
+ },
+
+ /* Action for current link. */
+ _gotoToday: function(id) {
+ var date,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ if (this._get(inst, "gotoCurrent") && inst.currentDay) {
+ inst.selectedDay = inst.currentDay;
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth;
+ inst.drawYear = inst.selectedYear = inst.currentYear;
+ } else {
+ date = new Date();
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ }
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a new month/year. */
+ _selectMonthYear: function(id, select, period) {
+ var target = $(id),
+ inst = this._getInst(target[0]);
+
+ inst["selected" + (period === "M" ? "Month" : "Year")] =
+ inst["draw" + (period === "M" ? "Month" : "Year")] =
+ parseInt(select.options[select.selectedIndex].value,10);
+
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a day. */
+ _selectDay: function(id, month, year, td) {
+ var inst,
+ target = $(id);
+
+ if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+
+ inst = this._getInst(target[0]);
+ inst.selectedDay = inst.currentDay = $("a", td).html();
+ inst.selectedMonth = inst.currentMonth = month;
+ inst.selectedYear = inst.currentYear = year;
+ this._selectDate(id, this._formatDate(inst,
+ inst.currentDay, inst.currentMonth, inst.currentYear));
+ },
+
+ /* Erase the input field and hide the date picker. */
+ _clearDate: function(id) {
+ var target = $(id);
+ this._selectDate(target, "");
+ },
+
+ /* Update the input field with the selected date. */
+ _selectDate: function(id, dateStr) {
+ var onSelect,
+ target = $(id),
+ inst = this._getInst(target[0]);
+
+ dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
+ if (inst.input) {
+ inst.input.val(dateStr);
+ }
+ this._updateAlternate(inst);
+
+ onSelect = this._get(inst, "onSelect");
+ if (onSelect) {
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
+ } else if (inst.input) {
+ inst.input.trigger("change"); // fire the change event
+ }
+
+ if (inst.inline){
+ this._updateDatepicker(inst);
+ } else {
+ this._hideDatepicker();
+ this._lastInput = inst.input[0];
+ if (typeof(inst.input[0]) !== "object") {
+ inst.input.focus(); // restore focus
+ }
+ this._lastInput = null;
+ }
+ },
+
+ /* Update any alternate field to synchronise with the main field. */
+ _updateAlternate: function(inst) {
+ var altFormat, date, dateStr,
+ altField = this._get(inst, "altField");
+
+ if (altField) { // update alternate field too
+ altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
+ date = this._getDate(inst);
+ dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
+ $(altField).each(function() { $(this).val(dateStr); });
+ }
+ },
+
+ /* Set as beforeShowDay function to prevent selection of weekends.
+ * @param date Date - the date to customise
+ * @return [boolean, string] - is this date selectable?, what is its CSS class?
+ */
+ noWeekends: function(date) {
+ var day = date.getDay();
+ return [(day > 0 && day < 6), ""];
+ },
+
+ /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+ * @param date Date - the date to get the week for
+ * @return number - the number of the week within the year that contains this date
+ */
+ iso8601Week: function(date) {
+ var time,
+ checkDate = new Date(date.getTime());
+
+ // Find Thursday of this week starting on Monday
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+
+ time = checkDate.getTime();
+ checkDate.setMonth(0); // Compare with Jan 1
+ checkDate.setDate(1);
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+ },
+
+ /* Parse a string value into a date object.
+ * See formatDate below for the possible formats.
+ *
+ * @param format string - the expected format of the date
+ * @param value string - the date in the above format
+ * @param settings Object - attributes include:
+ * shortYearCutoff number - the cutoff year for determining the century (optional)
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return Date - the extracted date value or null if value is blank
+ */
+ parseDate: function (format, value, settings) {
+ if (format == null || value == null) {
+ throw "Invalid arguments";
+ }
+
+ value = (typeof value === "object" ? value.toString() : value + "");
+ if (value === "") {
+ return null;
+ }
+
+ var iFormat, dim, extra,
+ iValue = 0,
+ shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
+ shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ year = -1,
+ month = -1,
+ day = -1,
+ doy = -1,
+ literal = false,
+ date,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Extract a number from the string value
+ getNumber = function(match) {
+ var isDoubled = lookAhead(match),
+ size = (match === "@" ? 14 : (match === "!" ? 20 :
+ (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
+ digits = new RegExp("^\\d{1," + size + "}"),
+ num = value.substring(iValue).match(digits);
+ if (!num) {
+ throw "Missing number at position " + iValue;
+ }
+ iValue += num[0].length;
+ return parseInt(num[0], 10);
+ },
+ // Extract a name from the string value and convert to an index
+ getName = function(match, shortNames, longNames) {
+ var index = -1,
+ names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
+ return [ [k, v] ];
+ }).sort(function (a, b) {
+ return -(a[1].length - b[1].length);
+ });
+
+ $.each(names, function (i, pair) {
+ var name = pair[1];
+ if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
+ index = pair[0];
+ iValue += name.length;
+ return false;
+ }
+ });
+ if (index !== -1) {
+ return index + 1;
+ } else {
+ throw "Unknown name at position " + iValue;
+ }
+ },
+ // Confirm that a literal character matches the string value
+ checkLiteral = function() {
+ if (value.charAt(iValue) !== format.charAt(iFormat)) {
+ throw "Unexpected literal at position " + iValue;
+ }
+ iValue++;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ checkLiteral();
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ day = getNumber("d");
+ break;
+ case "D":
+ getName("D", dayNamesShort, dayNames);
+ break;
+ case "o":
+ doy = getNumber("o");
+ break;
+ case "m":
+ month = getNumber("m");
+ break;
+ case "M":
+ month = getName("M", monthNamesShort, monthNames);
+ break;
+ case "y":
+ year = getNumber("y");
+ break;
+ case "@":
+ date = new Date(getNumber("@"));
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "!":
+ date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "'":
+ if (lookAhead("'")){
+ checkLiteral();
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ checkLiteral();
+ }
+ }
+ }
+
+ if (iValue < value.length){
+ extra = value.substr(iValue);
+ if (!/^\s+/.test(extra)) {
+ throw "Extra/unparsed characters found in date: " + extra;
+ }
+ }
+
+ if (year === -1) {
+ year = new Date().getFullYear();
+ } else if (year < 100) {
+ year += new Date().getFullYear() - new Date().getFullYear() % 100 +
+ (year <= shortYearCutoff ? 0 : -100);
+ }
+
+ if (doy > -1) {
+ month = 1;
+ day = doy;
+ do {
+ dim = this._getDaysInMonth(year, month - 1);
+ if (day <= dim) {
+ break;
+ }
+ month++;
+ day -= dim;
+ } while (true);
+ }
+
+ date = this._daylightSavingAdjust(new Date(year, month - 1, day));
+ if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
+ throw "Invalid date"; // E.g. 31/02/00
+ }
+ return date;
+ },
+
+ /* Standard date formats. */
+ ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
+ COOKIE: "D, dd M yy",
+ ISO_8601: "yy-mm-dd",
+ RFC_822: "D, d M y",
+ RFC_850: "DD, dd-M-y",
+ RFC_1036: "D, d M y",
+ RFC_1123: "D, d M yy",
+ RFC_2822: "D, d M yy",
+ RSS: "D, d M y", // RFC 822
+ TICKS: "!",
+ TIMESTAMP: "@",
+ W3C: "yy-mm-dd", // ISO 8601
+
+ _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
+ Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
+
+ /* Format a date object into a string value.
+ * The format can be combinations of the following:
+ * d - day of month (no leading zero)
+ * dd - day of month (two digit)
+ * o - day of year (no leading zeros)
+ * oo - day of year (three digit)
+ * D - day name short
+ * DD - day name long
+ * m - month of year (no leading zero)
+ * mm - month of year (two digit)
+ * M - month name short
+ * MM - month name long
+ * y - year (two digit)
+ * yy - year (four digit)
+ * @ - Unix timestamp (ms since 01/01/1970)
+ * ! - Windows ticks (100ns since 01/01/0001)
+ * "..." - literal text
+ * '' - single quote
+ *
+ * @param format string - the desired format of the date
+ * @param date Date - the date value to format
+ * @param settings Object - attributes include:
+ * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ * dayNames string[7] - names of the days from Sunday (optional)
+ * monthNamesShort string[12] - abbreviated names of the months (optional)
+ * monthNames string[12] - names of the months (optional)
+ * @return string - the date in the above format
+ */
+ formatDate: function (format, date, settings) {
+ if (!date) {
+ return "";
+ }
+
+ var iFormat,
+ dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+ dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+ monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+ monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ },
+ // Format a number, with leading zero if necessary
+ formatNumber = function(match, value, len) {
+ var num = "" + value;
+ if (lookAhead(match)) {
+ while (num.length < len) {
+ num = "0" + num;
+ }
+ }
+ return num;
+ },
+ // Format a name, short or long as requested
+ formatName = function(match, value, shortNames, longNames) {
+ return (lookAhead(match) ? longNames[value] : shortNames[value]);
+ },
+ output = "",
+ literal = false;
+
+ if (date) {
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ output += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d":
+ output += formatNumber("d", date.getDate(), 2);
+ break;
+ case "D":
+ output += formatName("D", date.getDay(), dayNamesShort, dayNames);
+ break;
+ case "o":
+ output += formatNumber("o",
+ Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
+ break;
+ case "m":
+ output += formatNumber("m", date.getMonth() + 1, 2);
+ break;
+ case "M":
+ output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
+ break;
+ case "y":
+ output += (lookAhead("y") ? date.getFullYear() :
+ (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
+ break;
+ case "@":
+ output += date.getTime();
+ break;
+ case "!":
+ output += date.getTime() * 10000 + this._ticksTo1970;
+ break;
+ case "'":
+ if (lookAhead("'")) {
+ output += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ output += format.charAt(iFormat);
+ }
+ }
+ }
+ }
+ return output;
+ },
+
+ /* Extract all possible characters from the date format. */
+ _possibleChars: function (format) {
+ var iFormat,
+ chars = "",
+ literal = false,
+ // Check whether a format character is doubled
+ lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+ if (matches) {
+ iFormat++;
+ }
+ return matches;
+ };
+
+ for (iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal) {
+ if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+ literal = false;
+ } else {
+ chars += format.charAt(iFormat);
+ }
+ } else {
+ switch (format.charAt(iFormat)) {
+ case "d": case "m": case "y": case "@":
+ chars += "0123456789";
+ break;
+ case "D": case "M":
+ return null; // Accept anything
+ case "'":
+ if (lookAhead("'")) {
+ chars += "'";
+ } else {
+ literal = true;
+ }
+ break;
+ default:
+ chars += format.charAt(iFormat);
+ }
+ }
+ }
+ return chars;
+ },
+
+ /* Get a setting value, defaulting if necessary. */
+ _get: function(inst, name) {
+ return inst.settings[name] !== undefined ?
+ inst.settings[name] : this._defaults[name];
+ },
+
+ /* Parse existing date and initialise date picker. */
+ _setDateFromField: function(inst, noDefault) {
+ if (inst.input.val() === inst.lastVal) {
+ return;
+ }
+
+ var dateFormat = this._get(inst, "dateFormat"),
+ dates = inst.lastVal = inst.input ? inst.input.val() : null,
+ defaultDate = this._getDefaultDate(inst),
+ date = defaultDate,
+ settings = this._getFormatConfig(inst);
+
+ try {
+ date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+ } catch (event) {
+ dates = (noDefault ? "" : dates);
+ }
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ inst.currentDay = (dates ? date.getDate() : 0);
+ inst.currentMonth = (dates ? date.getMonth() : 0);
+ inst.currentYear = (dates ? date.getFullYear() : 0);
+ this._adjustInstDate(inst);
+ },
+
+ /* Retrieve the default date shown on opening. */
+ _getDefaultDate: function(inst) {
+ return this._restrictMinMax(inst,
+ this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
+ },
+
+ /* A date may be specified as an exact value or a relative one. */
+ _determineDate: function(inst, date, defaultDate) {
+ var offsetNumeric = function(offset) {
+ var date = new Date();
+ date.setDate(date.getDate() + offset);
+ return date;
+ },
+ offsetString = function(offset) {
+ try {
+ return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+ offset, $.datepicker._getFormatConfig(inst));
+ }
+ catch (e) {
+ // Ignore
+ }
+
+ var date = (offset.toLowerCase().match(/^c/) ?
+ $.datepicker._getDate(inst) : null) || new Date(),
+ year = date.getFullYear(),
+ month = date.getMonth(),
+ day = date.getDate(),
+ pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
+ matches = pattern.exec(offset);
+
+ while (matches) {
+ switch (matches[2] || "d") {
+ case "d" : case "D" :
+ day += parseInt(matches[1],10); break;
+ case "w" : case "W" :
+ day += parseInt(matches[1],10) * 7; break;
+ case "m" : case "M" :
+ month += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ case "y": case "Y" :
+ year += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ }
+ matches = pattern.exec(offset);
+ }
+ return new Date(year, month, day);
+ },
+ newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
+ (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
+
+ newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
+ if (newDate) {
+ newDate.setHours(0);
+ newDate.setMinutes(0);
+ newDate.setSeconds(0);
+ newDate.setMilliseconds(0);
+ }
+ return this._daylightSavingAdjust(newDate);
+ },
+
+ /* Handle switch to/from daylight saving.
+ * Hours may be non-zero on daylight saving cut-over:
+ * > 12 when midnight changeover, but then cannot generate
+ * midnight datetime, so jump to 1AM, otherwise reset.
+ * @param date (Date) the date to check
+ * @return (Date) the corrected date
+ */
+ _daylightSavingAdjust: function(date) {
+ if (!date) {
+ return null;
+ }
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+ return date;
+ },
+
+ /* Set the date(s) directly. */
+ _setDate: function(inst, date, noChange) {
+ var clear = !date,
+ origMonth = inst.selectedMonth,
+ origYear = inst.selectedYear,
+ newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
+
+ inst.selectedDay = inst.currentDay = newDate.getDate();
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
+ inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
+ if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
+ this._notifyChange(inst);
+ }
+ this._adjustInstDate(inst);
+ if (inst.input) {
+ inst.input.val(clear ? "" : this._formatDate(inst));
+ }
+ },
+
+ /* Retrieve the date(s) directly. */
+ _getDate: function(inst) {
+ var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
+ this._daylightSavingAdjust(new Date(
+ inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return startDate;
+ },
+
+ /* Attach the onxxx handlers. These are declared statically so
+ * they work with static code transformers like Caja.
+ */
+ _attachHandlers: function(inst) {
+ var stepMonths = this._get(inst, "stepMonths"),
+ id = "#" + inst.id.replace( /\\\\/g, "\\" );
+ inst.dpDiv.find("[data-handler]").map(function () {
+ var handler = {
+ prev: function () {
+ $.datepicker._adjustDate(id, -stepMonths, "M");
+ },
+ next: function () {
+ $.datepicker._adjustDate(id, +stepMonths, "M");
+ },
+ hide: function () {
+ $.datepicker._hideDatepicker();
+ },
+ today: function () {
+ $.datepicker._gotoToday(id);
+ },
+ selectDay: function () {
+ $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
+ return false;
+ },
+ selectMonth: function () {
+ $.datepicker._selectMonthYear(id, this, "M");
+ return false;
+ },
+ selectYear: function () {
+ $.datepicker._selectMonthYear(id, this, "Y");
+ return false;
+ }
+ };
+ $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
+ });
+ },
+
+ /* Generate the HTML for the current state of the date picker. */
+ _generateHTML: function(inst) {
+ var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
+ controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
+ monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
+ selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
+ cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
+ printDate, dRow, tbody, daySettings, otherMonth, unselectable,
+ tempDate = new Date(),
+ today = this._daylightSavingAdjust(
+ new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
+ isRTL = this._get(inst, "isRTL"),
+ showButtonPanel = this._get(inst, "showButtonPanel"),
+ hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
+ navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
+ numMonths = this._getNumberOfMonths(inst),
+ showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
+ stepMonths = this._get(inst, "stepMonths"),
+ isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
+ currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
+ new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ drawMonth = inst.drawMonth - showCurrentAtPos,
+ drawYear = inst.drawYear;
+
+ if (drawMonth < 0) {
+ drawMonth += 12;
+ drawYear--;
+ }
+ if (maxDate) {
+ maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
+ maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
+ maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
+ while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
+ drawMonth--;
+ if (drawMonth < 0) {
+ drawMonth = 11;
+ drawYear--;
+ }
+ }
+ }
+ inst.drawMonth = drawMonth;
+ inst.drawYear = drawYear;
+
+ prevText = this._get(inst, "prevText");
+ prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
+ " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
+
+ nextText = this._get(inst, "nextText");
+ nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
+ this._getFormatConfig(inst)));
+
+ next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
+ "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
+ " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
+ (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
+
+ currentText = this._get(inst, "currentText");
+ gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
+ currentText = (!navigationAsDateFormat ? currentText :
+ this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
+
+ controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
+ this._get(inst, "closeText") + "</button>" : "");
+
+ buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
+ (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
+ ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
+
+ firstDay = parseInt(this._get(inst, "firstDay"),10);
+ firstDay = (isNaN(firstDay) ? 0 : firstDay);
+
+ showWeek = this._get(inst, "showWeek");
+ dayNames = this._get(inst, "dayNames");
+ dayNamesMin = this._get(inst, "dayNamesMin");
+ monthNames = this._get(inst, "monthNames");
+ monthNamesShort = this._get(inst, "monthNamesShort");
+ beforeShowDay = this._get(inst, "beforeShowDay");
+ showOtherMonths = this._get(inst, "showOtherMonths");
+ selectOtherMonths = this._get(inst, "selectOtherMonths");
+ defaultDate = this._getDefaultDate(inst);
+ html = "";
+ dow;
+ for (row = 0; row < numMonths[0]; row++) {
+ group = "";
+ this.maxRows = 4;
+ for (col = 0; col < numMonths[1]; col++) {
+ selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
+ cornerClass = " ui-corner-all";
+ calender = "";
+ if (isMultiMonth) {
+ calender += "<div class='ui-datepicker-group";
+ if (numMonths[1] > 1) {
+ switch (col) {
+ case 0: calender += " ui-datepicker-group-first";
+ cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
+ case numMonths[1]-1: calender += " ui-datepicker-group-last";
+ cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
+ default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
+ }
+ }
+ calender += "'>";
+ }
+ calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
+ (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
+ (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
+ this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
+ row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+ "</div><table class='ui-datepicker-calendar'><thead>" +
+ "<tr>";
+ thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
+ for (dow = 0; dow < 7; dow++) { // days of the week
+ day = (dow + firstDay) % 7;
+ thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
+ "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
+ }
+ calender += thead + "</tr></thead><tbody>";
+ daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
+ if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
+ inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
+ }
+ leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
+ curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
+ numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
+ this.maxRows = numRows;
+ printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
+ for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
+ calender += "<tr>";
+ tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
+ this._get(inst, "calculateWeek")(printDate) + "</td>");
+ for (dow = 0; dow < 7; dow++) { // create date picker days
+ daySettings = (beforeShowDay ?
+ beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
+ otherMonth = (printDate.getMonth() !== drawMonth);
+ unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
+ (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
+ tbody += "<td class='" +
+ ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
+ (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
+ ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
+ (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
+ // or defaultDate is current printedDate and defaultDate is selectedDate
+ " " + this._dayOverClass : "") + // highlight selected day
+ (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
+ (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
+ (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
+ (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
+ ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title
+ (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
+ (otherMonth && !showOtherMonths ? " " : // display for other months
+ (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
+ (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
+ (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
+ (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
+ "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
+ printDate.setDate(printDate.getDate() + 1);
+ printDate = this._daylightSavingAdjust(printDate);
+ }
+ calender += tbody + "</tr>";
+ }
+ drawMonth++;
+ if (drawMonth > 11) {
+ drawMonth = 0;
+ drawYear++;
+ }
+ calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
+ ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
+ group += calender;
+ }
+ html += group;
+ }
+ html += buttonPanel;
+ inst._keyEvent = false;
+ return html;
+ },
+
+ /* Generate the month and year header. */
+ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
+ secondary, monthNames, monthNamesShort) {
+
+ var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
+ changeMonth = this._get(inst, "changeMonth"),
+ changeYear = this._get(inst, "changeYear"),
+ showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
+ html = "<div class='ui-datepicker-title'>",
+ monthHtml = "";
+
+ // month selection
+ if (secondary || !changeMonth) {
+ monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
+ } else {
+ inMinYear = (minDate && minDate.getFullYear() === drawYear);
+ inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
+ monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
+ for ( month = 0; month < 12; month++) {
+ if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
+ monthHtml += "<option value='" + month + "'" +
+ (month === drawMonth ? " selected='selected'" : "") +
+ ">" + monthNamesShort[month] + "</option>";
+ }
+ }
+ monthHtml += "</select>";
+ }
+
+ if (!showMonthAfterYear) {
+ html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : "");
+ }
+
+ // year selection
+ if ( !inst.yearshtml ) {
+ inst.yearshtml = "";
+ if (secondary || !changeYear) {
+ html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
+ } else {
+ // determine range of years to display
+ years = this._get(inst, "yearRange").split(":");
+ thisYear = new Date().getFullYear();
+ determineYear = function(value) {
+ var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
+ (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
+ parseInt(value, 10)));
+ return (isNaN(year) ? thisYear : year);
+ };
+ year = determineYear(years[0]);
+ endYear = Math.max(year, determineYear(years[1] || ""));
+ year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+ endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+ inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
+ for (; year <= endYear; year++) {
+ inst.yearshtml += "<option value='" + year + "'" +
+ (year === drawYear ? " selected='selected'" : "") +
+ ">" + year + "</option>";
+ }
+ inst.yearshtml += "</select>";
+
+ html += inst.yearshtml;
+ inst.yearshtml = null;
+ }
+ }
+
+ html += this._get(inst, "yearSuffix");
+ if (showMonthAfterYear) {
+ html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml;
+ }
+ html += "</div>"; // Close datepicker_header
+ return html;
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustInstDate: function(inst, offset, period) {
+ var year = inst.drawYear + (period === "Y" ? offset : 0),
+ month = inst.drawMonth + (period === "M" ? offset : 0),
+ day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
+ date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
+
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ if (period === "M" || period === "Y") {
+ this._notifyChange(inst);
+ }
+ },
+
+ /* Ensure a date is within any min/max bounds. */
+ _restrictMinMax: function(inst, date) {
+ var minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ newDate = (minDate && date < minDate ? minDate : date);
+ return (maxDate && newDate > maxDate ? maxDate : newDate);
+ },
+
+ /* Notify change of month/year. */
+ _notifyChange: function(inst) {
+ var onChange = this._get(inst, "onChangeMonthYear");
+ if (onChange) {
+ onChange.apply((inst.input ? inst.input[0] : null),
+ [inst.selectedYear, inst.selectedMonth + 1, inst]);
+ }
+ },
+
+ /* Determine the number of months to show. */
+ _getNumberOfMonths: function(inst) {
+ var numMonths = this._get(inst, "numberOfMonths");
+ return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
+ },
+
+ /* Determine the current maximum date - ensure no time components are set. */
+ _getMinMaxDate: function(inst, minMax) {
+ return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
+ },
+
+ /* Find the number of days in a given month. */
+ _getDaysInMonth: function(year, month) {
+ return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
+ },
+
+ /* Find the day of the week of the first of a month. */
+ _getFirstDayOfMonth: function(year, month) {
+ return new Date(year, month, 1).getDay();
+ },
+
+ /* Determines if we should allow a "next/prev" month display change. */
+ _canAdjustMonth: function(inst, offset, curYear, curMonth) {
+ var numMonths = this._getNumberOfMonths(inst),
+ date = this._daylightSavingAdjust(new Date(curYear,
+ curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
+
+ if (offset < 0) {
+ date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+ }
+ return this._isInRange(inst, date);
+ },
+
+ /* Is the given date in the accepted range? */
+ _isInRange: function(inst, date) {
+ var yearSplit, currentYear,
+ minDate = this._getMinMaxDate(inst, "min"),
+ maxDate = this._getMinMaxDate(inst, "max"),
+ minYear = null,
+ maxYear = null,
+ years = this._get(inst, "yearRange");
+ if (years){
+ yearSplit = years.split(":");
+ currentYear = new Date().getFullYear();
+ minYear = parseInt(yearSplit[0], 10);
+ maxYear = parseInt(yearSplit[1], 10);
+ if ( yearSplit[0].match(/[+\-].*/) ) {
+ minYear += currentYear;
+ }
+ if ( yearSplit[1].match(/[+\-].*/) ) {
+ maxYear += currentYear;
+ }
+ }
+
+ return ((!minDate || date.getTime() >= minDate.getTime()) &&
+ (!maxDate || date.getTime() <= maxDate.getTime()) &&
+ (!minYear || date.getFullYear() >= minYear) &&
+ (!maxYear || date.getFullYear() <= maxYear));
+ },
+
+ /* Provide the configuration settings for formatting/parsing. */
+ _getFormatConfig: function(inst) {
+ var shortYearCutoff = this._get(inst, "shortYearCutoff");
+ shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+ return {shortYearCutoff: shortYearCutoff,
+ dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
+ monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
+ },
+
+ /* Format the given date for display. */
+ _formatDate: function(inst, day, month, year) {
+ if (!day) {
+ inst.currentDay = inst.selectedDay;
+ inst.currentMonth = inst.selectedMonth;
+ inst.currentYear = inst.selectedYear;
+ }
+ var date = (day ? (typeof day === "object" ? day :
+ this._daylightSavingAdjust(new Date(year, month, day))) :
+ this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
+ }
+});
+
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
*/
-jQuery.effects||function(f,j){function l(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
-16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return m.transparent;return m[f.trim(c).toLowerCase()]}function r(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return l(b)}function n(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
-a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function o(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in s||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function t(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
-a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:f.fx.speeds[b]||f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=r(b.elem,a);b.end=l(b.end);b.colorInit=
-true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var m={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,
-183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,
-165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},p=["add","remove","toggle"],s={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,d){if(f.isFunction(b)){d=b;b=null}return this.each(function(){var e=f(this),g=e.attr("style")||" ",h=o(n.call(this)),q,u=e.attr("className");f.each(p,function(v,
-i){c[i]&&e[i+"Class"](c[i])});q=o(n.call(this));e.attr("className",u);e.animate(t(h,q),a,b,function(){f.each(p,function(v,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)})})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?
-f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.5",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==
-null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();
-var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});
-c.css({position:"relative",top:0,left:0})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments);a={options:a[1],duration:a[2],callback:a[3]};var b=f.effects[c];return b&&!f.fx.off?b.call(this,a):this},_show:f.fn.show,show:function(c){if(!c||
-typeof c=="number"||f.fx.speeds[c]||!f.effects[c])return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||!f.effects[c])return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(!c||typeof c=="number"||f.fx.speeds[c]||!f.effects[c]||typeof c==
-"boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,
-a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=
-e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+
-b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/
-2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*
-a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;
-return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,
-a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);
-;/*
- * jQuery UI Effects Blind 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Blind
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","left"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,g);b.effects.removeWrapper(a);
-c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);
-;/*
- * jQuery UI Effects Bounce 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Bounce
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","left"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/
-3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);
-b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);
-;/*
- * jQuery UI Effects Clip 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Clip
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","left","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,c/2)}var h={};h[g.size]=
-f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);
-;/*
- * jQuery UI Effects Drop 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Drop
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","left","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e=="show"?1:
-0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
-;/*
- * jQuery UI Effects Explode 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Explode
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=
-0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+
-e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);
-;/*
- * jQuery UI Effects Fade 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Fade
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);
-;/*
- * jQuery UI Effects Fold 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Fold
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","left"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],10)/100*
-f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);
-;/*
- * jQuery UI Effects Highlight 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Highlight
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&
-this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
-;/*
- * jQuery UI Effects Pulsate 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Pulsate
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,
-a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);
-;/*
- * jQuery UI Effects Scale 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Scale
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,
-b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=
-1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","left","width","height","overflow","opacity"],g=["position","top","left","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=c.effects.setMode(a,
-b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};if(m=="box"||m=="both"){if(d.from.y!=
-d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);a.css("overflow","hidden").css(a.from);
-if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);child.to=c.effects.setTransition(child,
-f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,n?e:g);c.effects.removeWrapper(a);b.callback&&
-b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
-;/*
- * jQuery UI Effects Shake 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Shake
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","left"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=(h=="pos"?"-=":"+=")+
-e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);
-;/*
- * jQuery UI Effects Slide 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Slide
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","left"],e=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(e=="show")a.css(f,b=="pos"?-g:g);var i={};i[f]=(e=="show"?b=="pos"?
-"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);
-;/*
- * jQuery UI Effects Transfer 1.8.5
- *
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * http://docs.jquery.com/UI/Effects/Transfer
- *
- * Depends:
- * jquery.effects.core.js
- */
-(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);
-b.dequeue()})})}})(jQuery);
-;
\ No newline at end of file
+function bindHover(dpDiv) {
+ var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
+ return dpDiv.delegate(selector, "mouseout", function() {
+ $(this).removeClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).removeClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).removeClass("ui-datepicker-next-hover");
+ }
+ })
+ .delegate(selector, "mouseover", function(){
+ if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
+ $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
+ $(this).addClass("ui-state-hover");
+ if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+ $(this).addClass("ui-datepicker-prev-hover");
+ }
+ if (this.className.indexOf("ui-datepicker-next") !== -1) {
+ $(this).addClass("ui-datepicker-next-hover");
+ }
+ }
+ });
+}
+
+/* jQuery extend now ignores nulls! */
+function extendRemove(target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] == null) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+}
+
+/* Invoke the datepicker functionality.
+ @param options string - a command, optionally followed by additional parameters or
+ Object - settings for attaching new datepicker functionality
+ @return jQuery object */
+$.fn.datepicker = function(options){
+
+ /* Verify an empty collection wasn't passed - Fixes #6976 */
+ if ( !this.length ) {
+ return this;
+ }
+
+ /* Initialise the date picker. */
+ if (!$.datepicker.initialized) {
+ $(document).mousedown($.datepicker._checkExternalClick);
+ $.datepicker.initialized = true;
+ }
+
+ /* Append datepicker main container to body if not exist. */
+ if ($("#"+$.datepicker._mainDivId).length === 0) {
+ $("body").append($.datepicker.dpDiv);
+ }
+
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
+ if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
+ return $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ }
+ return this.each(function() {
+ typeof options === "string" ?
+ $.datepicker["_" + options + "Datepicker"].
+ apply($.datepicker, [this].concat(otherArgs)) :
+ $.datepicker._attachDatepicker(this, options);
+ });
+};
+
+$.datepicker = new Datepicker(); // singleton instance
+$.datepicker.initialized = false;
+$.datepicker.uuid = new Date().getTime();
+$.datepicker.version = "1.10.3";
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+var sizeRelatedOptions = {
+ buttons: true,
+ height: true,
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true,
+ width: true
+ },
+ resizableRelatedOptions = {
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true
+ };
+
+$.widget( "ui.dialog", {
+ version: "1.10.3",
+ options: {
+ appendTo: "body",
+ autoOpen: true,
+ buttons: [],
+ closeOnEscape: true,
+ closeText: "close",
+ dialogClass: "",
+ draggable: true,
+ hide: null,
+ height: "auto",
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 150,
+ minWidth: 150,
+ modal: false,
+ position: {
+ my: "center",
+ at: "center",
+ of: window,
+ collision: "fit",
+ // Ensure the titlebar is always visible
+ using: function( pos ) {
+ var topOffset = $( this ).css( pos ).offset().top;
+ if ( topOffset < 0 ) {
+ $( this ).css( "top", pos.top - topOffset );
+ }
+ }
+ },
+ resizable: true,
+ show: null,
+ title: null,
+ width: 300,
+
+ // callbacks
+ beforeClose: null,
+ close: null,
+ drag: null,
+ dragStart: null,
+ dragStop: null,
+ focus: null,
+ open: null,
+ resize: null,
+ resizeStart: null,
+ resizeStop: null
+ },
+
+ _create: function() {
+ this.originalCss = {
+ display: this.element[0].style.display,
+ width: this.element[0].style.width,
+ minHeight: this.element[0].style.minHeight,
+ maxHeight: this.element[0].style.maxHeight,
+ height: this.element[0].style.height
+ };
+ this.originalPosition = {
+ parent: this.element.parent(),
+ index: this.element.parent().children().index( this.element )
+ };
+ this.originalTitle = this.element.attr("title");
+ this.options.title = this.options.title || this.originalTitle;
+
+ this._createWrapper();
+
+ this.element
+ .show()
+ .removeAttr("title")
+ .addClass("ui-dialog-content ui-widget-content")
+ .appendTo( this.uiDialog );
+
+ this._createTitlebar();
+ this._createButtonPane();
+
+ if ( this.options.draggable && $.fn.draggable ) {
+ this._makeDraggable();
+ }
+ if ( this.options.resizable && $.fn.resizable ) {
+ this._makeResizable();
+ }
+
+ this._isOpen = false;
+ },
+
+ _init: function() {
+ if ( this.options.autoOpen ) {
+ this.open();
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+ if ( element && (element.jquery || element.nodeType) ) {
+ return $( element );
+ }
+ return this.document.find( element || "body" ).eq( 0 );
+ },
+
+ _destroy: function() {
+ var next,
+ originalPosition = this.originalPosition;
+
+ this._destroyOverlay();
+
+ this.element
+ .removeUniqueId()
+ .removeClass("ui-dialog-content ui-widget-content")
+ .css( this.originalCss )
+ // Without detaching first, the following becomes really slow
+ .detach();
+
+ this.uiDialog.stop( true, true ).remove();
+
+ if ( this.originalTitle ) {
+ this.element.attr( "title", this.originalTitle );
+ }
+
+ next = originalPosition.parent.children().eq( originalPosition.index );
+ // Don't try to place the dialog next to itself (#8613)
+ if ( next.length && next[0] !== this.element[0] ) {
+ next.before( this.element );
+ } else {
+ originalPosition.parent.append( this.element );
+ }
+ },
+
+ widget: function() {
+ return this.uiDialog;
+ },
+
+ disable: $.noop,
+ enable: $.noop,
+
+ close: function( event ) {
+ var that = this;
+
+ if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
+ return;
+ }
+
+ this._isOpen = false;
+ this._destroyOverlay();
+
+ if ( !this.opener.filter(":focusable").focus().length ) {
+ // Hiding a focused element doesn't trigger blur in WebKit
+ // so in case we have nothing to focus on, explicitly blur the active element
+ // https://bugs.webkit.org/show_bug.cgi?id=47182
+ $( this.document[0].activeElement ).blur();
+ }
+
+ this._hide( this.uiDialog, this.options.hide, function() {
+ that._trigger( "close", event );
+ });
+ },
+
+ isOpen: function() {
+ return this._isOpen;
+ },
+
+ moveToTop: function() {
+ this._moveToTop();
+ },
+
+ _moveToTop: function( event, silent ) {
+ var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
+ if ( moved && !silent ) {
+ this._trigger( "focus", event );
+ }
+ return moved;
+ },
+
+ open: function() {
+ var that = this;
+ if ( this._isOpen ) {
+ if ( this._moveToTop() ) {
+ this._focusTabbable();
+ }
+ return;
+ }
+
+ this._isOpen = true;
+ this.opener = $( this.document[0].activeElement );
+
+ this._size();
+ this._position();
+ this._createOverlay();
+ this._moveToTop( null, true );
+ this._show( this.uiDialog, this.options.show, function() {
+ that._focusTabbable();
+ that._trigger("focus");
+ });
+
+ this._trigger("open");
+ },
+
+ _focusTabbable: function() {
+ // Set focus to the first match:
+ // 1. First element inside the dialog matching [autofocus]
+ // 2. Tabbable element inside the content element
+ // 3. Tabbable element inside the buttonpane
+ // 4. The close button
+ // 5. The dialog itself
+ var hasFocus = this.element.find("[autofocus]");
+ if ( !hasFocus.length ) {
+ hasFocus = this.element.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogButtonPane.find(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
+ }
+ if ( !hasFocus.length ) {
+ hasFocus = this.uiDialog;
+ }
+ hasFocus.eq( 0 ).focus();
+ },
+
+ _keepFocus: function( event ) {
+ function checkFocus() {
+ var activeElement = this.document[0].activeElement,
+ isActive = this.uiDialog[0] === activeElement ||
+ $.contains( this.uiDialog[0], activeElement );
+ if ( !isActive ) {
+ this._focusTabbable();
+ }
+ }
+ event.preventDefault();
+ checkFocus.call( this );
+ // support: IE
+ // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
+ // so we check again later
+ this._delay( checkFocus );
+ },
+
+ _createWrapper: function() {
+ this.uiDialog = $("<div>")
+ .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
+ this.options.dialogClass )
+ .hide()
+ .attr({
+ // Setting tabIndex makes the div focusable
+ tabIndex: -1,
+ role: "dialog"
+ })
+ .appendTo( this._appendTo() );
+
+ this._on( this.uiDialog, {
+ keydown: function( event ) {
+ if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+ event.keyCode === $.ui.keyCode.ESCAPE ) {
+ event.preventDefault();
+ this.close( event );
+ return;
+ }
+
+ // prevent tabbing out of dialogs
+ if ( event.keyCode !== $.ui.keyCode.TAB ) {
+ return;
+ }
+ var tabbables = this.uiDialog.find(":tabbable"),
+ first = tabbables.filter(":first"),
+ last = tabbables.filter(":last");
+
+ if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
+ first.focus( 1 );
+ event.preventDefault();
+ } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
+ last.focus( 1 );
+ event.preventDefault();
+ }
+ },
+ mousedown: function( event ) {
+ if ( this._moveToTop( event ) ) {
+ this._focusTabbable();
+ }
+ }
+ });
+
+ // We assume that any existing aria-describedby attribute means
+ // that the dialog content is marked up properly
+ // otherwise we brute force the content as the description
+ if ( !this.element.find("[aria-describedby]").length ) {
+ this.uiDialog.attr({
+ "aria-describedby": this.element.uniqueId().attr("id")
+ });
+ }
+ },
+
+ _createTitlebar: function() {
+ var uiDialogTitle;
+
+ this.uiDialogTitlebar = $("<div>")
+ .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
+ .prependTo( this.uiDialog );
+ this._on( this.uiDialogTitlebar, {
+ mousedown: function( event ) {
+ // Don't prevent click on close button (#8838)
+ // Focusing a dialog that is partially scrolled out of view
+ // causes the browser to scroll it into view, preventing the click event
+ if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
+ // Dialog isn't getting focus when dragging (#8063)
+ this.uiDialog.focus();
+ }
+ }
+ });
+
+ this.uiDialogTitlebarClose = $("<button></button>")
+ .button({
+ label: this.options.closeText,
+ icons: {
+ primary: "ui-icon-closethick"
+ },
+ text: false
+ })
+ .addClass("ui-dialog-titlebar-close")
+ .appendTo( this.uiDialogTitlebar );
+ this._on( this.uiDialogTitlebarClose, {
+ click: function( event ) {
+ event.preventDefault();
+ this.close( event );
+ }
+ });
+
+ uiDialogTitle = $("<span>")
+ .uniqueId()
+ .addClass("ui-dialog-title")
+ .prependTo( this.uiDialogTitlebar );
+ this._title( uiDialogTitle );
+
+ this.uiDialog.attr({
+ "aria-labelledby": uiDialogTitle.attr("id")
+ });
+ },
+
+ _title: function( title ) {
+ if ( !this.options.title ) {
+ title.html(" ");
+ }
+ title.text( this.options.title );
+ },
+
+ _createButtonPane: function() {
+ this.uiDialogButtonPane = $("<div>")
+ .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
+
+ this.uiButtonSet = $("<div>")
+ .addClass("ui-dialog-buttonset")
+ .appendTo( this.uiDialogButtonPane );
+
+ this._createButtons();
+ },
+
+ _createButtons: function() {
+ var that = this,
+ buttons = this.options.buttons;
+
+ // if we already have a button pane, remove it
+ this.uiDialogButtonPane.remove();
+ this.uiButtonSet.empty();
+
+ if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
+ this.uiDialog.removeClass("ui-dialog-buttons");
+ return;
+ }
+
+ $.each( buttons, function( name, props ) {
+ var click, buttonOptions;
+ props = $.isFunction( props ) ?
+ { click: props, text: name } :
+ props;
+ // Default to a non-submitting button
+ props = $.extend( { type: "button" }, props );
+ // Change the context for the click callback to be the main element
+ click = props.click;
+ props.click = function() {
+ click.apply( that.element[0], arguments );
+ };
+ buttonOptions = {
+ icons: props.icons,
+ text: props.showText
+ };
+ delete props.icons;
+ delete props.showText;
+ $( "<button></button>", props )
+ .button( buttonOptions )
+ .appendTo( that.uiButtonSet );
+ });
+ this.uiDialog.addClass("ui-dialog-buttons");
+ this.uiDialogButtonPane.appendTo( this.uiDialog );
+ },
+
+ _makeDraggable: function() {
+ var that = this,
+ options = this.options;
+
+ function filteredUi( ui ) {
+ return {
+ position: ui.position,
+ offset: ui.offset
+ };
+ }
+
+ this.uiDialog.draggable({
+ cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
+ handle: ".ui-dialog-titlebar",
+ containment: "document",
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-dragging");
+ that._blockFrames();
+ that._trigger( "dragStart", event, filteredUi( ui ) );
+ },
+ drag: function( event, ui ) {
+ that._trigger( "drag", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.position = [
+ ui.position.left - that.document.scrollLeft(),
+ ui.position.top - that.document.scrollTop()
+ ];
+ $( this ).removeClass("ui-dialog-dragging");
+ that._unblockFrames();
+ that._trigger( "dragStop", event, filteredUi( ui ) );
+ }
+ });
+ },
+
+ _makeResizable: function() {
+ var that = this,
+ options = this.options,
+ handles = options.resizable,
+ // .ui-resizable has position: relative defined in the stylesheet
+ // but dialogs have to use absolute or fixed positioning
+ position = this.uiDialog.css("position"),
+ resizeHandles = typeof handles === "string" ?
+ handles :
+ "n,e,s,w,se,sw,ne,nw";
+
+ function filteredUi( ui ) {
+ return {
+ originalPosition: ui.originalPosition,
+ originalSize: ui.originalSize,
+ position: ui.position,
+ size: ui.size
+ };
+ }
+
+ this.uiDialog.resizable({
+ cancel: ".ui-dialog-content",
+ containment: "document",
+ alsoResize: this.element,
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ minWidth: options.minWidth,
+ minHeight: this._minHeight(),
+ handles: resizeHandles,
+ start: function( event, ui ) {
+ $( this ).addClass("ui-dialog-resizing");
+ that._blockFrames();
+ that._trigger( "resizeStart", event, filteredUi( ui ) );
+ },
+ resize: function( event, ui ) {
+ that._trigger( "resize", event, filteredUi( ui ) );
+ },
+ stop: function( event, ui ) {
+ options.height = $( this ).height();
+ options.width = $( this ).width();
+ $( this ).removeClass("ui-dialog-resizing");
+ that._unblockFrames();
+ that._trigger( "resizeStop", event, filteredUi( ui ) );
+ }
+ })
+ .css( "position", position );
+ },
+
+ _minHeight: function() {
+ var options = this.options;
+
+ return options.height === "auto" ?
+ options.minHeight :
+ Math.min( options.minHeight, options.height );
+ },
+
+ _position: function() {
+ // Need to show the dialog to get the actual offset in the position plugin
+ var isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( this.options.position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ },
+
+ _setOptions: function( options ) {
+ var that = this,
+ resize = false,
+ resizableOptions = {};
+
+ $.each( options, function( key, value ) {
+ that._setOption( key, value );
+
+ if ( key in sizeRelatedOptions ) {
+ resize = true;
+ }
+ if ( key in resizableRelatedOptions ) {
+ resizableOptions[ key ] = value;
+ }
+ });
+
+ if ( resize ) {
+ this._size();
+ this._position();
+ }
+ if ( this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", resizableOptions );
+ }
+ },
+
+ _setOption: function( key, value ) {
+ /*jshint maxcomplexity:15*/
+ var isDraggable, isResizable,
+ uiDialog = this.uiDialog;
+
+ if ( key === "dialogClass" ) {
+ uiDialog
+ .removeClass( this.options.dialogClass )
+ .addClass( value );
+ }
+
+ if ( key === "disabled" ) {
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "appendTo" ) {
+ this.uiDialog.appendTo( this._appendTo() );
+ }
+
+ if ( key === "buttons" ) {
+ this._createButtons();
+ }
+
+ if ( key === "closeText" ) {
+ this.uiDialogTitlebarClose.button({
+ // Ensure that we always pass a string
+ label: "" + value
+ });
+ }
+
+ if ( key === "draggable" ) {
+ isDraggable = uiDialog.is(":data(ui-draggable)");
+ if ( isDraggable && !value ) {
+ uiDialog.draggable("destroy");
+ }
+
+ if ( !isDraggable && value ) {
+ this._makeDraggable();
+ }
+ }
+
+ if ( key === "position" ) {
+ this._position();
+ }
+
+ if ( key === "resizable" ) {
+ // currently resizable, becoming non-resizable
+ isResizable = uiDialog.is(":data(ui-resizable)");
+ if ( isResizable && !value ) {
+ uiDialog.resizable("destroy");
+ }
+
+ // currently resizable, changing handles
+ if ( isResizable && typeof value === "string" ) {
+ uiDialog.resizable( "option", "handles", value );
+ }
+
+ // currently non-resizable, becoming resizable
+ if ( !isResizable && value !== false ) {
+ this._makeResizable();
+ }
+ }
+
+ if ( key === "title" ) {
+ this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
+ }
+ },
+
+ _size: function() {
+ // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
+ // divs will both have width and height set, so we need to reset them
+ var nonContentHeight, minContentHeight, maxContentHeight,
+ options = this.options;
+
+ // Reset content sizing
+ this.element.show().css({
+ width: "auto",
+ minHeight: 0,
+ maxHeight: "none",
+ height: 0
+ });
+
+ if ( options.minWidth > options.width ) {
+ options.width = options.minWidth;
+ }
+
+ // reset wrapper sizing
+ // determine the height of all the non-content elements
+ nonContentHeight = this.uiDialog.css({
+ height: "auto",
+ width: options.width
+ })
+ .outerHeight();
+ minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
+ maxContentHeight = typeof options.maxHeight === "number" ?
+ Math.max( 0, options.maxHeight - nonContentHeight ) :
+ "none";
+
+ if ( options.height === "auto" ) {
+ this.element.css({
+ minHeight: minContentHeight,
+ maxHeight: maxContentHeight,
+ height: "auto"
+ });
+ } else {
+ this.element.height( Math.max( 0, options.height - nonContentHeight ) );
+ }
+
+ if (this.uiDialog.is(":data(ui-resizable)") ) {
+ this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
+ }
+ },
+
+ _blockFrames: function() {
+ this.iframeBlocks = this.document.find( "iframe" ).map(function() {
+ var iframe = $( this );
+
+ return $( "<div>" )
+ .css({
+ position: "absolute",
+ width: iframe.outerWidth(),
+ height: iframe.outerHeight()
+ })
+ .appendTo( iframe.parent() )
+ .offset( iframe.offset() )[0];
+ });
+ },
+
+ _unblockFrames: function() {
+ if ( this.iframeBlocks ) {
+ this.iframeBlocks.remove();
+ delete this.iframeBlocks;
+ }
+ },
+
+ _allowInteraction: function( event ) {
+ if ( $( event.target ).closest(".ui-dialog").length ) {
+ return true;
+ }
+
+ // TODO: Remove hack when datepicker implements
+ // the .ui-front logic (#8989)
+ return !!$( event.target ).closest(".ui-datepicker").length;
+ },
+
+ _createOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ var that = this,
+ widgetFullName = this.widgetFullName;
+ if ( !$.ui.dialog.overlayInstances ) {
+ // Prevent use of anchors and inputs.
+ // We use a delay in case the overlay is created from an
+ // event that we're going to be cancelling. (#2804)
+ this._delay(function() {
+ // Handle .dialog().dialog("close") (#4065)
+ if ( $.ui.dialog.overlayInstances ) {
+ this.document.bind( "focusin.dialog", function( event ) {
+ if ( !that._allowInteraction( event ) ) {
+ event.preventDefault();
+ $(".ui-dialog:visible:last .ui-dialog-content")
+ .data( widgetFullName )._focusTabbable();
+ }
+ });
+ }
+ });
+ }
+
+ this.overlay = $("<div>")
+ .addClass("ui-widget-overlay ui-front")
+ .appendTo( this._appendTo() );
+ this._on( this.overlay, {
+ mousedown: "_keepFocus"
+ });
+ $.ui.dialog.overlayInstances++;
+ },
+
+ _destroyOverlay: function() {
+ if ( !this.options.modal ) {
+ return;
+ }
+
+ if ( this.overlay ) {
+ $.ui.dialog.overlayInstances--;
+
+ if ( !$.ui.dialog.overlayInstances ) {
+ this.document.unbind( "focusin.dialog" );
+ }
+ this.overlay.remove();
+ this.overlay = null;
+ }
+ }
+});
+
+$.ui.dialog.overlayInstances = 0;
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+ // position option with array notation
+ // just override with old implementation
+ $.widget( "ui.dialog", $.ui.dialog, {
+ _position: function() {
+ var position = this.options.position,
+ myAt = [],
+ offset = [ 0, 0 ],
+ isVisible;
+
+ if ( position ) {
+ if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
+ myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
+ if ( myAt.length === 1 ) {
+ myAt[1] = myAt[0];
+ }
+
+ $.each( [ "left", "top" ], function( i, offsetPosition ) {
+ if ( +myAt[ i ] === myAt[ i ] ) {
+ offset[ i ] = myAt[ i ];
+ myAt[ i ] = offsetPosition;
+ }
+ });
+
+ position = {
+ my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
+ myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
+ at: myAt.join(" ")
+ };
+ }
+
+ position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
+ } else {
+ position = $.ui.dialog.prototype.options.position;
+ }
+
+ // need to show the dialog to get the actual offset in the position plugin
+ isVisible = this.uiDialog.is(":visible");
+ if ( !isVisible ) {
+ this.uiDialog.show();
+ }
+ this.uiDialog.position( position );
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ }
+ });
+}
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+var rvertical = /up|down|vertical/,
+ rpositivemotion = /up|left|vertical|horizontal/;
+
+$.effects.effect.blind = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ direction = o.direction || "up",
+ vertical = rvertical.test( direction ),
+ ref = vertical ? "height" : "width",
+ ref2 = vertical ? "top" : "left",
+ motion = rpositivemotion.test( direction ),
+ animation = {},
+ show = mode === "show",
+ wrapper, distance, margin;
+
+ // if already wrapped, the wrapper's properties are my property. #6245
+ if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+ $.effects.save( el.parent(), props );
+ } else {
+ $.effects.save( el, props );
+ }
+ el.show();
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ distance = wrapper[ ref ]();
+ margin = parseFloat( wrapper.css( ref2 ) ) || 0;
+
+ animation[ ref ] = show ? distance : 0;
+ if ( !motion ) {
+ el
+ .css( vertical ? "bottom" : "right", 0 )
+ .css( vertical ? "top" : "left", "auto" )
+ .css({ position: "absolute" });
+
+ animation[ ref2 ] = show ? margin : distance + margin;
+ }
+
+ // start at 0 if we are showing
+ if ( show ) {
+ wrapper.css( ref, 0 );
+ if ( ! motion ) {
+ wrapper.css( ref2, margin + distance );
+ }
+ }
+
+ // Animate
+ wrapper.animate( animation, {
+ duration: o.duration,
+ easing: o.easing,
+ queue: false,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.bounce = function( o, done ) {
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+
+ // defaults:
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ hide = mode === "hide",
+ show = mode === "show",
+ direction = o.direction || "up",
+ distance = o.distance,
+ times = o.times || 5,
+
+ // number of internal animations
+ anims = times * 2 + ( show || hide ? 1 : 0 ),
+ speed = o.duration / anims,
+ easing = o.easing,
+
+ // utility:
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ),
+ i,
+ upAnim,
+ downAnim,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ // Avoid touching opacity to prevent clearType and PNG issues in IE
+ if ( show || hide ) {
+ props.push( "opacity" );
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el ); // Create Wrapper
+
+ // default distance for the BIGGEST bounce is the outer Distance / 3
+ if ( !distance ) {
+ distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
+ }
+
+ if ( show ) {
+ downAnim = { opacity: 1 };
+ downAnim[ ref ] = 0;
+
+ // if we are showing, force opacity 0 and set the initial position
+ // then do the "first" animation
+ el.css( "opacity", 0 )
+ .css( ref, motion ? -distance * 2 : distance * 2 )
+ .animate( downAnim, speed, easing );
+ }
+
+ // start at the smallest distance if we are hiding
+ if ( hide ) {
+ distance = distance / Math.pow( 2, times - 1 );
+ }
+
+ downAnim = {};
+ downAnim[ ref ] = 0;
+ // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
+ for ( i = 0; i < times; i++ ) {
+ upAnim = {};
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing )
+ .animate( downAnim, speed, easing );
+
+ distance = hide ? distance * 2 : distance / 2;
+ }
+
+ // Last Bounce when Hiding
+ if ( hide ) {
+ upAnim = { opacity: 0 };
+ upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+ el.animate( upAnim, speed, easing );
+ }
+
+ el.queue(function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.clip = function( o, done ) {
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "vertical",
+ vert = direction === "vertical",
+ size = vert ? "height" : "width",
+ position = vert ? "top" : "left",
+ animation = {},
+ wrapper, animate, distance;
+
+ // Save & Show
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
+ distance = animate[ size ]();
+
+ // Shift
+ if ( show ) {
+ animate.css( size, 0 );
+ animate.css( position, distance / 2 );
+ }
+
+ // Create Animation Object:
+ animation[ size ] = show ? distance : 0;
+ animation[ position ] = show ? 0 : distance / 2;
+
+ // Animate
+ animate.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( !show ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.drop = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
+ animation = {
+ opacity: show ? 1 : 0
+ },
+ distance;
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
+
+ if ( show ) {
+ el
+ .css( "opacity", 0 )
+ .css( ref, motion === "pos" ? -distance : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( motion === "pos" ? "+=" : "-=" ) :
+ ( motion === "pos" ? "-=" : "+=" ) ) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.explode = function( o, done ) {
+
+ var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
+ cells = rows,
+ el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+
+ // show and then visibility:hidden the element before calculating offset
+ offset = el.show().css( "visibility", "hidden" ).offset(),
+
+ // width and height of a piece
+ width = Math.ceil( el.outerWidth() / cells ),
+ height = Math.ceil( el.outerHeight() / rows ),
+ pieces = [],
+
+ // loop
+ i, j, left, top, mx, my;
+
+ // children animate complete:
+ function childComplete() {
+ pieces.push( this );
+ if ( pieces.length === rows * cells ) {
+ animComplete();
+ }
+ }
+
+ // clone the element for each row and cell.
+ for( i = 0; i < rows ; i++ ) { // ===>
+ top = offset.top + i * height;
+ my = i - ( rows - 1 ) / 2 ;
+
+ for( j = 0; j < cells ; j++ ) { // |||
+ left = offset.left + j * width;
+ mx = j - ( cells - 1 ) / 2 ;
+
+ // Create a clone of the now hidden main element that will be absolute positioned
+ // within a wrapper div off the -left and -top equal to size of our pieces
+ el
+ .clone()
+ .appendTo( "body" )
+ .wrap( "<div></div>" )
+ .css({
+ position: "absolute",
+ visibility: "visible",
+ left: -j * width,
+ top: -i * height
+ })
+
+ // select the wrapper - make it overflow: hidden and absolute positioned based on
+ // where the original was located +left and +top equal to the size of pieces
+ .parent()
+ .addClass( "ui-effects-explode" )
+ .css({
+ position: "absolute",
+ overflow: "hidden",
+ width: width,
+ height: height,
+ left: left + ( show ? mx * width : 0 ),
+ top: top + ( show ? my * height : 0 ),
+ opacity: show ? 0 : 1
+ }).animate({
+ left: left + ( show ? 0 : mx * width ),
+ top: top + ( show ? 0 : my * height ),
+ opacity: show ? 1 : 0
+ }, o.duration || 500, o.easing, childComplete );
+ }
+ }
+
+ function animComplete() {
+ el.css({
+ visibility: "visible"
+ });
+ $( pieces ).remove();
+ if ( !show ) {
+ el.hide();
+ }
+ done();
+ }
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.fade = function( o, done ) {
+ var el = $( this ),
+ mode = $.effects.setMode( el, o.mode || "toggle" );
+
+ el.animate({
+ opacity: mode
+ }, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: done
+ });
+};
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.effects.effect.fold = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "hide" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ size = o.size || 15,
+ percent = /([0-9]+)%/.exec( size ),
+ horizFirst = !!o.horizFirst,
+ widthFirst = show !== horizFirst,
+ ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
+ duration = o.duration / 2,
+ wrapper, distance,
+ animation1 = {},
+ animation2 = {};
+
+ $.effects.save( el, props );
+ el.show();
+
+ // Create Wrapper
+ wrapper = $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+ distance = widthFirst ?
+ [ wrapper.width(), wrapper.height() ] :
+ [ wrapper.height(), wrapper.width() ];
+
+ if ( percent ) {
+ size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
+ }
+ if ( show ) {
+ wrapper.css( horizFirst ? {
+ height: 0,
+ width: size
+ } : {
+ height: size,
+ width: 0
+ });
+ }
+
+ // Animation
+ animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
+ animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
+
+ // Animate
+ wrapper
+ .animate( animation1, duration, o.easing )
+ .animate( animation2, duration, o.easing, function() {
+ if ( hide ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.highlight = function( o, done ) {
+ var elem = $( this ),
+ props = [ "backgroundImage", "backgroundColor", "opacity" ],
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ animation = {
+ backgroundColor: elem.css( "backgroundColor" )
+ };
+
+ if (mode === "hide") {
+ animation.opacity = 0;
+ }
+
+ $.effects.save( elem, props );
+
+ elem
+ .show()
+ .css({
+ backgroundImage: "none",
+ backgroundColor: o.color || "#ffff99"
+ })
+ .animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ elem.hide();
+ }
+ $.effects.restore( elem, props );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.pulsate = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "show" ),
+ show = mode === "show",
+ hide = mode === "hide",
+ showhide = ( show || mode === "hide" ),
+
+ // showing or hiding leaves of the "last" animation
+ anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
+ duration = o.duration / anims,
+ animateTo = 0,
+ queue = elem.queue(),
+ queuelen = queue.length,
+ i;
+
+ if ( show || !elem.is(":visible")) {
+ elem.css( "opacity", 0 ).show();
+ animateTo = 1;
+ }
+
+ // anims - 1 opacity "toggles"
+ for ( i = 1; i < anims; i++ ) {
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing );
+ animateTo = 1 - animateTo;
+ }
+
+ elem.animate({
+ opacity: animateTo
+ }, duration, o.easing);
+
+ elem.queue(function() {
+ if ( hide ) {
+ elem.hide();
+ }
+ done();
+ });
+
+ // We just queued up "anims" animations, we need to put them next in the queue
+ if ( queuelen > 1 ) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ elem.dequeue();
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.puff = function( o, done ) {
+ var elem = $( this ),
+ mode = $.effects.setMode( elem, o.mode || "hide" ),
+ hide = mode === "hide",
+ percent = parseInt( o.percent, 10 ) || 150,
+ factor = percent / 100,
+ original = {
+ height: elem.height(),
+ width: elem.width(),
+ outerHeight: elem.outerHeight(),
+ outerWidth: elem.outerWidth()
+ };
+
+ $.extend( o, {
+ effect: "scale",
+ queue: false,
+ fade: true,
+ mode: mode,
+ complete: done,
+ percent: hide ? percent : 100,
+ from: hide ?
+ original :
+ {
+ height: original.height * factor,
+ width: original.width * factor,
+ outerHeight: original.outerHeight * factor,
+ outerWidth: original.outerWidth * factor
+ }
+ });
+
+ elem.effect( o );
+};
+
+$.effects.effect.scale = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ options = $.extend( true, {}, o ),
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ percent = parseInt( o.percent, 10 ) ||
+ ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
+ direction = o.direction || "both",
+ origin = o.origin,
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ },
+ factor = {
+ y: direction !== "horizontal" ? (percent / 100) : 1,
+ x: direction !== "vertical" ? (percent / 100) : 1
+ };
+
+ // We are going to pass this effect to the size effect:
+ options.effect = "size";
+ options.queue = false;
+ options.complete = done;
+
+ // Set default origin and restore for show/hide
+ if ( mode !== "effect" ) {
+ options.origin = origin || ["middle","center"];
+ options.restore = true;
+ }
+
+ options.from = o.from || ( mode === "show" ? {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ } : original );
+ options.to = {
+ height: original.height * factor.y,
+ width: original.width * factor.x,
+ outerHeight: original.outerHeight * factor.y,
+ outerWidth: original.outerWidth * factor.x
+ };
+
+ // Fade option to support puff
+ if ( options.fade ) {
+ if ( mode === "show" ) {
+ options.from.opacity = 0;
+ options.to.opacity = 1;
+ }
+ if ( mode === "hide" ) {
+ options.from.opacity = 1;
+ options.to.opacity = 0;
+ }
+ }
+
+ // Animate
+ el.effect( options );
+
+};
+
+$.effects.effect.size = function( o, done ) {
+
+ // Create element
+ var original, baseline, factor,
+ el = $( this ),
+ props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
+
+ // Always restore
+ props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
+
+ // Copy for children
+ props2 = [ "width", "height", "overflow" ],
+ cProps = [ "fontSize" ],
+ vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
+ hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
+
+ // Set options
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ restore = o.restore || mode !== "effect",
+ scale = o.scale || "both",
+ origin = o.origin || [ "middle", "center" ],
+ position = el.css( "position" ),
+ props = restore ? props0 : props1,
+ zero = {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ };
+
+ if ( mode === "show" ) {
+ el.show();
+ }
+ original = {
+ height: el.height(),
+ width: el.width(),
+ outerHeight: el.outerHeight(),
+ outerWidth: el.outerWidth()
+ };
+
+ if ( o.mode === "toggle" && mode === "show" ) {
+ el.from = o.to || zero;
+ el.to = o.from || original;
+ } else {
+ el.from = o.from || ( mode === "show" ? zero : original );
+ el.to = o.to || ( mode === "hide" ? zero : original );
+ }
+
+ // Set scaling factor
+ factor = {
+ from: {
+ y: el.from.height / original.height,
+ x: el.from.width / original.width
+ },
+ to: {
+ y: el.to.height / original.height,
+ x: el.to.width / original.width
+ }
+ };
+
+ // Scale the css box
+ if ( scale === "box" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( vProps );
+ el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ props = props.concat( hProps );
+ el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
+ el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
+ }
+ }
+
+ // Scale the content
+ if ( scale === "content" || scale === "both" ) {
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ props = props.concat( cProps ).concat( props2 );
+ el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
+ el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
+ }
+ }
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+ el.css( "overflow", "hidden" ).css( el.from );
+
+ // Adjust
+ if (origin) { // Calculate baseline shifts
+ baseline = $.effects.getBaseline( origin, original );
+ el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
+ el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
+ el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
+ el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
+ }
+ el.css( el.from ); // set top & left
+
+ // Animate
+ if ( scale === "content" || scale === "both" ) { // Scale the children
+
+ // Add margins/font-size
+ vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
+ hProps = hProps.concat([ "marginLeft", "marginRight" ]);
+ props2 = props0.concat(vProps).concat(hProps);
+
+ el.find( "*[width]" ).each( function(){
+ var child = $( this ),
+ c_original = {
+ height: child.height(),
+ width: child.width(),
+ outerHeight: child.outerHeight(),
+ outerWidth: child.outerWidth()
+ };
+ if (restore) {
+ $.effects.save(child, props2);
+ }
+
+ child.from = {
+ height: c_original.height * factor.from.y,
+ width: c_original.width * factor.from.x,
+ outerHeight: c_original.outerHeight * factor.from.y,
+ outerWidth: c_original.outerWidth * factor.from.x
+ };
+ child.to = {
+ height: c_original.height * factor.to.y,
+ width: c_original.width * factor.to.x,
+ outerHeight: c_original.height * factor.to.y,
+ outerWidth: c_original.width * factor.to.x
+ };
+
+ // Vertical props scaling
+ if ( factor.from.y !== factor.to.y ) {
+ child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
+ child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
+ }
+
+ // Horizontal props scaling
+ if ( factor.from.x !== factor.to.x ) {
+ child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
+ child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
+ }
+
+ // Animate children
+ child.css( child.from );
+ child.animate( child.to, o.duration, o.easing, function() {
+
+ // Restore children
+ if ( restore ) {
+ $.effects.restore( child, props2 );
+ }
+ });
+ });
+ }
+
+ // Animate
+ el.animate( el.to, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( el.to.opacity === 0 ) {
+ el.css( "opacity", el.from.opacity );
+ }
+ if( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ if ( !restore ) {
+
+ // we need to calculate our new positioning based on the scaling
+ if ( position === "static" ) {
+ el.css({
+ position: "relative",
+ top: el.to.top,
+ left: el.to.left
+ });
+ } else {
+ $.each([ "top", "left" ], function( idx, pos ) {
+ el.css( pos, function( _, str ) {
+ var val = parseInt( str, 10 ),
+ toRef = idx ? el.to.left : el.to.top;
+
+ // if original was "auto", recalculate the new value from wrapper
+ if ( str === "auto" ) {
+ return toRef + "px";
+ }
+
+ return val + toRef + "px";
+ });
+ });
+ }
+ }
+
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.shake = function( o, done ) {
+
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+ mode = $.effects.setMode( el, o.mode || "effect" ),
+ direction = o.direction || "left",
+ distance = o.distance || 20,
+ times = o.times || 3,
+ anims = times * 2 + 1,
+ speed = Math.round(o.duration/anims),
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ animation = {},
+ animation1 = {},
+ animation2 = {},
+ i,
+
+ // we will need to re-assemble the queue to stack our animations in place
+ queue = el.queue(),
+ queuelen = queue.length;
+
+ $.effects.save( el, props );
+ el.show();
+ $.effects.createWrapper( el );
+
+ // Animation
+ animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
+ animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
+ animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
+
+ // Animate
+ el.animate( animation, speed, o.easing );
+
+ // Shakes
+ for ( i = 1; i < times; i++ ) {
+ el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
+ }
+ el
+ .animate( animation1, speed, o.easing )
+ .animate( animation, speed / 2, o.easing )
+ .queue(function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ });
+
+ // inject all the animations we just queued to be first in line (after "inprogress")
+ if ( queuelen > 1) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+ }
+ el.dequeue();
+
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.slide = function( o, done ) {
+
+ // Create element
+ var el = $( this ),
+ props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
+ mode = $.effects.setMode( el, o.mode || "show" ),
+ show = mode === "show",
+ direction = o.direction || "left",
+ ref = (direction === "up" || direction === "down") ? "top" : "left",
+ positiveMotion = (direction === "up" || direction === "left"),
+ distance,
+ animation = {};
+
+ // Adjust
+ $.effects.save( el, props );
+ el.show();
+ distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
+
+ $.effects.createWrapper( el ).css({
+ overflow: "hidden"
+ });
+
+ if ( show ) {
+ el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
+ }
+
+ // Animation
+ animation[ ref ] = ( show ?
+ ( positiveMotion ? "+=" : "-=") :
+ ( positiveMotion ? "-=" : "+=")) +
+ distance;
+
+ // Animate
+ el.animate( animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.easing,
+ complete: function() {
+ if ( mode === "hide" ) {
+ el.hide();
+ }
+ $.effects.restore( el, props );
+ $.effects.removeWrapper( el );
+ done();
+ }
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.effects.effect.transfer = function( o, done ) {
+ var elem = $( this ),
+ target = $( o.to ),
+ targetFixed = target.css( "position" ) === "fixed",
+ body = $("body"),
+ fixTop = targetFixed ? body.scrollTop() : 0,
+ fixLeft = targetFixed ? body.scrollLeft() : 0,
+ endPosition = target.offset(),
+ animation = {
+ top: endPosition.top - fixTop ,
+ left: endPosition.left - fixLeft ,
+ height: target.innerHeight(),
+ width: target.innerWidth()
+ },
+ startPosition = elem.offset(),
+ transfer = $( "<div class='ui-effects-transfer'></div>" )
+ .appendTo( document.body )
+ .addClass( o.className )
+ .css({
+ top: startPosition.top - fixTop ,
+ left: startPosition.left - fixLeft ,
+ height: elem.innerHeight(),
+ width: elem.innerWidth(),
+ position: targetFixed ? "fixed" : "absolute"
+ })
+ .animate( animation, o.duration, o.easing, function() {
+ transfer.remove();
+ done();
+ });
+};
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$.widget( "ui.menu", {
+ version: "1.10.3",
+ defaultElement: "<ul>",
+ delay: 300,
+ options: {
+ icons: {
+ submenu: "ui-icon-carat-1-e"
+ },
+ menus: "ul",
+ position: {
+ my: "left top",
+ at: "right top"
+ },
+ role: "menu",
+
+ // callbacks
+ blur: null,
+ focus: null,
+ select: null
+ },
+
+ _create: function() {
+ this.activeMenu = this.element;
+ // flag used to prevent firing of the click handler
+ // as the event bubbles up through nested menus
+ this.mouseHandled = false;
+ this.element
+ .uniqueId()
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
+ .attr({
+ role: this.options.role,
+ tabIndex: 0
+ })
+ // need to catch all clicks on disabled menu
+ // not possible through _on
+ .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
+ if ( this.options.disabled ) {
+ event.preventDefault();
+ }
+ }, this ));
+
+ if ( this.options.disabled ) {
+ this.element
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ }
+
+ this._on({
+ // Prevent focus from sticking to links inside menu after clicking
+ // them (focus should always stay on UL during navigation).
+ "mousedown .ui-menu-item > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-state-disabled > a": function( event ) {
+ event.preventDefault();
+ },
+ "click .ui-menu-item:has(a)": function( event ) {
+ var target = $( event.target ).closest( ".ui-menu-item" );
+ if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
+ this.mouseHandled = true;
+
+ this.select( event );
+ // Open submenu on click
+ if ( target.has( ".ui-menu" ).length ) {
+ this.expand( event );
+ } else if ( !this.element.is( ":focus" ) ) {
+ // Redirect focus to the menu
+ this.element.trigger( "focus", [ true ] );
+
+ // If the active item is on the top level, let it stay active.
+ // Otherwise, blur the active item since it is no longer visible.
+ if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
+ clearTimeout( this.timer );
+ }
+ }
+ }
+ },
+ "mouseenter .ui-menu-item": function( event ) {
+ var target = $( event.currentTarget );
+ // Remove ui-state-active class from siblings of the newly focused menu item
+ // to avoid a jump caused by adjacent elements both having a class with a border
+ target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
+ this.focus( event, target );
+ },
+ mouseleave: "collapseAll",
+ "mouseleave .ui-menu": "collapseAll",
+ focus: function( event, keepActiveItem ) {
+ // If there's already an active item, keep it active
+ // If not, activate the first item
+ var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
+
+ if ( !keepActiveItem ) {
+ this.focus( event, item );
+ }
+ },
+ blur: function( event ) {
+ this._delay(function() {
+ if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
+ this.collapseAll( event );
+ }
+ });
+ },
+ keydown: "_keydown"
+ });
+
+ this.refresh();
+
+ // Clicks outside of a menu collapse any open menus
+ this._on( this.document, {
+ click: function( event ) {
+ if ( !$( event.target ).closest( ".ui-menu" ).length ) {
+ this.collapseAll( event );
+ }
+
+ // Reset the mouseHandled flag
+ this.mouseHandled = false;
+ }
+ });
+ },
+
+ _destroy: function() {
+ // Destroy (sub)menus
+ this.element
+ .removeAttr( "aria-activedescendant" )
+ .find( ".ui-menu" ).addBack()
+ .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-disabled" )
+ .removeUniqueId()
+ .show();
+
+ // Destroy menu items
+ this.element.find( ".ui-menu-item" )
+ .removeClass( "ui-menu-item" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-disabled" )
+ .children( "a" )
+ .removeUniqueId()
+ .removeClass( "ui-corner-all ui-state-hover" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-haspopup" )
+ .children().each( function() {
+ var elem = $( this );
+ if ( elem.data( "ui-menu-submenu-carat" ) ) {
+ elem.remove();
+ }
+ });
+
+ // Destroy menu dividers
+ this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
+ },
+
+ _keydown: function( event ) {
+ /*jshint maxcomplexity:20*/
+ var match, prev, character, skip, regex,
+ preventDefault = true;
+
+ function escape( value ) {
+ return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.PAGE_UP:
+ this.previousPage( event );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ this.nextPage( event );
+ break;
+ case $.ui.keyCode.HOME:
+ this._move( "first", "first", event );
+ break;
+ case $.ui.keyCode.END:
+ this._move( "last", "last", event );
+ break;
+ case $.ui.keyCode.UP:
+ this.previous( event );
+ break;
+ case $.ui.keyCode.DOWN:
+ this.next( event );
+ break;
+ case $.ui.keyCode.LEFT:
+ this.collapse( event );
+ break;
+ case $.ui.keyCode.RIGHT:
+ if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
+ this.expand( event );
+ }
+ break;
+ case $.ui.keyCode.ENTER:
+ case $.ui.keyCode.SPACE:
+ this._activate( event );
+ break;
+ case $.ui.keyCode.ESCAPE:
+ this.collapse( event );
+ break;
+ default:
+ preventDefault = false;
+ prev = this.previousFilter || "";
+ character = String.fromCharCode( event.keyCode );
+ skip = false;
+
+ clearTimeout( this.filterTimer );
+
+ if ( character === prev ) {
+ skip = true;
+ } else {
+ character = prev + character;
+ }
+
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ match = skip && match.index( this.active.next() ) !== -1 ?
+ this.active.nextAll( ".ui-menu-item" ) :
+ match;
+
+ // If no matches on the current filter, reset to the last character pressed
+ // to move down the menu to the first item that starts with that character
+ if ( !match.length ) {
+ character = String.fromCharCode( event.keyCode );
+ regex = new RegExp( "^" + escape( character ), "i" );
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
+ return regex.test( $( this ).children( "a" ).text() );
+ });
+ }
+
+ if ( match.length ) {
+ this.focus( event, match );
+ if ( match.length > 1 ) {
+ this.previousFilter = character;
+ this.filterTimer = this._delay(function() {
+ delete this.previousFilter;
+ }, 1000 );
+ } else {
+ delete this.previousFilter;
+ }
+ } else {
+ delete this.previousFilter;
+ }
+ }
+
+ if ( preventDefault ) {
+ event.preventDefault();
+ }
+ },
+
+ _activate: function( event ) {
+ if ( !this.active.is( ".ui-state-disabled" ) ) {
+ if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
+ this.expand( event );
+ } else {
+ this.select( event );
+ }
+ }
+ },
+
+ refresh: function() {
+ var menus,
+ icon = this.options.icons.submenu,
+ submenus = this.element.find( this.options.menus );
+
+ // Initialize nested menus
+ submenus.filter( ":not(.ui-menu)" )
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
+ .hide()
+ .attr({
+ role: this.options.role,
+ "aria-hidden": "true",
+ "aria-expanded": "false"
+ })
+ .each(function() {
+ var menu = $( this ),
+ item = menu.prev( "a" ),
+ submenuCarat = $( "<span>" )
+ .addClass( "ui-menu-icon ui-icon " + icon )
+ .data( "ui-menu-submenu-carat", true );
+
+ item
+ .attr( "aria-haspopup", "true" )
+ .prepend( submenuCarat );
+ menu.attr( "aria-labelledby", item.attr( "id" ) );
+ });
+
+ menus = submenus.add( this.element );
+
+ // Don't refresh list items that are already adapted
+ menus.children( ":not(.ui-menu-item):has(a)" )
+ .addClass( "ui-menu-item" )
+ .attr( "role", "presentation" )
+ .children( "a" )
+ .uniqueId()
+ .addClass( "ui-corner-all" )
+ .attr({
+ tabIndex: -1,
+ role: this._itemRole()
+ });
+
+ // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
+ menus.children( ":not(.ui-menu-item)" ).each(function() {
+ var item = $( this );
+ // hyphen, em dash, en dash
+ if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
+ item.addClass( "ui-widget-content ui-menu-divider" );
+ }
+ });
+
+ // Add aria-disabled attribute to any disabled menu item
+ menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
+
+ // If the active item has been removed, blur the menu
+ if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+ this.blur();
+ }
+ },
+
+ _itemRole: function() {
+ return {
+ menu: "menuitem",
+ listbox: "option"
+ }[ this.options.role ];
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "icons" ) {
+ this.element.find( ".ui-menu-icon" )
+ .removeClass( this.options.icons.submenu )
+ .addClass( value.submenu );
+ }
+ this._super( key, value );
+ },
+
+ focus: function( event, item ) {
+ var nested, focused;
+ this.blur( event, event && event.type === "focus" );
+
+ this._scrollIntoView( item );
+
+ this.active = item.first();
+ focused = this.active.children( "a" ).addClass( "ui-state-focus" );
+ // Only update aria-activedescendant if there's a role
+ // otherwise we assume focus is managed elsewhere
+ if ( this.options.role ) {
+ this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
+ }
+
+ // Highlight active parent menu item, if any
+ this.active
+ .parent()
+ .closest( ".ui-menu-item" )
+ .children( "a:first" )
+ .addClass( "ui-state-active" );
+
+ if ( event && event.type === "keydown" ) {
+ this._close();
+ } else {
+ this.timer = this._delay(function() {
+ this._close();
+ }, this.delay );
+ }
+
+ nested = item.children( ".ui-menu" );
+ if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
+ this._startOpening(nested);
+ }
+ this.activeMenu = item.parent();
+
+ this._trigger( "focus", event, { item: item } );
+ },
+
+ _scrollIntoView: function( item ) {
+ var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
+ if ( this._hasScroll() ) {
+ borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
+ paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
+ scroll = this.activeMenu.scrollTop();
+ elementHeight = this.activeMenu.height();
+ itemHeight = item.height();
+
+ if ( offset < 0 ) {
+ this.activeMenu.scrollTop( scroll + offset );
+ } else if ( offset + itemHeight > elementHeight ) {
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
+ }
+ }
+ },
+
+ blur: function( event, fromFocus ) {
+ if ( !fromFocus ) {
+ clearTimeout( this.timer );
+ }
+
+ if ( !this.active ) {
+ return;
+ }
+
+ this.active.children( "a" ).removeClass( "ui-state-focus" );
+ this.active = null;
+
+ this._trigger( "blur", event, { item: this.active } );
+ },
+
+ _startOpening: function( submenu ) {
+ clearTimeout( this.timer );
+
+ // Don't open if already open fixes a Firefox bug that caused a .5 pixel
+ // shift in the submenu position when mousing over the carat icon
+ if ( submenu.attr( "aria-hidden" ) !== "true" ) {
+ return;
+ }
+
+ this.timer = this._delay(function() {
+ this._close();
+ this._open( submenu );
+ }, this.delay );
+ },
+
+ _open: function( submenu ) {
+ var position = $.extend({
+ of: this.active
+ }, this.options.position );
+
+ clearTimeout( this.timer );
+ this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
+ .hide()
+ .attr( "aria-hidden", "true" );
+
+ submenu
+ .show()
+ .removeAttr( "aria-hidden" )
+ .attr( "aria-expanded", "true" )
+ .position( position );
+ },
+
+ collapseAll: function( event, all ) {
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ // If we were passed an event, look for the submenu that contains the event
+ var currentMenu = all ? this.element :
+ $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
+
+ // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
+ if ( !currentMenu.length ) {
+ currentMenu = this.element;
+ }
+
+ this._close( currentMenu );
+
+ this.blur( event );
+ this.activeMenu = currentMenu;
+ }, this.delay );
+ },
+
+ // With no arguments, closes the currently active menu - if nothing is active
+ // it closes all menus. If passed an argument, it will search for menus BELOW
+ _close: function( startMenu ) {
+ if ( !startMenu ) {
+ startMenu = this.active ? this.active.parent() : this.element;
+ }
+
+ startMenu
+ .find( ".ui-menu" )
+ .hide()
+ .attr( "aria-hidden", "true" )
+ .attr( "aria-expanded", "false" )
+ .end()
+ .find( "a.ui-state-active" )
+ .removeClass( "ui-state-active" );
+ },
+
+ collapse: function( event ) {
+ var newItem = this.active &&
+ this.active.parent().closest( ".ui-menu-item", this.element );
+ if ( newItem && newItem.length ) {
+ this._close();
+ this.focus( event, newItem );
+ }
+ },
+
+ expand: function( event ) {
+ var newItem = this.active &&
+ this.active
+ .children( ".ui-menu " )
+ .children( ".ui-menu-item" )
+ .first();
+
+ if ( newItem && newItem.length ) {
+ this._open( newItem.parent() );
+
+ // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
+ this._delay(function() {
+ this.focus( event, newItem );
+ });
+ }
+ },
+
+ next: function( event ) {
+ this._move( "next", "first", event );
+ },
+
+ previous: function( event ) {
+ this._move( "prev", "last", event );
+ },
+
+ isFirstItem: function() {
+ return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
+ },
+
+ isLastItem: function() {
+ return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
+ },
+
+ _move: function( direction, filter, event ) {
+ var next;
+ if ( this.active ) {
+ if ( direction === "first" || direction === "last" ) {
+ next = this.active
+ [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
+ .eq( -1 );
+ } else {
+ next = this.active
+ [ direction + "All" ]( ".ui-menu-item" )
+ .eq( 0 );
+ }
+ }
+ if ( !next || !next.length || !this.active ) {
+ next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
+ }
+
+ this.focus( event, next );
+ },
+
+ nextPage: function( event ) {
+ var item, base, height;
+
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isLastItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.nextAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base - height < 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )
+ [ !this.active ? "first" : "last" ]() );
+ }
+ },
+
+ previousPage: function( event ) {
+ var item, base, height;
+ if ( !this.active ) {
+ this.next( event );
+ return;
+ }
+ if ( this.isFirstItem() ) {
+ return;
+ }
+ if ( this._hasScroll() ) {
+ base = this.active.offset().top;
+ height = this.element.height();
+ this.active.prevAll( ".ui-menu-item" ).each(function() {
+ item = $( this );
+ return item.offset().top - base + height > 0;
+ });
+
+ this.focus( event, item );
+ } else {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
+ }
+ },
+
+ _hasScroll: function() {
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
+ },
+
+ select: function( event ) {
+ // TODO: It should never be possible to not have an active item at this
+ // point, but the tests don't trigger mouseenter before click.
+ this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
+ var ui = { item: this.active };
+ if ( !this.active.has( ".ui-menu" ).length ) {
+ this.collapseAll( event, true );
+ }
+ this._trigger( "select", event, ui );
+ }
+});
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth,
+ max = Math.max,
+ abs = Math.abs,
+ round = Math.round,
+ rhorizontal = /left|center|right/,
+ rvertical = /top|center|bottom/,
+ roffset = /[\+\-]\d+(\.[\d]+)?%?/,
+ rposition = /^\w+/,
+ rpercent = /%$/,
+ _position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+ return [
+ parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+ parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+ ];
+}
+
+function parseCss( element, property ) {
+ return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+ var raw = elem[0];
+ if ( raw.nodeType === 9 ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: 0, left: 0 }
+ };
+ }
+ if ( $.isWindow( raw ) ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+ };
+ }
+ if ( raw.preventDefault ) {
+ return {
+ width: 0,
+ height: 0,
+ offset: { top: raw.pageY, left: raw.pageX }
+ };
+ }
+ return {
+ width: elem.outerWidth(),
+ height: elem.outerHeight(),
+ offset: elem.offset()
+ };
+}
+
+$.position = {
+ scrollbarWidth: function() {
+ if ( cachedScrollbarWidth !== undefined ) {
+ return cachedScrollbarWidth;
+ }
+ var w1, w2,
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+ innerDiv = div.children()[0];
+
+ $( "body" ).append( div );
+ w1 = innerDiv.offsetWidth;
+ div.css( "overflow", "scroll" );
+
+ w2 = innerDiv.offsetWidth;
+
+ if ( w1 === w2 ) {
+ w2 = div[0].clientWidth;
+ }
+
+ div.remove();
+
+ return (cachedScrollbarWidth = w1 - w2);
+ },
+ getScrollInfo: function( within ) {
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
+ hasOverflowX = overflowX === "scroll" ||
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+ hasOverflowY = overflowY === "scroll" ||
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+ return {
+ width: hasOverflowY ? $.position.scrollbarWidth() : 0,
+ height: hasOverflowX ? $.position.scrollbarWidth() : 0
+ };
+ },
+ getWithinInfo: function( element ) {
+ var withinElement = $( element || window ),
+ isWindow = $.isWindow( withinElement[0] );
+ return {
+ element: withinElement,
+ isWindow: isWindow,
+ offset: withinElement.offset() || { left: 0, top: 0 },
+ scrollLeft: withinElement.scrollLeft(),
+ scrollTop: withinElement.scrollTop(),
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
+ };
+ }
+};
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+ target = $( options.of ),
+ within = $.position.getWithinInfo( options.within ),
+ scrollInfo = $.position.getScrollInfo( within ),
+ collision = ( options.collision || "flip" ).split( " " ),
+ offsets = {};
+
+ dimensions = getDimensions( target );
+ if ( target[0].preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ }
+ targetWidth = dimensions.width;
+ targetHeight = dimensions.height;
+ targetOffset = dimensions.offset;
+ // clone to reuse original targetOffset later
+ basePosition = $.extend( {}, targetOffset );
+
+ // force my and at to have valid horizontal and vertical positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[ this ] || "" ).split( " " ),
+ horizontalOffset,
+ verticalOffset;
+
+ if ( pos.length === 1) {
+ pos = rhorizontal.test( pos[ 0 ] ) ?
+ pos.concat( [ "center" ] ) :
+ rvertical.test( pos[ 0 ] ) ?
+ [ "center" ].concat( pos ) :
+ [ "center", "center" ];
+ }
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+ // calculate offsets
+ horizontalOffset = roffset.exec( pos[ 0 ] );
+ verticalOffset = roffset.exec( pos[ 1 ] );
+ offsets[ this ] = [
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
+ verticalOffset ? verticalOffset[ 0 ] : 0
+ ];
+
+ // reduce to just the positions without the offsets
+ options[ this ] = [
+ rposition.exec( pos[ 0 ] )[ 0 ],
+ rposition.exec( pos[ 1 ] )[ 0 ]
+ ];
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ if ( options.at[ 0 ] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[ 0 ] === "center" ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[ 1 ] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[ 1 ] === "center" ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+ basePosition.left += atOffset[ 0 ];
+ basePosition.top += atOffset[ 1 ];
+
+ return this.each(function() {
+ var collisionPosition, using,
+ elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseCss( this, "marginLeft" ),
+ marginTop = parseCss( this, "marginTop" ),
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+ position = $.extend( {}, basePosition ),
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+ if ( options.my[ 0 ] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[ 0 ] === "center" ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[ 1 ] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[ 1 ] === "center" ) {
+ position.top -= elemHeight / 2;
+ }
+
+ position.left += myOffset[ 0 ];
+ position.top += myOffset[ 1 ];
+
+ // if the browser doesn't support fractions, then round for consistent results
+ if ( !$.support.offsetFractions ) {
+ position.left = round( position.left );
+ position.top = round( position.top );
+ }
+
+ collisionPosition = {
+ marginLeft: marginLeft,
+ marginTop: marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[ i ] ] ) {
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+ my: options.my,
+ at: options.at,
+ within: within,
+ elem : elem
+ });
+ }
+ });
+
+ if ( options.using ) {
+ // adds feedback as second argument to using callback, if present
+ using = function( props ) {
+ var left = targetOffset.left - position.left,
+ right = left + targetWidth - elemWidth,
+ top = targetOffset.top - position.top,
+ bottom = top + targetHeight - elemHeight,
+ feedback = {
+ target: {
+ element: target,
+ left: targetOffset.left,
+ top: targetOffset.top,
+ width: targetWidth,
+ height: targetHeight
+ },
+ element: {
+ element: elem,
+ left: position.left,
+ top: position.top,
+ width: elemWidth,
+ height: elemHeight
+ },
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+ };
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+ feedback.horizontal = "center";
+ }
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+ feedback.vertical = "middle";
+ }
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+ feedback.important = "horizontal";
+ } else {
+ feedback.important = "vertical";
+ }
+ options.using.call( this, props, feedback );
+ };
+ }
+
+ elem.offset( $.extend( position, { using: using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+ outerWidth = within.width,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = withinOffset - collisionPosLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+ newOverRight;
+
+ // element is wider than within
+ if ( data.collisionWidth > outerWidth ) {
+ // element is initially over the left side of within
+ if ( overLeft > 0 && overRight <= 0 ) {
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+ position.left += overLeft - newOverRight;
+ // element is initially over right side of within
+ } else if ( overRight > 0 && overLeft <= 0 ) {
+ position.left = withinOffset;
+ // element is initially over both left and right sides of within
+ } else {
+ if ( overLeft > overRight ) {
+ position.left = withinOffset + outerWidth - data.collisionWidth;
+ } else {
+ position.left = withinOffset;
+ }
+ }
+ // too far left -> align with left edge
+ } else if ( overLeft > 0 ) {
+ position.left += overLeft;
+ // too far right -> align with right edge
+ } else if ( overRight > 0 ) {
+ position.left -= overRight;
+ // adjust based on position and margin
+ } else {
+ position.left = max( position.left - collisionPosLeft, position.left );
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+ outerHeight = data.within.height,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = withinOffset - collisionPosTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+ newOverBottom;
+
+ // element is taller than within
+ if ( data.collisionHeight > outerHeight ) {
+ // element is initially over the top of within
+ if ( overTop > 0 && overBottom <= 0 ) {
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+ position.top += overTop - newOverBottom;
+ // element is initially over bottom of within
+ } else if ( overBottom > 0 && overTop <= 0 ) {
+ position.top = withinOffset;
+ // element is initially over both top and bottom of within
+ } else {
+ if ( overTop > overBottom ) {
+ position.top = withinOffset + outerHeight - data.collisionHeight;
+ } else {
+ position.top = withinOffset;
+ }
+ }
+ // too far up -> align with top
+ } else if ( overTop > 0 ) {
+ position.top += overTop;
+ // too far down -> align with bottom edge
+ } else if ( overBottom > 0 ) {
+ position.top -= overBottom;
+ // adjust based on position and margin
+ } else {
+ position.top = max( position.top - collisionPosTop, position.top );
+ }
+ }
+ },
+ flip: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.left + within.scrollLeft,
+ outerWidth = within.width,
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = collisionPosLeft - offsetLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ data.at[ 0 ] === "right" ?
+ -data.targetWidth :
+ 0,
+ offset = -2 * data.offset[ 0 ],
+ newOverRight,
+ newOverLeft;
+
+ if ( overLeft < 0 ) {
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overRight > 0 ) {
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.top + within.scrollTop,
+ outerHeight = within.height,
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = collisionPosTop - offsetTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+ top = data.my[ 1 ] === "top",
+ myOffset = top ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ data.at[ 1 ] === "bottom" ?
+ -data.targetHeight :
+ 0,
+ offset = -2 * data.offset[ 1 ],
+ newOverTop,
+ newOverBottom;
+ if ( overTop < 0 ) {
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overBottom > 0 ) {
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ }
+ },
+ flipfit: {
+ left: function() {
+ $.ui.position.flip.left.apply( this, arguments );
+ $.ui.position.fit.left.apply( this, arguments );
+ },
+ top: function() {
+ $.ui.position.flip.top.apply( this, arguments );
+ $.ui.position.fit.top.apply( this, arguments );
+ }
+ }
+};
+
+// fraction support test
+(function () {
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
+ body = document.getElementsByTagName( "body" )[ 0 ],
+ div = document.createElement( "div" );
+
+ //Create a "fake body" for testing based on method used in jQuery.support
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0,
+ background: "none"
+ };
+ if ( body ) {
+ $.extend( testElementStyle, {
+ position: "absolute",
+ left: "-1000px",
+ top: "-1000px"
+ });
+ }
+ for ( i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || document.documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+ offsetLeft = $( div ).offset().left;
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+})();
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+$.widget( "ui.progressbar", {
+ version: "1.10.3",
+ options: {
+ max: 100,
+ value: 0,
+
+ change: null,
+ complete: null
+ },
+
+ min: 0,
+
+ _create: function() {
+ // Constrain initial value
+ this.oldValue = this.options.value = this._constrainedValue();
+
+ this.element
+ .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .attr({
+ // Only set static values, aria-valuenow and aria-valuemax are
+ // set inside _refreshValue()
+ role: "progressbar",
+ "aria-valuemin": this.min
+ });
+
+ this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+ .appendTo( this.element );
+
+ this._refreshValue();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+
+ this.valueDiv.remove();
+ },
+
+ value: function( newValue ) {
+ if ( newValue === undefined ) {
+ return this.options.value;
+ }
+
+ this.options.value = this._constrainedValue( newValue );
+ this._refreshValue();
+ },
+
+ _constrainedValue: function( newValue ) {
+ if ( newValue === undefined ) {
+ newValue = this.options.value;
+ }
+
+ this.indeterminate = newValue === false;
+
+ // sanitize value
+ if ( typeof newValue !== "number" ) {
+ newValue = 0;
+ }
+
+ return this.indeterminate ? false :
+ Math.min( this.options.max, Math.max( this.min, newValue ) );
+ },
+
+ _setOptions: function( options ) {
+ // Ensure "value" option is set after other values (like max)
+ var value = options.value;
+ delete options.value;
+
+ this._super( options );
+
+ this.options.value = this._constrainedValue( value );
+ this._refreshValue();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "max" ) {
+ // Don't allow a max less than min
+ value = Math.max( this.min, value );
+ }
+
+ this._super( key, value );
+ },
+
+ _percentage: function() {
+ return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
+ },
+
+ _refreshValue: function() {
+ var value = this.options.value,
+ percentage = this._percentage();
+
+ this.valueDiv
+ .toggle( this.indeterminate || value > this.min )
+ .toggleClass( "ui-corner-right", value === this.options.max )
+ .width( percentage.toFixed(0) + "%" );
+
+ this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
+
+ if ( this.indeterminate ) {
+ this.element.removeAttr( "aria-valuenow" );
+ if ( !this.overlayDiv ) {
+ this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
+ }
+ } else {
+ this.element.attr({
+ "aria-valuemax": this.options.max,
+ "aria-valuenow": value
+ });
+ if ( this.overlayDiv ) {
+ this.overlayDiv.remove();
+ this.overlayDiv = null;
+ }
+ }
+
+ if ( this.oldValue !== value ) {
+ this.oldValue = value;
+ this._trigger( "change" );
+ }
+ if ( value === this.options.max ) {
+ this._trigger( "complete" );
+ }
+ }
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// number of pages in a slider
+// (how many times can you page up/down to go through the whole range)
+var numPages = 5;
+
+$.widget( "ui.slider", $.ui.mouse, {
+ version: "1.10.3",
+ widgetEventPrefix: "slide",
+
+ options: {
+ animate: false,
+ distance: 0,
+ max: 100,
+ min: 0,
+ orientation: "horizontal",
+ range: false,
+ step: 1,
+ value: 0,
+ values: null,
+
+ // callbacks
+ change: null,
+ slide: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ this._keySliding = false;
+ this._mouseSliding = false;
+ this._animateOff = true;
+ this._handleIndex = null;
+ this._detectOrientation();
+ this._mouseInit();
+
+ this.element
+ .addClass( "ui-slider" +
+ " ui-slider-" + this.orientation +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all");
+
+ this._refresh();
+ this._setOption( "disabled", this.options.disabled );
+
+ this._animateOff = false;
+ },
+
+ _refresh: function() {
+ this._createRange();
+ this._createHandles();
+ this._setupEvents();
+ this._refreshValue();
+ },
+
+ _createHandles: function() {
+ var i, handleCount,
+ options = this.options,
+ existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+ handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
+ handles = [];
+
+ handleCount = ( options.values && options.values.length ) || 1;
+
+ if ( existingHandles.length > handleCount ) {
+ existingHandles.slice( handleCount ).remove();
+ existingHandles = existingHandles.slice( 0, handleCount );
+ }
+
+ for ( i = existingHandles.length; i < handleCount; i++ ) {
+ handles.push( handle );
+ }
+
+ this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
+
+ this.handle = this.handles.eq( 0 );
+
+ this.handles.each(function( i ) {
+ $( this ).data( "ui-slider-handle-index", i );
+ });
+ },
+
+ _createRange: function() {
+ var options = this.options,
+ classes = "";
+
+ if ( options.range ) {
+ if ( options.range === true ) {
+ if ( !options.values ) {
+ options.values = [ this._valueMin(), this._valueMin() ];
+ } else if ( options.values.length && options.values.length !== 2 ) {
+ options.values = [ options.values[0], options.values[0] ];
+ } else if ( $.isArray( options.values ) ) {
+ options.values = options.values.slice(0);
+ }
+ }
+
+ if ( !this.range || !this.range.length ) {
+ this.range = $( "<div></div>" )
+ .appendTo( this.element );
+
+ classes = "ui-slider-range" +
+ // note: this isn't the most fittingly semantic framework class for this element,
+ // but worked best visually with a variety of themes
+ " ui-widget-header ui-corner-all";
+ } else {
+ this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
+ // Handle range switching from true to min/max
+ .css({
+ "left": "",
+ "bottom": ""
+ });
+ }
+
+ this.range.addClass( classes +
+ ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
+ } else {
+ this.range = $([]);
+ }
+ },
+
+ _setupEvents: function() {
+ var elements = this.handles.add( this.range ).filter( "a" );
+ this._off( elements );
+ this._on( elements, this._handleEvents );
+ this._hoverable( elements );
+ this._focusable( elements );
+ },
+
+ _destroy: function() {
+ this.handles.remove();
+ this.range.remove();
+
+ this.element
+ .removeClass( "ui-slider" +
+ " ui-slider-horizontal" +
+ " ui-slider-vertical" +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all" );
+
+ this._mouseDestroy();
+ },
+
+ _mouseCapture: function( event ) {
+ var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
+ that = this,
+ o = this.options;
+
+ if ( o.disabled ) {
+ return false;
+ }
+
+ this.elementSize = {
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight()
+ };
+ this.elementOffset = this.element.offset();
+
+ position = { x: event.pageX, y: event.pageY };
+ normValue = this._normValueFromMouse( position );
+ distance = this._valueMax() - this._valueMin() + 1;
+ this.handles.each(function( i ) {
+ var thisDistance = Math.abs( normValue - that.values(i) );
+ if (( distance > thisDistance ) ||
+ ( distance === thisDistance &&
+ (i === that._lastChangedValue || that.values(i) === o.min ))) {
+ distance = thisDistance;
+ closestHandle = $( this );
+ index = i;
+ }
+ });
+
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return false;
+ }
+ this._mouseSliding = true;
+
+ this._handleIndex = index;
+
+ closestHandle
+ .addClass( "ui-state-active" )
+ .focus();
+
+ offset = closestHandle.offset();
+ mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
+ this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+ left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+ top: event.pageY - offset.top -
+ ( closestHandle.height() / 2 ) -
+ ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+ ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+ ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+ };
+
+ if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+ this._slide( event, index, normValue );
+ }
+ this._animateOff = true;
+ return true;
+ },
+
+ _mouseStart: function() {
+ return true;
+ },
+
+ _mouseDrag: function( event ) {
+ var position = { x: event.pageX, y: event.pageY },
+ normValue = this._normValueFromMouse( position );
+
+ this._slide( event, this._handleIndex, normValue );
+
+ return false;
+ },
+
+ _mouseStop: function( event ) {
+ this.handles.removeClass( "ui-state-active" );
+ this._mouseSliding = false;
+
+ this._stop( event, this._handleIndex );
+ this._change( event, this._handleIndex );
+
+ this._handleIndex = null;
+ this._clickOffset = null;
+ this._animateOff = false;
+
+ return false;
+ },
+
+ _detectOrientation: function() {
+ this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+ },
+
+ _normValueFromMouse: function( position ) {
+ var pixelTotal,
+ pixelMouse,
+ percentMouse,
+ valueTotal,
+ valueMouse;
+
+ if ( this.orientation === "horizontal" ) {
+ pixelTotal = this.elementSize.width;
+ pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+ } else {
+ pixelTotal = this.elementSize.height;
+ pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+ }
+
+ percentMouse = ( pixelMouse / pixelTotal );
+ if ( percentMouse > 1 ) {
+ percentMouse = 1;
+ }
+ if ( percentMouse < 0 ) {
+ percentMouse = 0;
+ }
+ if ( this.orientation === "vertical" ) {
+ percentMouse = 1 - percentMouse;
+ }
+
+ valueTotal = this._valueMax() - this._valueMin();
+ valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+ return this._trimAlignValue( valueMouse );
+ },
+
+ _start: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+ return this._trigger( "start", event, uiHash );
+ },
+
+ _slide: function( event, index, newVal ) {
+ var otherVal,
+ newValues,
+ allowed;
+
+ if ( this.options.values && this.options.values.length ) {
+ otherVal = this.values( index ? 0 : 1 );
+
+ if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+ ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+ ) {
+ newVal = otherVal;
+ }
+
+ if ( newVal !== this.values( index ) ) {
+ newValues = this.values();
+ newValues[ index ] = newVal;
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal,
+ values: newValues
+ } );
+ otherVal = this.values( index ? 0 : 1 );
+ if ( allowed !== false ) {
+ this.values( index, newVal, true );
+ }
+ }
+ } else {
+ if ( newVal !== this.value() ) {
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal
+ } );
+ if ( allowed !== false ) {
+ this.value( newVal );
+ }
+ }
+ }
+ },
+
+ _stop: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ this._trigger( "stop", event, uiHash );
+ },
+
+ _change: function( event, index ) {
+ if ( !this._keySliding && !this._mouseSliding ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ //store the last changed value index for reference when handles overlap
+ this._lastChangedValue = index;
+
+ this._trigger( "change", event, uiHash );
+ }
+ },
+
+ value: function( newValue ) {
+ if ( arguments.length ) {
+ this.options.value = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, 0 );
+ return;
+ }
+
+ return this._value();
+ },
+
+ values: function( index, newValue ) {
+ var vals,
+ newValues,
+ i;
+
+ if ( arguments.length > 1 ) {
+ this.options.values[ index ] = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, index );
+ return;
+ }
+
+ if ( arguments.length ) {
+ if ( $.isArray( arguments[ 0 ] ) ) {
+ vals = this.options.values;
+ newValues = arguments[ 0 ];
+ for ( i = 0; i < vals.length; i += 1 ) {
+ vals[ i ] = this._trimAlignValue( newValues[ i ] );
+ this._change( null, i );
+ }
+ this._refreshValue();
+ } else {
+ if ( this.options.values && this.options.values.length ) {
+ return this._values( index );
+ } else {
+ return this.value();
+ }
+ }
+ } else {
+ return this._values();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var i,
+ valsLength = 0;
+
+ if ( key === "range" && this.options.range === true ) {
+ if ( value === "min" ) {
+ this.options.value = this._values( 0 );
+ this.options.values = null;
+ } else if ( value === "max" ) {
+ this.options.value = this._values( this.options.values.length-1 );
+ this.options.values = null;
+ }
+ }
+
+ if ( $.isArray( this.options.values ) ) {
+ valsLength = this.options.values.length;
+ }
+
+ $.Widget.prototype._setOption.apply( this, arguments );
+
+ switch ( key ) {
+ case "orientation":
+ this._detectOrientation();
+ this.element
+ .removeClass( "ui-slider-horizontal ui-slider-vertical" )
+ .addClass( "ui-slider-" + this.orientation );
+ this._refreshValue();
+ break;
+ case "value":
+ this._animateOff = true;
+ this._refreshValue();
+ this._change( null, 0 );
+ this._animateOff = false;
+ break;
+ case "values":
+ this._animateOff = true;
+ this._refreshValue();
+ for ( i = 0; i < valsLength; i += 1 ) {
+ this._change( null, i );
+ }
+ this._animateOff = false;
+ break;
+ case "min":
+ case "max":
+ this._animateOff = true;
+ this._refreshValue();
+ this._animateOff = false;
+ break;
+ case "range":
+ this._animateOff = true;
+ this._refresh();
+ this._animateOff = false;
+ break;
+ }
+ },
+
+ //internal value getter
+ // _value() returns value trimmed by min and max, aligned by step
+ _value: function() {
+ var val = this.options.value;
+ val = this._trimAlignValue( val );
+
+ return val;
+ },
+
+ //internal values getter
+ // _values() returns array of values trimmed by min and max, aligned by step
+ // _values( index ) returns single value trimmed by min and max, aligned by step
+ _values: function( index ) {
+ var val,
+ vals,
+ i;
+
+ if ( arguments.length ) {
+ val = this.options.values[ index ];
+ val = this._trimAlignValue( val );
+
+ return val;
+ } else if ( this.options.values && this.options.values.length ) {
+ // .slice() creates a copy of the array
+ // this copy gets trimmed by min and max and then returned
+ vals = this.options.values.slice();
+ for ( i = 0; i < vals.length; i+= 1) {
+ vals[ i ] = this._trimAlignValue( vals[ i ] );
+ }
+
+ return vals;
+ } else {
+ return [];
+ }
+ },
+
+ // returns the step-aligned value that val is closest to, between (inclusive) min and max
+ _trimAlignValue: function( val ) {
+ if ( val <= this._valueMin() ) {
+ return this._valueMin();
+ }
+ if ( val >= this._valueMax() ) {
+ return this._valueMax();
+ }
+ var step = ( this.options.step > 0 ) ? this.options.step : 1,
+ valModStep = (val - this._valueMin()) % step,
+ alignValue = val - valModStep;
+
+ if ( Math.abs(valModStep) * 2 >= step ) {
+ alignValue += ( valModStep > 0 ) ? step : ( -step );
+ }
+
+ // Since JavaScript has problems with large floats, round
+ // the final value to 5 digits after the decimal point (see #4124)
+ return parseFloat( alignValue.toFixed(5) );
+ },
+
+ _valueMin: function() {
+ return this.options.min;
+ },
+
+ _valueMax: function() {
+ return this.options.max;
+ },
+
+ _refreshValue: function() {
+ var lastValPercent, valPercent, value, valueMin, valueMax,
+ oRange = this.options.range,
+ o = this.options,
+ that = this,
+ animate = ( !this._animateOff ) ? o.animate : false,
+ _set = {};
+
+ if ( this.options.values && this.options.values.length ) {
+ this.handles.each(function( i ) {
+ valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
+ _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+ if ( that.options.range === true ) {
+ if ( that.orientation === "horizontal" ) {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ } else {
+ if ( i === 0 ) {
+ that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ }
+ lastValPercent = valPercent;
+ });
+ } else {
+ value = this.value();
+ valueMin = this._valueMin();
+ valueMax = this._valueMax();
+ valPercent = ( valueMax !== valueMin ) ?
+ ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+ 0;
+ _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+ if ( oRange === "min" && this.orientation === "horizontal" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "horizontal" ) {
+ this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ if ( oRange === "min" && this.orientation === "vertical" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "vertical" ) {
+ this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ },
+
+ _handleEvents: {
+ keydown: function( event ) {
+ /*jshint maxcomplexity:25*/
+ var allowed, curVal, newVal, step,
+ index = $( event.target ).data( "ui-slider-handle-index" );
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ case $.ui.keyCode.END:
+ case $.ui.keyCode.PAGE_UP:
+ case $.ui.keyCode.PAGE_DOWN:
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ event.preventDefault();
+ if ( !this._keySliding ) {
+ this._keySliding = true;
+ $( event.target ).addClass( "ui-state-active" );
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return;
+ }
+ }
+ break;
+ }
+
+ step = this.options.step;
+ if ( this.options.values && this.options.values.length ) {
+ curVal = newVal = this.values( index );
+ } else {
+ curVal = newVal = this.value();
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ newVal = this._valueMin();
+ break;
+ case $.ui.keyCode.END:
+ newVal = this._valueMax();
+ break;
+ case $.ui.keyCode.PAGE_UP:
+ newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ if ( curVal === this._valueMax() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal + step );
+ break;
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ if ( curVal === this._valueMin() ) {
+ return;
+ }
+ newVal = this._trimAlignValue( curVal - step );
+ break;
+ }
+
+ this._slide( event, index, newVal );
+ },
+ click: function( event ) {
+ event.preventDefault();
+ },
+ keyup: function( event ) {
+ var index = $( event.target ).data( "ui-slider-handle-index" );
+
+ if ( this._keySliding ) {
+ this._keySliding = false;
+ this._stop( event, index );
+ this._change( event, index );
+ $( event.target ).removeClass( "ui-state-active" );
+ }
+ }
+ }
+
+});
+
+}(jQuery));
+
+(function( $ ) {
+
+function modifier( fn ) {
+ return function() {
+ var previous = this.element.val();
+ fn.apply( this, arguments );
+ this._refresh();
+ if ( previous !== this.element.val() ) {
+ this._trigger( "change" );
+ }
+ };
+}
+
+$.widget( "ui.spinner", {
+ version: "1.10.3",
+ defaultElement: "<input>",
+ widgetEventPrefix: "spin",
+ options: {
+ culture: null,
+ icons: {
+ down: "ui-icon-triangle-1-s",
+ up: "ui-icon-triangle-1-n"
+ },
+ incremental: true,
+ max: null,
+ min: null,
+ numberFormat: null,
+ page: 10,
+ step: 1,
+
+ change: null,
+ spin: null,
+ start: null,
+ stop: null
+ },
+
+ _create: function() {
+ // handle string values that need to be parsed
+ this._setOption( "max", this.options.max );
+ this._setOption( "min", this.options.min );
+ this._setOption( "step", this.options.step );
+
+ // format the value, but don't constrain
+ this._value( this.element.val(), true );
+
+ this._draw();
+ this._on( this._events );
+ this._refresh();
+
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ this._on( this.window, {
+ beforeunload: function() {
+ this.element.removeAttr( "autocomplete" );
+ }
+ });
+ },
+
+ _getCreateOptions: function() {
+ var options = {},
+ element = this.element;
+
+ $.each( [ "min", "max", "step" ], function( i, option ) {
+ var value = element.attr( option );
+ if ( value !== undefined && value.length ) {
+ options[ option ] = value;
+ }
+ });
+
+ return options;
+ },
+
+ _events: {
+ keydown: function( event ) {
+ if ( this._start( event ) && this._keydown( event ) ) {
+ event.preventDefault();
+ }
+ },
+ keyup: "_stop",
+ focus: function() {
+ this.previous = this.element.val();
+ },
+ blur: function( event ) {
+ if ( this.cancelBlur ) {
+ delete this.cancelBlur;
+ return;
+ }
+
+ this._stop();
+ this._refresh();
+ if ( this.previous !== this.element.val() ) {
+ this._trigger( "change", event );
+ }
+ },
+ mousewheel: function( event, delta ) {
+ if ( !delta ) {
+ return;
+ }
+ if ( !this.spinning && !this._start( event ) ) {
+ return false;
+ }
+
+ this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
+ clearTimeout( this.mousewheelTimer );
+ this.mousewheelTimer = this._delay(function() {
+ if ( this.spinning ) {
+ this._stop( event );
+ }
+ }, 100 );
+ event.preventDefault();
+ },
+ "mousedown .ui-spinner-button": function( event ) {
+ var previous;
+
+ // We never want the buttons to have focus; whenever the user is
+ // interacting with the spinner, the focus should be on the input.
+ // If the input is focused then this.previous is properly set from
+ // when the input first received focus. If the input is not focused
+ // then we need to set this.previous based on the value before spinning.
+ previous = this.element[0] === this.document[0].activeElement ?
+ this.previous : this.element.val();
+ function checkFocus() {
+ var isActive = this.element[0] === this.document[0].activeElement;
+ if ( !isActive ) {
+ this.element.focus();
+ this.previous = previous;
+ // support: IE
+ // IE sets focus asynchronously, so we need to check if focus
+ // moved off of the input because the user clicked on the button.
+ this._delay(function() {
+ this.previous = previous;
+ });
+ }
+ }
+
+ // ensure focus is on (or stays on) the text field
+ event.preventDefault();
+ checkFocus.call( this );
+
+ // support: IE
+ // IE doesn't prevent moving focus even with event.preventDefault()
+ // so we set a flag to know when we should ignore the blur event
+ // and check (again) if focus moved off of the input.
+ this.cancelBlur = true;
+ this._delay(function() {
+ delete this.cancelBlur;
+ checkFocus.call( this );
+ });
+
+ if ( this._start( event ) === false ) {
+ return;
+ }
+
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ "mouseup .ui-spinner-button": "_stop",
+ "mouseenter .ui-spinner-button": function( event ) {
+ // button will add ui-state-active if mouse was down while mouseleave and kept down
+ if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
+ return;
+ }
+
+ if ( this._start( event ) === false ) {
+ return false;
+ }
+ this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+ },
+ // TODO: do we really want to consider this a stop?
+ // shouldn't we just stop the repeater and wait until mouseup before
+ // we trigger the stop event?
+ "mouseleave .ui-spinner-button": "_stop"
+ },
+
+ _draw: function() {
+ var uiSpinner = this.uiSpinner = this.element
+ .addClass( "ui-spinner-input" )
+ .attr( "autocomplete", "off" )
+ .wrap( this._uiSpinnerHtml() )
+ .parent()
+ // add buttons
+ .append( this._buttonHtml() );
+
+ this.element.attr( "role", "spinbutton" );
+
+ // button bindings
+ this.buttons = uiSpinner.find( ".ui-spinner-button" )
+ .attr( "tabIndex", -1 )
+ .button()
+ .removeClass( "ui-corner-all" );
+
+ // IE 6 doesn't understand height: 50% for the buttons
+ // unless the wrapper has an explicit height
+ if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
+ uiSpinner.height() > 0 ) {
+ uiSpinner.height( uiSpinner.height() );
+ }
+
+ // disable spinner if element was already disabled
+ if ( this.options.disabled ) {
+ this.disable();
+ }
+ },
+
+ _keydown: function( event ) {
+ var options = this.options,
+ keyCode = $.ui.keyCode;
+
+ switch ( event.keyCode ) {
+ case keyCode.UP:
+ this._repeat( null, 1, event );
+ return true;
+ case keyCode.DOWN:
+ this._repeat( null, -1, event );
+ return true;
+ case keyCode.PAGE_UP:
+ this._repeat( null, options.page, event );
+ return true;
+ case keyCode.PAGE_DOWN:
+ this._repeat( null, -options.page, event );
+ return true;
+ }
+
+ return false;
+ },
+
+ _uiSpinnerHtml: function() {
+ return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
+ },
+
+ _buttonHtml: function() {
+ return "" +
+ "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
+ "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" +
+ "</a>" +
+ "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
+ "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" +
+ "</a>";
+ },
+
+ _start: function( event ) {
+ if ( !this.spinning && this._trigger( "start", event ) === false ) {
+ return false;
+ }
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+ this.spinning = true;
+ return true;
+ },
+
+ _repeat: function( i, steps, event ) {
+ i = i || 500;
+
+ clearTimeout( this.timer );
+ this.timer = this._delay(function() {
+ this._repeat( 40, steps, event );
+ }, i );
+
+ this._spin( steps * this.options.step, event );
+ },
+
+ _spin: function( step, event ) {
+ var value = this.value() || 0;
+
+ if ( !this.counter ) {
+ this.counter = 1;
+ }
+
+ value = this._adjustValue( value + step * this._increment( this.counter ) );
+
+ if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
+ this._value( value );
+ this.counter++;
+ }
+ },
+
+ _increment: function( i ) {
+ var incremental = this.options.incremental;
+
+ if ( incremental ) {
+ return $.isFunction( incremental ) ?
+ incremental( i ) :
+ Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
+ }
+
+ return 1;
+ },
+
+ _precision: function() {
+ var precision = this._precisionOf( this.options.step );
+ if ( this.options.min !== null ) {
+ precision = Math.max( precision, this._precisionOf( this.options.min ) );
+ }
+ return precision;
+ },
+
+ _precisionOf: function( num ) {
+ var str = num.toString(),
+ decimal = str.indexOf( "." );
+ return decimal === -1 ? 0 : str.length - decimal - 1;
+ },
+
+ _adjustValue: function( value ) {
+ var base, aboveMin,
+ options = this.options;
+
+ // make sure we're at a valid step
+ // - find out where we are relative to the base (min or 0)
+ base = options.min !== null ? options.min : 0;
+ aboveMin = value - base;
+ // - round to the nearest step
+ aboveMin = Math.round(aboveMin / options.step) * options.step;
+ // - rounding is based on 0, so adjust back to our base
+ value = base + aboveMin;
+
+ // fix precision from bad JS floating point math
+ value = parseFloat( value.toFixed( this._precision() ) );
+
+ // clamp the value
+ if ( options.max !== null && value > options.max) {
+ return options.max;
+ }
+ if ( options.min !== null && value < options.min ) {
+ return options.min;
+ }
+
+ return value;
+ },
+
+ _stop: function( event ) {
+ if ( !this.spinning ) {
+ return;
+ }
+
+ clearTimeout( this.timer );
+ clearTimeout( this.mousewheelTimer );
+ this.counter = 0;
+ this.spinning = false;
+ this._trigger( "stop", event );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "culture" || key === "numberFormat" ) {
+ var prevValue = this._parse( this.element.val() );
+ this.options[ key ] = value;
+ this.element.val( this._format( prevValue ) );
+ return;
+ }
+
+ if ( key === "max" || key === "min" || key === "step" ) {
+ if ( typeof value === "string" ) {
+ value = this._parse( value );
+ }
+ }
+ if ( key === "icons" ) {
+ this.buttons.first().find( ".ui-icon" )
+ .removeClass( this.options.icons.up )
+ .addClass( value.up );
+ this.buttons.last().find( ".ui-icon" )
+ .removeClass( this.options.icons.down )
+ .addClass( value.down );
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.prop( "disabled", true );
+ this.buttons.button( "disable" );
+ } else {
+ this.element.prop( "disabled", false );
+ this.buttons.button( "enable" );
+ }
+ }
+ },
+
+ _setOptions: modifier(function( options ) {
+ this._super( options );
+ this._value( this.element.val() );
+ }),
+
+ _parse: function( val ) {
+ if ( typeof val === "string" && val !== "" ) {
+ val = window.Globalize && this.options.numberFormat ?
+ Globalize.parseFloat( val, 10, this.options.culture ) : +val;
+ }
+ return val === "" || isNaN( val ) ? null : val;
+ },
+
+ _format: function( value ) {
+ if ( value === "" ) {
+ return "";
+ }
+ return window.Globalize && this.options.numberFormat ?
+ Globalize.format( value, this.options.numberFormat, this.options.culture ) :
+ value;
+ },
+
+ _refresh: function() {
+ this.element.attr({
+ "aria-valuemin": this.options.min,
+ "aria-valuemax": this.options.max,
+ // TODO: what should we do with values that can't be parsed?
+ "aria-valuenow": this._parse( this.element.val() )
+ });
+ },
+
+ // update the value without triggering change
+ _value: function( value, allowAny ) {
+ var parsed;
+ if ( value !== "" ) {
+ parsed = this._parse( value );
+ if ( parsed !== null ) {
+ if ( !allowAny ) {
+ parsed = this._adjustValue( parsed );
+ }
+ value = this._format( parsed );
+ }
+ }
+ this.element.val( value );
+ this._refresh();
+ },
+
+ _destroy: function() {
+ this.element
+ .removeClass( "ui-spinner-input" )
+ .prop( "disabled", false )
+ .removeAttr( "autocomplete" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+ this.uiSpinner.replaceWith( this.element );
+ },
+
+ stepUp: modifier(function( steps ) {
+ this._stepUp( steps );
+ }),
+ _stepUp: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * this.options.step );
+ this._stop();
+ }
+ },
+
+ stepDown: modifier(function( steps ) {
+ this._stepDown( steps );
+ }),
+ _stepDown: function( steps ) {
+ if ( this._start() ) {
+ this._spin( (steps || 1) * -this.options.step );
+ this._stop();
+ }
+ },
+
+ pageUp: modifier(function( pages ) {
+ this._stepUp( (pages || 1) * this.options.page );
+ }),
+
+ pageDown: modifier(function( pages ) {
+ this._stepDown( (pages || 1) * this.options.page );
+ }),
+
+ value: function( newVal ) {
+ if ( !arguments.length ) {
+ return this._parse( this.element.val() );
+ }
+ modifier( this._value ).call( this, newVal );
+ },
+
+ widget: function() {
+ return this.uiSpinner;
+ }
+});
+
+}( jQuery ) );
+
+(function( $, undefined ) {
+
+var tabId = 0,
+ rhash = /#.*$/;
+
+function getNextTabId() {
+ return ++tabId;
+}
+
+function isLocal( anchor ) {
+ return anchor.hash.length > 1 &&
+ decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
+ decodeURIComponent( location.href.replace( rhash, "" ) );
+}
+
+$.widget( "ui.tabs", {
+ version: "1.10.3",
+ delay: 300,
+ options: {
+ active: null,
+ collapsible: false,
+ event: "click",
+ heightStyle: "content",
+ hide: null,
+ show: null,
+
+ // callbacks
+ activate: null,
+ beforeActivate: null,
+ beforeLoad: null,
+ load: null
+ },
+
+ _create: function() {
+ var that = this,
+ options = this.options;
+
+ this.running = false;
+
+ this.element
+ .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
+ .toggleClass( "ui-tabs-collapsible", options.collapsible )
+ // Prevent users from focusing disabled tabs via click
+ .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
+ if ( $( this ).is( ".ui-state-disabled" ) ) {
+ event.preventDefault();
+ }
+ })
+ // support: IE <9
+ // Preventing the default action in mousedown doesn't prevent IE
+ // from focusing the element, so if the anchor gets focused, blur.
+ // We don't have to worry about focusing the previously focused
+ // element since clicking on a non-focusable element should focus
+ // the body anyway.
+ .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
+ if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+ this.blur();
+ }
+ });
+
+ this._processTabs();
+ options.active = this._initialActive();
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ if ( $.isArray( options.disabled ) ) {
+ options.disabled = $.unique( options.disabled.concat(
+ $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+ return that.tabs.index( li );
+ })
+ ) ).sort();
+ }
+
+ // check for length avoids error when initializing empty list
+ if ( this.options.active !== false && this.anchors.length ) {
+ this.active = this._findActive( options.active );
+ } else {
+ this.active = $();
+ }
+
+ this._refresh();
+
+ if ( this.active.length ) {
+ this.load( options.active );
+ }
+ },
+
+ _initialActive: function() {
+ var active = this.options.active,
+ collapsible = this.options.collapsible,
+ locationHash = location.hash.substring( 1 );
+
+ if ( active === null ) {
+ // check the fragment identifier in the URL
+ if ( locationHash ) {
+ this.tabs.each(function( i, tab ) {
+ if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+ active = i;
+ return false;
+ }
+ });
+ }
+
+ // check for a tab marked active via a class
+ if ( active === null ) {
+ active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+ }
+
+ // no active tab, set to false
+ if ( active === null || active === -1 ) {
+ active = this.tabs.length ? 0 : false;
+ }
+ }
+
+ // handle numbers: negative, out of range
+ if ( active !== false ) {
+ active = this.tabs.index( this.tabs.eq( active ) );
+ if ( active === -1 ) {
+ active = collapsible ? false : 0;
+ }
+ }
+
+ // don't allow collapsible: false and active: false
+ if ( !collapsible && active === false && this.anchors.length ) {
+ active = 0;
+ }
+
+ return active;
+ },
+
+ _getCreateEventData: function() {
+ return {
+ tab: this.active,
+ panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+ };
+ },
+
+ _tabKeydown: function( event ) {
+ /*jshint maxcomplexity:15*/
+ var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
+ selectedIndex = this.tabs.index( focusedTab ),
+ goingForward = true;
+
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ selectedIndex++;
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.LEFT:
+ goingForward = false;
+ selectedIndex--;
+ break;
+ case $.ui.keyCode.END:
+ selectedIndex = this.anchors.length - 1;
+ break;
+ case $.ui.keyCode.HOME:
+ selectedIndex = 0;
+ break;
+ case $.ui.keyCode.SPACE:
+ // Activate only, no collapsing
+ event.preventDefault();
+ clearTimeout( this.activating );
+ this._activate( selectedIndex );
+ return;
+ case $.ui.keyCode.ENTER:
+ // Toggle (cancel delayed activation, allow collapsing)
+ event.preventDefault();
+ clearTimeout( this.activating );
+ // Determine if we should collapse or activate
+ this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+ return;
+ default:
+ return;
+ }
+
+ // Focus the appropriate tab, based on which key was pressed
+ event.preventDefault();
+ clearTimeout( this.activating );
+ selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+ // Navigating with control key will prevent automatic activation
+ if ( !event.ctrlKey ) {
+ // Update aria-selected immediately so that AT think the tab is already selected.
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
+ // but the tab will already be activated by the time the announcement finishes.
+ focusedTab.attr( "aria-selected", "false" );
+ this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+ this.activating = this._delay(function() {
+ this.option( "active", selectedIndex );
+ }, this.delay );
+ }
+ },
+
+ _panelKeydown: function( event ) {
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ // Ctrl+up moves focus to the current tab
+ if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+ event.preventDefault();
+ this.active.focus();
+ }
+ },
+
+ // Alt+page up/down moves focus to the previous/next tab (and activates)
+ _handlePageNav: function( event ) {
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+ this._activate( this._focusNextTab( this.options.active - 1, false ) );
+ return true;
+ }
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+ this._activate( this._focusNextTab( this.options.active + 1, true ) );
+ return true;
+ }
+ },
+
+ _findNextTab: function( index, goingForward ) {
+ var lastTabIndex = this.tabs.length - 1;
+
+ function constrain() {
+ if ( index > lastTabIndex ) {
+ index = 0;
+ }
+ if ( index < 0 ) {
+ index = lastTabIndex;
+ }
+ return index;
+ }
+
+ while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+ index = goingForward ? index + 1 : index - 1;
+ }
+
+ return index;
+ },
+
+ _focusNextTab: function( index, goingForward ) {
+ index = this._findNextTab( index, goingForward );
+ this.tabs.eq( index ).focus();
+ return index;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ if ( key === "disabled" ) {
+ // don't use the widget factory's disabled handling
+ this._setupDisabled( value );
+ return;
+ }
+
+ this._super( key, value);
+
+ if ( key === "collapsible" ) {
+ this.element.toggleClass( "ui-tabs-collapsible", value );
+ // Setting collapsible: false while collapsed; open first panel
+ if ( !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+ }
+
+ if ( key === "event" ) {
+ this._setupEvents( value );
+ }
+
+ if ( key === "heightStyle" ) {
+ this._setupHeightStyle( value );
+ }
+ },
+
+ _tabId: function( tab ) {
+ return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
+ },
+
+ _sanitizeSelector: function( hash ) {
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+ },
+
+ refresh: function() {
+ var options = this.options,
+ lis = this.tablist.children( ":has(a[href])" );
+
+ // get disabled tabs from class attribute from HTML
+ // this will get converted to a boolean if needed in _refresh()
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+ return lis.index( tab );
+ });
+
+ this._processTabs();
+
+ // was collapsed or no tabs
+ if ( options.active === false || !this.anchors.length ) {
+ options.active = false;
+ this.active = $();
+ // was active, but active tab is gone
+ } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+ // all remaining tabs are disabled
+ if ( this.tabs.length === options.disabled.length ) {
+ options.active = false;
+ this.active = $();
+ // activate previous tab
+ } else {
+ this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+ }
+ // was active, active tab still exists
+ } else {
+ // make sure active index is correct
+ options.active = this.tabs.index( this.active );
+ }
+
+ this._refresh();
+ },
+
+ _refresh: function() {
+ this._setupDisabled( this.options.disabled );
+ this._setupEvents( this.options.event );
+ this._setupHeightStyle( this.options.heightStyle );
+
+ this.tabs.not( this.active ).attr({
+ "aria-selected": "false",
+ tabIndex: -1
+ });
+ this.panels.not( this._getPanelForTab( this.active ) )
+ .hide()
+ .attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+
+ // Make sure one tab is in the tab order
+ if ( !this.active.length ) {
+ this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active
+ .addClass( "ui-tabs-active ui-state-active" )
+ .attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ this._getPanelForTab( this.active )
+ .show()
+ .attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ }
+ },
+
+ _processTabs: function() {
+ var that = this;
+
+ this.tablist = this._getList()
+ .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .attr( "role", "tablist" );
+
+ this.tabs = this.tablist.find( "> li:has(a[href])" )
+ .addClass( "ui-state-default ui-corner-top" )
+ .attr({
+ role: "tab",
+ tabIndex: -1
+ });
+
+ this.anchors = this.tabs.map(function() {
+ return $( "a", this )[ 0 ];
+ })
+ .addClass( "ui-tabs-anchor" )
+ .attr({
+ role: "presentation",
+ tabIndex: -1
+ });
+
+ this.panels = $();
+
+ this.anchors.each(function( i, anchor ) {
+ var selector, panel, panelId,
+ anchorId = $( anchor ).uniqueId().attr( "id" ),
+ tab = $( anchor ).closest( "li" ),
+ originalAriaControls = tab.attr( "aria-controls" );
+
+ // inline tab
+ if ( isLocal( anchor ) ) {
+ selector = anchor.hash;
+ panel = that.element.find( that._sanitizeSelector( selector ) );
+ // remote tab
+ } else {
+ panelId = that._tabId( tab );
+ selector = "#" + panelId;
+ panel = that.element.find( selector );
+ if ( !panel.length ) {
+ panel = that._createPanel( panelId );
+ panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+ }
+ panel.attr( "aria-live", "polite" );
+ }
+
+ if ( panel.length) {
+ that.panels = that.panels.add( panel );
+ }
+ if ( originalAriaControls ) {
+ tab.data( "ui-tabs-aria-controls", originalAriaControls );
+ }
+ tab.attr({
+ "aria-controls": selector.substring( 1 ),
+ "aria-labelledby": anchorId
+ });
+ panel.attr( "aria-labelledby", anchorId );
+ });
+
+ this.panels
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .attr( "role", "tabpanel" );
+ },
+
+ // allow overriding how to find the list for rare usage scenarios (#7715)
+ _getList: function() {
+ return this.element.find( "ol,ul" ).eq( 0 );
+ },
+
+ _createPanel: function( id ) {
+ return $( "<div>" )
+ .attr( "id", id )
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .data( "ui-tabs-destroy", true );
+ },
+
+ _setupDisabled: function( disabled ) {
+ if ( $.isArray( disabled ) ) {
+ if ( !disabled.length ) {
+ disabled = false;
+ } else if ( disabled.length === this.anchors.length ) {
+ disabled = true;
+ }
+ }
+
+ // disable tabs
+ for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
+ if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+ $( li )
+ .addClass( "ui-state-disabled" )
+ .attr( "aria-disabled", "true" );
+ } else {
+ $( li )
+ .removeClass( "ui-state-disabled" )
+ .removeAttr( "aria-disabled" );
+ }
+ }
+
+ this.options.disabled = disabled;
+ },
+
+ _setupEvents: function( event ) {
+ var events = {
+ click: function( event ) {
+ event.preventDefault();
+ }
+ };
+ if ( event ) {
+ $.each( event.split(" "), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ });
+ }
+
+ this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+ this._on( this.anchors, events );
+ this._on( this.tabs, { keydown: "_tabKeydown" } );
+ this._on( this.panels, { keydown: "_panelKeydown" } );
+
+ this._focusable( this.tabs );
+ this._hoverable( this.tabs );
+ },
+
+ _setupHeightStyle: function( heightStyle ) {
+ var maxHeight,
+ parent = this.element.parent();
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ maxHeight -= this.element.outerHeight() - this.element.height();
+
+ this.element.siblings( ":visible" ).each(function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ });
+
+ this.element.children().not( this.panels ).each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.panels.each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.panels.each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+ }).height( maxHeight );
+ }
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ anchor = $( event.currentTarget ),
+ tab = anchor.closest( "li" ),
+ clickedIsActive = tab[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : this._getPanelForTab( tab ),
+ toHide = !active.length ? $() : this._getPanelForTab( active ),
+ eventData = {
+ oldTab: active,
+ oldPanel: toHide,
+ newTab: collapsing ? $() : tab,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if ( tab.hasClass( "ui-state-disabled" ) ||
+ // tab is already loading
+ tab.hasClass( "ui-tabs-loading" ) ||
+ // can't switch durning an animation
+ this.running ||
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.tabs.index( tab );
+
+ this.active = clickedIsActive ? $() : tab;
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ if ( !toHide.length && !toShow.length ) {
+ $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+ }
+
+ if ( toShow.length ) {
+ this.load( this.tabs.index( tab ), event );
+ }
+ this._toggle( event, eventData );
+ },
+
+ // handles show/hide for selecting tabs
+ _toggle: function( event, eventData ) {
+ var that = this,
+ toShow = eventData.newPanel,
+ toHide = eventData.oldPanel;
+
+ this.running = true;
+
+ function complete() {
+ that.running = false;
+ that._trigger( "activate", event, eventData );
+ }
+
+ function show() {
+ eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
+
+ if ( toShow.length && that.options.show ) {
+ that._show( toShow, that.options.show, complete );
+ } else {
+ toShow.show();
+ complete();
+ }
+ }
+
+ // start out by hiding, then showing, then completing
+ if ( toHide.length && this.options.hide ) {
+ this._hide( toHide, this.options.hide, function() {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ show();
+ });
+ } else {
+ eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+ toHide.hide();
+ show();
+ }
+
+ toHide.attr({
+ "aria-expanded": "false",
+ "aria-hidden": "true"
+ });
+ eventData.oldTab.attr( "aria-selected", "false" );
+ // If we're switching tabs, remove the old tab from the tab order.
+ // If we're opening from collapsed state, remove the previous tab from the tab order.
+ // If we're collapsing, then keep the collapsing tab in the tab order.
+ if ( toShow.length && toHide.length ) {
+ eventData.oldTab.attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.tabs.filter(function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ })
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow.attr({
+ "aria-expanded": "true",
+ "aria-hidden": "false"
+ });
+ eventData.newTab.attr({
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ },
+
+ _activate: function( index ) {
+ var anchor,
+ active = this._findActive( index );
+
+ // trying to activate the already active panel
+ if ( active[ 0 ] === this.active[ 0 ] ) {
+ return;
+ }
+
+ // trying to collapse, simulate a click on the current active header
+ if ( !active.length ) {
+ active = this.active;
+ }
+
+ anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+ this._eventHandler({
+ target: anchor,
+ currentTarget: anchor,
+ preventDefault: $.noop
+ });
+ },
+
+ _findActive: function( index ) {
+ return index === false ? $() : this.tabs.eq( index );
+ },
+
+ _getIndex: function( index ) {
+ // meta-function to give users option to provide a href string instead of a numerical index.
+ if ( typeof index === "string" ) {
+ index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
+ }
+
+ return index;
+ },
+
+ _destroy: function() {
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
+
+ this.tablist
+ .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+ .removeAttr( "role" );
+
+ this.anchors
+ .removeClass( "ui-tabs-anchor" )
+ .removeAttr( "role" )
+ .removeAttr( "tabIndex" )
+ .removeUniqueId();
+
+ this.tabs.add( this.panels ).each(function() {
+ if ( $.data( this, "ui-tabs-destroy" ) ) {
+ $( this ).remove();
+ } else {
+ $( this )
+ .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
+ "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
+ .removeAttr( "tabIndex" )
+ .removeAttr( "aria-live" )
+ .removeAttr( "aria-busy" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "aria-labelledby" )
+ .removeAttr( "aria-hidden" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "role" );
+ }
+ });
+
+ this.tabs.each(function() {
+ var li = $( this ),
+ prev = li.data( "ui-tabs-aria-controls" );
+ if ( prev ) {
+ li
+ .attr( "aria-controls", prev )
+ .removeData( "ui-tabs-aria-controls" );
+ } else {
+ li.removeAttr( "aria-controls" );
+ }
+ });
+
+ this.panels.show();
+
+ if ( this.options.heightStyle !== "content" ) {
+ this.panels.css( "height", "" );
+ }
+ },
+
+ enable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === false ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = false;
+ } else {
+ index = this._getIndex( index );
+ if ( $.isArray( disabled ) ) {
+ disabled = $.map( disabled, function( num ) {
+ return num !== index ? num : null;
+ });
+ } else {
+ disabled = $.map( this.tabs, function( li, num ) {
+ return num !== index ? num : null;
+ });
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ disable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === true ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = true;
+ } else {
+ index = this._getIndex( index );
+ if ( $.inArray( index, disabled ) !== -1 ) {
+ return;
+ }
+ if ( $.isArray( disabled ) ) {
+ disabled = $.merge( [ index ], disabled ).sort();
+ } else {
+ disabled = [ index ];
+ }
+ }
+ this._setupDisabled( disabled );
+ },
+
+ load: function( index, event ) {
+ index = this._getIndex( index );
+ var that = this,
+ tab = this.tabs.eq( index ),
+ anchor = tab.find( ".ui-tabs-anchor" ),
+ panel = this._getPanelForTab( tab ),
+ eventData = {
+ tab: tab,
+ panel: panel
+ };
+
+ // not remote
+ if ( isLocal( anchor[ 0 ] ) ) {
+ return;
+ }
+
+ this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+ // support: jQuery <1.8
+ // jQuery <1.8 returns false if the request is canceled in beforeSend,
+ // but as of 1.8, $.ajax() always returns a jqXHR object.
+ if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+ tab.addClass( "ui-tabs-loading" );
+ panel.attr( "aria-busy", "true" );
+
+ this.xhr
+ .success(function( response ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ panel.html( response );
+ that._trigger( "load", event, eventData );
+ }, 1 );
+ })
+ .complete(function( jqXHR, status ) {
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout(function() {
+ if ( status === "abort" ) {
+ that.panels.stop( false, true );
+ }
+
+ tab.removeClass( "ui-tabs-loading" );
+ panel.removeAttr( "aria-busy" );
+
+ if ( jqXHR === that.xhr ) {
+ delete that.xhr;
+ }
+ }, 1 );
+ });
+ }
+ },
+
+ _ajaxSettings: function( anchor, event, eventData ) {
+ var that = this;
+ return {
+ url: anchor.attr( "href" ),
+ beforeSend: function( jqXHR, settings ) {
+ return that._trigger( "beforeLoad", event,
+ $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
+ }
+ };
+ },
+
+ _getPanelForTab: function( tab ) {
+ var id = $( tab ).attr( "aria-controls" );
+ return this.element.find( this._sanitizeSelector( "#" + id ) );
+ }
+});
+
+})( jQuery );
+
+(function( $ ) {
+
+var increments = 0;
+
+function addDescribedBy( elem, id ) {
+ var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
+ describedby.push( id );
+ elem
+ .data( "ui-tooltip-id", id )
+ .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
+}
+
+function removeDescribedBy( elem ) {
+ var id = elem.data( "ui-tooltip-id" ),
+ describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
+ index = $.inArray( id, describedby );
+ if ( index !== -1 ) {
+ describedby.splice( index, 1 );
+ }
+
+ elem.removeData( "ui-tooltip-id" );
+ describedby = $.trim( describedby.join( " " ) );
+ if ( describedby ) {
+ elem.attr( "aria-describedby", describedby );
+ } else {
+ elem.removeAttr( "aria-describedby" );
+ }
+}
+
+$.widget( "ui.tooltip", {
+ version: "1.10.3",
+ options: {
+ content: function() {
+ // support: IE<9, Opera in jQuery <1.7
+ // .text() can't accept undefined, so coerce to a string
+ var title = $( this ).attr( "title" ) || "";
+ // Escape title, since we're going from an attribute to raw HTML
+ return $( "<a>" ).text( title ).html();
+ },
+ hide: true,
+ // Disabled elements have inconsistent behavior across browsers (#8661)
+ items: "[title]:not([disabled])",
+ position: {
+ my: "left top+15",
+ at: "left bottom",
+ collision: "flipfit flip"
+ },
+ show: true,
+ tooltipClass: null,
+ track: false,
+
+ // callbacks
+ close: null,
+ open: null
+ },
+
+ _create: function() {
+ this._on({
+ mouseover: "open",
+ focusin: "open"
+ });
+
+ // IDs of generated tooltips, needed for destroy
+ this.tooltips = {};
+ // IDs of parent tooltips where we removed the title attribute
+ this.parents = {};
+
+ if ( this.options.disabled ) {
+ this._disable();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var that = this;
+
+ if ( key === "disabled" ) {
+ this[ value ? "_disable" : "_enable" ]();
+ this.options[ key ] = value;
+ // disable element style changes
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "content" ) {
+ $.each( this.tooltips, function( id, element ) {
+ that._updateContent( element );
+ });
+ }
+ },
+
+ _disable: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+ });
+
+ // remove title attributes to prevent native tooltips
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.is( "[title]" ) ) {
+ element
+ .data( "ui-tooltip-title", element.attr( "title" ) )
+ .attr( "title", "" );
+ }
+ });
+ },
+
+ _enable: function() {
+ // restore title attributes
+ this.element.find( this.options.items ).addBack().each(function() {
+ var element = $( this );
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ }
+ });
+ },
+
+ open: function( event ) {
+ var that = this,
+ target = $( event ? event.target : this.element )
+ // we need closest here due to mouseover bubbling,
+ // but always pointing at the same event target
+ .closest( this.options.items );
+
+ // No element to show a tooltip for or the tooltip is already open
+ if ( !target.length || target.data( "ui-tooltip-id" ) ) {
+ return;
+ }
+
+ if ( target.attr( "title" ) ) {
+ target.data( "ui-tooltip-title", target.attr( "title" ) );
+ }
+
+ target.data( "ui-tooltip-open", true );
+
+ // kill parent tooltips, custom or native, for hover
+ if ( event && event.type === "mouseover" ) {
+ target.parents().each(function() {
+ var parent = $( this ),
+ blurEvent;
+ if ( parent.data( "ui-tooltip-open" ) ) {
+ blurEvent = $.Event( "blur" );
+ blurEvent.target = blurEvent.currentTarget = this;
+ that.close( blurEvent, true );
+ }
+ if ( parent.attr( "title" ) ) {
+ parent.uniqueId();
+ that.parents[ this.id ] = {
+ element: this,
+ title: parent.attr( "title" )
+ };
+ parent.attr( "title", "" );
+ }
+ });
+ }
+
+ this._updateContent( target, event );
+ },
+
+ _updateContent: function( target, event ) {
+ var content,
+ contentOption = this.options.content,
+ that = this,
+ eventType = event ? event.type : null;
+
+ if ( typeof contentOption === "string" ) {
+ return this._open( event, target, contentOption );
+ }
+
+ content = contentOption.call( target[0], function( response ) {
+ // ignore async response if tooltip was closed already
+ if ( !target.data( "ui-tooltip-open" ) ) {
+ return;
+ }
+ // IE may instantly serve a cached response for ajax requests
+ // delay this call to _open so the other call to _open runs first
+ that._delay(function() {
+ // jQuery creates a special event for focusin when it doesn't
+ // exist natively. To improve performance, the native event
+ // object is reused and the type is changed. Therefore, we can't
+ // rely on the type being correct after the event finished
+ // bubbling, so we set it back to the previous value. (#8740)
+ if ( event ) {
+ event.type = eventType;
+ }
+ this._open( event, target, response );
+ });
+ });
+ if ( content ) {
+ this._open( event, target, content );
+ }
+ },
+
+ _open: function( event, target, content ) {
+ var tooltip, events, delayedShow,
+ positionOption = $.extend( {}, this.options.position );
+
+ if ( !content ) {
+ return;
+ }
+
+ // Content can be updated multiple times. If the tooltip already
+ // exists, then just update the content and bail.
+ tooltip = this._find( target );
+ if ( tooltip.length ) {
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+ return;
+ }
+
+ // if we have a title, clear it to prevent the native tooltip
+ // we have to check first to avoid defining a title if none exists
+ // (we don't want to cause an element to start matching [title])
+ //
+ // We use removeAttr only for key events, to allow IE to export the correct
+ // accessible attributes. For mouse events, set to empty string to avoid
+ // native tooltip showing up (happens only when removing inside mouseover).
+ if ( target.is( "[title]" ) ) {
+ if ( event && event.type === "mouseover" ) {
+ target.attr( "title", "" );
+ } else {
+ target.removeAttr( "title" );
+ }
+ }
+
+ tooltip = this._tooltip( target );
+ addDescribedBy( target, tooltip.attr( "id" ) );
+ tooltip.find( ".ui-tooltip-content" ).html( content );
+
+ function position( event ) {
+ positionOption.of = event;
+ if ( tooltip.is( ":hidden" ) ) {
+ return;
+ }
+ tooltip.position( positionOption );
+ }
+ if ( this.options.track && event && /^mouse/.test( event.type ) ) {
+ this._on( this.document, {
+ mousemove: position
+ });
+ // trigger once to override element-relative positioning
+ position( event );
+ } else {
+ tooltip.position( $.extend({
+ of: target
+ }, this.options.position ) );
+ }
+
+ tooltip.hide();
+
+ this._show( tooltip, this.options.show );
+ // Handle tracking tooltips that are shown with a delay (#8644). As soon
+ // as the tooltip is visible, position the tooltip using the most recent
+ // event.
+ if ( this.options.show && this.options.show.delay ) {
+ delayedShow = this.delayedShow = setInterval(function() {
+ if ( tooltip.is( ":visible" ) ) {
+ position( positionOption.of );
+ clearInterval( delayedShow );
+ }
+ }, $.fx.interval );
+ }
+
+ this._trigger( "open", event, { tooltip: tooltip } );
+
+ events = {
+ keyup: function( event ) {
+ if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
+ var fakeEvent = $.Event(event);
+ fakeEvent.currentTarget = target[0];
+ this.close( fakeEvent, true );
+ }
+ },
+ remove: function() {
+ this._removeTooltip( tooltip );
+ }
+ };
+ if ( !event || event.type === "mouseover" ) {
+ events.mouseleave = "close";
+ }
+ if ( !event || event.type === "focusin" ) {
+ events.focusout = "close";
+ }
+ this._on( true, target, events );
+ },
+
+ close: function( event ) {
+ var that = this,
+ target = $( event ? event.currentTarget : this.element ),
+ tooltip = this._find( target );
+
+ // disabling closes the tooltip, so we need to track when we're closing
+ // to avoid an infinite loop in case the tooltip becomes disabled on close
+ if ( this.closing ) {
+ return;
+ }
+
+ // Clear the interval for delayed tracking tooltips
+ clearInterval( this.delayedShow );
+
+ // only set title if we had one before (see comment in _open())
+ if ( target.data( "ui-tooltip-title" ) ) {
+ target.attr( "title", target.data( "ui-tooltip-title" ) );
+ }
+
+ removeDescribedBy( target );
+
+ tooltip.stop( true );
+ this._hide( tooltip, this.options.hide, function() {
+ that._removeTooltip( $( this ) );
+ });
+
+ target.removeData( "ui-tooltip-open" );
+ this._off( target, "mouseleave focusout keyup" );
+ // Remove 'remove' binding only on delegated targets
+ if ( target[0] !== this.element[0] ) {
+ this._off( target, "remove" );
+ }
+ this._off( this.document, "mousemove" );
+
+ if ( event && event.type === "mouseleave" ) {
+ $.each( this.parents, function( id, parent ) {
+ $( parent.element ).attr( "title", parent.title );
+ delete that.parents[ id ];
+ });
+ }
+
+ this.closing = true;
+ this._trigger( "close", event, { tooltip: tooltip } );
+ this.closing = false;
+ },
+
+ _tooltip: function( element ) {
+ var id = "ui-tooltip-" + increments++,
+ tooltip = $( "<div>" )
+ .attr({
+ id: id,
+ role: "tooltip"
+ })
+ .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
+ ( this.options.tooltipClass || "" ) );
+ $( "<div>" )
+ .addClass( "ui-tooltip-content" )
+ .appendTo( tooltip );
+ tooltip.appendTo( this.document[0].body );
+ this.tooltips[ id ] = element;
+ return tooltip;
+ },
+
+ _find: function( target ) {
+ var id = target.data( "ui-tooltip-id" );
+ return id ? $( "#" + id ) : $();
+ },
+
+ _removeTooltip: function( tooltip ) {
+ tooltip.remove();
+ delete this.tooltips[ tooltip.attr( "id" ) ];
+ },
+
+ _destroy: function() {
+ var that = this;
+
+ // close open tooltips
+ $.each( this.tooltips, function( id, element ) {
+ // Delegate to close method to handle common cleanup
+ var event = $.Event( "blur" );
+ event.target = event.currentTarget = element[0];
+ that.close( event, true );
+
+ // Remove immediately; destroying an open tooltip doesn't use the
+ // hide animation
+ $( "#" + id ).remove();
+
+ // Restore the title
+ if ( element.data( "ui-tooltip-title" ) ) {
+ element.attr( "title", element.data( "ui-tooltip-title" ) );
+ element.removeData( "ui-tooltip-title" );
+ }
+ });
+ }
+});
+
+}( jQuery ) );
Binary file web/data/rhythm15.png has changed
Binary file web/data/rhythm18.png has changed
Binary file web/data/rhythm20.png has changed
Binary file web/data/rhythm22.png has changed
Binary file web/data/rhythm24.png has changed
Binary file web/data/rhythm26.png has changed
Binary file web/data/shadow.gif has changed
--- a/web/data/uiprops.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/data/uiprops.py Mon Jan 13 13:47:47 2014 +0100
@@ -9,7 +9,7 @@
# Javascripts files to include systematically in HTML headers
JAVASCRIPTS = [data('jquery.js'),
- data('jquery.corner.js'),
+ data('jquery-migrate.js'),
data('jquery.json.js'),
data('cubicweb.js'),
data('cubicweb.compat.js'),
@@ -66,7 +66,6 @@
defaultSize = '12px'
defaultLineHeight = '1.5'
defaultLineHeightEm = lazystr('%(defaultLineHeight)sem')
-baseRhythmBg = 'rhythm18.png'
inputHeight = '1.3em'
inputPadding = 'O.2em'
--- a/web/facet.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/facet.py Mon Jan 13 13:47:47 2014 +0100
@@ -74,10 +74,11 @@
def rtype_facet_title(facet):
- ptypes = facet.cw_rset.column_types(0)
- if len(ptypes) == 1:
- return display_name(facet._cw, facet.rtype, form=facet.role,
- context=iter(ptypes).next())
+ if facet.cw_rset:
+ ptypes = facet.cw_rset.column_types(0)
+ if len(ptypes) == 1:
+ return display_name(facet._cw, facet.rtype, form=facet.role,
+ context=iter(ptypes).next())
return display_name(facet._cw, facet.rtype, form=facet.role)
def get_facet(req, facetid, select, filtered_variable):
@@ -126,11 +127,9 @@
return filtered_variable, baserql
def get_filtered_variable(select, mainvar=None):
- """drop any limit/offset from select (in-place modification) and return the
- variable whose name is `mainvar` or the first variable selected in column 0
+ """ Return the variable whose name is `mainvar`
+ or the first variable selected in column 0
"""
- select.set_limit(None)
- select.set_offset(None)
if mainvar is None:
vref = select.selection[0].iget_nodes(nodes.VariableRef).next()
return vref.variable
@@ -1516,7 +1515,8 @@
cssclass += ' hideFacetBody'
w(u'<div class="%s" cubicweb:facetName="%s">%s</div>\n' %
(cssclass, xml_escape(self.facet.__regid__), title))
- w(u'<input name="%s" type="text" value="%s" />\n' % (facetid, self.value or u''))
+ w(u'<input name="%s" type="text" value="%s" />\n' % (
+ xml_escape(self.facet.__regid__), self.value or u''))
w(u'</div>\n')
--- a/web/formfields.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/formfields.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -404,17 +404,6 @@
for label, value in vocab]
if self.sort:
vocab = vocab_sort(vocab)
- # XXX pre 3.9 bw compat
- for i, option in enumerate(vocab):
- # option may be a 2 or 3-uple (see Select widget _render method for
- # explanation)
- value = option[1]
- if value is not None and not isinstance(value, basestring):
- warn('[3.9] %s: vocabulary value should be an unicode string'
- % self, DeprecationWarning)
- option = list(option)
- option[1] = unicode(value)
- vocab[i] = option
return vocab
# support field as argument to avoid warning when used as format field value
@@ -506,7 +495,7 @@
if field is self:
try:
value = field.process_form_value(form)
- if value is None and field.required:
+ if field.no_value(value) and field.required:
raise ProcessFormError(form._cw._("required field"))
yield field, value
except UnmodifiedField:
@@ -517,6 +506,11 @@
for field, value in field.process_posted(form):
yield field, value
+ @staticmethod
+ def no_value(value):
+ """return True if the value can be considered as no value for the field"""
+ return value is None
+
class StringField(Field):
"""Use this field to edit unicode string (`String` yams type). This field
@@ -559,7 +553,7 @@
widget.attrs.setdefault('maxlength', self.max_length)
def init_text_area(self, widget):
- if self.max_length < 513:
+ if self.max_length and self.max_length < 513:
widget.attrs.setdefault('cols', 60)
widget.attrs.setdefault('rows', 5)
@@ -755,8 +749,13 @@
# raise UnmodifiedField instead of returning None, since the later
# will try to remove already attached file if any
raise UnmodifiedField()
- # value is a 2-uple (filename, stream)
+ # value is a 2-uple (filename, stream) or a list of such
+ # tuples (multiple files)
try:
+ if isinstance(value, list):
+ value = value[0]
+ form.warning('mutiple files provided, however '
+ 'only the first will be picked')
filename, stream = value
except ValueError:
raise UnmodifiedField()
@@ -1148,16 +1147,29 @@
elif not isinstance(values, list):
values = (values,)
eids = set()
+ rschema = form._cw.vreg.schema.rschema(self.name)
for eid in values:
if not eid or eid == INTERNAL_FIELD_VALUE:
continue
typed_eid = form.actual_eid(eid)
+ # if entity doesn't exist yet
if typed_eid is None:
- form._cw.data['pendingfields'].add( (form, self) )
+ # inlined relations of to-be-created **subject entities** have
+ # to be handled separatly
+ if self.role == 'object' and rschema.inlined:
+ form._cw.data['pending_inlined'][eid].add( (form, self) )
+ else:
+ form._cw.data['pending_others'].add( (form, self) )
return None
eids.add(typed_eid)
return eids
+ @staticmethod
+ def no_value(value):
+ """return True if the value can be considered as no value for the field"""
+ # value is None is the 'not yet ready value, consider the empty set
+ return value is not None and not value
+
_AFF_KWARGS = uicfg.autoform_field_kwargs
--- a/web/formwidgets.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/formwidgets.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -515,7 +515,8 @@
name=field.dom_id(form),
type="hidden"))
else:
- options.append(tags.option(label, value=value))
+ if value not in values:
+ options.append(tags.option(label, value=value))
if 'size' not in attrs:
attrs['size'] = self.default_size
if 'id' in attrs :
@@ -542,6 +543,7 @@
'removeinput': self.remove_button % jsnodes
})
+
class BitSelect(Select):
"""Select widget for IntField using a vocabulary with bit masks as values.
@@ -587,13 +589,7 @@
def _render(self, form, field, renderer):
curvalues, attrs = self.values_and_attributes(form, field)
domid = attrs.pop('id', None)
- # XXX turn this as initializer argument
- try:
- sep = attrs.pop('separator')
- warn('[3.8] separator should be specified using initializer argument',
- DeprecationWarning)
- except KeyError:
- sep = self.separator
+ sep = self.separator
options = []
for i, option in enumerate(field.vocabulary(form)):
try:
@@ -691,16 +687,17 @@
'{buttonImage: "%s", dateFormat: "%s", firstDay: 1,'
' showOn: "button", buttonImageOnly: true})' % (
domid, req.uiprops['CALENDAR_ICON'], fmt))
- return self._render_input(form, field, domid)
+ return self._render_input(form, field)
- def _render_input(self, form, field, domid):
+ def _render_input(self, form, field):
if self.value is None:
value = self.values(form, field)[0]
else:
value = self.value
attrs = self.attributes(form, field)
attrs.setdefault('size', unicode(self.default_size))
- return tags.input(name=domid, value=value, type='text', **attrs)
+ return tags.input(name=field.input_name(form, self.suffix),
+ value=value, type='text', **attrs)
class JQueryTimePicker(JQueryDatePicker):
@@ -720,7 +717,7 @@
domid = field.dom_id(form, self.suffix)
form._cw.add_onload(u'cw.jqNode("%s").timePicker({step: %s, separator: "%s"})' % (
domid, self.timesteps, self.separator))
- return self._render_input(form, field, domid)
+ return self._render_input(form, field)
class JQueryDateTimePicker(FieldWidget):
@@ -1016,6 +1013,8 @@
time, you should not give an already translated string.
"""
type = 'button'
+ css_class = 'validateButton'
+
def __init__(self, label=stdmsgs.BUTTON_OK, attrs=None,
setdomid=None, settabindex=None,
name='', value='', onclick=None, cwaction=None):
@@ -1030,7 +1029,7 @@
self.value = ''
self.onclick = onclick
self.cwaction = cwaction
- self.attrs.setdefault('class', 'validateButton')
+ self.attrs.setdefault('class', self.css_class)
def render(self, form, field=None, renderer=None):
label = form._cw._(self.label)
--- a/web/request.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/request.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -673,12 +673,6 @@
cssfile = self.data_url(cssfile)
add_css(cssfile, media, *extraargs)
- @deprecated('[3.9] use ajax_replace_url() instead, naming rql and vid arguments')
- def build_ajax_replace_url(self, nodeid, rql, vid, replacemode='replace',
- **extraparams):
- return self.ajax_replace_url(nodeid, replacemode, rql=rql, vid=vid,
- **extraparams)
-
def ajax_replace_url(self, nodeid, replacemode='replace', **extraparams):
"""builds an ajax url that will replace nodeid's content
@@ -760,11 +754,13 @@
return controller
return 'view'
- def validate_cache(self):
- """raise a `StatusResponse` exception if a cached page along the way
- exists and is still usable.
+ def is_client_cache_valid(self):
+ """check if a client cached page exists (as specified in request
+ headers) and is still usable.
- calls the client-dependant implementation of `_validate_cache`
+ Return False if the page has to be calculated, else True.
+
+ Some response cache headers may be set by this method.
"""
modified = True
if self.get_header('Cache-Control') not in ('max-age=0', 'no-cache'):
@@ -779,15 +775,30 @@
# Expires header seems to be required by IE7 -- Are you sure ?
self.add_header('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
if self.http_method() == 'HEAD':
- raise StatusResponse(200, '')
- # /!\ no raise, the function returns and we keep processing the request)
+ self.status_out = 200
+ # XXX replace by True once validate_cache bw compat method is dropped
+ return 200
+ # /!\ no raise, the function returns and we keep processing the request
else:
# overwrite headers_out to forge a brand new not-modified response
self.headers_out = self._forge_cached_headers()
if self.http_method() in ('HEAD', 'GET'):
- raise StatusResponse(httplib.NOT_MODIFIED)
+ self.status_out = httplib.NOT_MODIFIED
else:
- raise StatusResponse(httplib.PRECONDITION_FAILED)
+ self.status_out = httplib.PRECONDITION_FAILED
+ # XXX replace by True once validate_cache bw compat method is dropped
+ return self.status_out
+ # XXX replace by False once validate_cache bw compat method is dropped
+ return None
+
+ @deprecated('[3.18] use .is_client_cache_valid() method instead')
+ def validate_cache(self):
+ """raise a `StatusResponse` exception if a cached page along the way
+ exists and is still usable.
+ """
+ status_code = self.is_client_cache_valid()
+ if status_code is not None:
+ raise StatusResponse(status_code)
# abstract methods to override according to the web front-end #############
@@ -917,7 +928,7 @@
if reset_xmldecl is not None:
warn('[3.17] reset_xmldecl is deprecated as we only serve html',
DeprecationWarning, stacklevel=2)
- self.main_stream.set_doctype(doctype, reset_xmldecl)
+ self.main_stream.set_doctype(doctype)
# page data management ####################################################
@@ -970,18 +981,6 @@
def html_content_type(self):
return 'text/html'
- @deprecated('[3.9] use req.uiprops[rid]')
- def external_resource(self, rid, default=_MARKER):
- """return a path to an external resource, using its identifier
-
- raise `KeyError` if the resource is not defined
- """
- try:
- return self.uiprops[rid]
- except KeyError:
- if default is _MARKER:
- raise
- return default
class DBAPICubicWebRequestBase(_CubicWebRequestBase, DBAPIRequest):
--- a/web/test/data/schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/data/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -15,16 +15,14 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""
-
-"""
from yams.buildobjs import (EntityType, RelationDefinition, SubjectRelation,
String, Int, Datetime, Boolean, Float)
from yams.constraints import IntervalBoundConstraint
class Salesterm(EntityType):
- described_by_test = SubjectRelation('File', cardinality='1*', composite='subject')
+ described_by_test = SubjectRelation('File', cardinality='1*',
+ composite='subject', inlined=True)
amount = Int(constraints=[IntervalBoundConstraint(0, 100)])
reason = String(maxsize=20, vocabulary=[u'canceled', u'sold'])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/views.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,48 @@
+# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+from cubicweb.web.views.ajaxcontroller import ajaxfunc
+
+def _recursive_replace_stream_by_content(tree):
+ """ Search for streams (i.e. object that have a 'read' method) in a tree
+ (which branches are lists or tuples), and substitute them by their content,
+ leaving other leafs identical. A copy of the tree with only lists as
+ branches is returned.
+ """
+ if not isinstance(tree, (list, tuple)):
+ if hasattr(tree, 'read'):
+ return tree.read()
+ return tree
+ else:
+ return [_recursive_replace_stream_by_content(value)
+ for value in tree]
+
+
+@ajaxfunc(output_type='json')
+def fileupload(self):
+ """ Return a json copy of the web request formin which uploaded files
+ are read and their content substitute the received streams.
+ """
+ try:
+ result_dict = {}
+ for key, value in self._cw.form.iteritems():
+ result_dict[key] = _recursive_replace_stream_by_content(value)
+ return result_dict
+ except Exception, ex:
+ import traceback as tb
+ tb.print_exc(ex)
--- a/web/test/jstests/test_utils.js Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/jstests/test_utils.js Mon Jan 13 13:47:47 2014 +0100
@@ -47,11 +47,11 @@
module("sliceList");
test("test slicelist", function() {
var list = ['a', 'b', 'c', 'd', 'e', 'f'];
- same(sliceList(list, 2), ['c', 'd', 'e', 'f']);
- same(sliceList(list, 2, -2), ['c', 'd']);
- same(sliceList(list, -3), ['d', 'e', 'f']);
- same(sliceList(list, 0, -2), ['a', 'b', 'c', 'd']);
- same(sliceList(list), list);
+ same(cw.utils.sliceList(list, 2), ['c', 'd', 'e', 'f']);
+ same(cw.utils.sliceList(list, 2, -2), ['c', 'd']);
+ same(cw.utils.sliceList(list, -3), ['d', 'e', 'f']);
+ same(cw.utils.sliceList(list, 0, -2), ['a', 'b', 'c', 'd']);
+ same(cw.utils.sliceList(list), list);
});
module("formContents", {
@@ -83,7 +83,7 @@
'value="one" />');
$('#test-form').append('<input name="unchecked-choice" type="radio" ' +
'value="two"/>');
- same(formContents($('#test-form')[0]), [
+ same(cw.utils.formContents($('#test-form')[0]), [
['input-text', 'mytextarea', 'choice', 'check', 'theselect'],
['toto', 'Hello World!', 'no', 'no', 'foo']
]);
--- a/web/test/unittest_form.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_form.py Mon Jan 13 13:47:47 2014 +0100
@@ -94,8 +94,7 @@
form.build_context({})
self.assertEqual(field.widget.values(form, field), (u'toto',))
-
- def test_linkto_field_duplication(self):
+ def test_linkto_field_duplication_inout(self):
e = self.vreg['etypes'].etype_class('CWUser')(self.request())
e.eid = 'A'
e._cw = self.req
@@ -111,7 +110,6 @@
self.assertEqual(optionnode.get('value'), str(geid))
self.assertEqual(ok, False)
ok = True
- self.assertEqual(ok, True, 'expected option not found')
inputs = pageinfo.find_tag('input', False)
self.assertFalse(list(pageinfo.matching_nodes('input', name='__linkto')))
--- a/web/test/unittest_http.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_http.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,15 +1,30 @@
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
from logilab.common.testlib import TestCase, unittest_main, tag, Tags
-from cubicweb.web import StatusResponse
from cubicweb.devtools.fake import FakeRequest
def _test_cache(hin, hout, method='GET'):
- """forge and process a request
+ """forge and process an HTTP request using given headers in/out and method,
+ then return it once its .is_client_cache_valid() method has been called.
- return status code and the request object
-
- status is None is no cache is involved
+ req.status_out is None if the page should have been calculated.
"""
# forge request
req = FakeRequest(method=method)
@@ -18,12 +33,9 @@
for key, value in hout:
req.headers_out.addRawHeader(key, str(value))
# process
- status = None
- try:
- req.validate_cache()
- except StatusResponse as ex:
- status = ex.status
- return status, req
+ req.status_out = None
+ req.is_client_cache_valid()
+ return req
class HTTPCache(TestCase):
"""Check that the http cache logiac work as expected
@@ -48,42 +60,42 @@
def test_IN_none_OUT_none(self):
#: test that no caching is requested when not data is available
#: on any side
- status, req =_test_cache((),())
- self.assertIsNone(status)
+ req =_test_cache((), ())
+ self.assertIsNone(req.status_out)
def test_IN_Some_OUT_none(self):
#: test that no caching is requested when no data is available
#: server (origin) side
hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, ())
- self.assertIsNone(status)
+ req = _test_cache(hin, ())
+ self.assertIsNone(req.status_out)
hin = [('if-none-match','babar/huitre'),
]
- status, req = _test_cache(hin, ())
- self.assertIsNone(status)
+ req = _test_cache(hin, ())
+ self.assertIsNone(req.status_out)
hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
('if-none-match','babar/huitre'),
]
- status, req = _test_cache(hin, ())
- self.assertIsNone(status)
+ req = _test_cache(hin, ())
+ self.assertIsNone(req.status_out)
def test_IN_none_OUT_Some(self):
#: test that no caching is requested when no data is provided
#: by the client
hout = [('last-modified','Sat, 14 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache((), hout)
- self.assertIsNone(status)
+ req = _test_cache((), hout)
+ self.assertIsNone(req.status_out)
hout = [('etag','babar/huitre'),
]
- status, req = _test_cache((), hout)
- self.assertIsNone(status)
+ req = _test_cache((), hout)
+ self.assertIsNone(req.status_out)
hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
('etag','babar/huitre'),
]
- status, req = _test_cache((), hout)
- self.assertIsNone(status)
+ req = _test_cache((), hout)
+ self.assertIsNone(req.status_out)
@tag('last_modified')
def test_last_modified_newer(self):
@@ -93,8 +105,8 @@
]
hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(None, status, 'origin is newer than client')
+ req = _test_cache(hin, hout)
+ self.assertCache(None, req.status_out, 'origin is newer than client')
@tag('last_modified')
def test_last_modified_older(self):
@@ -103,8 +115,8 @@
]
hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(304, status, 'origin is older than client')
+ req = _test_cache(hin, hout)
+ self.assertCache(304, req.status_out, 'origin is older than client')
@tag('last_modified')
def test_last_modified_same(self):
@@ -113,8 +125,8 @@
]
hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(304, status, 'origin is equal to client')
+ req = _test_cache(hin, hout)
+ self.assertCache(304, req.status_out, 'origin is equal to client')
@tag('etag')
def test_etag_mismatch(self):
@@ -124,8 +136,8 @@
]
hout = [('etag', 'celestine'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(None, status, 'etag mismatch')
+ req = _test_cache(hin, hout)
+ self.assertCache(None, req.status_out, 'etag mismatch')
@tag('etag')
def test_etag_match(self):
@@ -134,23 +146,23 @@
]
hout = [('etag', 'babar'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(304, status, 'etag match')
+ req = _test_cache(hin, hout)
+ self.assertCache(304, req.status_out, 'etag match')
# etag match in multiple
hin = [('if-none-match', 'loutre'),
('if-none-match', 'babar'),
]
hout = [('etag', 'babar'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(304, status, 'etag match in multiple')
+ req = _test_cache(hin, hout)
+ self.assertCache(304, req.status_out, 'etag match in multiple')
# client use "*" as etag
hin = [('if-none-match', '*'),
]
hout = [('etag', 'babar'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(304, status, 'client use "*" as etag')
+ req = _test_cache(hin, hout)
+ self.assertCache(304, req.status_out, 'client use "*" as etag')
@tag('etag', 'last_modified')
def test_both(self):
@@ -162,8 +174,8 @@
hout = [('etag', 'loutre'),
('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(None, status, 'both wrong')
+ req = _test_cache(hin, hout)
+ self.assertCache(None, req.status_out, 'both wrong')
@tag('etag', 'last_modified')
def test_both_etag_mismatch(self):
@@ -174,8 +186,8 @@
hout = [('etag', 'loutre'),
('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(None, status, 'both but etag mismatch')
+ req = _test_cache(hin, hout)
+ self.assertCache(None, req.status_out, 'both but etag mismatch')
@tag('etag', 'last_modified')
def test_both_but_modified(self):
@@ -186,8 +198,8 @@
hout = [('etag', 'babar'),
('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(None, status, 'both but modified')
+ req = _test_cache(hin, hout)
+ self.assertCache(None, req.status_out, 'both but modified')
@tag('etag', 'last_modified')
def test_both_ok(self):
@@ -198,8 +210,8 @@
hout = [('etag', 'babar'),
('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(304, status, 'both ok')
+ req = _test_cache(hin, hout)
+ self.assertCache(304, req.status_out, 'both ok')
@tag('etag', 'HEAD')
def test_head_verb(self):
@@ -210,15 +222,15 @@
]
hout = [('etag', 'rhino/really-not-babar'),
]
- status, req = _test_cache(hin, hout, method='HEAD')
- self.assertCache(200, status, 'modifier HEAD verb')
+ req = _test_cache(hin, hout, method='HEAD')
+ self.assertCache(200, req.status_out, 'modifier HEAD verb')
# not modified
hin = [('if-none-match', 'babar'),
]
hout = [('etag', 'babar'),
]
- status, req = _test_cache(hin, hout, method='HEAD')
- self.assertCache(304, status, 'not modifier HEAD verb')
+ req = _test_cache(hin, hout, method='HEAD')
+ self.assertCache(304, req.status_out, 'not modifier HEAD verb')
@tag('etag', 'POST')
def test_post_verb(self):
@@ -227,15 +239,15 @@
]
hout = [('etag', 'rhino/really-not-babar'),
]
- status, req = _test_cache(hin, hout, method='POST')
- self.assertCache(None, status, 'modifier HEAD verb')
+ req = _test_cache(hin, hout, method='POST')
+ self.assertCache(None, req.status_out, 'modifier HEAD verb')
# not modified
hin = [('if-none-match', 'babar'),
]
hout = [('etag', 'babar'),
]
- status, req = _test_cache(hin, hout, method='POST')
- self.assertCache(412, status, 'not modifier HEAD verb')
+ req = _test_cache(hin, hout, method='POST')
+ self.assertCache(412, req.status_out, 'not modifier HEAD verb')
@tag('expires')
def test_expires_added(self):
@@ -246,8 +258,8 @@
]
hout = [('etag', 'rhino/really-not-babar'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(None, status, 'modifier HEAD verb')
+ req = _test_cache(hin, hout)
+ self.assertCache(None, req.status_out, 'modifier HEAD verb')
value = req.headers_out.getHeader('expires')
self.assertIsNotNone(value)
@@ -258,8 +270,8 @@
]
hout = [('etag', 'babar'),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(304, status, 'not modifier HEAD verb')
+ req = _test_cache(hin, hout)
+ self.assertCache(304, req.status_out, 'not modifier HEAD verb')
value = req.headers_out.getHeader('expires')
self.assertIsNone(value)
@@ -272,8 +284,8 @@
hout = [('etag', 'rhino/really-not-babar'),
('expires', DATE),
]
- status, req = _test_cache(hin, hout)
- self.assertCache(None, status, 'not modifier HEAD verb')
+ req = _test_cache(hin, hout)
+ self.assertCache(None, req.status_out, 'not modifier HEAD verb')
value = req.headers_out.getRawHeaders('expires')
self.assertEqual(value, [DATE])
--- a/web/test/unittest_uicfg.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_uicfg.py Mon Jan 13 13:47:47 2014 +0100
@@ -73,6 +73,14 @@
uihelper.set_fields_order('CWUser', ('login', 'firstname', 'surname'))
self.assertEqual(afk_get('CWUser', 'firstname', 'String', 'subject'), {'order': 1})
+ @tag('uicfg', 'order', 'func')
+ def test_uicfg_primaryview_set_fields_order(self):
+ pvdc = uicfg.primaryview_display_ctrl
+ pvdc.set_fields_order('CWUser', ('login', 'firstname', 'surname'))
+ self.assertEqual(pvdc.get('CWUser', 'login', 'String', 'subject'), {'order': 0})
+ self.assertEqual(pvdc.get('CWUser', 'firstname', 'String', 'subject'), {'order': 1})
+ self.assertEqual(pvdc.get('CWUser', 'surname', 'String', 'subject'), {'order': 2})
+
@tag('uihelper', 'kwargs', 'func')
def test_uihelper_set_field_kwargs(self):
afk_get = uicfg.autoform_field_kwargs.get
@@ -85,15 +93,15 @@
def test_uihelper_hide_fields(self):
# original conf : in_group is edited in 'attributes' section everywhere
section_conf = uicfg.autoform_section.get('CWUser', 'in_group', '*', 'subject')
- self.assertItemsEqual(section_conf, ['main_attributes', 'muledit_attributes'])
+ self.assertCountEqual(section_conf, ['main_attributes', 'muledit_attributes'])
# hide field in main form
uihelper.hide_fields('CWUser', ('login', 'in_group'))
section_conf = uicfg.autoform_section.get('CWUser', 'in_group', '*', 'subject')
- self.assertItemsEqual(section_conf, ['main_hidden', 'muledit_attributes'])
+ self.assertCountEqual(section_conf, ['main_hidden', 'muledit_attributes'])
# hide field in muledit form
uihelper.hide_fields('CWUser', ('login', 'in_group'), formtype='muledit')
section_conf = uicfg.autoform_section.get('CWUser', 'in_group', '*', 'subject')
- self.assertItemsEqual(section_conf, ['main_hidden', 'muledit_hidden'])
+ self.assertCountEqual(section_conf, ['main_hidden', 'muledit_hidden'])
@tag('uihelper', 'hidden', 'formconfig')
def test_uihelper_formconfig(self):
@@ -103,7 +111,7 @@
hidden = ('in_group',)
fields_order = ('login', 'firstname')
section_conf = uicfg.autoform_section.get('CWUser', 'in_group', '*', 'subject')
- self.assertItemsEqual(section_conf, ['main_hidden', 'muledit_attributes'])
+ self.assertCountEqual(section_conf, ['main_hidden', 'muledit_attributes'])
self.assertEqual(afk_get('CWUser', 'firstname', 'String', 'subject'), {'order': 1})
--- a/web/test/unittest_urlpublisher.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_urlpublisher.py Mon Jan 13 13:47:47 2014 +0100
@@ -62,42 +62,42 @@
self.assertEqual(ctrl, 'view')
self.assertEqual(rset.description[0][0], 'CWEType')
self.assertEqual(rset.printable_rql(),
- "Any X,AA,AB ORDERBY AA WHERE X is CWEType, X name AA, X modification_date AB")
+ "Any X,AA,AB ORDERBY AA WHERE X is_instance_of CWEType, X name AA, X modification_date AB")
def test_rest_path_by_attr(self):
ctrl, rset = self.process('CWUser/login/admin')
self.assertEqual(ctrl, 'view')
self.assertEqual(len(rset), 1)
self.assertEqual(rset.description[0][0], 'CWUser')
- self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"')
+ self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"')
def test_rest_path_unique_attr(self):
ctrl, rset = self.process('cwuser/admin')
self.assertEqual(ctrl, 'view')
self.assertEqual(len(rset), 1)
self.assertEqual(rset.description[0][0], 'CWUser')
- self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"')
+ self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "admin"')
def test_rest_path_eid(self):
ctrl, rset = self.process('cwuser/eid/%s' % self.user().eid)
self.assertEqual(ctrl, 'view')
self.assertEqual(len(rset), 1)
self.assertEqual(rset.description[0][0], 'CWUser')
- self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X eid %s' % rset[0][0])
+ self.assertEqual(rset.printable_rql(), 'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X eid %s' % rset[0][0])
def test_rest_path_non_ascii_paths(self):
ctrl, rset = self.process('CWUser/login/%C3%BFsa%C3%BFe')
self.assertEqual(ctrl, 'view')
self.assertEqual(len(rset), 1)
self.assertEqual(rset.description[0][0], 'CWUser')
- self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC,AD WHERE X is CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "\xffsa\xffe"')
+ self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC,AD WHERE X is_instance_of CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, X login "\xffsa\xffe"')
def test_rest_path_quoted_paths(self):
ctrl, rset = self.process('BlogEntry/title/hell%27o')
self.assertEqual(ctrl, 'view')
self.assertEqual(len(rset), 1)
self.assertEqual(rset.description[0][0], 'BlogEntry')
- self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC WHERE X is BlogEntry, X creation_date AA, X title AB, X modification_date AC, X title "hell\'o"')
+ self.assertEqual(rset.printable_rql(), u'Any X,AA,AB,AC WHERE X is_instance_of BlogEntry, X creation_date AA, X title AB, X modification_date AC, X title "hell\'o"')
def test_rest_path_errors(self):
self.assertRaises(NotFound, self.process, 'CWUser/eid/30000')
--- a/web/test/unittest_urlrewrite.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_urlrewrite.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -15,7 +15,8 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-from logilab.common.testlib import TestCase, unittest_main
+
+from logilab.common import tempattr
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.devtools.fake import FakeRequest
@@ -96,6 +97,24 @@
rewriter.rewrite(req, '/add/Task/')
self.assertEqual(req.form, {'vid' : "creation", 'etype' : "Task"})
+ def test_inheritance(self):
+ BaseTransition = self.vreg['etypes'].etype_class('BaseTransition')
+ req = self.request()
+ x = req.create_entity('WorkflowTransition', name=u'test')
+ ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.eid)
+ self.assertEqual(ctrlid, 'view')
+ self.assertEqual(x.eid, rset[0][0])
+ # cw_rest_attr_info is cached but clear_cache doesn't like cached class
+ # method
+ del BaseTransition._cw_rest_attr_info_cache_
+ try:
+ with tempattr(BaseTransition, 'rest_attr', 'name'):
+
+ ctrlid, rset = self.app.url_resolver.process(req, 'basetransition/%s' % x.name)
+ self.assertEqual(ctrlid, 'view')
+ self.assertEqual(x.eid, rset[0][0])
+ finally:
+ del BaseTransition._cw_rest_attr_info_cache_
@@ -192,4 +211,5 @@
if __name__ == '__main__':
+ from logilab.common.testlib import unittest_main
unittest_main()
--- a/web/test/unittest_views_actions.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_views_actions.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -15,21 +15,32 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""
-"""
from logilab.common.testlib import unittest_main
from cubicweb.devtools.testlib import CubicWebTC
+from cubicweb.web.views import actions, uicfg
class ActionsTC(CubicWebTC):
def test_view_action(self):
- req = self.request(__message='bla bla bla', vid='rss', rql='CWUser X')
+ req = self.request(vid='rss', rql='CWUser X')
rset = self.execute('CWUser X')
actions = self.vreg['actions'].poss_visible_objects(req, rset=rset)
vaction = [action for action in actions if action.__regid__ == 'view'][0]
self.assertEqual(vaction.url(), 'http://testing.fr/cubicweb/view?rql=CWUser%20X')
+ def test_has_editable_relations(self):
+ """ensure has_editable_relation predicate used by ModifyAction
+ return positive score if there is only some inlined forms
+ """
+ use_email = self.schema['use_email'].rdefs['CWUser', 'EmailAddress']
+ with self.temporary_permissions((use_email, {'add': ('guests',)}),
+ ):
+ with self.login('anon'):
+ req = self.request()
+ predicate = actions.has_editable_relation()
+ self.assertEqual(predicate(None, req, rset=req.user.as_rset()),
+ 1)
if __name__ == '__main__':
unittest_main()
--- a/web/test/unittest_views_basecontrollers.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_views_basecontrollers.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -39,6 +39,8 @@
from cubicweb.web.views.basecontrollers import JSonController, xhtmlize, jsonize
from cubicweb.web.views.ajaxcontroller import ajaxfunc, AjaxFunction
import cubicweb.transaction as tx
+from cubicweb.server.hook import Hook, Operation
+from cubicweb.predicates import is_instance
u = unicode
@@ -171,6 +173,54 @@
email = e.use_email[0]
self.assertEqual(email.address, 'dima@logilab.fr')
+ def test_create_mandatory_inlined(self):
+ req = self.request()
+ req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
+
+ '__type:X': 'Salesterm',
+ '_cw_entity_fields:X': '',
+
+ '__type:Y': 'File',
+ '_cw_entity_fields:Y': 'data-subject,described_by_test-object',
+ 'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+ 'described_by_test-object:Y': 'X',
+ }
+ path, params = self.expect_redirect_handle_request(req, 'edit')
+ self.assertTrue(path.startswith('salesterm/'), path)
+ eid = path.split('/')[1]
+ salesterm = req.entity_from_eid(eid)
+ # The NOT NULL constraint of mandatory relation implies that the File
+ # must be created before the Salesterm, otherwise Salesterm insertion
+ # will fail.
+ # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
+ # insertion does not fail and we have to check dumbly that File is
+ # created before.
+ self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
+
+ def test_create_mandatory_inlined2(self):
+ req = self.request()
+ req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
+
+ '__type:X': 'Salesterm',
+ '_cw_entity_fields:X': 'described_by_test-subject',
+ 'described_by_test-subject:X': 'Y',
+
+ '__type:Y': 'File',
+ '_cw_entity_fields:Y': 'data-subject',
+ 'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+ }
+ path, params = self.expect_redirect_handle_request(req, 'edit')
+ self.assertTrue(path.startswith('salesterm/'), path)
+ eid = path.split('/')[1]
+ salesterm = req.entity_from_eid(eid)
+ # The NOT NULL constraint of mandatory relation implies that the File
+ # must be created before the Salesterm, otherwise Salesterm insertion
+ # will fail.
+ # NOTE: sqlite does have NOT NULL constraint, unlike Postgres so the
+ # insertion does not fail and we have to check dumbly that File is
+ # created before.
+ self.assertGreater(salesterm.eid, salesterm.described_by_test[0].eid)
+
def test_edit_multiple_linked(self):
req = self.request()
peid = u(self.create_user(req, 'adim').eid)
@@ -263,6 +313,7 @@
self.ctrl_publish(req)
cm.exception.translate(unicode)
self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
+
req = self.request(rollbackfirst=True)
req.form = {'eid': ['X'],
'__type:X': 'Salesterm',
@@ -276,6 +327,67 @@
e = self.execute('Salesterm X').get_entity(0, 0)
self.assertEqual(e.amount, 10)
+ def test_interval_bound_constraint_validateform(self):
+ """Test the FormValidatorController controller on entity with
+ constrained attributes"""
+ feid = self.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
+ {'data': Binary('yo')})[0][0]
+ seid = self.request().create_entity('Salesterm', amount=0, described_by_test=feid).eid
+ self.commit()
+
+ # ensure a value that violate a constraint is properly detected
+ req = self.request(rollbackfirst=True)
+ req.form = {'eid': [unicode(seid)],
+ '__type:%s'%seid: 'Salesterm',
+ '_cw_entity_fields:%s'%seid: 'amount-subject',
+ 'amount-subject:%s'%seid: u'-10',
+ }
+ self.assertEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [false, [%s, {"amount-subject": "value -10 must be >= 0"}], null], null);
+</script>'''%seid, self.ctrl_publish(req, 'validateform'))
+
+ # ensure a value that comply a constraint is properly processed
+ req = self.request(rollbackfirst=True)
+ req.form = {'eid': [unicode(seid)],
+ '__type:%s'%seid: 'Salesterm',
+ '_cw_entity_fields:%s'%seid: 'amount-subject',
+ 'amount-subject:%s'%seid: u'20',
+ }
+ self.assertEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
+</script>''', self.ctrl_publish(req, 'validateform'))
+ self.assertEqual(20, self.execute('Any V WHERE X amount V, X eid %(eid)s', {'eid': seid})[0][0])
+
+ req = self.request(rollbackfirst=True)
+ req.form = {'eid': ['X'],
+ '__type:X': 'Salesterm',
+ '_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
+ 'amount-subject:X': u'0',
+ 'described_by_test-subject:X': u(feid),
+ }
+
+ # ensure a value that is modified in an operation on a modify
+ # hook works as it should (see
+ # https://www.cubicweb.org/ticket/2509729 )
+ class MyOperation(Operation):
+ def precommit_event(self):
+ self.entity.cw_set(amount=-10)
+ class ValidationErrorInOpAfterHook(Hook):
+ __regid__ = 'valerror-op-after-hook'
+ __select__ = Hook.__select__ & is_instance('Salesterm')
+ events = ('after_add_entity',)
+ def __call__(self):
+ MyOperation(self._cw, entity=self.entity)
+
+ with self.temporary_appobjects(ValidationErrorInOpAfterHook):
+ self.assertEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [false, ["X", {"amount-subject": "value -10 must be >= 0"}], null], null);
+</script>''', self.ctrl_publish(req, 'validateform'))
+
+ self.assertEqual('''<script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
+</script>''', self.ctrl_publish(req, 'validateform'))
+
def test_req_pending_insert(self):
"""make sure req's pending insertions are taken into account"""
tmpgroup = self.request().create_entity('CWGroup', name=u"test")
@@ -285,10 +397,9 @@
path, params = self.expect_redirect_handle_request(req, 'edit')
usergroups = [gname for gname, in
self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
- self.assertItemsEqual(usergroups, ['managers', 'test'])
+ self.assertCountEqual(usergroups, ['managers', 'test'])
self.assertEqual(get_pending_inserts(req), [])
-
def test_req_pending_delete(self):
"""make sure req's pending deletions are taken into account"""
user = self.user()
@@ -297,14 +408,14 @@
usergroups = [gname for gname, in
self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
# just make sure everything was set correctly
- self.assertItemsEqual(usergroups, ['managers', 'test'])
+ self.assertCountEqual(usergroups, ['managers', 'test'])
# now try to delete the relation
req = self.request(**req_form(user))
req.session.data['pending_delete'] = set([(user.eid, 'in_group', groupeid)])
path, params = self.expect_redirect_handle_request(req, 'edit')
usergroups = [gname for gname, in
self.execute('Any N WHERE G name N, U in_group G, U eid %(u)s', {'u': user.eid})]
- self.assertItemsEqual(usergroups, ['managers'])
+ self.assertCountEqual(usergroups, ['managers'])
self.assertEqual(get_pending_deletes(req), [])
def test_redirect_apply_button(self):
@@ -534,6 +645,34 @@
finally:
p.__class__.skip_copy_for = old_skips
+ def test_regr_inlined_forms(self):
+ self.schema['described_by_test'].inlined = False
+ try:
+ req = self.request()
+ req.data['eidmap'] = {}
+ req.data['pending_others'] = set()
+ req.data['pending_inlined'] = {}
+ req.form = {'eid': ['X', 'Y'], '__maineid' : 'X',
+
+ '__type:X': 'Salesterm',
+ '_cw_entity_fields:X': 'described_by_test-subject',
+ 'described_by_test-subject:X': 'Y',
+
+ '__type:Y': 'File',
+ '_cw_entity_fields:Y': 'data-subject',
+ 'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+ }
+ values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
+ for eid in req.edited_eids())
+ editctrl = self.vreg['controllers'].select('edit', req)
+ # don't call publish to enforce select order
+ editctrl.errors = []
+ editctrl._to_create = {}
+ editctrl.edit_entity(values_by_eid['X']) # #3064653 raise ValidationError
+ editctrl.edit_entity(values_by_eid['Y'])
+ finally:
+ self.schema['described_by_test'].inlined = False
+
class ReportBugControllerTC(CubicWebTC):
@@ -576,7 +715,7 @@
def test_remote_add_existing_tag(self):
self.remote_call('tag_entity', self.john.eid, ['python'])
- self.assertItemsEqual(
+ self.assertCountEqual(
[tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
['python', 'cubicweb'])
self.assertEqual(
@@ -585,7 +724,7 @@
def test_remote_add_new_tag(self):
self.remote_call('tag_entity', self.john.eid, ['javascript'])
- self.assertItemsEqual(
+ self.assertCountEqual(
[tname for tname, in self.execute('Any N WHERE T is Tag, T name N')],
['python', 'cubicweb', 'javascript'])
self.assertEqual(
--- a/web/test/unittest_views_baseviews.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_views_baseviews.py Mon Jan 13 13:47:47 2014 +0100
@@ -144,7 +144,7 @@
class MyView(StartupView):
__regid__ = 'my-view'
def call(self):
- self._cw.set_doctype(html_doctype, reset_xmldecl=False)
+ self._cw.set_doctype(html_doctype)
self._cw.main_stream.set_htmlattrs([('lang', 'cz')])
with self.temporary_appobjects(MyView):
--- a/web/test/unittest_views_staticcontrollers.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_views_staticcontrollers.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,3 +1,4 @@
+from logilab.common import tempattr
from logilab.common.testlib import tag, Tags
from cubicweb.devtools.testlib import CubicWebTC
@@ -29,6 +30,46 @@
self.assertEqual(304, req.status_out)
+
+class DataControllerTC(CubicWebTC):
+
+ tags = CubicWebTC.tags | Tags('static_controller', 'data', 'http')
+
+ def _publish_static_files(self, url, header={}):
+ req = self.request(headers=header)
+ req._url = url
+ return self.app_handle_request(req, url), req
+
+ def _check_datafile_ok(self, fname):
+ _, req = self._publish_static_files(fname)
+ self.assertEqual(200, req.status_out)
+ self.assertIn('last-modified', req.headers_out)
+ next_headers = {
+ 'if-modified-since': req.get_response_header('last-modified', raw=True),
+ }
+ _, req = self._publish_static_files(fname, next_headers)
+ self.assertEqual(304, req.status_out)
+
+ def _check_no_datafile(self, fname):
+ _, req = self._publish_static_files(fname)
+ self.assertEqual(404, req.status_out)
+
+ def test_static_data_mode(self):
+ hash = self.vreg.config.instance_md5_version()
+ self.assertEqual(32, len(hash))
+
+ with tempattr(self.vreg.config, 'mode', 'test'):
+ self._check_datafile_ok('data/cubicweb.css')
+ self._check_no_datafile('data/does/not/exist')
+ self._check_no_datafile('data/%s/cubicweb.css' % ('0'*len(hash)))
+
+ with tempattr(self.vreg.config, 'mode', 'notest'):
+ self._check_datafile_ok('data/cubicweb.css')
+ self._check_datafile_ok('data/%s/cubicweb.css' % hash)
+ self._check_no_datafile('data/does/not/exist')
+ self._check_no_datafile('data/%s/cubicweb.css' % ('0'*len(hash)))
+
+
class ConcatFilesTC(CubicWebTC):
tags = CubicWebTC.tags | Tags('static_controller', 'concat')
--- a/web/test/unittest_web.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_web.py Mon Jan 13 13:47:47 2014 +0100
@@ -16,7 +16,17 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from json import loads
+from os.path import join
+
+try:
+ import requests
+ assert [int(n) for n in requests.__version__.split('.', 2)][:2] >= [1, 2]
+except (ImportError, AssertionError):
+ requests = None
+
from logilab.common.testlib import TestCase, unittest_main
+from cubicweb.devtools.httptest import CubicWebServerTC
from cubicweb.devtools.fake import FakeRequest
class AjaxReplaceUrlTC(TestCase):
@@ -43,5 +53,45 @@
(cbname, qs, req.pageid),
req.html_headers.post_inlined_scripts[0])
+
+class FileUploadTC(CubicWebServerTC):
+
+ def setUp(self):
+ "Skip whole test class if a suitable requests module is not available"
+ if requests is None:
+ self.skipTest('Python ``requests`` module is not available')
+ super(FileUploadTC, self).setUp()
+
+ @property
+ def _post_url(self):
+ return self.request().build_url('ajax', fname='fileupload')
+
+ def _fobject(self, fname):
+ return open(join(self.datadir, fname), 'rb')
+
+ def _fcontent(self, fname):
+ return self._fobject(fname).read()
+
+ def test_single_file_upload(self):
+ files = {'file': ('schema.py', self._fobject('schema.py'))}
+ webreq = requests.post(self._post_url, files=files)
+ # check backward compat : a single uploaded file leads to a single
+ # 2-uple in the request form
+ expect = {'fname': u'fileupload',
+ 'file': ['schema.py', self._fcontent('schema.py')]}
+ self.assertEqual(webreq.status_code, 200)
+ self.assertDictEqual(expect, loads(webreq.content))
+
+ def test_multiple_file_upload(self):
+ files = [('files', ('schema.py', self._fobject('schema.py'))),
+ ('files', ('views.py', self._fobject('views.py')))]
+ webreq = requests.post(self._post_url, files=files,)
+ expect = {'fname': u'fileupload',
+ 'files': [['schema.py', self._fcontent('schema.py')],
+ ['views.py', self._fcontent('views.py')]],}
+ self.assertEqual(webreq.status_code, 200)
+ self.assertDictEqual(expect, loads(webreq.content))
+
+
if __name__ == '__main__':
unittest_main()
--- a/web/test/unittest_webconfig.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/test/unittest_webconfig.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,5 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# -*- coding: utf-8 -*-
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -15,13 +16,11 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""
+"""cubicweb.web.webconfig unit tests"""
-"""
import os
from logilab.common.testlib import TestCase, unittest_main
-
from cubicweb.devtools import ApptestConfiguration, fake
class WebconfigTC(TestCase):
@@ -45,6 +44,10 @@
cubicwebcsspath = self.config.locate_resource('cubicweb.css')[0].split(os.sep)
self.assertTrue('web' in cubicwebcsspath or 'shared' in cubicwebcsspath) # 'shared' if tests under apycot
+ def test_sign_text(self):
+ signature = self.config.sign_text(u'hôp')
+ self.assertTrue(self.config.check_text_sign(u'hôp', signature))
+
if __name__ == '__main__':
unittest_main()
--- a/web/uihelper.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/uihelper.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2011-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2011-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -66,8 +66,8 @@
for funcname, tag in backward_compat_funcs:
msg = ('[3.16] uihelper.%(name)s is deprecated, please use '
- 'web.uicfg.%(classname)s.%(name)s' % dict(
- name=funcname, classname=tag.__class__.__name__))
+ 'web.views.uicfg.%(rtagid)s.%(name)s' % dict(
+ name=funcname, rtagid=tag.__regid__))
globals()[funcname] = deprecated(msg)(getattr(tag, funcname))
--- a/web/views/__init__.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/__init__.py Mon Jan 13 13:47:47 2014 +0100
@@ -25,6 +25,7 @@
from rql import nodes
from logilab.mtconverter import xml_escape
+from logilab.common.deprecation import class_deprecated
def need_table_view(rset, schema):
@@ -125,7 +126,10 @@
return u''
+
class TmpFileViewMixin(object):
+ __metaclass__ = class_deprecated
+ __deprecation_warning__ = '[3.18] %(cls)s is deprecated'
binary = True
content_type = 'application/octet-stream'
cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
--- a/web/views/actions.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/actions.py Mon Jan 13 13:47:47 2014 +0100
@@ -50,8 +50,9 @@
entity=entity, mainform=False)
for dummy in form.editable_relations():
return 1
- editableattrs = form.editable_attributes(strict=True)
- for rschema, role in editableattrs:
+ for dummy in form.inlined_relations():
+ return 1
+ for dummy in form.editable_attributes(strict=True):
return 1
return 0
@@ -418,22 +419,6 @@
def url(self):
return 'http://www.cubicweb.org'
-class GotRhythmAction(action.Action):
- __regid__ = 'rhythm'
- __select__ = debug_mode()
-
- category = 'footer'
- order = 3
- title = _('Got rhythm?')
-
- def url(self):
- return xml_escape(self._cw.url()+'#')
-
- def html_class(self):
- self._cw.add_js('cubicweb.rhythm.js')
- return 'rhythm'
-
-
## default actions ui configuration ###########################################
addmenu = uicfg.actionbox_appearsin_addmenu
--- a/web/views/ajaxcontroller.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/ajaxcontroller.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -371,7 +371,8 @@
vid = req.form.get('fallbackvid', 'noresult')
viewobj = self._cw.vreg['views'].select(vid, req, rset=rset)
viewobj.set_http_cache_headers()
- req.validate_cache()
+ if req.is_client_cache_valid():
+ return ''
return self._call_view(viewobj, paginate=req.form.pop('paginate', False))
--- a/web/views/authentication.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/authentication.py Mon Jan 13 13:47:47 2014 +0100
@@ -22,6 +22,7 @@
from threading import Lock
from logilab.common.decorators import clear_cache
+from logilab.common.deprecation import class_renamed
from cubicweb import AuthenticationError, BadConnectionId
from cubicweb.view import Component
@@ -32,18 +33,18 @@
class NoAuthInfo(Exception): pass
-class WebAuthInfoRetreiver(Component):
+class WebAuthInfoRetriever(Component):
__registry__ = 'webauth'
order = None
__abstract__ = True
def authentication_information(self, req):
- """retreive authentication information from the given request, raise
+ """retrieve authentication information from the given request, raise
NoAuthInfo if expected information is not found.
"""
raise NotImplementedError()
- def authenticated(self, retreiver, req, cnx, login, authinfo):
+ def authenticated(self, retriever, req, cnx, login, authinfo):
"""callback when return authentication information have opened a
repository connection successfully. Take care req has no session
attached yet, hence req.execute isn't available.
@@ -66,12 +67,17 @@
def cleanup_authentication_information(self, req):
"""called when the retriever has returned some authentication
information but we get an authentication error when using them, so it
- get a chance to cleanup things (e.g. remove cookie)
+ get a chance to clean things up (e.g. remove cookie)
"""
pass
+WebAuthInfoRetreiver = class_renamed(
+ 'WebAuthInfoRetreiver', WebAuthInfoRetriever,
+ '[3.17] WebAuthInfoRetreiver had been renamed into WebAuthInfoRetriever '
+ '("ie" instead of "ei")')
-class LoginPasswordRetreiver(WebAuthInfoRetreiver):
+
+class LoginPasswordRetriever(WebAuthInfoRetriever):
__regid__ = 'loginpwdauth'
order = 10
@@ -90,6 +96,12 @@
def revalidate_login(self, req):
return req.get_authorization()[0]
+LoginPasswordRetreiver = class_renamed(
+ 'LoginPasswordRetreiver', LoginPasswordRetriever,
+ '[3.17] LoginPasswordRetreiver had been renamed into LoginPasswordRetriever '
+ '("ie" instead of "ei")')
+
+
class RepositoryAuthenticationManager(AbstractAuthenticationManager):
"""authenticate user associated to a request and check session validity"""
--- a/web/views/autoform.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/autoform.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -145,8 +145,11 @@
class InlinedFormField(ff.Field):
def __init__(self, view=None, **kwargs):
kwargs.setdefault('label', None)
+ # don't add eidparam=True since this field doesn't actually hold the
+ # relation value (the subform does) hence should not be listed in
+ # _cw_entity_fields
super(InlinedFormField, self).__init__(name=view.rtype, role=view.role,
- eidparam=True, **kwargs)
+ **kwargs)
self.view = view
def render(self, form, renderer):
@@ -723,16 +726,17 @@
# action on the form tag
_default_form_action_path = 'validateform'
- # pre 3.8.3 compat
+ @deprecated('[3.18] you should override form_action()')
def set_action(self, action):
self._action = action
+
+ @deprecated('[3.18] use form_action()')
def get_action(self):
try:
return self._action
except AttributeError:
return self._cw.build_url(self._default_form_action_path)
- action = property(deprecated('[3.9] use form.form_action()')(get_action),
- set_action)
+
@iclassmethod
def field_by_name(cls_or_self, name, role=None, eschema=None):
@@ -888,23 +892,14 @@
formviews += self.inline_creation_form_view(rschema, ttype, role)
# we can create more than one related entity, we thus display a link
# to add new related entities
- if self.should_display_add_new_relation_link(rschema, formviews, card):
- rdef = entity.e_schema.rdef(rschema, role, ttype)
- if entity.has_eid():
- if role == 'subject':
- rdefkwargs = {'fromeid': entity.eid}
- else:
- rdefkwargs = {'toeid': entity.eid}
- else:
- rdefkwargs = {}
- if (tschema.has_perm(self._cw, 'add')
- and rdef.has_perm(self._cw, 'add', **rdefkwargs)):
- addnewlink = self._cw.vreg['views'].select(
- 'inline-addnew-link', self._cw,
- etype=ttype, rtype=rschema, role=role, card=card,
- peid=self.edited_entity.eid,
- petype=self.edited_entity.e_schema, pform=self)
- formviews.append(addnewlink)
+ if self.must_display_add_new_relation_link(rschema, role, tschema,
+ ttype, formviews, card):
+ addnewlink = self._cw.vreg['views'].select(
+ 'inline-addnew-link', self._cw,
+ etype=ttype, rtype=rschema, role=role, card=card,
+ peid=self.edited_entity.eid,
+ petype=self.edited_entity.e_schema, pform=self)
+ formviews.append(addnewlink)
allformviews += formviews
return allformviews
@@ -924,6 +919,36 @@
"""
return not existant or card in '+*'
+ def must_display_add_new_relation_link(self, rschema, role, tschema,
+ ttype, existant, card):
+ """return true if we must add a link to add a new creation form
+ (through ajax call)
+
+ by default true if there is no related entity or if the relation has
+ multiple cardinality and it is permitted to add the inlined object and
+ relation.
+ """
+ return (self.should_display_add_new_relation_link(
+ rschema, existant, card) and
+ self.check_inlined_rdef_permissions(
+ rschema, role, tschema, ttype))
+
+ def check_inlined_rdef_permissions(self, rschema, role, tschema, ttype):
+ """return true if permissions are granted on the inlined object and
+ relation"""
+ entity = self.edited_entity
+ rdef = entity.e_schema.rdef(rschema, role, ttype)
+ if entity.has_eid():
+ if role == 'subject':
+ rdefkwargs = {'fromeid': entity.eid}
+ else:
+ rdefkwargs = {'toeid': entity.eid}
+ else:
+ rdefkwargs = {}
+ return (tschema.has_perm(self._cw, 'add')
+ and rdef.has_perm(self._cw, 'add', **rdefkwargs))
+
+
def should_hide_add_new_relation_link(self, rschema, card):
"""return true if once an inlined creation form is added, the 'add new'
link should be hidden
--- a/web/views/basecontrollers.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/basecontrollers.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -128,7 +128,9 @@
"""publish a request, returning an encoded string"""
view, rset = self._select_view_and_rset(rset)
self.add_to_breadcrumbs(view)
- self.validate_cache(view)
+ view.set_http_cache_headers()
+ if self._cw.is_client_cache_valid():
+ return ''
template = self.appli.main_template_id(self._cw)
return self._cw.vreg['views'].main_template(self._cw, template,
rset=rset, view=view)
--- a/web/views/basetemplates.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/basetemplates.py Mon Jan 13 13:47:47 2014 +0100
@@ -86,6 +86,11 @@
@objectify_predicate
+def modal_view(cls, req, rset, *args, **kwargs):
+ if req.form.get('__modal', None):
+ return 1
+
+@objectify_predicate
def templatable_view(cls, req, rset, *args, **kwargs):
view = kwargs.pop('view', None)
if view is None:
@@ -118,6 +123,17 @@
self._stream = view._stream
+class ModalMainTemplate(MainTemplate):
+ """ a no-decoration main template for standard views
+ that typically live in a modal context """
+ __regid__ = 'main-template'
+ __select__ = templatable_view() & modal_view()
+
+ def call(self, view):
+ view.set_request_content_type()
+ view.render(w=self.w)
+
+
class TheMainTemplate(MainTemplate):
"""default main template :
@@ -162,6 +178,7 @@
self.write_doctype()
# explictly close the <base> tag to avoid IE 6 bugs while browsing DOM
self._cw.html_headers.define_var('BASE_URL', self._cw.base_url())
+ self._cw.html_headers.define_var('DATA_URL', self._cw.datadir_url)
w(u'<meta http-equiv="content-type" content="%s; charset=%s"/>\n'
% (content_type, self._cw.encoding))
w(u'\n'.join(additional_headers) + u'\n')
--- a/web/views/baseviews.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/baseviews.py Mon Jan 13 13:47:47 2014 +0100
@@ -424,11 +424,7 @@
redirect_vid = 'incontext'
def call(self, subvid=None, **kwargs):
- if subvid is None and 'vid' in kwargs:
- warn("[3.9] should give a 'subvid' argument instead of 'vid'",
- DeprecationWarning, stacklevel=2)
- else:
- kwargs['vid'] = subvid
+ kwargs['vid'] = subvid
rset = self.cw_rset
for i in xrange(len(rset)):
self.cell_call(i, 0, **kwargs)
@@ -643,14 +639,3 @@
RssView = class_moved(xmlrss.RSSView)
RssItemView = class_moved(xmlrss.RSSItemView)
TableView = class_moved(tableview.TableView)
-
-
-class SecondaryView(EntityView):
- __metaclass__ = class_deprecated
- __deprecation_warning__ = '[3.9] the secondary view is deprecated, use one of oneline/incontext/outofcontext'
- __regid__ = 'secondary'
-
- def cell_call(self, row, col, **kwargs):
- entity = self.cw_rset.get_entity(row, col)
- self.w(u' ')
- self.wview('oneline', self.cw_rset, row=row, col=col)
--- a/web/views/calendar.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/calendar.py Mon Jan 13 13:47:47 2014 +0100
@@ -27,9 +27,8 @@
from logilab.common.date import todatetime
from cubicweb.utils import json_dumps, make_uid
-from cubicweb.interfaces import ICalendarable
-from cubicweb.predicates import implements, adaptable
-from cubicweb.view import EntityView, EntityAdapter, implements_adapter_compat
+from cubicweb.predicates import adaptable
+from cubicweb.view import EntityView, EntityAdapter
# useful constants & functions ################################################
@@ -46,16 +45,14 @@
class ICalendarableAdapter(EntityAdapter):
__needs_bw_compat__ = True
__regid__ = 'ICalendarable'
- __select__ = implements(ICalendarable, warn=False) # XXX for bw compat, should be abstract
+ __abstract__ = True
@property
- @implements_adapter_compat('ICalendarable')
def start(self):
"""return start date"""
raise NotImplementedError
@property
- @implements_adapter_compat('ICalendarable')
def stop(self):
"""return stop date"""
raise NotImplementedError
--- a/web/views/dotgraphview.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/dotgraphview.py Mon Jan 13 13:47:47 2014 +0100
@@ -22,6 +22,7 @@
import tempfile
import os
+import codecs
from logilab.mtconverter import xml_escape
from logilab.common.graph import GraphGenerator, DotBackend
@@ -33,30 +34,22 @@
__abstract__ = True
backend_class = DotBackend
backend_kwargs = {'ratio': 'compress', 'size': '30,10'}
+
def cell_call(self, row, col):
+ if 'MSIE 8' in self._cw.useragent():
+ return
entity = self.cw_rset.get_entity(row, col)
visitor = self.build_visitor(entity)
prophdlr = self.build_dotpropshandler()
graphname = 'dotgraph%s' % str(entity.eid)
generator = GraphGenerator(self.backend_class(graphname, None,
**self.backend_kwargs))
- # map file
- pmap, mapfile = tempfile.mkstemp(".map", graphname)
- os.close(pmap)
# image file
- fd, tmpfile = tempfile.mkstemp('.png')
+ fd, tmpfile = tempfile.mkstemp('.svg')
os.close(fd)
- generator.generate(visitor, prophdlr, tmpfile, mapfile)
- filekeyid = make_uid()
- self._cw.session.data[filekeyid] = tmpfile
- self.w(u'<img src="%s" alt="%s" usemap="#%s" />' % (
- xml_escape(entity.absolute_url(vid='tmppng', tmpfile=filekeyid)),
- xml_escape(self._cw._('Data connection graph for %s') % entity.dc_title()),
- graphname))
- stream = open(mapfile, 'r').read()
- stream = stream.decode(self._cw.encoding)
- self.w(stream)
- os.unlink(mapfile)
+ generator.generate(visitor, prophdlr, tmpfile)
+ with codecs.open(tmpfile, 'rb', encoding='utf-8') as svgfile:
+ self.w(svgfile.read())
def build_visitor(self, entity):
raise NotImplementedError
--- a/web/views/editcontroller.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/editcontroller.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -20,13 +20,15 @@
__docformat__ = "restructuredtext en"
from warnings import warn
+from collections import defaultdict
from logilab.common.deprecation import deprecated
+from logilab.common.graph import ordered_nodes
from rql.utils import rqlvar_maker
from cubicweb import Binary, ValidationError
-from cubicweb.view import EntityAdapter, implements_adapter_compat
+from cubicweb.view import EntityAdapter
from cubicweb.predicates import is_instance
from cubicweb.web import (INTERNAL_FIELD_VALUE, RequestError, NothingToEdit,
ProcessFormError)
@@ -34,7 +36,6 @@
class IEditControlAdapter(EntityAdapter):
- __needs_bw_compat__ = True
__regid__ = 'IEditControl'
__select__ = is_instance('Any')
@@ -45,7 +46,6 @@
DeprecationWarning)
super(IEditControlAdapter, self).__init__(_cw, **kwargs)
- @implements_adapter_compat('IEditControl')
def after_deletion_path(self):
"""return (path, parameters) which should be used as redirect
information when this entity is being deleted
@@ -55,7 +55,6 @@
return parent.rest_path(), {}
return str(self.entity.e_schema).lower(), {}
- @implements_adapter_compat('IEditControl')
def pre_web_edit(self):
"""callback called by the web editcontroller when an entity will be
created/modified, to let a chance to do some entity specific stuff.
@@ -101,6 +100,15 @@
self.kwargs[var] = eid
return rql
+ def set_attribute(self, attr, value):
+ self.kwargs[attr] = value
+ self.edited.append('X %s %%(%s)s' % (attr, attr))
+
+ def set_inlined(self, relation, value):
+ self.kwargs[relation] = value
+ self.edited.append('X %s %s' % (relation, relation.upper()))
+ self.restrictions.append('%s eid %%(%s)s' % (relation.upper(), relation))
+
class EditController(basecontrollers.ViewController):
__regid__ = 'edit'
@@ -120,6 +128,49 @@
self._default_publish()
self.reset()
+ def _ordered_formparams(self):
+ """ Return form parameters dictionaries for each edited entity.
+
+ We ensure that entities can be created in this order accounting for
+ mandatory inlined relations.
+ """
+ req = self._cw
+ graph = {}
+ get_rschema = self._cw.vreg.schema.rschema
+ # minparams = 2, because at least __type and eid are needed
+ values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
+ for eid in req.edited_eids())
+ # iterate over all the edited entities
+ for eid, values in values_by_eid.iteritems():
+ # add eid to the dependency graph
+ graph.setdefault(eid, set())
+ # search entity's edited fields for mandatory inlined relation
+ for param in values['_cw_entity_fields'].split(','):
+ try:
+ rtype, role = param.split('-')
+ except ValueError:
+ # e.g. param='__type'
+ continue
+ rschema = get_rschema(rtype)
+ if rschema.inlined:
+ for target in rschema.targets(values['__type'], role):
+ rdef = rschema.role_rdef(values['__type'], target, role)
+ # if cardinality is 1 and if the target entity is being
+ # simultaneously edited, the current entity must be
+ # created before the target one
+ if rdef.cardinality[0] == '1':
+ target_eid = values[param]
+ if target_eid in values_by_eid:
+ # add dependency from the target entity to the
+ # current one
+ if role == 'object':
+ graph.setdefault(target_eid, set()).add(eid)
+ else:
+ graph.setdefault(eid, set()).add(target_eid)
+ break
+ for eid in reversed(ordered_nodes(graph)):
+ yield values_by_eid[eid]
+
def _default_publish(self):
req = self._cw
self.errors = []
@@ -130,22 +181,27 @@
req.set_shared_data('__maineid', form['__maineid'], txdata=True)
# no specific action, generic edition
self._to_create = req.data['eidmap'] = {}
- self._pending_fields = req.data['pendingfields'] = set()
+ # those two data variables are used to handle relation from/to entities
+ # which doesn't exist at time where the entity is edited and that
+ # deserves special treatment
+ req.data['pending_inlined'] = defaultdict(set)
+ req.data['pending_others'] = set()
try:
- for eid in req.edited_eids():
- # __type and eid
- formparams = req.extract_entity_params(eid, minparams=2)
+ for formparams in self._ordered_formparams():
eid = self.edit_entity(formparams)
except (RequestError, NothingToEdit) as ex:
if '__linkto' in req.form and 'eid' in req.form:
self.execute_linkto()
elif not ('__delete' in req.form or '__insert' in req.form):
raise ValidationError(None, {None: unicode(ex)})
- # handle relations in newly created entities
- if self._pending_fields:
- for form, field in self._pending_fields:
- self.handle_formfield(form, field)
- # execute rql to set all relations
+ # all pending inlined relations to newly created entities have been
+ # treated now (pop to ensure there are no attempt to add new ones)
+ pending_inlined = req.data.pop('pending_inlined')
+ assert not pending_inlined, pending_inlined
+ # handle all other remaining relations now
+ for form_, field in req.data.pop('pending_others'):
+ self.handle_formfield(form_, field)
+ # then execute rql to set all relations
for querydef in self.relations_rql:
self._cw.execute(*querydef)
# XXX this processes *all* pending operations of *all* entities
@@ -176,10 +232,11 @@
def edit_entity(self, formparams, multiple=False):
"""edit / create / copy an entity and return its eid"""
+ req = self._cw
etype = formparams['__type']
- entity = self._cw.vreg['etypes'].etype_class(etype)(self._cw)
+ entity = req.vreg['etypes'].etype_class(etype)(req)
entity.eid = valerror_eid(formparams['eid'])
- is_main_entity = self._cw.form.get('__maineid') == formparams['eid']
+ is_main_entity = req.form.get('__maineid') == formparams['eid']
# let a chance to do some entity specific stuff
entity.cw_adapt_to('IEditControl').pre_web_edit()
# create a rql query from parameters
@@ -188,12 +245,12 @@
# this will generate less rql queries and might be useful in
# a few dark corners
if is_main_entity:
- formid = self._cw.form.get('__form_id', 'edition')
+ formid = req.form.get('__form_id', 'edition')
else:
# XXX inlined forms formid should be saved in a different formparams entry
# inbetween, use cubicweb standard formid for inlined forms
formid = 'edition'
- form = self._cw.vreg['forms'].select(formid, self._cw, entity=entity)
+ form = req.vreg['forms'].select(formid, req, entity=entity)
eid = form.actual_eid(entity.eid)
try:
editedfields = formparams['_cw_entity_fields']
@@ -203,10 +260,14 @@
warn('[3.13] _cw_edited_fields has been renamed _cw_entity_fields',
DeprecationWarning)
except KeyError:
- raise RequestError(self._cw._('no edited fields specified for entity %s' % entity.eid))
+ raise RequestError(req._('no edited fields specified for entity %s' % entity.eid))
form.formvalues = {} # init fields value cache
for field in form.iter_modified_fields(editedfields, entity):
self.handle_formfield(form, field, rqlquery)
+ # if there are some inlined field which were waiting for this entity's
+ # creation, add relevant data to the rqlquery
+ for form_, field in req.data['pending_inlined'].pop(entity.eid, ()):
+ rqlquery.set_inlined(field.name, form_.edited_entity.eid)
if self.errors:
errors = dict((f.role_name(), unicode(ex)) for f, ex in self.errors)
raise ValidationError(valerror_eid(entity.eid), errors)
@@ -218,8 +279,8 @@
self.notify_edited(entity)
if '__delete' in formparams:
# XXX deprecate?
- todelete = self._cw.list_form_param('__delete', formparams, pop=True)
- autoform.delete_relations(self._cw, todelete)
+ todelete = req.list_form_param('__delete', formparams, pop=True)
+ autoform.delete_relations(req, todelete)
if '__cloned_eid' in formparams:
entity.copy_relations(int(formparams['__cloned_eid']))
if is_main_entity: # only execute linkto for the main entity
@@ -237,8 +298,7 @@
continue
rschema = self._cw.vreg.schema.rschema(field.name)
if rschema.final:
- rqlquery.kwargs[field.name] = value
- rqlquery.edited.append('X %s %%(%s)s' % (rschema, rschema))
+ rqlquery.set_attribute(field.name, value)
else:
if form.edited_entity.has_eid():
origvalues = set(entity.eid for entity in form.edited_entity.related(field.name, field.role, entities=True))
@@ -251,19 +311,15 @@
elif form.edited_entity.has_eid():
self.handle_relation(form, field, value, origvalues)
else:
- self._pending_fields.add( (form, field) )
-
+ form._cw.data['pending_others'].add( (form, field) )
except ProcessFormError as exc:
self.errors.append((field, exc))
def handle_inlined_relation(self, form, field, values, origvalues, rqlquery):
"""handle edition for the (rschema, x) relation of the given entity
"""
- attr = field.name
if values:
- rqlquery.kwargs[attr] = iter(values).next()
- rqlquery.edited.append('X %s %s' % (attr, attr.upper()))
- rqlquery.restrictions.append('%s eid %%(%s)s' % (attr.upper(), attr))
+ rqlquery.set_inlined(field.name, iter(values).next())
elif form.edited_entity.has_eid():
self.handle_relation(form, field, values, origvalues)
--- a/web/views/facets.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/facets.py Mon Jan 13 13:47:47 2014 +0100
@@ -128,7 +128,6 @@
needs_js = ['cubicweb.ajax.js', 'cubicweb.facets.js']
needs_css = ['cubicweb.facets.css']
- roundcorners = True
def generate_form(self, w, rset, divid, vid, vidargs=None, mainvar=None,
paginate=False, cssclass='', hiddens=None, **kwargs):
@@ -164,9 +163,6 @@
self._cw.add_css(self.needs_css)
self._cw.html_headers.define_var('facetLoadingMsg',
self._cw._('facet-loading-msg'))
- if self.roundcorners:
- self._cw.html_headers.add_onload(
- 'jQuery(".facet").corner("tl br 10px");')
if vidargs is not None:
warn("[3.14] vidargs is deprecated. Maybe you're using some TableView?",
DeprecationWarning, stacklevel=2)
--- a/web/views/ibreadcrumbs.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/ibreadcrumbs.py Mon Jan 13 13:47:47 2014 +0100
@@ -24,7 +24,6 @@
from logilab.mtconverter import xml_escape
-#from cubicweb.interfaces import IBreadCrumbs
from cubicweb import tags, uilib
from cubicweb.entity import Entity
from cubicweb.predicates import (is_instance, one_line_rset, adaptable,
@@ -35,15 +34,6 @@
# don't use AnyEntity since this may cause bug with isinstance() due to reloading
-# ease bw compat
-def ibreadcrumb_adapter(entity):
- if hasattr(entity, 'breadcrumbs'):
- warn('[3.9] breadcrumbs() method is deprecated, define a custom '
- 'IBreadCrumbsAdapter for %s instead' % entity.__class__,
- DeprecationWarning)
- return entity
- return entity.cw_adapt_to('IBreadCrumbs')
-
class IBreadCrumbsAdapter(EntityAdapter):
"""adapters for entities which can be"located" on some path to display in
@@ -53,11 +43,6 @@
__select__ = is_instance('Any', accept_none=False)
def parent_entity(self):
- if hasattr(self.entity, 'parent') and callable(self.entity.parent):
- warn('[3.9] parent() method is deprecated, define a '
- 'custom IBreadCrumbsAdapter/ITreeAdapter for %s instead'
- % self.entity.__class__, DeprecationWarning)
- return self.entity.parent()
itree = self.entity.cw_adapt_to('ITree')
if itree is not None:
return itree.parent()
@@ -94,7 +79,7 @@
self.error('cycle in breadcrumbs for entity %s' % self.entity)
return []
_recurs.add(parent.eid)
- adapter = ibreadcrumb_adapter(parent)
+ adapter = parent.cw_adapt_to('IBreadCrumbs')
path = adapter.breadcrumbs(view, _recurs) + [self.entity]
else:
path = [self.entity]
@@ -125,18 +110,18 @@
entity = self.cw_extra_kwargs['entity']
except KeyError:
entity = self.cw_rset.get_entity(0, 0)
- adapter = ibreadcrumb_adapter(entity)
+ adapter = entity.cw_adapt_to('IBreadCrumbs')
view = self.cw_extra_kwargs.get('view')
path = adapter.breadcrumbs(view)
if path:
self.open_breadcrumbs(w)
- if self.first_separator:
- w(self.separator)
self.render_breadcrumbs(w, entity, path)
self.close_breadcrumbs(w)
def open_breadcrumbs(self, w):
w(u'<span id="breadcrumbs" class="pathbar">')
+ if self.first_separator:
+ w(self.separator)
def close_breadcrumbs(self, w):
w(u'</span>')
@@ -187,11 +172,9 @@
# XXX support kwargs for compat with other components which gets the view as
# argument
def render(self, w, **kwargs):
- w(u'<span id="breadcrumbs" class="pathbar">')
- if self.first_separator:
- w(self.separator)
+ self.open_breadcrumbs(w)
w(self._cw._('search'))
- w(u'</span>')
+ self.close_breadcrumbs(w)
class BreadCrumbLinkToVComponent(BreadCrumbEntityVComponent):
--- a/web/views/navigation.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/navigation.py Mon Jan 13 13:47:47 2014 +0100
@@ -55,10 +55,9 @@
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import deprecated
-from cubicweb.predicates import (paginated_rset, sorted_rset,
- adaptable, implements)
+from cubicweb.predicates import paginated_rset, sorted_rset, adaptable
from cubicweb.uilib import cut
-from cubicweb.view import EntityAdapter, implements_adapter_compat
+from cubicweb.view import EntityAdapter
from cubicweb.web.component import EmptyComponent, EntityCtxComponent, NavigationComponent
@@ -324,7 +323,6 @@
View.handle_pagination = False
-from cubicweb.interfaces import IPrevNext
class IPrevNextAdapter(EntityAdapter):
"""Interface for entities which can be linked to a previous and/or next
@@ -335,14 +333,12 @@
"""
__needs_bw_compat__ = True
__regid__ = 'IPrevNext'
- __select__ = implements(IPrevNext, warn=False) # XXX for bw compat, else should be abstract
+ __abstract__ = True
- @implements_adapter_compat('IPrevNext')
def next_entity(self):
"""return the 'next' entity"""
raise NotImplementedError
- @implements_adapter_compat('IPrevNext')
def previous_entity(self):
"""return the 'previous' entity"""
raise NotImplementedError
@@ -398,7 +394,7 @@
title = self._cw._('i18nprevnext_previous')
icon = self.prev_icon
cssclass = u'previousEntity left'
- content = icon + content
+ content = icon + '  ' + content
else:
title = self._cw._('i18nprevnext_next')
icon = self.next_icon
--- a/web/views/primary.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/primary.py Mon Jan 13 13:47:47 2014 +0100
@@ -109,7 +109,7 @@
"""
return []
- def entity_call(self, entity):
+ def entity_call(self, entity, **kwargs):
entity.complete()
uicfg_reg = self._cw.vreg['uicfg']
if self.rsection is None:
@@ -189,10 +189,6 @@
def render_entity_toolbox(self, entity):
self.content_navigation_components('ctxtoolbar')
- @deprecated('[3.8] render_entity_metadata method is deprecated')
- def render_entity_metadata(self, entity):
- entity.view('metadata', w=self.w)
-
def summary(self, entity):
"""default implementation return an empty string"""
return u''
@@ -217,16 +213,8 @@
if display_attributes:
self.w(u'<table>')
for rschema, role, dispctrl, value in display_attributes:
- # pylint: disable=E1101
- if not hasattr(self, '_render_attribute'):
- label = self._rel_label(entity, rschema, role, dispctrl)
- self.render_attribute(label, value, table=True)
- else:
- warn('[3.9] _render_attribute prototype has changed and '
- 'renamed to render_attribute, please update %s'
- % self.__class__, DeprecationWarning)
- self._render_attribute(dispctrl, rschema, value, role=role,
- table=True)
+ label = self._rel_label(entity, rschema, role, dispctrl)
+ self.render_attribute(label, value, table=True)
self.w(u'</table>')
def render_attribute(self, label, value, table=False):
@@ -253,13 +241,6 @@
rset = self._relation_rset(entity, rschema, role, dispctrl, limit=limit)
if not rset:
continue
- if hasattr(self, '_render_relation'):
- # pylint: disable=E1101
- self._render_relation(dispctrl, rset, 'autolimited')
- warn('[3.9] _render_relation prototype has changed and has '
- 'been renamed to render_relation, please update %s'
- % self.__class__, DeprecationWarning)
- continue
try:
rview = self._cw.vreg['views'].select(
vid, self._cw, rset=rset, dispctrl=dispctrl)
--- a/web/views/reledit.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/reledit.py Mon Jan 13 13:47:47 2014 +0100
@@ -91,9 +91,6 @@
rschema = self._cw.vreg.schema[rtype]
rctrl = self._cw.vreg['uicfg'].select('reledit', self._cw, entity=entity)
self._rules = rctrl.etype_get(self.entity.e_schema.type, rschema.type, role, '*')
- if rvid is not None or default_value is not None:
- warn('[3.9] specifying rvid/default_value on select is deprecated, '
- 'reledit_ctrl rtag to control this' % self, DeprecationWarning)
reload = self._compute_reload(rschema, role, reload)
divid = self._build_divid(rtype, role, self.entity.eid)
if rschema.final:
@@ -322,19 +319,11 @@
rdef = entity.e_schema.rdef(rschema)
return rdef.has_perm(self._cw, 'update', eid=entity.eid)
- should_edit_attributes = deprecated('[3.9] should_edit_attributes is deprecated,'
- ' use _should_edit_attribute instead',
- _should_edit_attribute)
-
def _should_edit_relation(self, rschema, role):
eeid = self.entity.eid
perm_args = {'fromeid': eeid} if role == 'subject' else {'toeid': eeid}
return rschema.has_perm(self._cw, 'add', **perm_args)
- should_edit_relations = deprecated('[3.9] should_edit_relations is deprecated,'
- ' use _should_edit_relation instead',
- _should_edit_relation)
-
def _open_form_wrapper(self, divid, value, form, renderer,
_edit_related, _add_related, _delete_related):
w = self.w
--- a/web/views/schema.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/schema.py Mon Jan 13 13:47:47 2014 +0100
@@ -24,6 +24,7 @@
import tempfile
import os, os.path as osp
+import codecs
from logilab.common.graph import GraphGenerator, DotBackend
from logilab.common.ureports import Section, Table
@@ -40,7 +41,6 @@
from cubicweb.view import EntityView, StartupView
from cubicweb import tags, uilib
from cubicweb.web import action, facet, schemaviewer
-from cubicweb.web.views import TmpFileViewMixin
from cubicweb.web.views import uicfg, primary, baseviews, tabs, tableview, ibreadcrumbs
ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES
@@ -225,6 +225,7 @@
{'x': entity.eid})
self.wview('table', rset, 'null',
cellvids={0: 'rdef-name-cell',
+ 2: 'etype-attr-defaultval-cell',
3: 'etype-attr-cardinality-cell',
4: 'rdef-constraints-cell',
6: 'rdef-options-cell'},
@@ -271,6 +272,14 @@
self.w(self._cw._(u'no'))
+class CWETypeAttributeDefaultValCell(baseviews.FinalView):
+ __regid__ = 'etype-attr-defaultval-cell'
+
+ def cell_call(self, row, col):
+ defaultval = self.cw_rset.rows[row][col]
+ if defaultval is not None:
+ self.w(unicode(self.cw_rset.rows[row][col].unzpickle()))
+
class CWETypeRelationCardinalityCell(baseviews.FinalView):
__regid__ = 'etype-rel-cardinality-cell'
@@ -616,6 +625,8 @@
__regid__ = 'schemagraph'
def call(self, etype=None, rtype=None, alt=''):
+ if 'MSIE 8' in self._cw.useragent():
+ return
schema = self._cw.vreg.schema
if etype:
assert rtype is None
@@ -643,22 +654,12 @@
'splines':'true',
'sep':'0.2',
}))
- # map file
- pmap, mapfile = tempfile.mkstemp(".map")
- os.close(pmap)
- # image file
- fd, tmpfile = tempfile.mkstemp('.png')
+ # svg image file
+ fd, tmpfile = tempfile.mkstemp('.svg')
os.close(fd)
- generator.generate(visitor, prophdlr, tmpfile, mapfile)
- filekeyid = make_uid()
- self._cw.session.data[filekeyid] = tmpfile
- self.w(u'<img src="%s" alt="%s" usemap="#schema" />' % (
- xml_escape(self._cw.build_url(vid='tmppng', tmpfile=filekeyid)),
- xml_escape(self._cw._(alt))))
- stream = open(mapfile, 'r').read()
- stream = stream.decode(self._cw.encoding)
- self.w(stream)
- os.unlink(mapfile)
+ generator.generate(visitor, prophdlr, tmpfile)
+ with codecs.open(tmpfile, 'rb', encoding='utf-8') as svgfile:
+ self.w(svgfile.read())
# breadcrumbs ##################################################################
--- a/web/views/staticcontrollers.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/staticcontrollers.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -20,18 +20,18 @@
- /data/...
- /static/...
- /fckeditor/...
-
"""
import os
import os.path as osp
import hashlib
import mimetypes
+import threading
from time import mktime
from datetime import datetime, timedelta
from logging import getLogger
-from cubicweb import Unauthorized
+from cubicweb import Forbidden
from cubicweb.web import NotFound
from cubicweb.web.http_headers import generateDateTime
from cubicweb.web.controller import Controller
@@ -59,7 +59,7 @@
if osp.isdir(path):
if self.directory_listing_allowed:
return u''
- raise Unauthorized(path)
+ raise Forbidden(path)
if not osp.isfile(path):
raise NotFound()
if not debugmode:
@@ -77,7 +77,8 @@
#
# Real production environment should use dedicated static file serving.
self._cw.set_header('last-modified', generateDateTime(os.stat(path).st_mtime))
- self._cw.validate_cache()
+ if self._cw.is_client_cache_valid():
+ return ''
# XXX elif uri.startswith('/https/'): uri = uri[6:]
mimetype, encoding = mimetypes.guess_type(path)
if mimetype is None:
@@ -105,6 +106,7 @@
self._resources = {}
self.config = config
self.logger = getLogger('cubicweb.web')
+ self.lock = threading.Lock()
def _resource(self, path):
"""get the resouce"""
@@ -143,21 +145,32 @@
def concat_cached_filepath(self, paths):
filepath = self.build_filepath(paths)
if not self._up_to_date(filepath, paths):
- with open(filepath, 'wb') as f:
- for path in paths:
- dirpath, rid = self._resource(path)
- if rid is None:
- # In production mode log an error, do not return a 404
- # XXX the erroneous content is cached anyway
- self.logger.error('concatenated data url error: %r file '
- 'does not exist', path)
- if self.config.debugmode:
- raise NotFound(path)
- else:
- with open(osp.join(dirpath, rid), 'rb') as source:
- for line in source:
- f.write(line)
- f.write('\n')
+ tmpfile = filepath + '.tmp'
+ try:
+ with self.lock:
+ if self._up_to_date(filepath, paths):
+ # first check could have raced with some other thread
+ # updating the file
+ return filepath
+ with open(tmpfile, 'wb') as f:
+ for path in paths:
+ dirpath, rid = self._resource(path)
+ if rid is None:
+ # In production mode log an error, do not return a 404
+ # XXX the erroneous content is cached anyway
+ self.logger.error('concatenated data url error: %r file '
+ 'does not exist', path)
+ if self.config.debugmode:
+ raise NotFound(path)
+ else:
+ with open(osp.join(dirpath, rid), 'rb') as source:
+ for line in source:
+ f.write(line)
+ f.write('\n')
+ os.rename(tmpfile, filepath)
+ except:
+ os.remove(tmpfile)
+ raise
return filepath
@@ -186,7 +199,12 @@
filepath = self.concat_files_registry.concat_cached_filepath(paths)
else:
# skip leading '/data/' and url params
- relpath = relpath[len(self.base_datapath):].split('?', 1)[0]
+ if relpath.startswith(self.base_datapath):
+ prefix = self.base_datapath
+ else:
+ prefix = 'data/'
+ relpath = relpath[len(prefix):]
+ relpath = relpath.split('?', 1)[0]
dirpath, rid = config.locate_resource(relpath)
if dirpath is None:
raise NotFound()
--- a/web/views/tableview.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/tableview.py Mon Jan 13 13:47:47 2014 +0100
@@ -201,10 +201,11 @@
facetsform.render(w, vid=self.view.__regid__, cssclass=cssclass,
divid=self.view.domid)
actions = []
- if self.add_view_actions:
- actions = self.view.table_actions()
- if self.display_filter and self.hide_filter and (facetsform or not generate_form):
- actions += self.show_hide_filter_actions(not generate_form)
+ if self.display_actions:
+ if self.add_view_actions:
+ actions = self.view.table_actions()
+ if self.display_filter and self.hide_filter and (facetsform or not generate_form):
+ actions += self.show_hide_filter_actions(not generate_form)
self.render_table(w, actions, self.view.paginable)
if facetsform and self.display_filter == 'bottom':
cssclass = u'hidden' if self.hide_filter else u''
@@ -355,9 +356,9 @@
self.colid = None
def __str__(self):
- return '<%s.%s (column %s)>' % (self.view.__class__.__name__,
+ return '<%s.%s (column %s) at 0x%x>' % (self.view.__class__.__name__,
self.__class__.__name__,
- self.colid)
+ self.colid, id(self))
def bind(self, view, colid):
"""Bind the column renderer to its view. This is where `_cw`, `view`,
@@ -445,12 +446,13 @@
handle_pagination = True
def call(self, **kwargs):
+ self._cw.add_js('cubicweb.ajax.js') # for pagination
self.layout_render(self.w)
def column_renderer(self, colid, *args, **kwargs):
"""Return a column renderer for column of the given id."""
try:
- crenderer = self.column_renderers[colid]
+ crenderer = self.column_renderers[colid].copy()
except KeyError:
crenderer = self.default_column_renderer_class(*args, **kwargs)
crenderer.bind(self, colid)
@@ -620,7 +622,7 @@
else:
msg = '[3.14] %s argument is deprecated' % ', '.join(kwargs)
warn(msg, DeprecationWarning, stacklevel=2)
- self.layout_render(self.w)
+ super(RsetTableView, self).call(**kwargs)
def main_var_index(self):
"""returns the index of the first non-attribute variable among the RQL
@@ -865,7 +867,7 @@
class EntityTableView(TableMixIn, EntityView):
"""This abstract table view is designed to be used with an
:class:`is_instance()` or :class:`adaptable` predicate, hence doesn't depend
- the result set shape as the :class:`TableView` does.
+ the result set shape as the :class:`RsetTableView` does.
It will display columns that should be defined using the `columns` class
attribute containing a list of column ids. By default, each column is
--- a/web/views/tabs.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/tabs.py Mon Jan 13 13:47:47 2014 +0100
@@ -172,9 +172,9 @@
if self.lazy:
self._cw.add_onload(u"""
jQuery('#entity-tabs-%(uid)s').tabs(
- { selected: %(tabindex)s,
- select: function(event, ui) {
- setTab(ui.panel.id, '%(cookiename)s');
+ { active: %(tabindex)s,
+ activate: function(event, ui) {
+ setTab(ui.newPanel.attr('id'), '%(cookiename)s');
}
});
setTab('%(domid)s', '%(cookiename)s');
@@ -184,7 +184,7 @@
'cookiename' : self.cookie_name})
else:
self._cw.add_onload(
- u"jQuery('#entity-tabs-%(uid)s').tabs({selected: %(tabindex)s});"
+ u"jQuery('#entity-tabs-%(uid)s').tabs({active: %(tabindex)s});"
% {'tabindex': active_tab_idx, 'uid': uid})
--- a/web/views/timeline.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/timeline.py Mon Jan 13 13:47:47 2014 +0100
@@ -15,7 +15,7 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""basic support for SIMILE's timline widgets
+"""basic support for SIMILE's timeline widgets
cf. http://code.google.com/p/simile-widgets/
"""
--- a/web/views/treeview.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/treeview.py Mon Jan 13 13:47:47 2014 +0100
@@ -29,13 +29,26 @@
from cubicweb.utils import make_uid, json
from cubicweb.predicates import adaptable
from cubicweb.view import EntityView
-from cubicweb.mixins import _done_init
from cubicweb.web.views import baseviews
from cubicweb.web.views.ajaxcontroller import ajaxfunc
def treecookiename(treeid):
return str('%s-treestate' % treeid)
+def _done_init(done, view, row, col):
+ """handle an infinite recursion safety belt"""
+ if done is None:
+ done = set()
+ entity = view.cw_rset.get_entity(row, col)
+ if entity.eid in done:
+ msg = entity._cw._('loop in %(rel)s relation (%(eid)s)') % {
+ 'rel': entity.cw_adapt_to('ITree').tree_relation,
+ 'eid': entity.eid
+ }
+ return None, msg
+ done.add(entity.eid)
+ return done, entity
+
class BaseTreeView(baseviews.ListView):
"""base tree view"""
--- a/web/views/uicfg.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/uicfg.py Mon Jan 13 13:47:47 2014 +0100
@@ -114,6 +114,36 @@
'order',
self.counter)
+ def set_fields_order(self, etype, relations):
+ """specify the field order in `etype` primary view.
+
+ :param etype: the entity type as a string
+ :param attrs: the ordered list of attribute names (or relations)
+
+ `attrs` can be strings or 2-tuples (relname, role_of_etype_in_the_rel)
+
+ Unspecified fields will be displayed after specified ones, their
+ order being consistent with the schema definition.
+
+ Examples:
+
+ .. sourcecode:: python
+
+ from cubicweb.web.views.uicfg import primaryview_display_ctrl as pvdc
+ pvdc.set_fields_order('CWUser', ('firstname', ('in_group', 'subject'),
+ 'surname', 'login'))
+
+ """
+ for index, relation in enumerate(relations):
+ if not isinstance(relation, tuple):
+ relation = (relation, 'subject')
+ rtype, role = relation
+ if role == 'subject':
+ self.tag_subject_of((etype, rtype, '*'), {'order': index})
+ else:
+ self.tag_object_of((etype, rtype, '*'), {'order': index})
+
+
primaryview_display_ctrl = DisplayCtrlRelationTags()
--- a/web/views/urlrewrite.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/urlrewrite.py Mon Jan 13 13:47:47 2014 +0100
@@ -140,7 +140,7 @@
return None, None
-def build_rset(rql, rgxgroups=None, cachekey=None, setuser=False,
+def build_rset(rql, rgxgroups=None, setuser=False,
vid=None, vtitle=None, form={}, **kwargs):
def do_build_rset(inputurl, uri, req, schema, kwargs=kwargs):
@@ -156,7 +156,7 @@
req.form['vid'] = vid
if vtitle:
req.form['vtitle'] = req._(vtitle) % kwargs
- return None, req.execute(rql, kwargs, cachekey)
+ return None, req.execute(rql, kwargs)
return do_build_rset
def update_form(**kwargs):
--- a/web/views/workflow.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/workflow.py Mon Jan 13 13:47:47 2014 +0100
@@ -29,6 +29,7 @@
from logilab.mtconverter import xml_escape
from logilab.common.graph import escape
+from logilab.common.deprecation import class_deprecated
from cubicweb import Unauthorized
from cubicweb.predicates import (has_related_entities, one_line_rset,
@@ -436,6 +437,8 @@
class TmpPngView(TmpFileViewMixin, EntityView):
+ __metaclass__ = class_deprecated
+ __deprecation_warning__ = '[3.18] %(cls)s is deprecated'
__regid__ = 'tmppng'
__select__ = match_form_params('tmpfile')
content_type = 'image/png'
--- a/web/views/xmlrss.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/views/xmlrss.py Mon Jan 13 13:47:47 2014 +0100
@@ -28,7 +28,6 @@
from cubicweb.predicates import (is_instance, non_final_entity, one_line_rset,
appobject_selectable, adaptable)
from cubicweb.view import EntityView, EntityAdapter, AnyRsetView, Component
-from cubicweb.view import implements_adapter_compat
from cubicweb.uilib import simple_sgml_tag
from cubicweb.web import httpcache, component
@@ -185,7 +184,6 @@
__regid__ = 'IFeed'
__select__ = is_instance('Any')
- @implements_adapter_compat('IFeed')
def rss_feed_url(self):
"""return an url to the rss feed for this entity"""
return self.entity.absolute_url(vid='rss')
--- a/web/webconfig.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/webconfig.py Mon Jan 13 13:47:47 2014 +0100
@@ -135,7 +135,7 @@
('https-deny-anonymous',
{'type': 'yn',
'default': False,
- 'help': 'Prevent anonymous user to browse thought https version of '
+ 'help': 'Prevent anonymous user to browse through https version of '
'the site (https-url). Login form will then be displayed '
'until logged',
'group': 'web',
@@ -235,6 +235,18 @@
'help': 'anonymize the connection before executing any jsonp query.',
'group': 'web', 'level': 1
}),
+ ('generate-staticdir',
+ {'type': 'yn',
+ 'default': True,
+ 'help': 'Generate the static data resource directory on upgrade.',
+ 'group': 'web', 'level': 2,
+ }),
+ ('staticdir-path',
+ {'type': 'string',
+ 'default': None,
+ 'help': 'The static data resource directory path.',
+ 'group': 'web', 'level': 2,
+ }),
))
def __init__(self, *args, **kwargs):
@@ -296,6 +308,9 @@
def sign_text(self, text):
"""sign some text for later checking"""
+ # hmac.new expect bytes
+ if isinstance(text, unicode):
+ text = text.encode('utf-8')
# replace \r\n so we do not depend on whether a browser "reencode"
# original message using \r\n or not
return hmac.new(self._instance_salt,
@@ -305,7 +320,6 @@
"""check the text signature is equal to the given signature"""
return self.sign_text(text) == signature
-
def locate_resource(self, rid):
"""return the (directory, filename) where the given resource
may be found
@@ -401,7 +415,7 @@
self._load_ui_properties_file(uiprops, path)
self._load_ui_properties_file(uiprops, self.apphome)
datadir_url = uiprops.context['datadir_url']
- # XXX pre 3.9 css compat
+ # pre 3.9 css compat, however the old css still rules
if self['use-old-css']:
if (datadir_url+'/cubicweb.css') in uiprops['STYLESHEETS']:
idx = uiprops['STYLESHEETS'].index(datadir_url+'/cubicweb.css')
@@ -413,21 +427,6 @@
uiprops['JAVASCRIPTS'].insert(0, cubicweb_js_url)
def _load_ui_properties_file(self, uiprops, path):
- resourcesfile = join(path, 'data', 'external_resources')
- if exists(resourcesfile):
- warn('[3.9] %s file is deprecated, use an uiprops.py file'
- % resourcesfile, DeprecationWarning)
- datadir_url = uiprops.context['datadir_url']
- for rid, val in read_config(resourcesfile).iteritems():
- if rid in ('STYLESHEETS', 'STYLESHEETS_PRINT',
- 'IE_STYLESHEETS', 'JAVASCRIPTS'):
- val = [w.strip().replace('DATADIR', datadir_url)
- for w in val.split(',') if w.strip()]
- if rid == 'IE_STYLESHEETS':
- rid = 'STYLESHEETS_IE'
- else:
- val = val.strip().replace('DATADIR', datadir_url)
- uiprops[rid] = val
uipropsfile = join(path, 'uiprops.py')
if exists(uipropsfile):
self.debug('loading %s', uipropsfile)
--- a/web/webctl.py Tue Jul 02 17:09:04 2013 +0200
+++ b/web/webctl.py Mon Jan 13 13:47:47 2014 +0100
@@ -22,7 +22,7 @@
__docformat__ = "restructuredtext en"
import os, os.path as osp
-from shutil import copy
+from shutil import copy, rmtree
from logilab.common.shellutils import ASK
@@ -58,7 +58,64 @@
"""hooks called once instance's initialization has been completed"""
-class GenStaticDataDir(Command):
+class GenStaticDataDirMixIn(object):
+ """Create a directory merging all data directory content from cubes and CW.
+ """
+ def generate_static_dir(self, config, dest=None, ask_clean=False, repo=None):
+ if not dest:
+ dest = config['staticdir-path']
+ if not dest:
+ dest = osp.join(config.appdatahome, 'data')
+ if osp.exists(dest):
+ if (not ask_clean or
+ not ASK.confirm('Remove existing data directory %s?' % dest)):
+ raise ExecutionError('Directory %s already exists. '
+ 'Remove it first.' % dest)
+ rmtree(dest)
+ config.quick_start = True # notify this is not a regular start
+ # list all resources (no matter their order)
+ resources = set()
+ for datadir in self._datadirs(config, repo=repo):
+ for dirpath, dirnames, filenames in os.walk(datadir):
+ rel_dirpath = dirpath[len(datadir)+1:]
+ resources.update(osp.join(rel_dirpath, f) for f in filenames)
+ # locate resources and copy them to destination
+ for resource in resources:
+ dest_resource = osp.join(dest, resource)
+ dirname = osp.dirname(dest_resource)
+ if not osp.isdir(dirname):
+ os.makedirs(dirname)
+ resource_dir, resource_path = config.locate_resource(resource)
+ copy(osp.join(resource_dir, resource_path), dest_resource)
+ # handle md5 version subdirectory
+ linkdir(dest, osp.join(dest, config.instance_md5_version()))
+ print ('You can use apache rewrite rule below :\n'
+ 'RewriteRule ^/data/(.*) %s/$1 [L]' % dest)
+
+ def _datadirs(self, config, repo=None):
+ if repo is None:
+ repo = config.repository()
+ if config._cubes is None:
+ # web only config
+ config.init_cubes(repo.get_cubes())
+ for cube in repo.get_cubes():
+ cube_datadir = osp.join(cwcfg.cube_dir(cube), 'data')
+ if osp.isdir(cube_datadir):
+ yield cube_datadir
+ yield osp.join(config.shared_dir(), 'data')
+
+
+class WebUpgradeHandler(CommandHandler, GenStaticDataDirMixIn):
+ cmdname = 'upgrade'
+
+ def postupgrade(self, repo):
+ config = self.config
+ if not config['generate-staticdir']:
+ return
+ self.generate_static_dir(config, ask_clean=True, repo=repo)
+
+
+class GenStaticDataDir(Command, GenStaticDataDirMixIn):
"""Create a directory merging all data directory content from cubes and CW.
"""
name = 'gen-static-datadir'
@@ -71,42 +128,10 @@
def run(self, args):
appid = args.pop(0)
config = cwcfg.config_for(appid)
+ dest = None
if args:
dest = args[0]
- else:
- dest = osp.join(config.appdatahome, 'data')
- if osp.exists(dest):
- raise ExecutionError('Directory %s already exists. '
- 'Remove it first.' % dest)
- config.quick_start = True # notify this is not a regular start
- # list all resources (no matter their order)
- resources = set()
- for datadir in self._datadirs(config):
- for dirpath, dirnames, filenames in os.walk(datadir):
- rel_dirpath = dirpath[len(datadir)+1:]
- resources.update(osp.join(rel_dirpath, f) for f in filenames)
- # locate resources and copy them to destination
- for resource in resources:
- dirname = osp.dirname(resource)
- dest_resource = osp.join(dest, dirname)
- if not osp.isdir(dest_resource):
- os.makedirs(dest_resource)
- resource_dir, resource_path = config.locate_resource(resource)
- copy(osp.join(resource_dir, resource_path), dest_resource)
- # handle md5 version subdirectory
- linkdir(dest, osp.join(dest, config.instance_md5_version()))
- print ('You can use apache rewrite rule below :\n'
- 'RewriteRule ^/data/(.*) %s/$1 [L]' % dest)
+ self.generate_static_dir(config, dest)
- def _datadirs(self, config):
- repo = config.repository()
- if config._cubes is None:
- # web only config
- config.init_cubes(repo.get_cubes())
- for cube in repo.get_cubes():
- cube_datadir = osp.join(cwcfg.cube_dir(cube), 'data')
- if osp.isdir(cube_datadir):
- yield cube_datadir
- yield osp.join(config.shared_dir(), 'data')
CWCTL.register(GenStaticDataDir)
--- a/wsgi/handler.py Tue Jul 02 17:09:04 2013 +0200
+++ b/wsgi/handler.py Mon Jan 13 13:47:47 2014 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -17,8 +17,6 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""WSGI request handler for cubicweb"""
-
-
__docformat__ = "restructuredtext en"
from itertools import chain, repeat, izip
@@ -92,29 +90,21 @@
return iter(self.body)
-
class CubicWebWSGIApplication(object):
"""This is the wsgi application which will be called by the
wsgi server with the WSGI ``environ`` and ``start_response``
parameters.
-
- XXX: missing looping tasks and proper repository shutdown when
- the application is stopped.
- NOTE: no pyro
"""
def __init__(self, repo, config):
self.appli = CubicWebPublisher(repo, config)
self.config = config
self.base_url = self.config['base-url']
- self.https_url = self.config['https-url']
self.url_rewriter = self.appli.vreg['components'].select_or_none('urlrewriter')
def _render(self, req):
"""this function performs the actual rendering
"""
- if self.base_url is None:
- self.base_url = self.config._base_url = req.base_url()
try:
path = req.path
result = self.appli.handle_request(req, path)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wsgi/server.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,46 @@
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""dummy wsgi server for CubicWeb web instances"""
+
+__docformat__ = "restructuredtext en"
+
+from cubicweb.wsgi.handler import CubicWebWSGIApplication
+from cubicweb import ConfigurationError
+from wsgiref import simple_server
+
+from logging import getLogger
+LOGGER = getLogger('cubicweb')
+
+
+def run(config):
+ config.check_writeable_uid_directory(config.appdatahome)
+
+ port = config['port'] or 8080
+ interface = config['interface']
+
+ app = CubicWebWSGIApplication(config)
+ handler_cls = simple_server.WSGIRequestHandler
+ httpd = simple_server.WSGIServer((interface, port), handler_cls)
+ httpd.set_app(app)
+ repo = app.appli.repo
+ try:
+ repo.start_looping_tasks()
+ LOGGER.info('starting http server on %s', config['base-url'])
+ httpd.serve_forever()
+ finally:
+ repo.shutdown()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wsgi/wz.py Mon Jan 13 13:47:47 2014 +0100
@@ -0,0 +1,47 @@
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""dummy wsgi server for CubicWeb web instances"""
+
+__docformat__ = "restructuredtext en"
+
+import socket
+
+from cubicweb.wsgi.handler import CubicWebWSGIApplication
+from cubicweb import ConfigurationError
+from werkzeug.serving import run_simple
+
+from logging import getLogger
+LOGGER = getLogger('cubicweb')
+
+
+def run(config):
+ config.check_writeable_uid_directory(config.appdatahome)
+
+ port = config['port'] or 8080
+ interface = config['interface']
+
+ app = CubicWebWSGIApplication(config)
+ repo = app.appli.repo
+ try:
+ repo.start_looping_tasks()
+ run_simple(interface, port, app,
+ threaded=True,
+ use_debugger=True,
+ processes=1) # more processes yield weird errors
+ finally:
+ repo.shutdown()