Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cda35fd48a | ||
|
|
85c37af1f4 | ||
|
|
87935a45ba | ||
|
|
0692272991 | ||
|
|
c9f11c068c | ||
|
|
54b0feeffb | ||
|
|
8666f993d1 | ||
|
|
822e68ac16 | ||
|
|
292af5adc6 | ||
|
|
c6d4fb8f38 | ||
|
|
82d79e74c6 | ||
|
|
944d8bd8f3 | ||
|
|
33c1144e2e | ||
|
|
ca21bb0b9a | ||
|
|
a2b98cd6df | ||
|
|
51c3b633fe | ||
|
|
1e74c332d0 | ||
|
|
4bd002aee9 | ||
|
|
1b42fe6547 | ||
|
|
810520b3f0 | ||
|
|
af18582198 | ||
|
|
2d6ca49675 | ||
|
|
db36e4380d | ||
|
|
2031a43058 | ||
|
|
07d764f3c6 | ||
|
|
b8b63302f4 | ||
|
|
fa1af36adf | ||
|
|
2fc1378399 | ||
|
|
b6ee82bbde | ||
|
|
8ed6736e82 | ||
|
|
99b083ad43 | ||
|
|
c6b844a3e4 | ||
|
|
c7bb69a0b0 | ||
|
|
8b402b491c | ||
|
|
735d79c211 | ||
|
|
4177b4fe58 | ||
|
|
82aec9ba39 | ||
|
|
dc28664270 | ||
|
|
78bb8e9b26 | ||
|
|
0a633236e5 | ||
|
|
42d1544478 | ||
|
|
85819a5f83 | ||
|
|
9ca1c28db3 | ||
|
|
37fa90fbd2 | ||
|
|
2f0de8d8a0 | ||
|
|
70a0209e31 | ||
|
|
92b3c8f777 | ||
|
|
d622a8aa66 | ||
|
|
2a2771c4cc | ||
|
|
4fbd612d1b | ||
|
|
190c77e0e7 | ||
|
|
4fa8b3ed67 | ||
|
|
f109be363d | ||
|
|
b7cc1b2db5 | ||
|
|
81d0291ce2 | ||
|
|
894ff3c140 | ||
|
|
216ce5507c | ||
|
|
068aecff93 | ||
|
|
59cbe99347 | ||
|
|
bdbc053285 | ||
|
|
d746d43be5 | ||
|
|
9a3e73031b | ||
|
|
0468c16bc2 | ||
|
|
8c5858b6b7 | ||
|
|
6400e28a85 | ||
|
|
3e46d50aa1 | ||
|
|
cb94fde80b | ||
|
|
98593eefce | ||
|
|
4bbfe70927 | ||
|
|
02a0d1c9b0 | ||
|
|
2bf0ad9268 | ||
|
|
2e63b7637a | ||
|
|
67485d16a5 | ||
|
|
a9c5cf3072 | ||
|
|
eba8ad4b55 | ||
|
|
4ed6fb7ed9 | ||
|
|
294c67194f | ||
|
|
70f793b422 | ||
|
|
9552d9d6d0 | ||
|
|
9ead66b6db | ||
|
|
00c65ad160 | ||
|
|
b5c8b3ad25 | ||
|
|
5ca65d55d2 | ||
|
|
3f200fdc22 | ||
|
|
409c973dc4 | ||
|
|
59a194842d | ||
|
|
ee8b11db2c | ||
|
|
8ef04ac425 | ||
|
|
83cf098c07 | ||
|
|
70b41fa15e | ||
|
|
56af81f247 | ||
|
|
7fd30d8360 | ||
|
|
e1aefa2307 | ||
|
|
7a2316ec9a | ||
|
|
e48e47beb2 | ||
|
|
864c308246 | ||
|
|
994f3e7ae4 | ||
|
|
1d2f74440e | ||
|
|
704ceec16f | ||
|
|
038e25c259 | ||
|
|
c3aa02b3ce | ||
|
|
5cc4487d8c | ||
|
|
d50e6aab6b | ||
|
|
1d21f45e3e | ||
|
|
99a323c7ad | ||
|
|
e0d86462c8 | ||
|
|
ff0d10ac4f | ||
|
|
eee7be75c8 | ||
|
|
3c69716672 | ||
|
|
ad4b0eee54 | ||
|
|
0128ce3a93 | ||
|
|
0629df71ef | ||
|
|
4d1a4c48e6 | ||
|
|
2ffdb716cd | ||
|
|
40f04de9d2 | ||
|
|
52615fbca7 | ||
|
|
6abb78c559 | ||
|
|
db701ffea8 | ||
|
|
0804c28331 | ||
|
|
24bc51447c | ||
|
|
ccbbdc2493 | ||
|
|
d94e8415c7 | ||
|
|
0a62e86156 | ||
|
|
5744c06f59 | ||
|
|
947f92774b | ||
|
|
4001407add | ||
|
|
46ffaa6aea | ||
|
|
ba2be80080 | ||
|
|
3a9221a2b9 | ||
|
|
e0eb425223 | ||
|
|
f7ad31f066 | ||
|
|
d0f6ef4783 | ||
|
|
104d616cb9 | ||
|
|
a8703270da | ||
|
|
ad57c3c613 | ||
|
|
5c292640ba | ||
|
|
5cbf381a2c | ||
|
|
a0bbd7885a | ||
|
|
c2ce90a1fe | ||
|
|
197b018534 | ||
|
|
9ac1e7188f | ||
|
|
58a8ba067c | ||
|
|
060aeff867 | ||
|
|
d4572c5f38 | ||
|
|
46dc83a1bb | ||
|
|
f414356b67 | ||
|
|
460a017bab | ||
|
|
0b966d7c0a | ||
|
|
d2d16d4081 | ||
|
|
ebcf6e5671 | ||
|
|
778cc3902b | ||
|
|
32650f0cbf | ||
|
|
8f8ef4cca5 | ||
|
|
c9e92fc686 | ||
|
|
0820926b50 | ||
|
|
1856c9dc7a | ||
|
|
973bb4a16f | ||
|
|
2fa54f069c | ||
|
|
b11260d2e2 | ||
|
|
a6a9b004ea | ||
|
|
6ed204301d | ||
|
|
52392a10ae | ||
|
|
6d68a40ddf | ||
|
|
51bf802978 | ||
|
|
34267b7673 | ||
|
|
26eb5e6f38 | ||
|
|
13964c2c9b | ||
|
|
6a876fffc2 | ||
|
|
cd7850cc36 | ||
|
|
e4705dd48a | ||
|
|
2ef079289b | ||
|
|
76e95a9f1c | ||
|
|
4c5664f701 | ||
|
|
cafba3fbe2 | ||
|
|
8cb6678505 | ||
|
|
9fabfaac96 | ||
|
|
797ade202f | ||
|
|
dda81d1b95 | ||
|
|
13ed29ffc3 | ||
|
|
785276d294 | ||
|
|
52f634cb58 | ||
|
|
f921b24a95 | ||
|
|
753c54dbfc | ||
|
|
89cf314358 | ||
|
|
9299ecb64d | ||
|
|
94afe61477 | ||
|
|
a22f56ca0c | ||
|
|
656c490a21 | ||
|
|
8859ef04d3 | ||
|
|
5cf835d856 | ||
|
|
6a569bf56e | ||
|
|
bd6115ad62 | ||
|
|
3a265e3111 | ||
|
|
78fc14df81 | ||
|
|
4311820494 | ||
|
|
d1094e7b0c | ||
|
|
dbbbd44642 | ||
|
|
fa9d1ccb8b | ||
|
|
e6fad4f007 | ||
|
|
23292754e3 | ||
|
|
dcd7f8b46c | ||
|
|
7fd67c4e2e | ||
|
|
ec3ae8211f | ||
|
|
e8c0e0df92 | ||
|
|
7f9262f8f8 | ||
|
|
11da1ed19a | ||
|
|
9735477c35 | ||
|
|
f6f946f867 | ||
|
|
8683b0680d | ||
|
|
fbb5776432 | ||
|
|
92b4bc4f94 | ||
|
|
d886bf759e | ||
|
|
d5d25e8110 | ||
|
|
86c70df1e7 | ||
|
|
b6d923753a | ||
|
|
d4cad7634c | ||
|
|
45c28b1d76 | ||
|
|
b978bb90de | ||
|
|
e76ecec14f | ||
|
|
8ce528327c | ||
|
|
fe0e23f4b9 | ||
|
|
e05da97b1d | ||
|
|
5290308dea | ||
|
|
5817a1893b | ||
|
|
aa2e302936 | ||
|
|
d02755eac2 | ||
|
|
d037eaab44 | ||
|
|
9aa5995924 | ||
|
|
a981ca52e8 | ||
|
|
327c40cd17 | ||
|
|
f9745e8a63 | ||
|
|
51ce35c4e5 | ||
|
|
0f7e4d774b | ||
|
|
6e6612a57d | ||
|
|
83a3149849 | ||
|
|
98d33bdded | ||
|
|
f370187332 | ||
|
|
1b15b0c6dc | ||
|
|
507c3d6c33 | ||
|
|
e62069c8b7 | ||
|
|
d94ea6b295 | ||
|
|
9533978b37 | ||
|
|
9706d125b4 | ||
|
|
01aa9de919 | ||
|
|
55994c489b | ||
|
|
983627daa4 | ||
|
|
7c299936e4 | ||
|
|
df55f52d8f | ||
|
|
c81f1fd6c8 | ||
|
|
f15dd4b6e5 | ||
|
|
e9e61cbca4 | ||
|
|
700821e372 | ||
|
|
1d04f8837e | ||
|
|
a375e047e9 | ||
|
|
fe6b222aaf | ||
|
|
0b5bb9b996 | ||
|
|
be4df0dee7 | ||
|
|
d877e8b6d0 | ||
|
|
2531c2c640 | ||
|
|
eca300af32 | ||
|
|
43c60df371 | ||
|
|
cdac608efc | ||
|
|
3311486b14 | ||
|
|
038d0d17a4 | ||
|
|
3999fd80f8 | ||
|
|
2db3975a32 | ||
|
|
ebe3434a86 | ||
|
|
b487583f92 | ||
|
|
702e7cbea2 | ||
|
|
18a901cce4 | ||
|
|
f23115cb9c | ||
|
|
ea5e86e11e | ||
|
|
db223dc70a | ||
|
|
bcc4ae2ec6 | ||
|
|
4b81f721ac | ||
|
|
66f231eb4b | ||
|
|
5fc9517803 | ||
|
|
98294e0c69 | ||
|
|
5e28112eda | ||
|
|
dc5cac07e1 | ||
|
|
8058dc2ce6 | ||
|
|
3808b1f6ae | ||
|
|
10f2e4c3ad | ||
|
|
3c6af5f920 | ||
|
|
a5269b1a1a | ||
|
|
9a079e092f | ||
|
|
218817753a | ||
|
|
ef9bf73973 | ||
|
|
f92f21b060 | ||
|
|
642ec2b934 | ||
|
|
d494ec9c88 | ||
|
|
c4d1f3f414 | ||
|
|
5a59149514 | ||
|
|
484f02cae1 | ||
|
|
d5db67d5ea | ||
|
|
1480a10d6b | ||
|
|
7259f273f3 | ||
|
|
8645365f58 | ||
|
|
106930ed73 | ||
|
|
f79b38a335 | ||
|
|
35216db750 | ||
|
|
faa3d1d477 | ||
|
|
7aff79ca57 | ||
|
|
63bb4a7e8a | ||
|
|
8fc322254e | ||
|
|
b4c28516ae | ||
|
|
d233d3babb | ||
|
|
f18a1d0555 | ||
|
|
2cb55b52e9 | ||
|
|
4f361b5aad | ||
|
|
db122e7709 | ||
|
|
005e565a11 | ||
|
|
1656c6cdeb | ||
|
|
b7a0f2043c | ||
|
|
05df3b3029 | ||
|
|
dc1c85928d | ||
|
|
ba2cb811be | ||
|
|
6a7c0525f5 | ||
|
|
5132616c6c | ||
|
|
e528c10c21 | ||
|
|
41fd02fa2c | ||
|
|
26dab37d9f | ||
|
|
cc40018e87 | ||
|
|
b6db314612 | ||
|
|
3498666115 | ||
|
|
562a559169 | ||
|
|
47cec80939 | ||
|
|
eceb579cdd | ||
|
|
bd19986380 | ||
|
|
12acdb51d7 | ||
|
|
918590d1f3 | ||
|
|
d57428e8f0 | ||
|
|
13e3adf22d | ||
|
|
d4ffcaf1b1 | ||
|
|
17f1a51133 | ||
|
|
d4bca008a8 | ||
|
|
90c33911ab | ||
|
|
0a263ffc8d | ||
|
|
e94946d3d5 | ||
|
|
1ca0c9b0c0 | ||
|
|
cee0f91b36 | ||
|
|
eb49831726 | ||
|
|
b517c898b8 | ||
|
|
71fba07e3a | ||
|
|
2a7a4a3d04 | ||
|
|
999f235b75 | ||
|
|
da22554aed | ||
|
|
0409d6f725 | ||
|
|
b6235249da | ||
|
|
fabadcd21f | ||
|
|
8e4ea3497b | ||
|
|
4b0e1856b5 | ||
|
|
94841c90c3 | ||
|
|
f14e5f728c | ||
|
|
8443c17839 | ||
|
|
be8114127e | ||
|
|
4eaef303ff | ||
|
|
319a3fc1dc | ||
|
|
463d643e2c | ||
|
|
0cbed12952 | ||
|
|
b5994e57a4 | ||
|
|
e239b975be | ||
|
|
0259ea3d29 | ||
|
|
db4c008de3 | ||
|
|
7921e5148a | ||
|
|
ee23eab77a | ||
|
|
2344386f77 | ||
|
|
b5e12031c5 | ||
|
|
85e6840cf0 | ||
|
|
4c3006acb4 | ||
|
|
f8f008cab5 | ||
|
|
6bff8af458 | ||
|
|
b67edb083e | ||
|
|
4125a97ce1 | ||
|
|
78cf55bf9a | ||
|
|
931daaff89 | ||
|
|
c6550f0adc | ||
|
|
22c89d8dcc | ||
|
|
1636528a0f | ||
|
|
c02229d79c | ||
|
|
acb05dbfe1 | ||
|
|
fda1117dd7 | ||
|
|
d1fde23182 | ||
|
|
adf4c93860 | ||
|
|
02f1903c3d | ||
|
|
1137027ecc | ||
|
|
229616b9fc | ||
|
|
a75a8cbf46 | ||
|
|
9650ff7516 | ||
|
|
5b90f3f532 | ||
|
|
483092787b | ||
|
|
9b17048882 | ||
|
|
30fe7400f9 | ||
|
|
ada9353a7e | ||
|
|
b0373297e0 | ||
|
|
2dbbef724c | ||
|
|
eb7017fd9a | ||
|
|
4c039574df | ||
|
|
ab900957fe | ||
|
|
f960c8f6df | ||
|
|
d2910327c0 | ||
|
|
dfd6d52192 | ||
|
|
7dd8a3c853 | ||
|
|
71ae754fcd | ||
|
|
0520770a7e | ||
|
|
6b880fb455 | ||
|
|
dd180019a1 | ||
|
|
638f1f902a | ||
|
|
73061e3bf5 | ||
|
|
5a18e29c2e | ||
|
|
721af77c90 | ||
|
|
2cf6797b43 | ||
|
|
5c4145743f | ||
|
|
b4733e4617 | ||
|
|
b51d217d9b | ||
|
|
864dbe73f2 | ||
|
|
b942fc8f7a | ||
|
|
b2a65dbba4 | ||
|
|
d36d4d77f7 | ||
|
|
c8db6d5fb7 | ||
|
|
1b77c2294a | ||
|
|
98a81c9fbd | ||
|
|
4bf5a70dc0 | ||
|
|
d883e3d84e | ||
|
|
db37cf6a58 | ||
|
|
dba5c97d51 | ||
|
|
948bd0c671 | ||
|
|
5d8ff8ba2c | ||
|
|
503cd59adc | ||
|
|
a0bcd2287b | ||
|
|
430163f70b | ||
|
|
52b59e9b71 | ||
|
|
e8f87ea274 | ||
|
|
fb6fa0c448 | ||
|
|
935c95ccfc | ||
|
|
e180e69467 | ||
|
|
5c9d197f93 | ||
|
|
e417d311e5 | ||
|
|
199f93f262 | ||
|
|
64a8880c80 | ||
|
|
257c514bd4 | ||
|
|
12f848c899 | ||
|
|
4de007a946 | ||
|
|
b59a93e24e | ||
|
|
bbed326c20 | ||
|
|
874398c38c | ||
|
|
a9f8fbadae | ||
|
|
e62320ff9f | ||
|
|
b3e606295e | ||
|
|
b8c2bd7303 | ||
|
|
1387b26606 | ||
|
|
c6a7732d32 | ||
|
|
0036d9c45b | ||
|
|
b99fb7dedf | ||
|
|
344590470b | ||
|
|
2c57dc084e | ||
|
|
c17ba0a020 | ||
|
|
7d4b460e1b | ||
|
|
6680ea8ab7 | ||
|
|
353db90a64 | ||
|
|
827e663ac4 | ||
|
|
de399691ce | ||
|
|
46f081c45c | ||
|
|
0fa0dbaeea | ||
|
|
b47511c896 | ||
|
|
e31318eaa8 | ||
|
|
72ee538883 | ||
|
|
b6ddc6098e | ||
|
|
90854eae44 | ||
|
|
2bceb3f95f | ||
|
|
9da1e29014 | ||
|
|
39ba9dc1a9 | ||
|
|
36db9719ef | ||
|
|
125cbd93a0 | ||
|
|
bc267ce17b | ||
|
|
65c87386c1 | ||
|
|
2a245d36f4 | ||
|
|
dcf64a661d | ||
|
|
1c74afc01b | ||
|
|
5dbcda9f38 | ||
|
|
ac02d52f05 | ||
|
|
d4270373e1 | ||
|
|
e4b27080ca | ||
|
|
692791a518 | ||
|
|
9190191c7a | ||
|
|
7bd8f6a1a9 | ||
|
|
64e115f442 | ||
|
|
61f685d225 | ||
|
|
c56fc2f6a0 | ||
|
|
bb2aa29867 | ||
|
|
08b6832809 | ||
|
|
cbbd1246db | ||
|
|
0a79bf3afd | ||
|
|
db5e58e49f | ||
|
|
5030d3144f | ||
|
|
edcc2e44dc | ||
|
|
2cf9f26b0d | ||
|
|
4b99b6fdd7 | ||
|
|
622430583f | ||
|
|
89cc5a5f70 | ||
|
|
6899154fcd | ||
|
|
47c0e461f1 | ||
|
|
93237837ed | ||
|
|
cf20ce5fae | ||
|
|
04c86f07ef | ||
|
|
1a12c4011b | ||
|
|
85bbe15758 | ||
|
|
5816481a44 | ||
|
|
2675e9d229 | ||
|
|
41498917d5 | ||
|
|
8f7acd8154 | ||
|
|
26865421b6 | ||
|
|
b9ee4d4730 | ||
|
|
8fd7a27d5f | ||
|
|
69231bdd7f | ||
|
|
55dfb9e8c4 | ||
|
|
7761219cba | ||
|
|
e31e4e236f | ||
|
|
a43d822412 | ||
|
|
f94bc250eb | ||
|
|
5775d2788d | ||
|
|
048f275076 | ||
|
|
8078d4b0f3 | ||
|
|
5ee8c9c930 | ||
|
|
6659bc0793 | ||
|
|
d7caaf04cc | ||
|
|
e95115deb4 | ||
|
|
42c69b6343 | ||
|
|
d2347dec41 | ||
|
|
8420020c21 | ||
|
|
571fc6d919 | ||
|
|
52ec228eeb | ||
|
|
5848d9acaa | ||
|
|
3e8cbd5a0d | ||
|
|
e276cc2fc1 | ||
|
|
39a048db61 | ||
|
|
df4b896334 | ||
|
|
6d58845153 | ||
|
|
ba1f8bf741 | ||
|
|
a378ab3e51 | ||
|
|
2d866647e2 | ||
|
|
81863d69c9 | ||
|
|
ee2879442f | ||
|
|
ad68d2415d | ||
|
|
928de67f8d | ||
|
|
68296f9e65 | ||
|
|
7ac6edae52 | ||
|
|
1fc90fdb6d | ||
|
|
34a9d72cde | ||
|
|
198ce939d0 | ||
|
|
e31a099cb3 | ||
|
|
cc7e10d216 | ||
|
|
d8b68036c2 | ||
|
|
f9cd7e4ef4 | ||
|
|
896b45b838 | ||
|
|
d6146c9c5d | ||
|
|
b3be806244 | ||
|
|
eac12d3a57 | ||
|
|
2fc081bc3c | ||
|
|
032af7c04d | ||
|
|
8e63825def | ||
|
|
5d2e5dded3 | ||
|
|
61e33da844 | ||
|
|
da9dbaa5d6 | ||
|
|
7543c54bdb | ||
|
|
00608e4f04 | ||
|
|
cdbf48f09b | ||
|
|
f39db6331a | ||
|
|
ef433da190 | ||
|
|
d2375b4187 | ||
|
|
26d87967c5 | ||
|
|
044b2331c3 | ||
|
|
c89614ada6 | ||
|
|
f0aba167b4 | ||
|
|
bde9562b78 | ||
|
|
9a1229470a | ||
|
|
f781b9e1f5 | ||
|
|
fa32b7577b | ||
|
|
68526a0c6d | ||
|
|
ad2003c618 | ||
|
|
c1ecf823d8 | ||
|
|
6134f82452 | ||
|
|
fbb5a8b9bb | ||
|
|
df34869d65 | ||
|
|
28e6999e7d | ||
|
|
f4f77b0cb6 | ||
|
|
23ddb6c3c2 | ||
|
|
b636a5d6e9 | ||
|
|
efc392966e | ||
|
|
cffa59a80c | ||
|
|
82a1b9f628 | ||
|
|
94d2f1453d | ||
|
|
a1875ee362 | ||
|
|
5f13dca712 | ||
|
|
f78d423c92 | ||
|
|
f60ae809b6 | ||
|
|
34dd8af101 | ||
|
|
6bf6ebab1b | ||
|
|
29bf50425b | ||
|
|
8a7612c976 | ||
|
|
97489fd277 | ||
|
|
b86184fe58 | ||
|
|
2ce53e9957 | ||
|
|
d61c372c95 | ||
|
|
73e176365f | ||
|
|
33f12d91a5 | ||
|
|
d0f1286f03 | ||
|
|
04d698109e | ||
|
|
0e9c5caf4d | ||
|
|
509b0a6987 | ||
|
|
e0074ebcac | ||
|
|
918fdf2f0c | ||
|
|
8e827f7a09 | ||
|
|
cf2d5b637b | ||
|
|
236fdcfafc | ||
|
|
ce0f83d00c | ||
|
|
156d771ab3 | ||
|
|
01474c99b0 | ||
|
|
66d15491ca | ||
|
|
376a27da73 | ||
|
|
0f95c13dc7 | ||
|
|
a2e7794b92 | ||
|
|
926de90ee4 | ||
|
|
538f375284 | ||
|
|
4c61c0962d | ||
|
|
9b71646fc5 | ||
|
|
1e66fa3a93 | ||
|
|
57a8dfe034 | ||
|
|
77e7631740 | ||
|
|
ba978d55cf | ||
|
|
12e8ee5c25 | ||
|
|
d293e98b43 | ||
|
|
4f316d0294 | ||
|
|
81e15879d4 | ||
|
|
cd1d6c5af1 | ||
|
|
c7d3758c77 | ||
|
|
040e52278e | ||
|
|
3daf953c66 | ||
|
|
de3d722ac9 | ||
|
|
ff10eab373 | ||
|
|
eb4d159b37 | ||
|
|
5ef7a8e9a1 | ||
|
|
76cfba7047 | ||
|
|
f77f307869 | ||
|
|
5ef8648929 | ||
|
|
ed042685ea | ||
|
|
d09ce57f12 | ||
|
|
169818b275 | ||
|
|
4b14a87463 | ||
|
|
cadf38b4f6 | ||
|
|
a6226d6391 | ||
|
|
5c167907eb | ||
|
|
587ff56a94 | ||
|
|
6f91fdd833 | ||
|
|
6e2f9ad043 | ||
|
|
cdca2793e0 | ||
|
|
a0ee649884 | ||
|
|
380b491724 | ||
|
|
f45bf73992 | ||
|
|
94461724f6 | ||
|
|
c36c391786 | ||
|
|
f6db7c995f | ||
|
|
ccc4b96709 | ||
|
|
71b02e3044 | ||
|
|
99fb1c3010 | ||
|
|
20067d7b93 | ||
|
|
44eb35c617 | ||
|
|
df03317054 | ||
|
|
9d873cbd1c | ||
|
|
1bb4117cbd | ||
|
|
e834186a86 | ||
|
|
1394942feb | ||
|
|
32b9b5c799 | ||
|
|
340d7b5e6f | ||
|
|
302f56ecc1 | ||
|
|
9b12459a82 | ||
|
|
8e3925820c | ||
|
|
279d71d4cd | ||
|
|
258e2e57ae | ||
|
|
9357d810d8 | ||
|
|
54b385b321 | ||
|
|
df039e734c | ||
|
|
58533954dc | ||
|
|
236dc4b943 | ||
|
|
6612fd1cfe | ||
|
|
520950ba74 | ||
|
|
e943aa9c25 | ||
|
|
756aec7206 | ||
|
|
970e2ed35c | ||
|
|
1388c39636 | ||
|
|
6e84737924 | ||
|
|
0ad50630f2 | ||
|
|
f42ee15f5f | ||
|
|
77f154a56b | ||
|
|
2b0bfba649 | ||
|
|
9f1edf267d | ||
|
|
f3bda9ad02 | ||
|
|
f8afc76263 | ||
|
|
65b4aaf842 | ||
|
|
1b729cfbfc | ||
|
|
1aa5f30091 | ||
|
|
b17174c04c | ||
|
|
ac80adc9b4 | ||
|
|
888fa3dfc8 | ||
|
|
f3d815e84b | ||
|
|
9915fdf093 | ||
|
|
ef8f802df9 | ||
|
|
f7bf1020df | ||
|
|
75b8ceb022 | ||
|
|
b4f3784136 | ||
|
|
f1297bb827 | ||
|
|
435ebeaae4 | ||
|
|
537045082c | ||
|
|
4bea52a7b5 | ||
|
|
33295e516f | ||
|
|
f33ccf3366 | ||
|
|
0784680c90 | ||
|
|
e940228eaf | ||
|
|
50769a627a | ||
|
|
e68ecaa131 | ||
|
|
95e6e8577b | ||
|
|
19c83d4ad6 | ||
|
|
9c92bd1050 | ||
|
|
b3b95ccf5f | ||
|
|
cefa30841b | ||
|
|
15ff8669cb | ||
|
|
a921751e8e | ||
|
|
842207ab33 | ||
|
|
b02e8a6d5f | ||
|
|
a2b17967cf | ||
|
|
343ebf1714 | ||
|
|
e330791fe3 | ||
|
|
5e1e97ffc4 | ||
|
|
60f8816a10 | ||
|
|
6187c89ba6 | ||
|
|
e441e15907 | ||
|
|
e6c3410639 | ||
|
|
6b6cb5839c | ||
|
|
2a7e9c0c59 | ||
|
|
5b637c0a82 | ||
|
|
5cdd7c1215 | ||
|
|
c58f29bb9c | ||
|
|
0b0f82b514 | ||
|
|
3ab8a7bfd6 | ||
|
|
c5a9d2c456 |
@@ -58,3 +58,5 @@ HOWTO-web2py-devel
|
|||||||
*.sublime-project
|
*.sublime-project
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
.idea/*
|
.idea/*
|
||||||
|
site-packages/
|
||||||
|
logs/
|
||||||
|
|||||||
+23
-2
@@ -12,19 +12,40 @@ python:
|
|||||||
- 'pypy'
|
- 'pypy'
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then
|
||||||
|
export PYENV_ROOT="$HOME/.pyenv"
|
||||||
|
if [ -f "$PYENV_ROOT/bin/pyenv" ]; then
|
||||||
|
pushd "$PYENV_ROOT" && git pull && popd
|
||||||
|
else
|
||||||
|
rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT"
|
||||||
|
fi
|
||||||
|
export PYPY_VERSION="5.0.1"
|
||||||
|
"$PYENV_ROOT/bin/pyenv" install --skip-existing "pypy-$PYPY_VERSION"
|
||||||
|
virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION"
|
||||||
|
source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate"
|
||||||
|
fi
|
||||||
- pip install -e .
|
- pip install -e .
|
||||||
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --download-cache $HOME/.pip-cache unittest2; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install --download-cache $HOME/.pip-cache unittest2; fi
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache coverage; fi;
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache coverage; fi;
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache python-coveralls; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install --download-cache $HOME/.pip-cache codecov; fi
|
||||||
|
- mysql -e 'create database pydal;'
|
||||||
|
- psql -c 'create database pydal;' -U postgres
|
||||||
|
- psql -c 'create extension postgis;' -U postgres -d pydal;
|
||||||
|
- psql -c 'SHOW SERVER_VERSION' -U postgres
|
||||||
|
|
||||||
|
|
||||||
script: export COVERAGE_PROCESS_START=gluon/tests/coverage.ini; ./web2py.py --run_system_tests --with_coverage
|
script: export COVERAGE_PROCESS_START=gluon/tests/coverage.ini; ./web2py.py --run_system_tests --with_coverage
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coverage combine; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coverage combine; fi
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coveralls --config_file=gluon/tests/coverage.ini; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then codecov; fi
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email: true
|
email: true
|
||||||
|
|
||||||
|
addons:
|
||||||
|
postgresql: "9.4"
|
||||||
|
|||||||
@@ -1,3 +1,96 @@
|
|||||||
|
## 2.14.6
|
||||||
|
|
||||||
|
- Increased test coverage (thanks Richard)
|
||||||
|
- Fixed some newly discovered security issues in admin:
|
||||||
|
CSRF vulnerability in admin that allows disabling apps
|
||||||
|
Brute force password attack vulnerability in admin
|
||||||
|
(thanks Narendra and Leonel)
|
||||||
|
|
||||||
|
## 2.14.1-5
|
||||||
|
|
||||||
|
- fixed two major security issues that caused the examples app to leak information
|
||||||
|
- new Auth(…,host_names=[…]) to prevent host header injection
|
||||||
|
- improved scheduler
|
||||||
|
- pep8 enhancements
|
||||||
|
- many bug fixes
|
||||||
|
- restored GAE support that was broken in 2.13.*
|
||||||
|
- improved fabfile for deployment
|
||||||
|
- refactored examples with stupid.css
|
||||||
|
- new JWT implementation (experimental)
|
||||||
|
- new gluon.contrib.redis_scheduler
|
||||||
|
- myconf.get
|
||||||
|
- LDAP groups (experimental)
|
||||||
|
- .flash -> .w2p_flash
|
||||||
|
- Updated feedparser.py 5.2.1
|
||||||
|
- Updated jQuery 1.12.2
|
||||||
|
- welcome app now checks for version number
|
||||||
|
- Redis improvements. New syntax:
|
||||||
|
|
||||||
|
BEFORE:
|
||||||
|
from gluon.contrib.redis_cache import RedisCache
|
||||||
|
cache.redis = RedisCache('localhost:6379',db=None, debug=True)
|
||||||
|
|
||||||
|
NOW:
|
||||||
|
from gluon.contrib.redis_utils import RConn
|
||||||
|
from gluon.contrib.redis_cache import RedisCache
|
||||||
|
rconn = RConn()
|
||||||
|
# or RConn(host='localhost', port=6379,
|
||||||
|
# db=0, password=None, socket_timeout=None,
|
||||||
|
# socket_connect_timeout=None, .....)
|
||||||
|
# exactly as a redis.StrictRedis instance
|
||||||
|
cache.redis = RedisCache(redis_conn=rconn, debug=True)
|
||||||
|
|
||||||
|
BEFORE:
|
||||||
|
from gluon.contrib.redis_session import RedisSession
|
||||||
|
sessiondb = RedisSession('localhost:6379',db=0, session_expiry=False)
|
||||||
|
session.connect(request, response, db = sessiondb)
|
||||||
|
|
||||||
|
NOW:
|
||||||
|
from gluon.contrib.redis_utils import RConn
|
||||||
|
from gluon.contrib.redis_session import RedisSession
|
||||||
|
rconn = RConn()
|
||||||
|
sessiondb = RedisSession(redis_conn=rconn, session_expiry=False)
|
||||||
|
session.connect(request, response, db = sessiondb)
|
||||||
|
|
||||||
|
Many thanks to Richard and Simone for their work and dedication.
|
||||||
|
|
||||||
|
## 2.13.*
|
||||||
|
|
||||||
|
- fixed a security issue in request_reset_password
|
||||||
|
- added fabfile.py
|
||||||
|
- fixed oauth2 renew token, thanks dokime7
|
||||||
|
- fixed add_membership, del_membership, add_membership IntegrityError (when auth.enable_record_versioning)
|
||||||
|
- allow passing unicode to template render
|
||||||
|
- allow IS_NOT_IN_DB to work with custom primarykey, thanks timmyborg
|
||||||
|
- allow HttpOnly cookies
|
||||||
|
- french pluralizaiton rules, thanks Mathieu Clabaut
|
||||||
|
- fixed bug in redirect to cas service, thanks Fernando González
|
||||||
|
- allow deploying to pythonanywhere from the web2py admin that you're running locally, thanks Leonel
|
||||||
|
- better tests
|
||||||
|
- many more bug fixes
|
||||||
|
|
||||||
|
## 2.12.1-3
|
||||||
|
|
||||||
|
- security fix: Validate for open redirect everywhere, not just in login()
|
||||||
|
- allow to pack invidual apps and selected files as packed exe files
|
||||||
|
- allow bulk user registration with default bulk_register_enabled=False
|
||||||
|
- allow unsorted multiword query in grid search
|
||||||
|
- better MongoDB support with newer pyDAL
|
||||||
|
- enable <app>/appadmin/manage/auth by default for user admin
|
||||||
|
- allow mail.settings.server='logging:filename' to log emails to a file
|
||||||
|
- better caching logic
|
||||||
|
- fixed order of confirm-password field
|
||||||
|
- TLS support in ldap
|
||||||
|
- prettydate can do UTC
|
||||||
|
- jquery 1.11.3
|
||||||
|
- bootstrap 3.3.5
|
||||||
|
- moved to codecov and enabled appveyor
|
||||||
|
- many bug fixes
|
||||||
|
|
||||||
|
## 2.11.1
|
||||||
|
|
||||||
|
- Many small but significative improvements and bug fixes
|
||||||
|
|
||||||
## 2.10.1-2.10.2
|
## 2.10.1-2.10.2
|
||||||
|
|
||||||
- welcome app defaults to Bootstrap 3
|
- welcome app defaults to Bootstrap 3
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ clean:
|
|||||||
find ./ -name '*.rej' -exec rm -f {} \;
|
find ./ -name '*.rej' -exec rm -f {} \;
|
||||||
find ./ -name '#*' -exec rm -f {} \;
|
find ./ -name '#*' -exec rm -f {} \;
|
||||||
find ./ -name 'Thumbs.db' -exec rm -f {} \;
|
find ./ -name 'Thumbs.db' -exec rm -f {} \;
|
||||||
find ./gluon/ -name '.*' -exec rm -f {} \;
|
# find ./gluon/ -name '.*' -exec rm -f {} \;
|
||||||
find ./gluon/ -name '*class' -exec rm -f {} \;
|
find ./gluon/ -name '*class' -exec rm -f {} \;
|
||||||
find ./applications/admin/ -name '.*' -exec rm -f {} \;
|
find ./applications/admin/ -name '.*' -exec rm -f {} \;
|
||||||
find ./applications/examples/ -name '.*' -exec rm -f {} \;
|
find ./applications/examples/ -name '.*' -exec rm -f {} \;
|
||||||
@@ -32,7 +32,7 @@ update:
|
|||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
### Use semantic versioning
|
### Use semantic versioning
|
||||||
echo 'Version 2.10.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
echo 'Version 2.14.6-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||||
### rm -f all junk files
|
### rm -f all junk files
|
||||||
make clean
|
make clean
|
||||||
### clean up baisc apps
|
### clean up baisc apps
|
||||||
|
|||||||
+5
-4
@@ -13,7 +13,7 @@ Learn more at http://web2py.com
|
|||||||
|
|
||||||
Then edit ./app.yaml and replace "yourappname" with yourappname.
|
Then edit ./app.yaml and replace "yourappname" with yourappname.
|
||||||
|
|
||||||
## Import about this GIT repo
|
## Important reminder about this GIT repo
|
||||||
|
|
||||||
An important part of web2py is the Database Abstraction Layer (DAL). In early 2015 this was decoupled into a separate code-base (PyDAL). In terms of git, it is a sub-module of the main repository.
|
An important part of web2py is the Database Abstraction Layer (DAL). In early 2015 this was decoupled into a separate code-base (PyDAL). In terms of git, it is a sub-module of the main repository.
|
||||||
|
|
||||||
@@ -38,9 +38,10 @@ PyDAL uses a separate stable release cycle to the rest of web2py. PyDAL releases
|
|||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
[](https://travis-ci.org/web2py/web2py)
|
[](https://travis-ci.org/web2py/web2py)
|
||||||
|
[](https://ci.appveyor.com/project/web2py/web2py)
|
||||||
|
[](https://codecov.io/github/web2py/web2py)
|
||||||
|
|
||||||
[](https://coveralls.io/r/web2py/web2py)
|
|
||||||
|
|
||||||
## Installation Instructions
|
## Installation Instructions
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ That's it!!!
|
|||||||
packages/ > web2py submodules
|
packages/ > web2py submodules
|
||||||
dal/
|
dal/
|
||||||
contrib/ > third party libraries
|
contrib/ > third party libraries
|
||||||
tests/ > unittests
|
tests/ > unittests
|
||||||
applications/ > are the apps
|
applications/ > are the apps
|
||||||
admin/ > web based IDE
|
admin/ > web based IDE
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.10.2-stable+timestamp.2015.03.31.22.25.23
|
Version 2.14.6-stable+timestamp.2016.05.09.19.18.48
|
||||||
|
|||||||
@@ -180,6 +180,11 @@ class Servers:
|
|||||||
s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address)
|
s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address)
|
||||||
s.start()
|
s.start()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def waitress(app, address, **options):
|
||||||
|
from waitress import serve
|
||||||
|
serve(app, host=address[0], port=address[1], _quiet=True)
|
||||||
|
|
||||||
|
|
||||||
def mongrel2_handler(application, conn, debug=False):
|
def mongrel2_handler(application, conn, debug=False):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ if request.function == 'manage':
|
|||||||
auth.table_group(),
|
auth.table_group(),
|
||||||
auth.table_permission()])
|
auth.table_permission()])
|
||||||
manager_role = manager_action.get('role', None) if manager_action else None
|
manager_role = manager_action.get('role', None) if manager_action else None
|
||||||
auth.requires_membership(manager_role)(lambda: None)()
|
if not (gluon.fileutils.check_credentials(request) or auth.has_membership(manager_role)):
|
||||||
|
raise HTTP(403, "Not authorized")
|
||||||
menu = False
|
menu = False
|
||||||
elif (request.application == 'admin' and not session.authorized) or \
|
elif (request.application == 'admin' and not session.authorized) or \
|
||||||
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||||
@@ -80,7 +81,6 @@ if False and request.tickets_db:
|
|||||||
def get_databases(request):
|
def get_databases(request):
|
||||||
dbs = {}
|
dbs = {}
|
||||||
for (key, value) in global_env.items():
|
for (key, value) in global_env.items():
|
||||||
cond = False
|
|
||||||
try:
|
try:
|
||||||
cond = isinstance(value, GQLDB)
|
cond = isinstance(value, GQLDB)
|
||||||
except:
|
except:
|
||||||
@@ -420,7 +420,7 @@ def ccache():
|
|||||||
'oldest': time.time(),
|
'oldest': time.time(),
|
||||||
'keys': []
|
'keys': []
|
||||||
}
|
}
|
||||||
|
|
||||||
disk = copy.copy(ram)
|
disk = copy.copy(ram)
|
||||||
total = copy.copy(ram)
|
total = copy.copy(ram)
|
||||||
disk['keys'] = []
|
disk['keys'] = []
|
||||||
@@ -445,30 +445,31 @@ def ccache():
|
|||||||
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
||||||
total.update(gae_stats)
|
total.update(gae_stats)
|
||||||
else:
|
else:
|
||||||
|
# get ram stats directly from the cache object
|
||||||
|
ram_stats = cache.ram.stats[request.application]
|
||||||
|
ram['hits'] = ram_stats['hit_total'] - ram_stats['misses']
|
||||||
|
ram['misses'] = ram_stats['misses']
|
||||||
|
try:
|
||||||
|
ram['ratio'] = ram['hits'] * 100 / ram_stats['hit_total']
|
||||||
|
except (KeyError, ZeroDivisionError):
|
||||||
|
ram['ratio'] = 0
|
||||||
|
|
||||||
for key, value in cache.ram.storage.iteritems():
|
for key, value in cache.ram.storage.iteritems():
|
||||||
if isinstance(value, dict):
|
if hp:
|
||||||
ram['hits'] = value['hit_total'] - value['misses']
|
ram['bytes'] += hp.iso(value[1]).size
|
||||||
ram['misses'] = value['misses']
|
ram['objects'] += hp.iso(value[1]).count
|
||||||
try:
|
ram['entries'] += 1
|
||||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
if value[0] < ram['oldest']:
|
||||||
except (KeyError, ZeroDivisionError):
|
ram['oldest'] = value[0]
|
||||||
ram['ratio'] = 0
|
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
else:
|
|
||||||
if hp:
|
|
||||||
ram['bytes'] += hp.iso(value[1]).size
|
|
||||||
ram['objects'] += hp.iso(value[1]).count
|
|
||||||
ram['entries'] += 1
|
|
||||||
if value[0] < ram['oldest']:
|
|
||||||
ram['oldest'] = value[0]
|
|
||||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
|
||||||
|
|
||||||
for key in cache.disk.storage:
|
for key in cache.disk.storage:
|
||||||
value = cache.disk.storage[key]
|
value = cache.disk.storage[key]
|
||||||
if isinstance(value, dict):
|
if isinstance(value[1], dict):
|
||||||
disk['hits'] = value['hit_total'] - value['misses']
|
disk['hits'] = value[1]['hit_total'] - value[1]['misses']
|
||||||
disk['misses'] = value['misses']
|
disk['misses'] = value[1]['misses']
|
||||||
try:
|
try:
|
||||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
disk['ratio'] = disk['hits'] * 100 / value[1]['hit_total']
|
||||||
except (KeyError, ZeroDivisionError):
|
except (KeyError, ZeroDivisionError):
|
||||||
disk['ratio'] = 0
|
disk['ratio'] = 0
|
||||||
else:
|
else:
|
||||||
@@ -480,12 +481,12 @@ def ccache():
|
|||||||
disk['oldest'] = value[0]
|
disk['oldest'] = value[0]
|
||||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
|
|
||||||
total['entries'] = ram['entries'] + disk['entries']
|
ram_keys = ram.keys() # ['hits', 'objects', 'ratio', 'entries', 'keys', 'oldest', 'bytes', 'misses']
|
||||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
ram_keys.remove('ratio')
|
||||||
total['objects'] = ram['objects'] + disk['objects']
|
ram_keys.remove('oldest')
|
||||||
total['hits'] = ram['hits'] + disk['hits']
|
for key in ram_keys:
|
||||||
total['misses'] = ram['misses'] + disk['misses']
|
total[key] = ram[key] + disk[key]
|
||||||
total['keys'] = ram['keys'] + disk['keys']
|
|
||||||
try:
|
try:
|
||||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||||
total['misses'])
|
total['misses'])
|
||||||
@@ -575,11 +576,9 @@ def bg_graph_model():
|
|||||||
meta_graphmodel = dict(group=request.application, color='#ECECEC')
|
meta_graphmodel = dict(group=request.application, color='#ECECEC')
|
||||||
|
|
||||||
group = meta_graphmodel['group'].replace(' ', '')
|
group = meta_graphmodel['group'].replace(' ', '')
|
||||||
if not subgraphs.has_key(group):
|
if group not in subgraphs:
|
||||||
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
|
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
|
||||||
subgraphs[group]['tables'].append(tablename)
|
subgraphs[group]['tables'].append(tablename)
|
||||||
else:
|
|
||||||
subgraphs[group]['tables'].append(tablename)
|
|
||||||
|
|
||||||
graph.add_node(tablename, name=tablename, shape='plaintext',
|
graph.add_node(tablename, name=tablename, shape='plaintext',
|
||||||
label=table_template(tablename))
|
label=table_template(tablename))
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ def list_breakpoints():
|
|||||||
"Return a list of linenumbers for current breakpoints"
|
"Return a list of linenumbers for current breakpoints"
|
||||||
|
|
||||||
breakpoints = []
|
breakpoints = []
|
||||||
ok = None
|
ok = False
|
||||||
try:
|
try:
|
||||||
filename = os.path.join(request.env['applications_parent'],
|
filename = os.path.join(request.env['applications_parent'],
|
||||||
'applications', request.vars.filename)
|
'applications', request.vars.filename)
|
||||||
@@ -235,5 +235,4 @@ def list_breakpoints():
|
|||||||
ok = True
|
ok = True
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
session.flash = str(e)
|
session.flash = str(e)
|
||||||
ok = False
|
|
||||||
return response.json({'ok': ok, 'breakpoints': breakpoints})
|
return response.json({'ok': ok, 'breakpoints': breakpoints})
|
||||||
|
|||||||
@@ -32,15 +32,15 @@ from gluon.languages import (read_possible_languages, read_dict, write_dict,
|
|||||||
|
|
||||||
|
|
||||||
if DEMO_MODE and request.function in ['change_password', 'pack',
|
if DEMO_MODE and request.function in ['change_password', 'pack',
|
||||||
'pack_custom','pack_plugin', 'upgrade_web2py', 'uninstall',
|
'pack_custom', 'pack_plugin', 'upgrade_web2py', 'uninstall',
|
||||||
'cleanup', 'compile_app', 'remove_compiled_app', 'delete',
|
'cleanup', 'compile_app', 'remove_compiled_app', 'delete',
|
||||||
'delete_plugin', 'create_file', 'upload_file', 'update_languages',
|
'delete_plugin', 'create_file', 'upload_file', 'update_languages',
|
||||||
'reload_routes', 'git_push', 'git_pull', 'install_plugin']:
|
'reload_routes', 'git_push', 'git_pull', 'install_plugin']:
|
||||||
session.flash = T('disabled in demo mode')
|
session.flash = T('disabled in demo mode')
|
||||||
redirect(URL('site'))
|
redirect(URL('site'))
|
||||||
|
|
||||||
if is_gae and request.function in ('edit', 'edit_language',
|
if is_gae and request.function in ('edit', 'edit_language',
|
||||||
'edit_plurals', 'update_languages', 'create_file', 'install_plugin'):
|
'edit_plurals', 'update_languages', 'create_file', 'install_plugin'):
|
||||||
session.flash = T('disabled in GAE mode')
|
session.flash = T('disabled in GAE mode')
|
||||||
redirect(URL('site'))
|
redirect(URL('site'))
|
||||||
|
|
||||||
@@ -74,8 +74,10 @@ def log_progress(app, mode='EDIT', filename=None, progress=0):
|
|||||||
def safe_open(a, b):
|
def safe_open(a, b):
|
||||||
if (DEMO_MODE or is_gae) and ('w' in b or 'a' in b):
|
if (DEMO_MODE or is_gae) and ('w' in b or 'a' in b):
|
||||||
class tmp:
|
class tmp:
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
return tmp()
|
return tmp()
|
||||||
@@ -119,6 +121,9 @@ def index():
|
|||||||
send = URL('site')
|
send = URL('site')
|
||||||
if session.authorized:
|
if session.authorized:
|
||||||
redirect(send)
|
redirect(send)
|
||||||
|
elif failed_login_count() >= allowed_number_of_attempts:
|
||||||
|
time.sleep(2 ** allowed_number_of_attempts)
|
||||||
|
raise HTTP(403)
|
||||||
elif request.vars.password:
|
elif request.vars.password:
|
||||||
if verify_password(request.vars.password[:1024]):
|
if verify_password(request.vars.password[:1024]):
|
||||||
session.authorized = True
|
session.authorized = True
|
||||||
@@ -208,6 +213,7 @@ def site():
|
|||||||
file_or_appurl = 'file' in request.vars or 'appurl' in request.vars
|
file_or_appurl = 'file' in request.vars or 'appurl' in request.vars
|
||||||
|
|
||||||
class IS_VALID_APPNAME(object):
|
class IS_VALID_APPNAME(object):
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
if not re.compile('^\w+$').match(value):
|
if not re.compile('^\w+$').match(value):
|
||||||
return (value, T('Invalid application name'))
|
return (value, T('Invalid application name'))
|
||||||
@@ -268,7 +274,7 @@ def site():
|
|||||||
raise Exception("404 file not found")
|
raise Exception("404 file not found")
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
session.flash = \
|
session.flash = \
|
||||||
DIV(T('Unable to download app because:'), PRE(str(e)))
|
DIV(T('Unable to download app because:'), PRE(repr(e)))
|
||||||
redirect(URL(r=request))
|
redirect(URL(r=request))
|
||||||
fname = form_update.vars.url
|
fname = form_update.vars.url
|
||||||
|
|
||||||
@@ -292,9 +298,6 @@ def site():
|
|||||||
log_progress(appname)
|
log_progress(appname)
|
||||||
session.flash = T(msg, dict(appname=appname,
|
session.flash = T(msg, dict(appname=appname,
|
||||||
digest=md5_hash(installed)))
|
digest=md5_hash(installed)))
|
||||||
elif f and form_update.vars.overwrite:
|
|
||||||
msg = 'unable to install application "%(appname)s"'
|
|
||||||
session.flash = T(msg, dict(appname=form_update.vars.name))
|
|
||||||
else:
|
else:
|
||||||
msg = 'unable to install application "%(appname)s"'
|
msg = 'unable to install application "%(appname)s"'
|
||||||
session.flash = T(msg, dict(appname=form_update.vars.name))
|
session.flash = T(msg, dict(appname=form_update.vars.name))
|
||||||
@@ -328,7 +331,7 @@ def report_progress(app):
|
|||||||
if not m:
|
if not m:
|
||||||
continue
|
continue
|
||||||
days = -(request.now - datetime.datetime.strptime(m[0],
|
days = -(request.now - datetime.datetime.strptime(m[0],
|
||||||
'%Y-%m-%d %H:%M:%S')).days
|
'%Y-%m-%d %H:%M:%S')).days
|
||||||
counter += int(m[1])
|
counter += int(m[1])
|
||||||
events.append([days, counter])
|
events.append([days, counter])
|
||||||
return events
|
return events
|
||||||
@@ -356,6 +359,7 @@ def pack():
|
|||||||
session.flash = T('internal error: %s', e)
|
session.flash = T('internal error: %s', e)
|
||||||
redirect(URL('site'))
|
redirect(URL('site'))
|
||||||
|
|
||||||
|
|
||||||
def pack_plugin():
|
def pack_plugin():
|
||||||
app = get_app()
|
app = get_app()
|
||||||
if len(request.args) == 2:
|
if len(request.args) == 2:
|
||||||
@@ -370,31 +374,66 @@ def pack_plugin():
|
|||||||
session.flash = T('internal error')
|
session.flash = T('internal error')
|
||||||
redirect(URL('plugin', args=request.args))
|
redirect(URL('plugin', args=request.args))
|
||||||
|
|
||||||
|
|
||||||
|
def pack_exe(app, base, filenames=None):
|
||||||
|
import urllib
|
||||||
|
import zipfile
|
||||||
|
from cStringIO import StringIO
|
||||||
|
# Download latest web2py_win and open it with zipfile
|
||||||
|
download_url = 'http://www.web2py.com/examples/static/web2py_win.zip'
|
||||||
|
out = StringIO()
|
||||||
|
out.write(urllib.urlopen(download_url).read())
|
||||||
|
web2py_win = zipfile.ZipFile(out, mode='a')
|
||||||
|
# Write routes.py with the application as default
|
||||||
|
routes = u'# -*- coding: utf-8 -*-\nrouters = dict(BASE=dict(default_application="%s"))' % app
|
||||||
|
web2py_win.writestr('web2py/routes.py', routes.encode('utf-8'))
|
||||||
|
# Copy the application into the zipfile
|
||||||
|
common_root = os.path.dirname(base)
|
||||||
|
for filename in filenames:
|
||||||
|
fname = os.path.join(base, filename)
|
||||||
|
arcname = os.path.join('web2py/applications', app, filename)
|
||||||
|
web2py_win.write(fname, arcname)
|
||||||
|
web2py_win.close()
|
||||||
|
response.headers['Content-Type'] = 'application/zip'
|
||||||
|
response.headers['Content-Disposition'] = 'attachment; filename=web2py.app.%s.zip' % app
|
||||||
|
out.seek(0)
|
||||||
|
return response.stream(out)
|
||||||
|
|
||||||
|
|
||||||
def pack_custom():
|
def pack_custom():
|
||||||
app = get_app()
|
app = get_app()
|
||||||
base = apath(app, r=request)
|
base = apath(app, r=request)
|
||||||
if request.post_vars.file:
|
|
||||||
files = request.post_vars.file
|
|
||||||
files = [files] if not isinstance(files,list) else files
|
|
||||||
fname = 'web2py.app.%s.w2p' % app
|
|
||||||
try:
|
|
||||||
filename = app_pack(app, request, raise_ex=True, filenames=files)
|
|
||||||
except Exception, e:
|
|
||||||
filename = None
|
|
||||||
if filename:
|
|
||||||
response.headers['Content-Type'] = 'application/w2p'
|
|
||||||
disposition = 'attachment; filename=%s' % fname
|
|
||||||
response.headers['Content-Disposition'] = disposition
|
|
||||||
return safe_read(filename, 'rb')
|
|
||||||
else:
|
|
||||||
session.flash = T('internal error: %s', e)
|
|
||||||
redirect(URL(args=request.args))
|
|
||||||
def ignore(fs):
|
def ignore(fs):
|
||||||
return [f for f in fs if not (
|
return [f for f in fs if not (
|
||||||
f[:1] in '#' or f.endswith('~') or f.endswith('.bak'))]
|
f[:1] in '#' or f.endswith('~') or f.endswith('.bak'))]
|
||||||
files = {}
|
files = {}
|
||||||
for (r,d,f) in os.walk(base):
|
for (r, d, f) in os.walk(base):
|
||||||
files[r] = {'folders':ignore(d),'files':ignore(f)}
|
files[r] = {'folders': ignore(d), 'files': ignore(f)}
|
||||||
|
|
||||||
|
if request.post_vars.file:
|
||||||
|
valid_set = set(os.path.relpath(os.path.join(r, f), base) for r in files for f in files[r]['files'])
|
||||||
|
files = request.post_vars.file
|
||||||
|
files = [files] if not isinstance(files, list) else files
|
||||||
|
files = [file for file in files if file in valid_set]
|
||||||
|
|
||||||
|
if request.post_vars.doexe is None:
|
||||||
|
fname = 'web2py.app.%s.w2p' % app
|
||||||
|
try:
|
||||||
|
filename = app_pack(app, request, raise_ex=True, filenames=files)
|
||||||
|
except Exception, e:
|
||||||
|
filename = None
|
||||||
|
if filename:
|
||||||
|
response.headers['Content-Type'] = 'application/w2p'
|
||||||
|
disposition = 'attachment; filename=%s' % fname
|
||||||
|
response.headers['Content-Disposition'] = disposition
|
||||||
|
return safe_read(filename, 'rb')
|
||||||
|
else:
|
||||||
|
session.flash = T('internal error: %s', e)
|
||||||
|
redirect(URL(args=request.args))
|
||||||
|
else:
|
||||||
|
return pack_exe(app, base, files)
|
||||||
|
|
||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
|
|
||||||
@@ -456,9 +495,15 @@ def cleanup():
|
|||||||
|
|
||||||
def compile_app():
|
def compile_app():
|
||||||
app = get_app()
|
app = get_app()
|
||||||
c = app_compile(app, request)
|
c = app_compile(app, request,
|
||||||
|
skip_failed_views=(request.args(1) == 'skip_failed_views'))
|
||||||
if not c:
|
if not c:
|
||||||
session.flash = T('application compiled')
|
session.flash = T('application compiled')
|
||||||
|
elif isinstance(c, list):
|
||||||
|
session.flash = DIV(*[T('application compiled'), BR(), BR(),
|
||||||
|
T('WARNING: The following views could not be compiled:'), BR()] +
|
||||||
|
[CAT(BR(), view) for view in c] +
|
||||||
|
[BR(), BR(), T('DO NOT use the "Pack compiled" feature.')])
|
||||||
else:
|
else:
|
||||||
session.flash = DIV(T('Cannot compile: there are errors in your app:'),
|
session.flash = DIV(T('Cannot compile: there are errors in your app:'),
|
||||||
CODE(c))
|
CODE(c))
|
||||||
@@ -499,8 +544,8 @@ def delete():
|
|||||||
redirect(URL(sender, anchor=request.vars.id2))
|
redirect(URL(sender, anchor=request.vars.id2))
|
||||||
return dict(dialog=dialog, filename=filename)
|
return dict(dialog=dialog, filename=filename)
|
||||||
|
|
||||||
|
|
||||||
def enable():
|
def enable():
|
||||||
|
if not URL.verify(request, hmac_key=session.hmac_key): raise HTTP(401)
|
||||||
app = get_app()
|
app = get_app()
|
||||||
filename = os.path.join(apath(app, r=request), 'DISABLED')
|
filename = os.path.join(apath(app, r=request), 'DISABLED')
|
||||||
if is_gae:
|
if is_gae:
|
||||||
@@ -512,6 +557,7 @@ def enable():
|
|||||||
safe_open(filename, 'wb').write('disabled: True\ntime-disabled: %s' % request.now)
|
safe_open(filename, 'wb').write('disabled: True\ntime-disabled: %s' % request.now)
|
||||||
return SPAN(T('Enable'), _style='color:red')
|
return SPAN(T('Enable'), _style='color:red')
|
||||||
|
|
||||||
|
|
||||||
def peek():
|
def peek():
|
||||||
""" Visualize object code """
|
""" Visualize object code """
|
||||||
app = get_app(request.vars.app)
|
app = get_app(request.vars.app)
|
||||||
@@ -575,7 +621,7 @@ def edit():
|
|||||||
# Load json only if it is ajax edited...
|
# Load json only if it is ajax edited...
|
||||||
app = get_app(request.vars.app)
|
app = get_app(request.vars.app)
|
||||||
app_path = apath(app, r=request)
|
app_path = apath(app, r=request)
|
||||||
preferences={'theme':'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth':'4', 'indentwithtabs':'false', 'linenumbers':'true', 'highlightline':'true'}
|
preferences = {'theme': 'web2py', 'editor': 'default', 'closetag': 'true', 'codefolding': 'false', 'tabwidth': '4', 'indentwithtabs': 'false', 'linenumbers': 'true', 'highlightline': 'true'}
|
||||||
config = Config(os.path.join(request.folder, 'settings.cfg'),
|
config = Config(os.path.join(request.folder, 'settings.cfg'),
|
||||||
section='editor', default_values={})
|
section='editor', default_values={})
|
||||||
preferences.update(config.read())
|
preferences.update(config.read())
|
||||||
@@ -583,14 +629,14 @@ def edit():
|
|||||||
if not(request.ajax) and not(is_mobile):
|
if not(request.ajax) and not(is_mobile):
|
||||||
# return the scaffolding, the rest will be through ajax requests
|
# return the scaffolding, the rest will be through ajax requests
|
||||||
response.title = T('Editing %s') % app
|
response.title = T('Editing %s') % app
|
||||||
return response.render ('default/edit.html', dict(app=app, editor_settings=preferences))
|
return response.render('default/edit.html', dict(app=app, editor_settings=preferences))
|
||||||
|
|
||||||
# show settings tab and save prefernces
|
# show settings tab and save prefernces
|
||||||
if 'settings' in request.vars:
|
if 'settings' in request.vars:
|
||||||
if request.post_vars: #save new preferences
|
if request.post_vars: # save new preferences
|
||||||
post_vars = request.post_vars.items()
|
post_vars = request.post_vars.items()
|
||||||
# Since unchecked checkbox are not serialized, we must set them as false by hand to store the correct preference in the settings
|
# Since unchecked checkbox are not serialized, we must set them as false by hand to store the correct preference in the settings
|
||||||
post_vars+= [(opt, 'false') for opt in preferences if opt not in request.post_vars ]
|
post_vars += [(opt, 'false') for opt in preferences if opt not in request.post_vars]
|
||||||
if config.save(post_vars):
|
if config.save(post_vars):
|
||||||
response.headers["web2py-component-flash"] = T('Preferences saved correctly')
|
response.headers["web2py-component-flash"] = T('Preferences saved correctly')
|
||||||
else:
|
else:
|
||||||
@@ -598,8 +644,8 @@ def edit():
|
|||||||
response.headers["web2py-component-command"] = "update_editor(%s);$('a[href=#editor_settings] button.close').click();" % response.json(config.read())
|
response.headers["web2py-component-command"] = "update_editor(%s);$('a[href=#editor_settings] button.close').click();" % response.json(config.read())
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
details = {'realfilename':'settings', 'filename':'settings', 'id':'editor_settings', 'force': False}
|
details = {'realfilename': 'settings', 'filename': 'settings', 'id': 'editor_settings', 'force': False}
|
||||||
details['plain_html'] = response.render('default/editor_settings.html', {'editor_settings':preferences})
|
details['plain_html'] = response.render('default/editor_settings.html', {'editor_settings': preferences})
|
||||||
return response.json(details)
|
return response.json(details)
|
||||||
|
|
||||||
""" File edit handler """
|
""" File edit handler """
|
||||||
@@ -706,7 +752,7 @@ def edit():
|
|||||||
B(ex_name), ' ' + T('at line %s', e.lineno),
|
B(ex_name), ' ' + T('at line %s', e.lineno),
|
||||||
offset and ' ' +
|
offset and ' ' +
|
||||||
T('at char %s', offset) or '',
|
T('at char %s', offset) or '',
|
||||||
PRE(str(e)))
|
PRE(repr(e)))
|
||||||
if data_or_revert and request.args[1] == 'modules':
|
if data_or_revert and request.args[1] == 'modules':
|
||||||
# Lets try to reload the modules
|
# Lets try to reload the modules
|
||||||
try:
|
try:
|
||||||
@@ -717,7 +763,7 @@ def edit():
|
|||||||
% (request.args[0], mopath)])
|
% (request.args[0], mopath)])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
response.flash = DIV(
|
response.flash = DIV(
|
||||||
T('failed to reload module because:'), PRE(str(e)))
|
T('failed to reload module because:'), PRE(repr(e)))
|
||||||
|
|
||||||
edit_controller = None
|
edit_controller = None
|
||||||
editviewlinks = None
|
editviewlinks = None
|
||||||
@@ -730,8 +776,8 @@ def edit():
|
|||||||
view = request.args[3].replace('.html', '')
|
view = request.args[3].replace('.html', '')
|
||||||
view_link = URL(request.args[0], request.args[2], view)
|
view_link = URL(request.args[0], request.args[2], view)
|
||||||
elif filetype == 'python' and request.args[1] == 'controllers':
|
elif filetype == 'python' and request.args[1] == 'controllers':
|
||||||
## it's a controller file.
|
# it's a controller file.
|
||||||
## Create links to all of the associated view files.
|
# Create links to all of the associated view files.
|
||||||
app = get_app()
|
app = get_app()
|
||||||
viewname = os.path.splitext(request.args[2])[0]
|
viewname = os.path.splitext(request.args[2])[0]
|
||||||
viewpath = os.path.join(app, 'views', viewname)
|
viewpath = os.path.join(app, 'views', viewname)
|
||||||
@@ -744,7 +790,7 @@ def edit():
|
|||||||
viewlist.append(aviewpath + '.html')
|
viewlist.append(aviewpath + '.html')
|
||||||
if len(viewlist):
|
if len(viewlist):
|
||||||
editviewlinks = []
|
editviewlinks = []
|
||||||
for v in viewlist:
|
for v in sorted(viewlist):
|
||||||
vf = os.path.split(v)[-1]
|
vf = os.path.split(v)[-1]
|
||||||
vargs = "/".join([viewpath.replace(os.sep, "/"), vf])
|
vargs = "/".join([viewpath.replace(os.sep, "/"), vf])
|
||||||
editviewlinks.append(A(vf.split(".")[0],
|
editviewlinks.append(A(vf.split(".")[0],
|
||||||
@@ -754,6 +800,7 @@ def edit():
|
|||||||
if len(request.args) > 2 and request.args[1] == 'controllers':
|
if len(request.args) > 2 and request.args[1] == 'controllers':
|
||||||
controller = (request.args[2])[:-3]
|
controller = (request.args[2])[:-3]
|
||||||
functions = find_exposed_functions(data)
|
functions = find_exposed_functions(data)
|
||||||
|
functions = functions and sorted(functions) or []
|
||||||
else:
|
else:
|
||||||
(controller, functions) = (None, None)
|
(controller, functions) = (None, None)
|
||||||
|
|
||||||
@@ -761,22 +808,22 @@ def edit():
|
|||||||
return response.json({'file_hash': file_hash, 'saved_on': saved_on, 'functions': functions, 'controller': controller, 'application': request.args[0], 'highlight': highlight})
|
return response.json({'file_hash': file_hash, 'saved_on': saved_on, 'functions': functions, 'controller': controller, 'application': request.args[0], 'highlight': highlight})
|
||||||
else:
|
else:
|
||||||
file_details = dict(app=request.args[0],
|
file_details = dict(app=request.args[0],
|
||||||
lineno=request.vars.lineno or 1,
|
lineno=request.vars.lineno or 1,
|
||||||
editor_settings=preferences,
|
editor_settings=preferences,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
realfilename=realfilename,
|
realfilename=realfilename,
|
||||||
filetype=filetype,
|
filetype=filetype,
|
||||||
data=data,
|
data=data,
|
||||||
edit_controller=edit_controller,
|
edit_controller=edit_controller,
|
||||||
file_hash=file_hash,
|
file_hash=file_hash,
|
||||||
saved_on=saved_on,
|
saved_on=saved_on,
|
||||||
controller=controller,
|
controller=controller,
|
||||||
functions=functions,
|
functions=functions,
|
||||||
view_link=view_link,
|
view_link=view_link,
|
||||||
editviewlinks=editviewlinks,
|
editviewlinks=editviewlinks,
|
||||||
id=IS_SLUG()(filename)[0],
|
id=IS_SLUG()(filename)[0],
|
||||||
force= True if (request.vars.restore or
|
force=True if (request.vars.restore or
|
||||||
request.vars.revert) else False)
|
request.vars.revert) else False)
|
||||||
plain_html = response.render('default/edit_js.html', file_details)
|
plain_html = response.render('default/edit_js.html', file_details)
|
||||||
file_details['plain_html'] = plain_html
|
file_details['plain_html'] = plain_html
|
||||||
if is_mobile:
|
if is_mobile:
|
||||||
@@ -785,14 +832,16 @@ def edit():
|
|||||||
else:
|
else:
|
||||||
return response.json(file_details)
|
return response.json(file_details)
|
||||||
|
|
||||||
|
|
||||||
def todolist():
|
def todolist():
|
||||||
""" Returns all TODO of the requested app
|
""" Returns all TODO of the requested app
|
||||||
"""
|
"""
|
||||||
app = request.vars.app or ''
|
app = request.vars.app or ''
|
||||||
app_path = apath('%(app)s' % {'app':app}, r=request)
|
app_path = apath('%(app)s' % {'app': app}, r=request)
|
||||||
dirs=['models', 'controllers', 'modules', 'private' ]
|
dirs = ['models', 'controllers', 'modules', 'private']
|
||||||
|
|
||||||
def listfiles(app, dir, regexp='.*\.py$'):
|
def listfiles(app, dir, regexp='.*\.py$'):
|
||||||
files = sorted( listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp))
|
files = sorted(listdir(apath('%(app)s/%(dir)s/' % {'app': app, 'dir': dir}, r=request), regexp))
|
||||||
files = [x.replace(os.path.sep, '/') for x in files if not x.endswith('.bak')]
|
files = [x.replace(os.path.sep, '/') for x in files if not x.endswith('.bak')]
|
||||||
return files
|
return files
|
||||||
|
|
||||||
@@ -803,17 +852,18 @@ def todolist():
|
|||||||
for d in dirs:
|
for d in dirs:
|
||||||
for f in listfiles(app, d):
|
for f in listfiles(app, d):
|
||||||
matches = []
|
matches = []
|
||||||
filename= apath(os.path.join(app, d, f), r=request)
|
filename = apath(os.path.join(app, d, f), r=request)
|
||||||
with open(filename, 'r') as f_s:
|
with open(filename, 'r') as f_s:
|
||||||
src = f_s.read()
|
src = f_s.read()
|
||||||
for m in regex.finditer(src):
|
for m in regex.finditer(src):
|
||||||
start = m.start()
|
start = m.start()
|
||||||
lineno = src.count('\n', 0, start) + 1
|
lineno = src.count('\n', 0, start) + 1
|
||||||
matches.append({'text':m.group(0), 'lineno':lineno})
|
matches.append({'text': m.group(0), 'lineno': lineno})
|
||||||
if len(matches) != 0:
|
if len(matches) != 0:
|
||||||
output.append({'filename':f,'matches':matches, 'dir':d})
|
output.append({'filename': f, 'matches': matches, 'dir': d})
|
||||||
|
|
||||||
|
return {'todo': output, 'app': app}
|
||||||
|
|
||||||
return {'todo':output, 'app': app}
|
|
||||||
|
|
||||||
def editor_sessions():
|
def editor_sessions():
|
||||||
config = Config(os.path.join(request.folder, 'settings.cfg'),
|
config = Config(os.path.join(request.folder, 'settings.cfg'),
|
||||||
@@ -823,13 +873,14 @@ def editor_sessions():
|
|||||||
if request.vars.session_name and request.vars.files:
|
if request.vars.session_name and request.vars.files:
|
||||||
session_name = request.vars.session_name
|
session_name = request.vars.session_name
|
||||||
files = request.vars.files
|
files = request.vars.files
|
||||||
preferences.update({session_name:','.join(files)})
|
preferences.update({session_name: ','.join(files)})
|
||||||
if config.save(preferences.items()):
|
if config.save(preferences.items()):
|
||||||
response.headers["web2py-component-flash"] = T('Session saved correctly')
|
response.headers["web2py-component-flash"] = T('Session saved correctly')
|
||||||
else:
|
else:
|
||||||
response.headers["web2py-component-flash"] = T('Session saved on session only')
|
response.headers["web2py-component-flash"] = T('Session saved on session only')
|
||||||
|
|
||||||
return response.render('default/editor_sessions.html', {'editor_sessions':preferences})
|
return response.render('default/editor_sessions.html', {'editor_sessions': preferences})
|
||||||
|
|
||||||
|
|
||||||
def resolve():
|
def resolve():
|
||||||
"""
|
"""
|
||||||
@@ -866,13 +917,9 @@ def resolve():
|
|||||||
|
|
||||||
def getclass(item):
|
def getclass(item):
|
||||||
""" Determine item class """
|
""" Determine item class """
|
||||||
|
operators = {' ': 'normal', '+': 'plus', '-': 'minus'}
|
||||||
|
|
||||||
if item[0] == ' ':
|
return operators[item[0]]
|
||||||
return 'normal'
|
|
||||||
if item[0] == '+':
|
|
||||||
return 'plus'
|
|
||||||
if item[0] == '-':
|
|
||||||
return 'minus'
|
|
||||||
|
|
||||||
if request.vars:
|
if request.vars:
|
||||||
c = '\n'.join([item[2:].rstrip() for (i, item) in enumerate(d) if item[0]
|
c = '\n'.join([item[2:].rstrip() for (i, item) in enumerate(d) if item[0]
|
||||||
@@ -890,7 +937,7 @@ def resolve():
|
|||||||
diff = TABLE(*[TR(TD(gen_data(i, item)),
|
diff = TABLE(*[TR(TD(gen_data(i, item)),
|
||||||
TD(item[0]),
|
TD(item[0]),
|
||||||
TD(leading(item[2:]),
|
TD(leading(item[2:]),
|
||||||
TT(item[2:].rstrip())),
|
TT(item[2:].rstrip())),
|
||||||
_class=getclass(item))
|
_class=getclass(item))
|
||||||
for (i, item) in enumerate(d) if item[0] != '?'])
|
for (i, item) in enumerate(d) if item[0] != '?'])
|
||||||
|
|
||||||
@@ -937,11 +984,11 @@ def edit_language():
|
|||||||
|
|
||||||
new_row = DIV(LABEL(prefix, k, _style="font-weight:normal;"),
|
new_row = DIV(LABEL(prefix, k, _style="font-weight:normal;"),
|
||||||
CAT(elem, '\n', TAG.BUTTON(
|
CAT(elem, '\n', TAG.BUTTON(
|
||||||
T('delete'),
|
T('delete'),
|
||||||
_onclick='return delkey("%s")' % name,
|
_onclick='return delkey("%s")' % name,
|
||||||
_class='btn')), _id=name, _class='span6 well well-small')
|
_class='btn')), _id=name, _class='span6 well well-small')
|
||||||
|
|
||||||
rows.append(DIV(new_row,_class="row-fluid"))
|
rows.append(DIV(new_row, _class="row-fluid"))
|
||||||
rows.append(DIV(INPUT(_type='submit', _value=T('update'), _class="btn btn-primary"), _class='controls'))
|
rows.append(DIV(INPUT(_type='submit', _value=T('update'), _class="btn btn-primary"), _class='controls'))
|
||||||
form = FORM(*rows)
|
form = FORM(*rows)
|
||||||
if form.accepts(request.vars, keepvalues=True):
|
if form.accepts(request.vars, keepvalues=True):
|
||||||
@@ -1067,7 +1114,7 @@ def design():
|
|||||||
for c in controllers:
|
for c in controllers:
|
||||||
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
|
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
|
||||||
items = find_exposed_functions(data)
|
items = find_exposed_functions(data)
|
||||||
functions[c] = items
|
functions[c] = items and sorted(items) or []
|
||||||
|
|
||||||
# Get all views
|
# Get all views
|
||||||
views = sorted(
|
views = sorted(
|
||||||
@@ -1097,18 +1144,18 @@ def design():
|
|||||||
|
|
||||||
# Get all static files
|
# Get all static files
|
||||||
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
|
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
|
||||||
maxnum = MAXNFILES)
|
maxnum=MAXNFILES)
|
||||||
statics = [x.replace(os.path.sep, '/') for x in statics]
|
statics = [x.replace(os.path.sep, '/') for x in statics]
|
||||||
statics.sort()
|
statics.sort()
|
||||||
|
|
||||||
# Get all languages
|
# Get all languages
|
||||||
langpath = os.path.join(apath(app, r=request),'languages')
|
langpath = os.path.join(apath(app, r=request), 'languages')
|
||||||
languages = dict([(lang, info) for lang, info
|
languages = dict([(lang, info) for lang, info
|
||||||
in read_possible_languages(langpath).iteritems()
|
in read_possible_languages(langpath).iteritems()
|
||||||
if info[2] != 0]) # info[2] is langfile_mtime:
|
if info[2] != 0]) # info[2] is langfile_mtime:
|
||||||
# get only existed files
|
# get only existed files
|
||||||
|
|
||||||
#Get crontab
|
# Get crontab
|
||||||
cronfolder = apath('%s/cron' % app, r=request)
|
cronfolder = apath('%s/cron' % app, r=request)
|
||||||
crontab = apath('%s/cron/crontab' % app, r=request)
|
crontab = apath('%s/cron/crontab' % app, r=request)
|
||||||
if not is_gae:
|
if not is_gae:
|
||||||
@@ -1205,7 +1252,7 @@ def plugin():
|
|||||||
for c in controllers:
|
for c in controllers:
|
||||||
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
|
data = safe_read(apath('%s/controllers/%s' % (app, c), r=request))
|
||||||
items = find_exposed_functions(data)
|
items = find_exposed_functions(data)
|
||||||
functions[c] = items
|
functions[c] = items and sorted(items) or []
|
||||||
|
|
||||||
# Get all views
|
# Get all views
|
||||||
views = sorted(
|
views = sorted(
|
||||||
@@ -1234,7 +1281,7 @@ def plugin():
|
|||||||
|
|
||||||
# Get all static files
|
# Get all static files
|
||||||
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
|
statics = listdir(apath('%s/static/' % app, r=request), '[^\.#].*',
|
||||||
maxnum = MAXNFILES)
|
maxnum=MAXNFILES)
|
||||||
statics = [x.replace(os.path.sep, '/') for x in statics]
|
statics = [x.replace(os.path.sep, '/') for x in statics]
|
||||||
statics.sort()
|
statics.sort()
|
||||||
|
|
||||||
@@ -1242,9 +1289,9 @@ def plugin():
|
|||||||
languages = sorted([lang + '.py' for lang, info in
|
languages = sorted([lang + '.py' for lang, info in
|
||||||
T.get_possible_languages_info().iteritems()
|
T.get_possible_languages_info().iteritems()
|
||||||
if info[2] != 0]) # info[2] is langfile_mtime:
|
if info[2] != 0]) # info[2] is langfile_mtime:
|
||||||
# get only existed files
|
# get only existed files
|
||||||
|
|
||||||
#Get crontab
|
# Get crontab
|
||||||
crontab = apath('%s/cron/crontab' % app, r=request)
|
crontab = apath('%s/cron/crontab' % app, r=request)
|
||||||
if not os.path.exists(crontab):
|
if not os.path.exists(crontab):
|
||||||
safe_write(crontab, '#crontab')
|
safe_write(crontab, '#crontab')
|
||||||
@@ -1267,6 +1314,7 @@ def plugin():
|
|||||||
languages=languages,
|
languages=languages,
|
||||||
crontab=crontab)
|
crontab=crontab)
|
||||||
|
|
||||||
|
|
||||||
def create_file():
|
def create_file():
|
||||||
""" Create files handler """
|
""" Create files handler """
|
||||||
if request.vars and not request.vars.token == session.token:
|
if request.vars and not request.vars.token == session.token:
|
||||||
@@ -1278,7 +1326,7 @@ def create_file():
|
|||||||
path = abspath(request.vars.location)
|
path = abspath(request.vars.location)
|
||||||
else:
|
else:
|
||||||
if request.vars.dir:
|
if request.vars.dir:
|
||||||
request.vars.location += request.vars.dir + '/'
|
request.vars.location += request.vars.dir + '/'
|
||||||
app = get_app(name=request.vars.location.split('/')[0])
|
app = get_app(name=request.vars.location.split('/')[0])
|
||||||
path = apath(request.vars.location, r=request)
|
path = apath(request.vars.location, r=request)
|
||||||
filename = re.sub('[^\w./-]+', '_', request.vars.filename)
|
filename = re.sub('[^\w./-]+', '_', request.vars.filename)
|
||||||
@@ -1388,7 +1436,7 @@ def create_file():
|
|||||||
|
|
||||||
elif (path[-8:] == '/static/') or (path[-9:] == '/private/'):
|
elif (path[-8:] == '/static/') or (path[-9:] == '/private/'):
|
||||||
if (request.vars.plugin and
|
if (request.vars.plugin and
|
||||||
not filename.startswith('plugin_%s/' % request.vars.plugin)):
|
not filename.startswith('plugin_%s/' % request.vars.plugin)):
|
||||||
filename = 'plugin_%s/%s' % (request.vars.plugin, filename)
|
filename = 'plugin_%s/%s' % (request.vars.plugin, filename)
|
||||||
text = ''
|
text = ''
|
||||||
|
|
||||||
@@ -1408,17 +1456,17 @@ def create_file():
|
|||||||
log_progress(app, 'CREATE', filename)
|
log_progress(app, 'CREATE', filename)
|
||||||
if request.vars.dir:
|
if request.vars.dir:
|
||||||
result = T('file "%(filename)s" created',
|
result = T('file "%(filename)s" created',
|
||||||
dict(filename=full_filename[len(path):]))
|
dict(filename=full_filename[len(path):]))
|
||||||
else:
|
else:
|
||||||
session.flash = T('file "%(filename)s" created',
|
session.flash = T('file "%(filename)s" created',
|
||||||
dict(filename=full_filename[len(path):]))
|
dict(filename=full_filename[len(path):]))
|
||||||
vars = {}
|
vars = {}
|
||||||
if request.vars.id:
|
if request.vars.id:
|
||||||
vars['id'] = request.vars.id
|
vars['id'] = request.vars.id
|
||||||
if request.vars.app:
|
if request.vars.app:
|
||||||
vars['app'] = request.vars.app
|
vars['app'] = request.vars.app
|
||||||
redirect(URL('edit',
|
redirect(URL('edit',
|
||||||
args=[os.path.join(request.vars.location, filename)], vars=vars))
|
args=[os.path.join(request.vars.location, filename)], vars=vars))
|
||||||
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
if not isinstance(e, HTTP):
|
if not isinstance(e, HTTP):
|
||||||
@@ -1429,7 +1477,7 @@ def create_file():
|
|||||||
response.headers['web2py-component-content'] = 'append'
|
response.headers['web2py-component-content'] = 'append'
|
||||||
response.headers['web2py-component-command'] = "%s %s %s" % (
|
response.headers['web2py-component-command'] = "%s %s %s" % (
|
||||||
"$.web2py.invalidate('#files_menu');",
|
"$.web2py.invalidate('#files_menu');",
|
||||||
"load_file('%s');" % URL('edit', args=[app,request.vars.dir,filename]),
|
"load_file('%s');" % URL('edit', args=[app, request.vars.dir, filename]),
|
||||||
"$.web2py.enableElement($('#form form').find($.web2py.formInputClickSelector));")
|
"$.web2py.enableElement($('#form form').find($.web2py.formInputClickSelector));")
|
||||||
return ''
|
return ''
|
||||||
else:
|
else:
|
||||||
@@ -1437,32 +1485,35 @@ def create_file():
|
|||||||
|
|
||||||
|
|
||||||
def listfiles(app, dir, regexp='.*\.py$'):
|
def listfiles(app, dir, regexp='.*\.py$'):
|
||||||
files = sorted(
|
files = sorted(
|
||||||
listdir(apath('%(app)s/%(dir)s/' % {'app':app, 'dir':dir}, r=request), regexp))
|
listdir(apath('%(app)s/%(dir)s/' % {'app': app, 'dir': dir}, r=request), regexp))
|
||||||
files = [x.replace('\\', '/') for x in files if not x.endswith('.bak')]
|
files = [x.replace('\\', '/') for x in files if not x.endswith('.bak')]
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def editfile(path, file, vars={}, app=None):
|
||||||
|
args = (path, file) if 'app' in vars else (app, path, file)
|
||||||
|
url = URL('edit', args=args, vars=vars)
|
||||||
|
return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;')
|
||||||
|
|
||||||
def editfile(path,file,vars={}, app = None):
|
|
||||||
args=(path,file) if 'app' in vars else (app,path,file)
|
|
||||||
url = URL('edit', args=args, vars=vars)
|
|
||||||
return A(file, _class='editor_filelink', _href=url, _style='word-wrap: nowrap;')
|
|
||||||
|
|
||||||
def files_menu():
|
def files_menu():
|
||||||
app = request.vars.app or 'welcome'
|
app = request.vars.app or 'welcome'
|
||||||
dirs=[{'name':'models', 'reg':'.*\.py$'},
|
dirs = [{'name': 'models', 'reg': '.*\.py$'},
|
||||||
{'name':'controllers', 'reg':'.*\.py$'},
|
{'name': 'controllers', 'reg': '.*\.py$'},
|
||||||
{'name':'views', 'reg':'[\w/\-]+(\.\w+)+$'},
|
{'name': 'views', 'reg': '[\w/\-]+(\.\w+)+$'},
|
||||||
{'name':'modules', 'reg':'.*\.py$'},
|
{'name': 'modules', 'reg': '.*\.py$'},
|
||||||
{'name':'static', 'reg': '[^\.#].*'},
|
{'name': 'static', 'reg': '[^\.#].*'},
|
||||||
{'name':'private', 'reg':'.*\.py$'}]
|
{'name': 'private', 'reg': '.*\.py$'}]
|
||||||
result_files = []
|
result_files = []
|
||||||
for dir in dirs:
|
for dir in dirs:
|
||||||
result_files.append(TAG[''](LI(dir['name'], _class="nav-header component", _onclick="collapse('" + dir['name'] + "_files');"),
|
result_files.append(TAG[''](LI(dir['name'], _class="nav-header component", _onclick="collapse('" + dir['name'] + "_files');"),
|
||||||
LI(UL(*[LI(editfile(dir['name'], f, dict(id=dir['name'] + f.replace('.','__')), app), _style="overflow:hidden", _id=dir['name']+"__"+f.replace('.','__'))
|
LI(UL(*[LI(editfile(dir['name'], f, dict(id=dir['name'] + f.replace('.', '__')), app), _style="overflow:hidden", _id=dir['name'] + "__" + f.replace('.', '__'))
|
||||||
for f in listfiles(app, dir['name'], regexp=dir['reg'])],
|
for f in listfiles(app, dir['name'], regexp=dir['reg'])],
|
||||||
_class="nav nav-list small-font"),
|
_class="nav nav-list small-font"),
|
||||||
_id=dir['name'] + '_files', _style="display: none;")))
|
_id=dir['name'] + '_files', _style="display: none;")))
|
||||||
return dict(result_files = result_files)
|
return dict(result_files=result_files)
|
||||||
|
|
||||||
|
|
||||||
def upload_file():
|
def upload_file():
|
||||||
""" File uploading handler """
|
""" File uploading handler """
|
||||||
@@ -1509,7 +1560,7 @@ def upload_file():
|
|||||||
if filename:
|
if filename:
|
||||||
d = dict(filename=filename[len(path):])
|
d = dict(filename=filename[len(path):])
|
||||||
else:
|
else:
|
||||||
d = dict(filename='unkown')
|
d = dict(filename='unknown')
|
||||||
session.flash = T('cannot upload file "%(filename)s"', d)
|
session.flash = T('cannot upload file "%(filename)s"', d)
|
||||||
|
|
||||||
redirect(request.vars.sender)
|
redirect(request.vars.sender)
|
||||||
@@ -1525,7 +1576,7 @@ def errors():
|
|||||||
app = get_app()
|
app = get_app()
|
||||||
if is_gae:
|
if is_gae:
|
||||||
method = 'dbold' if ('old' in
|
method = 'dbold' if ('old' in
|
||||||
(request.args(1) or '')) else 'dbnew'
|
(request.args(1) or '')) else 'dbnew'
|
||||||
else:
|
else:
|
||||||
method = request.args(1) or 'new'
|
method = request.args(1) or 'new'
|
||||||
db_ready = {}
|
db_ready = {}
|
||||||
@@ -1568,7 +1619,7 @@ def errors():
|
|||||||
hash2error[hash]['count'] += 1
|
hash2error[hash]['count'] += 1
|
||||||
except KeyError:
|
except KeyError:
|
||||||
error_lines = error['traceback'].split("\n")
|
error_lines = error['traceback'].split("\n")
|
||||||
last_line = error_lines[-2] if len(error_lines)>1 else 'unknown'
|
last_line = error_lines[-2] if len(error_lines) > 1 else 'unknown'
|
||||||
error_causer = os.path.split(error['layer'])[1]
|
error_causer = os.path.split(error['layer'])[1]
|
||||||
hash2error[hash] = dict(count=1, pickel=error,
|
hash2error[hash] = dict(count=1, pickel=error,
|
||||||
causer=error_causer,
|
causer=error_causer,
|
||||||
@@ -1607,9 +1658,9 @@ def errors():
|
|||||||
last_line = error_lines[-2]
|
last_line = error_lines[-2]
|
||||||
error_causer = os.path.split(error['layer'])[1]
|
error_causer = os.path.split(error['layer'])[1]
|
||||||
hash2error[hash] = dict(count=1,
|
hash2error[hash] = dict(count=1,
|
||||||
pickel=error, causer=error_causer,
|
pickel=error, causer=error_causer,
|
||||||
last_line=last_line, hash=hash,
|
last_line=last_line, hash=hash,
|
||||||
ticket=fn.ticket_id)
|
ticket=fn.ticket_id)
|
||||||
except AttributeError, e:
|
except AttributeError, e:
|
||||||
tk_db(tk_table.id == fn.id).delete()
|
tk_db(tk_table.id == fn.id).delete()
|
||||||
tk_db.commit()
|
tk_db.commit()
|
||||||
@@ -1626,11 +1677,11 @@ def errors():
|
|||||||
tk_db(tk_table.ticket_id == item[7:]).delete()
|
tk_db(tk_table.ticket_id == item[7:]).delete()
|
||||||
tk_db.commit()
|
tk_db.commit()
|
||||||
tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id,
|
tickets_ = tk_db(tk_table.id > 0).select(tk_table.ticket_id,
|
||||||
tk_table.created_datetime,
|
tk_table.created_datetime,
|
||||||
orderby=~tk_table.created_datetime)
|
orderby=~tk_table.created_datetime)
|
||||||
tickets = [row.ticket_id for row in tickets_]
|
tickets = [row.ticket_id for row in tickets_]
|
||||||
times = dict([(row.ticket_id, row.created_datetime) for
|
times = dict([(row.ticket_id, row.created_datetime) for
|
||||||
row in tickets_])
|
row in tickets_])
|
||||||
return dict(app=app, tickets=tickets, method=method,
|
return dict(app=app, tickets=tickets, method=method,
|
||||||
times=times, db_ready=db_ready)
|
times=times, db_ready=db_ready)
|
||||||
|
|
||||||
@@ -1690,7 +1741,7 @@ def make_link(path):
|
|||||||
if ext.lower() == editable[key] and check_extension:
|
if ext.lower() == editable[key] and check_extension:
|
||||||
return A('"' + tryFile + '"',
|
return A('"' + tryFile + '"',
|
||||||
_href=URL(r=request,
|
_href=URL(r=request,
|
||||||
f='edit/%s/%s/%s' % (app, key, filename))).xml()
|
f='edit/%s/%s/%s' % (app, key, filename))).xml()
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
@@ -1836,7 +1887,7 @@ def bulk_register():
|
|||||||
redirect(URL('site'))
|
redirect(URL('site'))
|
||||||
return locals()
|
return locals()
|
||||||
|
|
||||||
### Begin experimental stuff need fixes:
|
# Begin experimental stuff need fixes:
|
||||||
# 1) should run in its own process - cannot os.chdir
|
# 1) should run in its own process - cannot os.chdir
|
||||||
# 2) should not prompt user at console
|
# 2) should not prompt user at console
|
||||||
# 3) should give option to force commit and not reuqire manual merge
|
# 3) should give option to force commit and not reuqire manual merge
|
||||||
@@ -1903,6 +1954,7 @@ def git_push():
|
|||||||
redirect(URL('site'))
|
redirect(URL('site'))
|
||||||
return dict(app=app, form=form)
|
return dict(app=app, form=form)
|
||||||
|
|
||||||
|
|
||||||
def plugins():
|
def plugins():
|
||||||
app = request.args(0)
|
app = request.args(0)
|
||||||
from serializers import loads_json
|
from serializers import loads_json
|
||||||
@@ -1917,12 +1969,16 @@ def plugins():
|
|||||||
session.plugins = []
|
session.plugins = []
|
||||||
return dict(plugins=session.plugins["results"], app=request.args(0))
|
return dict(plugins=session.plugins["results"], app=request.args(0))
|
||||||
|
|
||||||
|
|
||||||
def install_plugin():
|
def install_plugin():
|
||||||
app = request.args(0)
|
app = request.args(0)
|
||||||
source = request.vars.source
|
source = request.vars.source
|
||||||
plugin = request.vars.plugin
|
plugin = request.vars.plugin
|
||||||
if not (source and app):
|
if not (source and app):
|
||||||
raise HTTP(500, T("Invalid request"))
|
raise HTTP(500, T("Invalid request"))
|
||||||
|
# make sure no XSS attacks in source
|
||||||
|
if not source.lower().split('://')[0] in ('http','https'):
|
||||||
|
raise HTTP(500, T("Invalid request"))
|
||||||
form = SQLFORM.factory()
|
form = SQLFORM.factory()
|
||||||
result = None
|
result = None
|
||||||
if form.process().accepted:
|
if form.process().accepted:
|
||||||
@@ -1938,5 +1994,5 @@ def install_plugin():
|
|||||||
else:
|
else:
|
||||||
session.flash = \
|
session.flash = \
|
||||||
T('unable to install plugin "%s"', filename)
|
T('unable to install plugin "%s"', filename)
|
||||||
redirect(URL(f="plugins", args=[app,]))
|
redirect(URL(f="plugins", args=[app, ]))
|
||||||
return dict(form=form, app=app, plugin=plugin, source=source)
|
return dict(form=form, app=app, plugin=plugin, source=source)
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import base64
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import gzip
|
||||||
|
import tarfile
|
||||||
|
try:
|
||||||
|
from cStringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from StringIO import StringIO
|
||||||
|
from xmlrpclib import ProtocolError
|
||||||
|
from gluon.contrib.simplejsonrpc import ServerProxy
|
||||||
|
|
||||||
|
|
||||||
|
def deploy():
|
||||||
|
response.title = T('Deploy to pythonanywhere')
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def create_account():
|
||||||
|
""" Create a PythonAnywhere account """
|
||||||
|
if not request.vars:
|
||||||
|
raise HTTP(400)
|
||||||
|
|
||||||
|
if request.vars.username and request.vars.web2py_admin_password:
|
||||||
|
# Check if web2py is already there otherwise we get an error 500 too.
|
||||||
|
client = ServerProxy('https://%(username)s:%(web2py_admin_password)s@%(username)s.pythonanywhere.com/admin/webservices/call/jsonrpc' % request.vars)
|
||||||
|
try:
|
||||||
|
if client.login() is True:
|
||||||
|
return response.json({'status': 'ok'})
|
||||||
|
except ProtocolError as error:
|
||||||
|
pass
|
||||||
|
|
||||||
|
import urllib, urllib2
|
||||||
|
url = 'https://www.pythonanywhere.com/api/web2py/create_account'
|
||||||
|
data = urllib.urlencode(request.vars)
|
||||||
|
req = urllib2.Request(url, data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
reply = urllib2.urlopen(req)
|
||||||
|
except urllib2.HTTPError as error:
|
||||||
|
if error.code == 400:
|
||||||
|
reply = error
|
||||||
|
elif error.code == 500:
|
||||||
|
return response.json({'status':'error', 'errors':{'username': ['An App other than web2py is installed in the domain %(username)s.pythonanywhere.com' % request.vars]}})
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
response.headers['Content-Type'] = 'application/json'
|
||||||
|
return reply.read()
|
||||||
|
|
||||||
|
|
||||||
|
def list_apps():
|
||||||
|
""" Get a list of apps both remote and local """
|
||||||
|
if not request.vars.username or not request.vars.password:
|
||||||
|
raise HTTP(400)
|
||||||
|
client = ServerProxy('https://%(username)s:%(password)s@%(username)s.pythonanywhere.com/admin/webservices/call/jsonrpc' % request.vars)
|
||||||
|
regex = re.compile('^\w+$')
|
||||||
|
local = [f for f in os.listdir(apath(r=request)) if regex.match(f)]
|
||||||
|
try:
|
||||||
|
pythonanywhere = client.list_apps()
|
||||||
|
except ProtocolError as error:
|
||||||
|
raise HTTP(error.errcode)
|
||||||
|
return response.json({'local': local, 'pythonanywhere': pythonanywhere})
|
||||||
|
|
||||||
|
|
||||||
|
def bulk_install():
|
||||||
|
""" Install a list of apps """
|
||||||
|
|
||||||
|
def b64pack(app):
|
||||||
|
"""
|
||||||
|
Given an app's name, return the base64 representation of its packed version.
|
||||||
|
"""
|
||||||
|
folder = apath(app, r=request)
|
||||||
|
tmpfile = StringIO()
|
||||||
|
tar = tarfile.TarFile(fileobj=tmpfile, mode='w')
|
||||||
|
try:
|
||||||
|
filenames = listdir(folder, '^[\w\.\-]+$', add_dirs=True,
|
||||||
|
exclude_content_from=['cache', 'sessions', 'errors'])
|
||||||
|
for fname in filenames:
|
||||||
|
tar.add(os.path.join(folder, fname), fname, False)
|
||||||
|
finally:
|
||||||
|
tar.close()
|
||||||
|
tmpfile.seek(0)
|
||||||
|
gzfile = StringIO()
|
||||||
|
w2pfp = gzip.GzipFile(fileobj=gzfile, mode='wb')
|
||||||
|
w2pfp.write(tmpfile.read())
|
||||||
|
w2pfp.close()
|
||||||
|
gzfile.seek(0)
|
||||||
|
return base64.b64encode(gzfile.read())
|
||||||
|
|
||||||
|
request.vars.apps = request.vars['apps[]']
|
||||||
|
if not request.vars.apps or not request.vars.username or not request.vars.password:
|
||||||
|
raise HTTP(400)
|
||||||
|
if not isinstance(request.vars.apps, list):
|
||||||
|
request.vars.apps = [request.vars.apps] # Only one app selected
|
||||||
|
|
||||||
|
client = ServerProxy('https://%(username)s:%(password)s@%(username)s.pythonanywhere.com/admin/webservices/call/jsonrpc' % request.vars)
|
||||||
|
|
||||||
|
for app in request.vars.apps:
|
||||||
|
try:
|
||||||
|
client.install(app, app+'.w2p', b64pack(app))
|
||||||
|
except ProtocolError as error:
|
||||||
|
raise HTTP(error.errcode)
|
||||||
|
|
||||||
|
return response.json({'status': 'ok'})
|
||||||
+340
-104
@@ -2,89 +2,131 @@
|
|||||||
{
|
{
|
||||||
'!langcode!': 'cs-cz',
|
'!langcode!': 'cs-cz',
|
||||||
'!langname!': 'čeština',
|
'!langname!': 'čeština',
|
||||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
|
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". (Avšak výsledky databázového JOINu nelze mazat ani upravovat.)',
|
||||||
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
|
'"User Exception" debug mode. ': '"Uživatelská výjimka", Debug mód.',
|
||||||
|
'"User Exception" debug mode. An error ticket could be issued!': '"Uživatelská výjimka", Debug mód. Může být vystaven chybový tiket.',
|
||||||
'%%{Row} in Table': '%%{řádek} v tabulce',
|
'%%{Row} in Table': '%%{řádek} v tabulce',
|
||||||
'%%{Row} selected': 'označených %%{řádek}',
|
'%%{Row} selected': 'označených %%{řádek}',
|
||||||
|
'%s': '%s',
|
||||||
'%s %%{row} deleted': '%s smazaných %%{záznam}',
|
'%s %%{row} deleted': '%s smazaných %%{záznam}',
|
||||||
'%s %%{row} updated': '%s upravených %%{záznam}',
|
'%s %%{row} updated': '%s upravených %%{záznam}',
|
||||||
'%s selected': '%s označených',
|
'%s selected': '%s označených',
|
||||||
|
'%s students registered': '%s studentů registrováno',
|
||||||
'%Y-%m-%d': '%d.%m.%Y',
|
'%Y-%m-%d': '%d.%m.%Y',
|
||||||
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
|
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
|
||||||
'(requires internet access)': '(vyžaduje připojení k internetu)',
|
'(requires internet access)': '(vyžaduje připojení k internetu)',
|
||||||
'(requires internet access, experimental)': '(requires internet access, experimental)',
|
'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)',
|
||||||
'(something like "it-it")': '(například "cs-cs")',
|
'(something like "it-it")': '(například "cs-cs")',
|
||||||
|
'(version %s)': '(verze %s)',
|
||||||
|
'?': '?',
|
||||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
|
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
|
||||||
|
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
|
||||||
'@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}',
|
'@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}',
|
||||||
|
'Abort': 'Ukončit',
|
||||||
'About': 'O programu',
|
'About': 'O programu',
|
||||||
'About application': 'O aplikaci',
|
'About application': 'O aplikaci',
|
||||||
|
'Accept Terms': 'Souhlasit s podmínkami',
|
||||||
'Access Control': 'Řízení přístupu',
|
'Access Control': 'Řízení přístupu',
|
||||||
'Add breakpoint': 'Přidat bod přerušení',
|
'Add breakpoint': 'Přidat bod přerušení',
|
||||||
'Additional code for your application': 'Další kód pro Vaši aplikaci',
|
'Additional code for your application': 'Další kód pro Vaši aplikaci (pro příkaz import). Neběží ve specifickém režimu ani ve vláknech jako model/kontrolér/šablona, ale jako standardní python moduly. Ty tedy můžete umístit sem (pouze pro tuto aplikaci) nebo používat systémově dostupné.',
|
||||||
'Admin design page': 'Admin design page',
|
'Admin design page': 'Admin design stránka',
|
||||||
|
'admin disabled because no admin password': 'admin je zakázán, protože chybí heslo administrátora',
|
||||||
|
'admin disabled because not supported on google app engine': 'admin je zakázán kvůli chybějící podpoře na Google App Engine',
|
||||||
|
'admin disabled because too many invalid login attempts': 'Admin je zakázán po příliš mnoha nesprávných pokusech o přihlášení',
|
||||||
|
'admin disabled because unable to access password file': 'Admin je zakázán, protože nelze číst soubor s heslem',
|
||||||
|
'Admin is disabled because insecure channel': 'Admin je zakázán na nezabezpečeném připojení',
|
||||||
'Admin language': 'jazyk rozhraní',
|
'Admin language': 'jazyk rozhraní',
|
||||||
|
'Admin versioning page': 'Admin verzovací stránka',
|
||||||
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
|
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
|
||||||
'Administrative Interface': 'Administrátorské rozhraní',
|
'Administrative Interface': 'Administrátorské rozhraní',
|
||||||
'administrative interface': 'rozhraní pro správu',
|
'administrative interface': 'rozhraní pro správu',
|
||||||
'Administrator Password:': 'Administrátorské heslo:',
|
'Administrator Password:': 'Administrátorské heslo:',
|
||||||
'Ajax Recipes': 'Recepty s ajaxem',
|
'Ajax Recipes': 'Recepty s ajaxem',
|
||||||
'An error occured, please %s the page': 'An error occured, please %s the page',
|
'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku',
|
||||||
'and rename it:': 'a přejmenovat na:',
|
'and rename it:': 'a přejmenovat na:',
|
||||||
|
'App does not exist or you are not authorized': 'Aplikace neexistuje nebo vám chybí oprávnění',
|
||||||
'appadmin': 'appadmin',
|
'appadmin': 'appadmin',
|
||||||
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
|
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
|
||||||
'Application': 'Application',
|
'Application': 'Aplikace',
|
||||||
'application "%s" uninstalled': 'application "%s" odinstalována',
|
'application "%s" uninstalled': 'application "%s" odinstalována',
|
||||||
|
'Application cannot be generated in demo mode': 'Aplikace nemůže být vytvořena v demo módu',
|
||||||
'application compiled': 'aplikace zkompilována',
|
'application compiled': 'aplikace zkompilována',
|
||||||
|
'Application exists already': 'Aplikace již existuje',
|
||||||
|
'application is compiled and cannot be designed': 'aplikace je přeložena a nelze ji editovat',
|
||||||
'Application name:': 'Název aplikace:',
|
'Application name:': 'Název aplikace:',
|
||||||
|
'Application updated via git pull': 'Aplikace byla aktualizována pomocí git pull',
|
||||||
'are not used': 'nepoužita',
|
'are not used': 'nepoužita',
|
||||||
'are not used yet': 'ještě nepoužita',
|
'are not used yet': 'ještě nepoužita',
|
||||||
|
'Are you sure you want to delete file "%s"?': 'Skutečně chcete smazat soubor "%s"?',
|
||||||
|
'Are you sure you want to delete plugin "%s"?': 'Skutečně chcete smazat plugin "%s"?',
|
||||||
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
|
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
|
||||||
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
|
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
|
||||||
'arguments': 'arguments',
|
'Are you sure?': 'Jste si jist(a)?',
|
||||||
'at char %s': 'at char %s',
|
'arguments': 'argumenty',
|
||||||
'at line %s': 'at line %s',
|
'at char %s': 'na pozici znaku %s',
|
||||||
'ATTENTION:': 'ATTENTION:',
|
'at line %s': 'na řádku %s',
|
||||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
|
'ATTENTION:': 'POZOR:',
|
||||||
|
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'POZOR: Přihlášení vyžaduje zabezpečené (HTTPS) připojení nebo spouštění na localhost.',
|
||||||
|
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'POZOR: TESTOVÁNÍ NENÍ BEZPEČNÉ PŘI SOUBĚŽNÝCH VLÁKNECH. NESPOUŠTĚJ VÍCE TESTŮ SOUBĚŽNĚ.',
|
||||||
|
'ATTENTION: you cannot edit the running application!': 'POZOR: Nelze editovat spuštěnou aplikaci.',
|
||||||
|
'Autocomplete Python Code': 'Autocomplete Python kód',
|
||||||
'Available Databases and Tables': 'Dostupné databáze a tabulky',
|
'Available Databases and Tables': 'Dostupné databáze a tabulky',
|
||||||
'back': 'zpět',
|
'back': 'zpět',
|
||||||
'Back to wizard': 'Back to wizard',
|
'Back to the plugins list': 'Zpět do seznamu pluginů',
|
||||||
'Basics': 'Basics',
|
'Back to wizard': 'Zpátky do průvodce',
|
||||||
|
'Basics': 'Základy',
|
||||||
'Begin': 'Začít',
|
'Begin': 'Začít',
|
||||||
'breakpoint': 'bod přerušení',
|
'breakpoint': 'bod přerušení',
|
||||||
'Breakpoints': 'Body přerušení',
|
'Breakpoints': 'Body přerušení',
|
||||||
'breakpoints': 'body přerušení',
|
'breakpoints': 'body přerušení',
|
||||||
|
'Bulk Register': 'Hromadná registrace',
|
||||||
|
'Bulk Student Registration': 'Hromadná registrace studentů',
|
||||||
'Buy this book': 'Koupit web2py knihu',
|
'Buy this book': 'Koupit web2py knihu',
|
||||||
'Cache': 'Cache',
|
'Cache': 'Cache',
|
||||||
'cache': 'cache',
|
'cache': 'cache',
|
||||||
|
'Cache Cleared': 'Cache byla vymazána',
|
||||||
'Cache Keys': 'Klíče cache',
|
'Cache Keys': 'Klíče cache',
|
||||||
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
|
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
|
||||||
'can be a git repo': 'může to být git repo',
|
'can be a git repo': 'může to být git repo',
|
||||||
'Cancel': 'Storno',
|
'Cancel': 'Storno',
|
||||||
'Cannot be empty': 'Nemůže být prázdné',
|
'Cannot be empty': 'Nemůže být prázdné',
|
||||||
|
'Cannot compile: there are errors in your app:': 'Nelze zkompilovat: ve vaší aplikaci jsou chyby:',
|
||||||
|
'cannot create file': 'nelze vytvořit soubor',
|
||||||
|
'cannot upload file "%(filename)s"': 'nelze nahrát soubor "%(filename)s"',
|
||||||
'Change Admin Password': 'Změnit heslo pro správu',
|
'Change Admin Password': 'Změnit heslo pro správu',
|
||||||
'Change admin password': 'Změnit heslo pro správu aplikací',
|
'Change admin password': 'Změnit heslo pro správu aplikací',
|
||||||
|
'change editor settings': 'změnit nastavení editoru',
|
||||||
'Change password': 'Změna hesla',
|
'Change password': 'Změna hesla',
|
||||||
|
'Changelog': 'Žurnál změn',
|
||||||
'check all': 'vše označit',
|
'check all': 'vše označit',
|
||||||
'Check for upgrades': 'Zkusit aktualizovat',
|
'Check for upgrades': 'Zkusit aktualizovat',
|
||||||
'Check to delete': 'Označit ke smazání',
|
'Check to delete': 'Označit ke smazání',
|
||||||
'Check to delete:': 'Označit ke smazání:',
|
'Check to delete:': 'Označit ke smazání:',
|
||||||
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
|
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
|
||||||
'Clean': 'Pročistit',
|
'Clean': 'Pročistit',
|
||||||
|
'Clear': 'Inicializovat',
|
||||||
'Clear CACHE?': 'Vymazat CACHE?',
|
'Clear CACHE?': 'Vymazat CACHE?',
|
||||||
'Clear DISK': 'Vymazat DISK',
|
'Clear DISK': 'Vymazat DISK',
|
||||||
'Clear RAM': 'Vymazat RAM',
|
'Clear RAM': 'Vymazat RAM',
|
||||||
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
|
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
|
||||||
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
|
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
|
||||||
'Client IP': 'IP adresa klienta',
|
'Client IP': 'IP adresa klienta',
|
||||||
'code': 'code',
|
'code': 'kód',
|
||||||
'Code listing': 'Code listing',
|
'Code listing': 'Výpis kódu',
|
||||||
'collapse/expand all': 'vše sbalit/rozbalit',
|
'collapse/expand all': 'vše sbalit/rozbalit',
|
||||||
|
'Command': 'Příkaz',
|
||||||
|
'Comment:': 'Komentář:',
|
||||||
|
'Commit': 'Potvrdit',
|
||||||
|
'Commit form': 'Potvrdit formulář',
|
||||||
|
'Committed files': 'Potvrzené soubory',
|
||||||
'Community': 'Komunita',
|
'Community': 'Komunita',
|
||||||
'Compile': 'Zkompilovat',
|
'Compile': 'Zkompilovat',
|
||||||
|
'Compile (all or nothing)': 'Přeložit (vše nebo nic)',
|
||||||
|
'Compile (skip failed views)': 'Přeložit (přeskočit chybné šablony)',
|
||||||
'compiled application removed': 'zkompilovaná aplikace smazána',
|
'compiled application removed': 'zkompilovaná aplikace smazána',
|
||||||
'Components and Plugins': 'Komponenty a zásuvné moduly',
|
'Components and Plugins': 'Komponenty a zásuvné moduly',
|
||||||
'Condition': 'Podmínka',
|
'Condition': 'Podmínka',
|
||||||
'continue': 'continue',
|
'continue': 'pokračovat',
|
||||||
'Controller': 'Kontrolér (Controller)',
|
'Controller': 'Kontrolér (Controller)',
|
||||||
'Controllers': 'Kontroléry',
|
'Controllers': 'Kontroléry',
|
||||||
'controllers': 'kontroléry',
|
'controllers': 'kontroléry',
|
||||||
@@ -92,9 +134,12 @@
|
|||||||
'Count': 'Počet',
|
'Count': 'Počet',
|
||||||
'Create': 'Vytvořit',
|
'Create': 'Vytvořit',
|
||||||
'create file with filename:': 'vytvořit soubor s názvem:',
|
'create file with filename:': 'vytvořit soubor s názvem:',
|
||||||
|
'Create/Upload': 'Vytvořit/Nahrát',
|
||||||
'created by': 'vytvořil',
|
'created by': 'vytvořil',
|
||||||
'Created By': 'Vytvořeno - kým',
|
'Created By': 'Vytvořeno - kým',
|
||||||
|
'Created by:': 'Vytvořil:',
|
||||||
'Created On': 'Vytvořeno - kdy',
|
'Created On': 'Vytvořeno - kdy',
|
||||||
|
'Created on:': 'Vytvořeno:',
|
||||||
'crontab': 'crontab',
|
'crontab': 'crontab',
|
||||||
'Current request': 'Aktuální požadavek',
|
'Current request': 'Aktuální požadavek',
|
||||||
'Current response': 'Aktuální odpověď',
|
'Current response': 'Aktuální odpověď',
|
||||||
@@ -105,18 +150,19 @@
|
|||||||
'data uploaded': 'data nahrána',
|
'data uploaded': 'data nahrána',
|
||||||
'Database': 'Rozhraní databáze',
|
'Database': 'Rozhraní databáze',
|
||||||
'Database %s select': 'databáze %s výběr',
|
'Database %s select': 'databáze %s výběr',
|
||||||
'Database administration': 'Database administration',
|
'Database administration': 'Administrace databáze',
|
||||||
'database administration': 'správa databáze',
|
'database administration': 'správa databáze',
|
||||||
|
'Database Administration (appadmin)': 'Administrace databáze (appadmin)',
|
||||||
'Date and Time': 'Datum a čas',
|
'Date and Time': 'Datum a čas',
|
||||||
'day': 'den',
|
'day': 'den',
|
||||||
'db': 'db',
|
'db': 'db',
|
||||||
'DB Model': 'Databázový model',
|
'DB Model': 'Databázový model',
|
||||||
'Debug': 'Ladění',
|
'Debug': 'Ladění',
|
||||||
'defines tables': 'defines tables',
|
'defines tables': 'definuje tabulky',
|
||||||
'Delete': 'Smazat',
|
'Delete': 'Smazat',
|
||||||
'delete': 'smazat',
|
'delete': 'smazat',
|
||||||
'delete all checked': 'smazat vše označené',
|
'delete all checked': 'smazat vše označené',
|
||||||
'delete plugin': 'delete plugin',
|
'delete plugin': 'zrušit plugin',
|
||||||
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
|
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
|
||||||
'Delete:': 'Smazat:',
|
'Delete:': 'Smazat:',
|
||||||
'deleted after first hit': 'smazat po prvním dosažení',
|
'deleted after first hit': 'smazat po prvním dosažení',
|
||||||
@@ -124,166 +170,265 @@
|
|||||||
'Deploy': 'Nahrát',
|
'Deploy': 'Nahrát',
|
||||||
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
|
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
|
||||||
'Deploy to OpenShift': 'Nahrát na OpenShift',
|
'Deploy to OpenShift': 'Nahrát na OpenShift',
|
||||||
|
'Deploy to pythonanywhere': 'Nahrát na PythonAnywhere',
|
||||||
|
'Deploy to PythonAnywhere': 'Nahrát na PythonAnywhere',
|
||||||
|
'Deployment form': 'Forumlář pro deployment (nasazení)',
|
||||||
|
'Deployment Interface': 'Rozhraní pro deployment (nasazení)',
|
||||||
'Deployment Recipes': 'Postupy pro deployment',
|
'Deployment Recipes': 'Postupy pro deployment',
|
||||||
'Description': 'Popis',
|
'Description': 'Popis',
|
||||||
|
'Description:': 'Popis:',
|
||||||
'design': 'návrh',
|
'design': 'návrh',
|
||||||
'Detailed traceback description': 'Podrobný výpis prostředí',
|
'Detailed traceback description': 'Podrobný výpis prostředí',
|
||||||
'details': 'podrobnosti',
|
'details': 'podrobnosti',
|
||||||
'direction: ltr': 'směr: ltr',
|
'direction: ltr': 'směr: ltr',
|
||||||
|
'directory not found': 'adresář nebyl nalezen',
|
||||||
'Disable': 'Zablokovat',
|
'Disable': 'Zablokovat',
|
||||||
|
'Disabled': 'Blokováno',
|
||||||
|
'disabled in demo mode': 'zakázáno v demo módu',
|
||||||
|
'disabled in GAE mode': 'zakázáno v GAE módu',
|
||||||
|
'disabled in multi user mode': 'zakázáno ve víceuživatelském módu',
|
||||||
'DISK': 'DISK',
|
'DISK': 'DISK',
|
||||||
'Disk Cache Keys': 'Klíče diskové cache',
|
'Disk Cache Keys': 'Klíče diskové cache',
|
||||||
'Disk Cleared': 'Disk smazán',
|
'Disk Cleared': 'Disk smazán',
|
||||||
|
'Display line numbers': 'Zobrazit čísla řádků',
|
||||||
|
'DO NOT use the "Pack compiled" feature.': 'NEPOUŽÍVEJ vlastnost "Zabalit zkompilované".',
|
||||||
'docs': 'dokumentace',
|
'docs': 'dokumentace',
|
||||||
|
'Docs': 'Dokumentace',
|
||||||
'Documentation': 'Dokumentace',
|
'Documentation': 'Dokumentace',
|
||||||
"Don't know what to do?": 'Nevíte kudy kam?',
|
"Don't know what to do?": 'Nevíte kudy kam?',
|
||||||
'done!': 'hotovo!',
|
'done!': 'hotovo!',
|
||||||
|
'Downgrade': 'Downgrade (vrácení verze)',
|
||||||
'Download': 'Stáhnout',
|
'Download': 'Stáhnout',
|
||||||
|
'Download .w2p': 'Stažení .w2p',
|
||||||
|
'Download as .exe': 'Stáhnout jako .exe',
|
||||||
'download layouts': 'stáhnout moduly rozvržení stránky',
|
'download layouts': 'stáhnout moduly rozvržení stránky',
|
||||||
|
'Download layouts from repository': 'Stáhnout moduly rozvržení z repozitáře',
|
||||||
'download plugins': 'stáhnout zásuvné moduly',
|
'download plugins': 'stáhnout zásuvné moduly',
|
||||||
|
'Download plugins from repository': 'Stáhnout pluginy z repozitáře',
|
||||||
'E-mail': 'E-mail',
|
'E-mail': 'E-mail',
|
||||||
'Edit': 'Upravit',
|
'Edit': 'Upravit',
|
||||||
'edit all': 'edit all',
|
'edit all': 'editovat vše',
|
||||||
'Edit application': 'Správa aplikace',
|
'Edit application': 'Správa aplikace',
|
||||||
'edit controller': 'edit controller',
|
'edit controller': 'editovat controller',
|
||||||
|
'edit controller:': 'editovat kontrolér:',
|
||||||
'Edit current record': 'Upravit aktuální záznam',
|
'Edit current record': 'Upravit aktuální záznam',
|
||||||
'Edit Profile': 'Upravit profil',
|
'Edit Profile': 'Upravit profil',
|
||||||
'edit views:': 'upravit pohled:',
|
'edit views:': 'upravit šablonu (view):',
|
||||||
|
'Editing %s': 'Editace %s',
|
||||||
'Editing file "%s"': 'Úprava souboru "%s"',
|
'Editing file "%s"': 'Úprava souboru "%s"',
|
||||||
'Editing Language file': 'Úprava jazykového souboru',
|
'Editing Language file': 'Úprava jazykového souboru',
|
||||||
'Editing Plural Forms File': 'Editing Plural Forms File',
|
'Editing Plural Forms File': 'Editování souboru množných čísel',
|
||||||
|
'Editor': 'Editor',
|
||||||
|
'Email Address': 'Emailová adresa',
|
||||||
'Email and SMS': 'Email a SMS',
|
'Email and SMS': 'Email a SMS',
|
||||||
'Enable': 'Odblokovat',
|
'Enable': 'Odblokovat',
|
||||||
|
'Enable Close-Tag': 'Povolit Close-Tag',
|
||||||
|
'Enable Code Folding': 'Povolit sdružování kódu',
|
||||||
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
|
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
|
||||||
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
|
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
|
||||||
'Error': 'Chyba',
|
'Error': 'Chyba',
|
||||||
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
|
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
|
||||||
'Error snapshot': 'Snapshot chyby',
|
'Error snapshot': 'Snapshot chyby',
|
||||||
'Error ticket': 'Ticket chyby',
|
'Error ticket': 'Tiket chyby',
|
||||||
'Errors': 'Chyby',
|
'Errors': 'Chyby',
|
||||||
'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s',
|
'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s',
|
||||||
'Exception %s': 'Exception %s',
|
'Exception %s': 'Výjimka %s',
|
||||||
'Exception instance attributes': 'Prvky instance výjimky',
|
'Exception instance attributes': 'Prvky instance výjimky',
|
||||||
'Expand Abbreviation': 'Expand Abbreviation',
|
'Exit Fullscreen': 'Ukončit režim celé obrazovky',
|
||||||
|
'Expand Abbreviation': 'Rozvinout zkratku',
|
||||||
|
'Expand Abbreviation (html files only)': 'Rozvinout zkratku (pouze html soubory)',
|
||||||
'export as csv file': 'exportovat do .csv souboru',
|
'export as csv file': 'exportovat do .csv souboru',
|
||||||
|
'Exports:': 'Exporty:',
|
||||||
'exposes': 'vystavuje',
|
'exposes': 'vystavuje',
|
||||||
'exposes:': 'vystavuje funkce:',
|
'exposes:': 'vystavuje funkce:',
|
||||||
'extends': 'rozšiřuje',
|
'extends': 'rozšiřuje',
|
||||||
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
|
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
|
||||||
|
'failed to reload module because:': 'nepodařilo se restartovat modul, protože:',
|
||||||
'FAQ': 'Často kladené dotazy',
|
'FAQ': 'Často kladené dotazy',
|
||||||
'File': 'Soubor',
|
'File': 'Soubor',
|
||||||
'file': 'soubor',
|
'file': 'soubor',
|
||||||
'file "%(filename)s" created': 'file "%(filename)s" created',
|
'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen',
|
||||||
|
'file "%(filename)s" deleted': 'soubor "%(filename)s" byl zrušen',
|
||||||
|
'file "%(filename)s" uploaded': 'soubor "%(filename)s" byl nahrán',
|
||||||
|
'file "%s" of %s restored': 'soubor "%s" z %s byl obnoven',
|
||||||
|
'file changed on disk': 'soubor se na disku změnil',
|
||||||
|
'file does not exist': 'soubor neexistuje',
|
||||||
|
'file not found': 'soubor nebyl nalezen',
|
||||||
'file saved on %(time)s': 'soubor uložen %(time)s',
|
'file saved on %(time)s': 'soubor uložen %(time)s',
|
||||||
'file saved on %s': 'soubor uložen %s',
|
'file saved on %s': 'soubor uložen %s',
|
||||||
|
'filename': 'jméno souboru',
|
||||||
'Filename': 'Název souboru',
|
'Filename': 'Název souboru',
|
||||||
|
'Files added': 'Soubory byly přidány',
|
||||||
'filter': 'filtr',
|
'filter': 'filtr',
|
||||||
'Find Next': 'Najít další',
|
'Find Next': 'Najít další',
|
||||||
'Find Previous': 'Najít předchozí',
|
'Find Previous': 'Najít předchozí',
|
||||||
'First name': 'Křestní jméno',
|
'First name': 'Křestní jméno',
|
||||||
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
|
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
|
||||||
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
|
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
|
||||||
|
'Form has errors': 'Ve formuláři jsou chyby',
|
||||||
'Forms and Validators': 'Formuláře a validátory',
|
'Forms and Validators': 'Formuláře a validátory',
|
||||||
'Frames': 'Frames',
|
'Frames': 'Framy',
|
||||||
'Free Applications': 'Aplikace zdarma',
|
'Free Applications': 'Aplikace zdarma',
|
||||||
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
|
'Functions with no doctests will result in [passed] tests.': 'Funkce bez doctestů se projeví jako [úspěšný] test.',
|
||||||
|
'GAE Email': 'GAE e-mail',
|
||||||
|
'GAE Output': 'GAE výstup',
|
||||||
|
'GAE Password': 'GAE heslo',
|
||||||
'Generate': 'Vytvořit',
|
'Generate': 'Vytvořit',
|
||||||
'Get from URL:': 'Stáhnout z internetu:',
|
'Get from URL:': 'Stáhnout z internetu:',
|
||||||
'Git Pull': 'Git Pull',
|
'Git Pull': 'Git Pull',
|
||||||
'Git Push': 'Git Push',
|
'Git Push': 'Git Push',
|
||||||
'Globals##debug': 'Globální proměnné',
|
'Globals##debug': 'Globální proměnné',
|
||||||
'go!': 'OK!',
|
'go!': 'OK!',
|
||||||
'Goto': 'Goto',
|
'Google App Engine Deployment Interface': 'Google App Engine - rozhraní pro nasazení',
|
||||||
'graph model': 'graph model',
|
'Google Application Id': 'ID Google Aplikace',
|
||||||
|
'Goto': 'Přejít na',
|
||||||
|
'graph model': 'grafický model',
|
||||||
|
'Graph Model': 'Grafický model',
|
||||||
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
|
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
|
||||||
'Group ID': 'ID skupiny',
|
'Group ID': 'ID skupiny',
|
||||||
'Groups': 'Skupiny',
|
'Groups': 'Skupiny',
|
||||||
'Hello World': 'Ahoj světe',
|
'Hello World': 'Ahoj světe',
|
||||||
'Help': 'Nápověda',
|
'Help': 'Nápověda',
|
||||||
|
'here': 'zde',
|
||||||
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
|
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
|
||||||
|
'Highlight current line': 'Zvýraznit aktuální řádek',
|
||||||
'Hits': 'Kolikrát dosaženo',
|
'Hits': 'Kolikrát dosaženo',
|
||||||
'Home': 'Domovská stránka',
|
'Home': 'Domovská stránka',
|
||||||
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
|
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
|
||||||
'How did you get here?': 'Jak jste se sem vlastně dostal?',
|
'How did you get here?': 'Jak jste se sem vlastně dostal?',
|
||||||
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
|
'If start the downgrade, be patient, it may take a while to rollback': 'Spustíte-li downgrade verze, vyčkejte, protože vrácení změn může trvat dlouho',
|
||||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
'If start the upgrade, be patient, it may take a while to download': 'Spustíte-li upgrade, vyčkejte, protože stahování může trvat dlouho',
|
||||||
|
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\n\t\tA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)',
|
||||||
|
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Jestliže přehled výše obsahuje číslo chybového tiketu, znamená to chybu v kontroléru, ještě před pokusem vykonat doctesty. (Často je to způsobeno chybou odsazení nebo chybou mimo kód funkce.) Zelený nadpis označuje, že žádný test nehavaroval. (V tom případě dílčí výsledky nejsou uvedeny.)',
|
||||||
|
'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'Jestliže vaše aplikace používá jinou databázi než SQLite, budete muset na PythonAnywhere konfigurovat její DAL() připojení.',
|
||||||
'import': 'import',
|
'import': 'import',
|
||||||
'Import/Export': 'Import/Export',
|
'Import/Export': 'Import/Export',
|
||||||
|
'In development, use the default Rocket webserver that is currently supported by this debugger.': 'Při vývoji je doporučeno použít předvolený webserver Rocket, se kterým tento debugger spolupracuje.',
|
||||||
'includes': 'zahrnuje',
|
'includes': 'zahrnuje',
|
||||||
|
'Indent with tabs': 'Odsazení tabelátory',
|
||||||
'Index': 'Index',
|
'Index': 'Index',
|
||||||
'insert new': 'vložit nový záznam ',
|
'insert new': 'vložit nový záznam ',
|
||||||
'insert new %s': 'vložit nový záznam %s',
|
'insert new %s': 'vložit nový záznam %s',
|
||||||
'inspect attributes': 'inspect attributes',
|
'inspect attributes': 'prohlédnout atributy',
|
||||||
'Install': 'Instalovat',
|
'Install': 'Instalovat',
|
||||||
|
'Installation of %(plugin)s for %(app)s': 'Instalace %(plugin)s pro %(app)s',
|
||||||
'Installed applications': 'Nainstalované aplikace',
|
'Installed applications': 'Nainstalované aplikace',
|
||||||
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
|
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
|
||||||
'Interactive console': 'Interaktivní příkazová řádka',
|
'Interactive console': 'Interaktivní příkazová řádka',
|
||||||
|
'internal error': 'vnitřní chyba',
|
||||||
|
'internal error: %s': 'vnitřní chyba: %s',
|
||||||
'Internal State': 'Vnitřní stav',
|
'Internal State': 'Vnitřní stav',
|
||||||
'Introduction': 'Úvod',
|
'Introduction': 'Úvod',
|
||||||
|
'Invalid action': 'Chybná akce',
|
||||||
|
'Invalid application name': 'Nesprávné jméno aplikace',
|
||||||
|
'invalid circular reference': 'nepovolený kruhový odkaz',
|
||||||
'Invalid email': 'Neplatný email',
|
'Invalid email': 'Neplatný email',
|
||||||
|
'Invalid git repository specified.': 'Byl zadán nesprávný git repozitář.',
|
||||||
'Invalid password': 'Nesprávné heslo',
|
'Invalid password': 'Nesprávné heslo',
|
||||||
|
'invalid password': 'nesprávné heslo',
|
||||||
'invalid password.': 'neplatné heslo',
|
'invalid password.': 'neplatné heslo',
|
||||||
'Invalid Query': 'Neplatný dotaz',
|
'Invalid Query': 'Neplatný dotaz',
|
||||||
'invalid request': 'Neplatný požadavek',
|
'invalid request': 'Neplatný požadavek',
|
||||||
|
'Invalid request': 'Nesprávný požadavek (request)',
|
||||||
|
'invalid table names (auth_* tables already defined)': 'chybná jména tabulek (auth_* tabulky už byly definovány)',
|
||||||
|
'invalid ticket': 'chybný tiket',
|
||||||
'Is Active': 'Je aktivní',
|
'Is Active': 'Je aktivní',
|
||||||
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
|
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
|
||||||
'Key': 'Klíč',
|
'Key': 'Klíč',
|
||||||
'Key bindings': 'Vazby klíčů',
|
'Key bindings': 'Vazby kláves',
|
||||||
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
|
'Key bindings for ZenCoding Plugin': 'Vazby kláves pro ZenCoding Plugin',
|
||||||
|
'Keyboard shortcuts': 'Klávesové zkratky',
|
||||||
|
'kill process': 'likvidovat proces',
|
||||||
|
'language file "%(filename)s" created/updated': 'jazykový soubor "%(filename)s" byl vytvořen/aktualizován',
|
||||||
|
'Language files (static strings) updated': 'Jazykové soubory (statické řetězce) byly aktualizovány',
|
||||||
'languages': 'jazyky',
|
'languages': 'jazyky',
|
||||||
'Languages': 'Jazyky',
|
'Languages': 'Jazyky',
|
||||||
'Last name': 'Příjmení',
|
'Last name': 'Příjmení',
|
||||||
|
'Last Revision': 'Minulá verze',
|
||||||
'Last saved on:': 'Naposledy uloženo:',
|
'Last saved on:': 'Naposledy uloženo:',
|
||||||
'Layout': 'Rozvržení stránky (layout)',
|
'Layout': 'Rozvržení stránky (layout)',
|
||||||
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
|
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
|
||||||
'Layouts': 'Rozvržení stránek',
|
'Layouts': 'Rozvržení stránek',
|
||||||
'License for': 'Licence pro',
|
'License for': 'Licence pro',
|
||||||
|
'License:': 'Licence:',
|
||||||
|
'Line Nr': 'Č.řádku',
|
||||||
'Line number': 'Číslo řádku',
|
'Line number': 'Číslo řádku',
|
||||||
'LineNo': 'Č.řádku',
|
'LineNo': 'Č.řádku',
|
||||||
'Live Chat': 'Online pokec',
|
'lists by exception': 'výpis podle výjimky',
|
||||||
|
'lists by ticket': 'výpis podle tiketu',
|
||||||
|
'Live Chat': 'Online chat',
|
||||||
|
'Loading...': 'Nahrávám...',
|
||||||
'loading...': 'nahrávám...',
|
'loading...': 'nahrávám...',
|
||||||
'locals': 'locals',
|
'Local Apps': 'Lokální aplikace',
|
||||||
|
'locals': 'lokální proměnné',
|
||||||
'Locals##debug': 'Lokální proměnné',
|
'Locals##debug': 'Lokální proměnné',
|
||||||
'Logged in': 'Přihlášení proběhlo úspěšně',
|
'Logged in': 'Přihlášení proběhlo úspěšně',
|
||||||
'Logged out': 'Odhlášení proběhlo úspěšně',
|
'Logged out': 'Odhlášení proběhlo úspěšně',
|
||||||
'Login': 'Přihlásit se',
|
|
||||||
'login': 'přihlásit se',
|
'login': 'přihlásit se',
|
||||||
|
'Login': 'Přihlásit se',
|
||||||
|
'Login successful': 'Přihlášení bylo úspěšné',
|
||||||
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
|
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
|
||||||
|
'Login/Register': 'Přihlásit se / Registrovat',
|
||||||
'logout': 'odhlásit se',
|
'logout': 'odhlásit se',
|
||||||
'Logout': 'Odhlásit se',
|
'Logout': 'Odhlásit se',
|
||||||
|
'lost password': 'ztracené heslo',
|
||||||
'Lost Password': 'Zapomněl jste heslo',
|
'Lost Password': 'Zapomněl jste heslo',
|
||||||
'Lost password?': 'Zapomněl jste heslo?',
|
'Lost password?': 'Zapomněl jste heslo?',
|
||||||
'lost password?': 'zapomněl jste heslo?',
|
'lost password?': 'zapomněl jste heslo?',
|
||||||
'Manage': 'Manage',
|
'Main Menu': 'Hlavní nabídka',
|
||||||
'Manage Cache': 'Manage Cache',
|
'Manage': 'Spravovat',
|
||||||
|
'Manage %(action)s': 'Spravovat %(action)s',
|
||||||
|
'Manage Access Control': 'Spravovat řízení přístupu',
|
||||||
|
'Manage Admin Users/Students': 'Spravovat Admin uživatele / Studenty',
|
||||||
|
'Manage Cache': 'Spravovat cache',
|
||||||
|
'Manage Students': 'Spravovat studenty',
|
||||||
|
'Memberships': 'Členství ve skupinách',
|
||||||
'Menu Model': 'Model rozbalovací nabídky',
|
'Menu Model': 'Model rozbalovací nabídky',
|
||||||
|
'merge': 'sloučit',
|
||||||
'Models': 'Modely',
|
'Models': 'Modely',
|
||||||
'models': 'modely',
|
'models': 'modely',
|
||||||
'Modified By': 'Změněno - kým',
|
'Modified By': 'Změněno - kým',
|
||||||
'Modified On': 'Změněno - kdy',
|
'Modified On': 'Změněno - kdy',
|
||||||
'Modules': 'Moduly',
|
'Modules': 'Moduly',
|
||||||
'modules': 'moduly',
|
'modules': 'moduly',
|
||||||
|
'Multi User Mode': 'Víceuživatelský mód',
|
||||||
'My Sites': 'Správa aplikací',
|
'My Sites': 'Správa aplikací',
|
||||||
'Name': 'Jméno',
|
'Name': 'Jméno',
|
||||||
'new application "%s" created': 'nová aplikace "%s" vytvořena',
|
'new application "%s" created': 'nová aplikace "%s" vytvořena',
|
||||||
|
'new application "%s" imported': 'nová aplikace "%s" byla importována',
|
||||||
'New Application Wizard': 'Nový průvodce aplikací',
|
'New Application Wizard': 'Nový průvodce aplikací',
|
||||||
'New application wizard': 'Nový průvodce aplikací',
|
'New application wizard': 'Nový průvodce aplikací',
|
||||||
'New password': 'Nové heslo',
|
'New password': 'Nové heslo',
|
||||||
|
'new plugin installed': 'nový plugin byl instalován',
|
||||||
|
'New plugin installed: %s': 'Nový plugin byl instalován: %s',
|
||||||
'New Record': 'Nový záznam',
|
'New Record': 'Nový záznam',
|
||||||
'new record inserted': 'nový záznam byl založen',
|
'new record inserted': 'nový záznam byl založen',
|
||||||
'New simple application': 'Vytvořit primitivní aplikaci',
|
'New simple application': 'Vytvořit novou aplikaci',
|
||||||
'next': 'next',
|
'next': 'další',
|
||||||
|
'next %s rows': 'dalších %s řádků',
|
||||||
'next 100 rows': 'dalších 100 řádků',
|
'next 100 rows': 'dalších 100 řádků',
|
||||||
|
'NO': 'NE',
|
||||||
|
'no changes': 'beze změn',
|
||||||
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
|
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
|
||||||
'No Interaction yet': 'Ještě žádná interakce nenastala',
|
'No Interaction yet': 'Ještě žádná interakce nenastala',
|
||||||
|
'no match': 'nenalezena shoda',
|
||||||
|
'no package selected': 'nebyla vybrána žádná package',
|
||||||
|
'no permission to uninstall "%s"': 'chybí oprávnění odinstalovat "%s"',
|
||||||
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
|
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
|
||||||
|
'Node:': 'Uzel (node):',
|
||||||
|
'Not Authorized': 'Chybí autorizace',
|
||||||
|
'Not supported': 'Není podporováno',
|
||||||
|
'Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.': 'Poznámka: Dostanete-li chybu s github status code = 128, ujistěte se, že systém a účet z něhož provádíte nasazení má odpovídající ssh klíč, konfigurovaný v OpenShift účtu.',
|
||||||
'Object or table name': 'Objekt či tabulka',
|
'Object or table name': 'Objekt či tabulka',
|
||||||
'Old password': 'Původní heslo',
|
'Old password': 'Původní heslo',
|
||||||
|
"On production, you'll have to configure your webserver to use one process and multiple threads to use this debugger.": 'Pro použití tohoto debuggeru na produkci je potřeba konfigurovat webserver, aby používal jeden proces a více vláken.',
|
||||||
'online designer': 'online návrhář',
|
'online designer': 'online návrhář',
|
||||||
'Online examples': 'Příklady online',
|
'Online examples': 'Příklady online',
|
||||||
'Open new app in new window': 'Open new app in new window',
|
'Open new app in new window': 'Otevřít novou aplikaci v novém okně',
|
||||||
'or alternatively': 'or alternatively',
|
'OpenShift Deployment Interface': 'OpenShift rozhraní pro nasazení aplikace',
|
||||||
'Or Get from URL:': 'Or Get from URL:',
|
'OpenShift Output': 'OpenShift výstup',
|
||||||
|
'or alternatively': 'nebo případně',
|
||||||
|
'Or Get from URL:': 'Nebo získat z URL adresy:',
|
||||||
'or import from csv file': 'nebo importovat z .csv souboru',
|
'or import from csv file': 'nebo importovat z .csv souboru',
|
||||||
'Origin': 'Původ',
|
'Origin': 'Původ',
|
||||||
'Original/Translation': 'Originál/Překlad',
|
'Original/Translation': 'Originál/Překlad',
|
||||||
@@ -293,30 +438,53 @@
|
|||||||
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
|
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
|
||||||
'Pack all': 'Zabalit',
|
'Pack all': 'Zabalit',
|
||||||
'Pack compiled': 'Zabalit zkompilované',
|
'Pack compiled': 'Zabalit zkompilované',
|
||||||
'pack plugin': 'pack plugin',
|
'Pack custom': 'Zabalit volitelně (custom)',
|
||||||
'password': 'heslo',
|
'pack plugin': 'zabalit plugin',
|
||||||
'Password': 'Heslo',
|
'Password': 'Heslo',
|
||||||
|
'password': 'heslo',
|
||||||
|
'password changed': 'heslo bylo změněno',
|
||||||
"Password fields don't match": 'Hesla se neshodují',
|
"Password fields don't match": 'Hesla se neshodují',
|
||||||
'Peeking at file': 'Peeking at file',
|
'Past revisions': 'Minulá verze',
|
||||||
|
'Path to appcfg.py': 'Cesta ke appcfg.py',
|
||||||
|
'Path to local openshift repo root.': 'Cesta ke kořenu (rootu) lokálního OpenShift repozitáře.',
|
||||||
|
'Peeking at file': 'Sledování souboru',
|
||||||
|
'Permission': 'Oprávnění',
|
||||||
|
'Permissions': 'Oprávnění',
|
||||||
'Please': 'Prosím',
|
'Please': 'Prosím',
|
||||||
'Plugin "%s" in application': 'Plugin "%s" in application',
|
'Please wait, giving pythonanywhere a moment...': 'Prosím, čekejte na dokončení činnosti PythonAnywhere...',
|
||||||
|
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" byl odstraněn',
|
||||||
|
'Plugin "%s" in application': 'Plugin "%s" v aplikaci',
|
||||||
|
'plugin not specified': 'plugin nebyl určen',
|
||||||
|
'Plugin page': 'Stránka pluginů',
|
||||||
'plugins': 'zásuvné moduly',
|
'plugins': 'zásuvné moduly',
|
||||||
'Plugins': 'Zásuvné moduly',
|
'Plugins': 'Zásuvné moduly',
|
||||||
'Plural Form #%s': 'Plural Form #%s',
|
'Plural Form #%s': 'Množné číslo #%s',
|
||||||
'Plural-Forms:': 'Množná čísla:',
|
'Plural-Forms:': 'Množná čísla:',
|
||||||
'Powered by': 'Poháněno',
|
'Powered by': 'používá technologii',
|
||||||
'Preface': 'Předmluva',
|
'Preface': 'Předmluva',
|
||||||
|
'Preferences saved correctly': 'Nastavení byla úspěšně uložena',
|
||||||
|
'Preferences saved on session only': 'Nastavení byla uložena pouze pro toto sezení',
|
||||||
|
'previous %s rows': 'předchozích %s řádků',
|
||||||
'previous 100 rows': 'předchozích 100 řádků',
|
'previous 100 rows': 'předchozích 100 řádků',
|
||||||
'Private files': 'Soukromé soubory',
|
'Private files': 'Soukromé soubory',
|
||||||
'private files': 'soukromé soubory',
|
'private files': 'soukromé soubory',
|
||||||
'profile': 'profil',
|
'profile': 'profil',
|
||||||
'Project Progress': 'Vývoj projektu',
|
'Project Progress': 'Vývoj projektu',
|
||||||
|
'Pull': 'Pull',
|
||||||
|
'Pull failed, certain files could not be checked out. Check logs for details.': 'Pull selhal, některé soubory nelze zkopírovat. Pro podrobnosti zkontrolujte logy.',
|
||||||
|
'Pull is not possible because you have unmerged files. Fix them up in the work tree, and then try again.': 'Pull nelze provést, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.',
|
||||||
|
'Push': 'Push',
|
||||||
|
'Push failed, there are unmerged entries in the cache. Resolve merge issues manually and try again.': 'Push selhal, protože máte nesloučené soubory. Vyřešte tyto konflikty a pak akci opakujte.',
|
||||||
|
'pygraphviz library not found': 'pygraphviz knihovna nebyla nalezena',
|
||||||
'Python': 'Python',
|
'Python': 'Python',
|
||||||
|
'PythonAnywhere Apps': 'PythonAnywhere aplikace',
|
||||||
|
'PythonAnywhere Password': 'PythonAnywhere heslo',
|
||||||
'Query:': 'Dotaz:',
|
'Query:': 'Dotaz:',
|
||||||
'Quick Examples': 'Krátké příklady',
|
'Quick Examples': 'Krátké příklady',
|
||||||
'RAM': 'RAM',
|
'RAM': 'RAM',
|
||||||
'RAM Cache Keys': 'Klíče RAM Cache',
|
'RAM Cache Keys': 'Klíče RAM Cache',
|
||||||
'Ram Cleared': 'RAM smazána',
|
'Ram Cleared': 'RAM smazána',
|
||||||
|
'Rapid Search': 'Rychlé hledání',
|
||||||
'Readme': 'Nápověda',
|
'Readme': 'Nápověda',
|
||||||
'Recipes': 'Postupy jak na to',
|
'Recipes': 'Postupy jak na to',
|
||||||
'Record': 'Záznam',
|
'Record': 'Záznam',
|
||||||
@@ -335,114 +503,167 @@
|
|||||||
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
|
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
|
||||||
'Replace': 'Zaměnit',
|
'Replace': 'Zaměnit',
|
||||||
'Replace All': 'Zaměnit vše',
|
'Replace All': 'Zaměnit vše',
|
||||||
'request': 'request',
|
'Repository (%s)': 'Repozitář (%s)',
|
||||||
|
'request': 'požadavek (request)',
|
||||||
|
'requires distutils, but not installed': 'vyžaduje distutils, jenže ty nejsou instalovány',
|
||||||
|
'requires python-git, but not installed': 'vyžaduje python-git, který ale není nainstalován',
|
||||||
'Reset Password key': 'Reset registračního klíče',
|
'Reset Password key': 'Reset registračního klíče',
|
||||||
'response': 'response',
|
'Resolve Conflict file': 'Vyřešit konflikty',
|
||||||
|
'response': 'odpověď (response)',
|
||||||
'restart': 'restart',
|
'restart': 'restart',
|
||||||
'restore': 'obnovit',
|
'restore': 'obnovit',
|
||||||
'Retrieve username': 'Získat přihlašovací jméno',
|
'Retrieve username': 'Získat přihlašovací jméno',
|
||||||
'return': 'return',
|
'return': 'return',
|
||||||
|
'Revert': 'Vrátit se k původnímu',
|
||||||
'revert': 'vrátit se k původnímu',
|
'revert': 'vrátit se k původnímu',
|
||||||
|
'reverted to revision %s': 'vráceno k verzi %s',
|
||||||
|
'Revision %s': 'Verze %s',
|
||||||
|
'Revision:': 'Verze:',
|
||||||
'Role': 'Role',
|
'Role': 'Role',
|
||||||
|
'Roles': 'Role',
|
||||||
'Rows in Table': 'Záznamy v tabulce',
|
'Rows in Table': 'Záznamy v tabulce',
|
||||||
'Rows selected': 'Záznamů zobrazeno',
|
'Rows selected': 'Záznamů zobrazeno',
|
||||||
'rules are not defined': 'pravidla nejsou definována',
|
'rules are not defined': 'pravidla nejsou definována',
|
||||||
|
'Run tests': 'Spustit testy',
|
||||||
|
'Run tests in this file': 'Spustit testy v souboru',
|
||||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
|
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
|
||||||
'Running on %s': 'Běží na %s',
|
'Running on %s': 'Běží na %s',
|
||||||
'Save': 'Uložit',
|
'Save': 'Uložit',
|
||||||
'Save file:': 'Save file:',
|
'Save file:': 'Uložit soubor:',
|
||||||
|
'Save file: %s': 'Uložit soubor: %s',
|
||||||
|
'Save model as...': 'Uložit model jako...',
|
||||||
'Save via Ajax': 'Uložit pomocí Ajaxu',
|
'Save via Ajax': 'Uložit pomocí Ajaxu',
|
||||||
'Saved file hash:': 'hash uloženého souboru:',
|
'Saved file hash:': 'hash uloženého souboru:',
|
||||||
|
'Screenshot %s': 'Screenshot %s',
|
||||||
|
'Search': 'Hledání',
|
||||||
|
'Select Files to Package': 'Vybrat soubory pro package',
|
||||||
'Semantic': 'Modul semantic',
|
'Semantic': 'Modul semantic',
|
||||||
'Services': 'Služby',
|
'Services': 'Služby',
|
||||||
'session': 'session',
|
'session': 'session (sezení)',
|
||||||
'session expired': 'session expired',
|
'session expired': 'vypršela session',
|
||||||
|
'Session saved correctly': 'Session byla úspěšně uložena',
|
||||||
|
'Session saved on session only': 'Session byla uložena jen pro toto sezení',
|
||||||
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
|
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
|
||||||
'shell': 'příkazová řádka',
|
'shell': 'příkazová řádka',
|
||||||
'Singular Form': 'Singular Form',
|
'Showing %s to %s of %s %s found': 'Zobrazuji %s až %s z %s %s nalezených',
|
||||||
|
'Singular Form': 'Jednotné číslo',
|
||||||
'Site': 'Správa aplikací',
|
'Site': 'Správa aplikací',
|
||||||
'Size of cache:': 'Velikost cache:',
|
'Size of cache:': 'Velikost cache:',
|
||||||
'skip to generate': 'skip to generate',
|
'skip to generate': 'přeskočit pro vytvoření',
|
||||||
|
'some files could not be removed': 'některé soubory nelze odstranit',
|
||||||
|
'Something went wrong please wait a few minutes before retrying': 'Něco se nepodařilo. Vyčkejte několik minut a pak zkuste znova',
|
||||||
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
|
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
|
||||||
|
'source : db': 'zdroj : db',
|
||||||
|
'source : filesystem': 'zdroj : souborový systém',
|
||||||
'Start a new app': 'Vytvořit novou aplikaci',
|
'Start a new app': 'Vytvořit novou aplikaci',
|
||||||
'Start searching': 'Začít hledání',
|
'Start searching': 'Začít hledání',
|
||||||
'Start wizard': 'Spustit průvodce',
|
'Start wizard': 'Spustit průvodce',
|
||||||
'state': 'stav',
|
'state': 'stav',
|
||||||
'Static': 'Static',
|
'Static': 'Statické soubory',
|
||||||
'static': 'statické soubory',
|
'static': 'statické soubory',
|
||||||
'Static files': 'Statické soubory',
|
'Static files': 'Statické soubory',
|
||||||
'Statistics': 'Statistika',
|
'Statistics': 'Statistika',
|
||||||
'Step': 'Step',
|
'Step': 'Krok',
|
||||||
'step': 'step',
|
'step': 'krok',
|
||||||
'stop': 'stop',
|
'stop': 'zastavit',
|
||||||
'Stylesheet': 'CSS styly',
|
'Stylesheet': 'CSS styly',
|
||||||
'submit': 'odeslat',
|
'submit': 'odeslat',
|
||||||
'Submit': 'Odeslat',
|
'Submit': 'Odeslat',
|
||||||
'successful': 'úspěšně',
|
'successful': 'úspěšně',
|
||||||
'Support': 'Podpora',
|
'Support': 'Podpora',
|
||||||
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
|
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
|
||||||
|
'switch to : db': 'přepnout na : db',
|
||||||
|
'switch to : filesystem': 'přepnout na : souborový systém',
|
||||||
|
'Tab width (# characters)': 'Šířka tabelátoru (# znaků)',
|
||||||
'Table': 'tabulka',
|
'Table': 'tabulka',
|
||||||
'Table name': 'Název tabulky',
|
'Table name': 'Název tabulky',
|
||||||
'Temporary': 'Dočasný',
|
'Temporary': 'Dočasný',
|
||||||
'test': 'test',
|
'test': 'test',
|
||||||
'Testing application': 'Testing application',
|
'Testing application': 'Zkušební aplikace',
|
||||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
|
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je například "db.tabulka1.pole1==\'hodnota\'". Dotaz se dvěma tabulkami "db.tabulka1.pole1==db.tabulka2.pole2" vytvoří SQL JOIN.',
|
||||||
|
'The app exists, was created by wizard, continue to overwrite!': 'Aplikace existuje, byla vytvořena průvodcem. Pokračováním ji přepíšete !',
|
||||||
|
'The app exists, was NOT created by wizard, continue to overwrite!': 'Aplikace existuje, a NEBYLA vytvořena průvodcem. Pokračováním ji přepíšete !',
|
||||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
|
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
|
||||||
'The Core': 'Jádro (The Core)',
|
'The Core': 'Jádro (The Core)',
|
||||||
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
|
'The data representation, define database tables and sets': 'Modely se vykonají při každém přístupu. Zde se obvykle definuje především reprezentace dat: Připojení k databázi a struktura tabulek databáze',
|
||||||
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.',
|
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je dictionary (slovník), který se zobrazil pomocí šablony (view) %s.',
|
||||||
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
|
'The presentations layer, views are also known as templates': 'Prezentační vrstva: šablony (neboli pohledy, templaty, view). Mixuje Html, Python kód a Python data.',
|
||||||
'The Views': 'Pohledy (The Views)',
|
'The Views': 'Pohledy (The Views)',
|
||||||
'There are no controllers': 'There are no controllers',
|
'Theme': 'Téma',
|
||||||
'There are no modules': 'There are no modules',
|
'There are no controllers': 'Nejsou vytvořeny žádné controllery',
|
||||||
|
'There are no models': 'Není vytvořen žádný model',
|
||||||
|
'There are no modules': 'Nejsou přidány žádné moduly',
|
||||||
'There are no plugins': 'Žádné moduly nejsou instalovány.',
|
'There are no plugins': 'Žádné moduly nejsou instalovány.',
|
||||||
'There are no private files': 'Žádné soukromé soubory neexistují.',
|
'There are no private files': 'Žádné soukromé soubory neexistují.',
|
||||||
'There are no static files': 'There are no static files',
|
'There are no static files': 'Nejsou přidány žádné statické soubory',
|
||||||
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
|
'There are no translators': 'Není vytvořen žádný překlad',
|
||||||
'There are no views': 'There are no views',
|
'There are no translators, only default language is supported': 'Není vytvořen žádný překlad, je podporován jen defaultní jazyk',
|
||||||
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
|
'There are no views': 'Nejsou vytvořeny žádné šablony (views)',
|
||||||
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
|
'These files are not served, they are only available from within your app': 'Tyto soubory jsou přístupné jen běžící aplikaci. Nejsou dostupné uživatelům, ani se nekopírují do případného vývojového repozitáře. Hesla a citlivá nastavení nedávejte nikam jinam.',
|
||||||
|
'These files are served without processing, your images go here': 'Tyto soubory jsou stahovány přímo, bez jakékoli přídavné logiky, sem patří např. obrázky.',
|
||||||
'This App': 'Tato aplikace',
|
'This App': 'Tato aplikace',
|
||||||
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
|
"This debugger may not work properly if you don't have a threaded webserver or you're using multiple daemon processes.": 'Tento debugger nebude pracovat správně, jestliže váš webový server nepracuje pomocí vláken nebo když používáte více procesů démonů.',
|
||||||
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
|
'This is a copy of the scaffolding application': 'Toto je kopie vzorové aplikace.',
|
||||||
'This is the %(filename)s template': 'This is the %(filename)s template',
|
'This is an experimental feature and it needs more testing. If you decide to downgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Návrat verze jen na vlastní riziko.',
|
||||||
|
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'Toto je experimentální vlastnost, která vyžaduje další testování. Upgrade verze jen na vlastní riziko.',
|
||||||
|
'This is the %(filename)s template': 'Toto je šablona %(filename)s',
|
||||||
|
"This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.": 'Tato stránka umožňuje potvrdit vaše změny do OpenShift aplikačního repozitáře a odeslat je do vaší cloud instance. Předpokladem je, že jste už vytvořili aplikační instanci pomocí Web2py předlohy a že tento repozitář máte někde na disku tak, aby k němu Web2py mělo přístup. Tato funkcionalita vyžaduje, aby byl instalován GitPython a aby mohl být nalezen pomocí cesty, se kterou Web2py pracuje.',
|
||||||
|
'This page can upload your application to the Google App Engine computing cloud. Mind that you must first create indexes locally and this is done by installing the Google appserver and running the app locally with it once, or there will be errors when selecting records. Attention: deployment may take long time, depending on the network speed. Attention: it will overwrite your app.yaml. DO NOT SUBMIT TWICE.': 'Tato stránka umožňuje zkopírovat vaši aplikaci do Google App Engine cloudu. Pamatujte, že nejprve je třeba vytvořit indexy lokálně, čehož dosáhnete instalací Google appserver a jedním lokálním spuštěním aplikace. V opačném případě bude docházet k chybám vyhledávání. Pozor: v závislosti na rychlosti sítě může nasazení trvat dlouhou dobu. Pozor: bude přepsán váš soubor app.yaml. BĚHEM SPUŠTĚNÍ NESPOUŠTĚJTE PODRUHÉ.',
|
||||||
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
|
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
|
||||||
'Ticket': 'Ticket',
|
'This will pull changes from the remote repo for application "%s"?': 'Toto stáhne (pull) změny ze vzdáleného repozitáře pro aplikaci "%s"?',
|
||||||
'Ticket ID': 'Ticket ID',
|
'This will push changes to the remote repo for application "%s".': 'Toto nahraje (push) změny do vzdáleného repozitáře pro aplikaci "%s".',
|
||||||
|
'Ticket': 'Tiket',
|
||||||
|
'Ticket ID': 'ID tiketu',
|
||||||
|
'Ticket Missing': 'Chybový tiket chybí',
|
||||||
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
|
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
|
||||||
'Timestamp': 'Časové razítko',
|
'Timestamp': 'Časové razítko',
|
||||||
'to previous version.': 'k předchozí verzi.',
|
'to previous version.': 'k předchozí verzi.',
|
||||||
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
|
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete skupinu souborů nebo adresář(e) plugin_[jméno modulu]',
|
||||||
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
|
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
|
||||||
'to use the debugger!': ', abyste mohli ladící program používat!',
|
'to use the debugger!': ', abyste mohli ladící program používat!',
|
||||||
'toggle breakpoint': 'vyp./zap. bod přerušení',
|
'toggle breakpoint': 'vyp./zap. bod přerušení',
|
||||||
|
'Toggle comment': 'Přepnout komentář',
|
||||||
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
|
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
|
||||||
'too short': 'Příliš krátké',
|
'too short': 'Příliš krátké',
|
||||||
'Traceback': 'Traceback',
|
'Traceback': 'Hierarchie volání',
|
||||||
'Translation strings for the application': 'Překlad textů pro aplikaci',
|
'Translation strings for the application': 'Překlad textů pro aplikaci',
|
||||||
'try something like': 'try something like',
|
'try something like': 'zkuste něco jako',
|
||||||
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
|
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
|
||||||
'try view': 'try view',
|
'try view': 'vyzkoušet šablonu (view)',
|
||||||
'Twitter': 'Twitter',
|
'Twitter': 'Twitter',
|
||||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
|
'Type PDB debugger command in here and hit Return (Enter) to execute it.': 'Zapište příkaz PDB debuggeru a stiskněte Return (Enter) pro jeho provedení.',
|
||||||
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
|
'Type python statement in here and hit Return (Enter) to execute it.': 'Zapište příkaz pythonu a stiskněte Return (Enter) pro jeho provedení.',
|
||||||
'Unable to check for upgrades': 'Unable to check for upgrades',
|
'Type some Python code in here and hit Return (Enter) to execute it.': 'Zapište kód v jazyce python a stiskněte Return (Enter) pro jeho provedení.',
|
||||||
|
'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích',
|
||||||
|
'unable to create application "%s"': 'nelze vytvořit aplikaci "%s"',
|
||||||
|
'unable to delete file "%(filename)s"': 'nelze zrušit soubor "%(filename)s"',
|
||||||
|
'unable to delete file plugin "%(plugin)s"': 'nelze zrušit plugin "%(plugin)s"',
|
||||||
|
'Unable to determine the line number!': 'Nelze určit číslo řádky!',
|
||||||
|
'Unable to download app because:': 'Nelze stáhnout aplikaci, protože:',
|
||||||
|
'unable to download layout': 'nelze stáhnout šablonu (layout)',
|
||||||
|
'unable to download plugin: %s': 'nelze stáhnout plugin: %s',
|
||||||
|
'Unable to download the list of plugins': 'Nelze stáhnout seznam pluginů',
|
||||||
|
'unable to install plugin "%s"': 'nelze instalovat plugin "%s"',
|
||||||
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
|
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
|
||||||
|
'unable to uninstall "%s"': 'nelze instalovat "%s"',
|
||||||
|
'unable to upgrade because "%s"': 'nelze upgradovat, protože "%s"',
|
||||||
'uncheck all': 'vše odznačit',
|
'uncheck all': 'vše odznačit',
|
||||||
'Uninstall': 'Odinstalovat',
|
'Uninstall': 'Odinstalovat',
|
||||||
|
'Unsupported webserver working mode: %s': 'Nepodporovaný mód webového serveru: %s',
|
||||||
'update': 'aktualizovat',
|
'update': 'aktualizovat',
|
||||||
'update all languages': 'aktualizovat všechny jazyky',
|
'update all languages': 'aktualizovat všechny jazyky o nové texty ze zdrojových souborů',
|
||||||
'Update:': 'Upravit:',
|
'Update:': 'Upravit:',
|
||||||
'Upgrade': 'Upgrade',
|
'Upgrade': 'Upgrade',
|
||||||
'upgrade now': 'upgrade now',
|
'upgrade now': 'upgradovat nyní',
|
||||||
'upgrade now to %s': 'upgrade now to %s',
|
'upgrade now to %s': 'upgradovat nyní na %s',
|
||||||
'upload': 'nahrát',
|
'upload': 'nahrát',
|
||||||
'Upload': 'Upload',
|
'Upload': 'Upload (nahrát)',
|
||||||
'Upload a package:': 'Nahrát balík:',
|
'Upload a package:': 'Nahrát balík:',
|
||||||
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
|
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
|
||||||
'upload file:': 'nahrát soubor:',
|
'upload file:': 'nahrát soubor:',
|
||||||
'upload plugin file:': 'nahrát soubor modulu:',
|
'upload plugin file:': 'nahrát soubor modulu:',
|
||||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
|
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
|
||||||
|
'User': 'Uživatel',
|
||||||
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
|
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
|
||||||
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
|
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
|
||||||
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
|
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
|
||||||
@@ -451,30 +672,45 @@
|
|||||||
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
|
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
|
||||||
'User ID': 'ID uživatele',
|
'User ID': 'ID uživatele',
|
||||||
'Username': 'Přihlašovací jméno',
|
'Username': 'Přihlašovací jméno',
|
||||||
'variables': 'variables',
|
'Users': 'Uživatelé',
|
||||||
|
'Using the shell may lock the database to other users of this app.': 'Použití příkazového shellu může uzamknout databázi ostatním uživatelům této aplikace.',
|
||||||
|
'variables': 'proměnné',
|
||||||
'Verify Password': 'Zopakujte heslo',
|
'Verify Password': 'Zopakujte heslo',
|
||||||
'Version': 'Verze',
|
'Version': 'Verze',
|
||||||
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
|
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
|
||||||
'Versioning': 'Verzování',
|
'Versioning': 'Verzování',
|
||||||
'Videos': 'Videa',
|
'Videos': 'Videa',
|
||||||
'View': 'Pohled (View)',
|
'View': 'Šablona (View)',
|
||||||
'Views': 'Pohledy',
|
'Views': 'Šablony (Views)',
|
||||||
'views': 'pohledy',
|
'views': 'šablony (views)',
|
||||||
'Web Framework': 'Web Framework',
|
'Warning!': 'Pozor!',
|
||||||
|
'WARNING:': 'POZOR:',
|
||||||
|
'WARNING: The following views could not be compiled:': 'POZOR: Následující šablony se nepodařilo zkompilovat:',
|
||||||
|
'Web Framework': 'Webový framework',
|
||||||
|
'web2py Admin Password': 'web2py Heslo administrátora',
|
||||||
|
'web2py apps to deploy': 'web2py aplikace k nasazení',
|
||||||
|
'web2py Debugger': 'web2py Debugger',
|
||||||
|
'web2py downgrade': 'web2py downgrade',
|
||||||
'web2py is up to date': 'Máte aktuální verzi web2py.',
|
'web2py is up to date': 'Máte aktuální verzi web2py.',
|
||||||
'web2py online debugger': 'Ladící online web2py program',
|
'web2py online debugger': 'Ladící online web2py program',
|
||||||
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
|
'web2py Recent Tweets': 'Nedávné tweety na Twitteru o web2py',
|
||||||
'web2py upgrade': 'web2py upgrade',
|
'web2py upgrade': 'aktualizace Web2py',
|
||||||
'web2py upgraded; please restart it': 'web2py upgraded; please restart it',
|
'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej',
|
||||||
'Welcome': 'Vítejte',
|
'Welcome': 'Vítejte',
|
||||||
'Welcome to web2py': 'Vitejte ve web2py',
|
'Welcome to web2py': 'Vitejte ve Web2py aplikaci.',
|
||||||
'Welcome to web2py!': 'Vítejte ve web2py!',
|
'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.',
|
||||||
'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.',
|
'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.',
|
||||||
|
'WSGI reference name': 'jméno WSGI reference',
|
||||||
|
'YES': 'ANO',
|
||||||
|
'Yes': 'Ano',
|
||||||
'You are successfully running web2py': 'Úspěšně jste spustili web2py.',
|
'You are successfully running web2py': 'Úspěšně jste spustili web2py.',
|
||||||
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
|
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
|
||||||
|
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
||||||
|
'You can inspect variables using the console below': 'You can inspect variables using the console below',
|
||||||
'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.',
|
'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.',
|
||||||
|
'You have one more login attempt before you are locked out': 'Máte jen jeden další pokus k přihlášení před zablokováním',
|
||||||
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
|
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
|
||||||
|
'You only need these if you have already registered': 'Toto potřebujete jen tehdy, jestliže jste se už registroval(a)',
|
||||||
'You visited the url %s': 'Navštívili jste stránku %s,',
|
'You visited the url %s': 'Navštívili jste stránku %s,',
|
||||||
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
|
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
|
||||||
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
|
||||||
}
|
}
|
||||||
|
|||||||
+408
-377
@@ -1,377 +1,408 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
{
|
{
|
||||||
'!langcode!': 'pt',
|
'!langcode!': 'pt',
|
||||||
'!langname!': 'Português',
|
'!langname!': 'Português',
|
||||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "campo1=\'novo_valor\'". Não é permitido atualizar ou apagar resultados de um JOIN',
|
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': '"update" é uma expressão opcional como "campo1=\'novo_valor\'". Não é permitido atualizar ou apagar resultados de um JOIN',
|
||||||
'%s %%{row} deleted': '%s registros apagados',
|
'%s %%{row} deleted': '%s registros apagados',
|
||||||
'%s %%{row} updated': '%s registros atualizados',
|
'%s %%{row} updated': '%s registros atualizados',
|
||||||
'%Y-%m-%d': '%d/%m/%Y',
|
'%Y-%m-%d': '%d/%m/%Y',
|
||||||
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
|
'%Y-%m-%d %H:%M:%S': '%d/%m/%Y %H:%M:%S',
|
||||||
'(requires internet access)': '(requer acesso à internet)',
|
'(requires internet access)': '(requer acesso à internet)',
|
||||||
'(requires internet access, experimental)': '(requer acesso à internet, experimental)',
|
'(requires internet access, experimental)': '(requer acesso à internet, experimental)',
|
||||||
'(something like "it-it")': '(algo como "it-it")',
|
'(something like "it-it")': '(algo como "it-it")',
|
||||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
|
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
|
||||||
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
|
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
|
||||||
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
|
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
|
||||||
'A new version of web2py is available': 'Está disponível uma nova versão do web2py',
|
'A new version of web2py is available': 'Está disponível uma nova versão do web2py',
|
||||||
'A new version of web2py is available: %s': 'Está disponível uma nova versão do web2py: %s',
|
'A new version of web2py is available: %s': 'Está disponível uma nova versão do web2py: %s',
|
||||||
'About': 'sobre',
|
'About': 'sobre',
|
||||||
'About application': 'Sobre a aplicação',
|
'About application': 'Sobre a aplicação',
|
||||||
'additional code for your application': 'código adicional para sua aplicação',
|
'Accept Terms': 'Accept Terms',
|
||||||
'Additional code for your application': 'Código adicional para a sua aplicação',
|
'additional code for your application': 'código adicional para sua aplicação',
|
||||||
'admin disabled because no admin password': ' admin desabilitado por falta de senha definida',
|
'Additional code for your application': 'Código adicional para a sua aplicação',
|
||||||
'admin disabled because not supported on google app engine': 'admin dehabilitado, não é soportado no GAE',
|
'admin disabled because no admin password': ' admin desabilitado por falta de senha definida',
|
||||||
'admin disabled because unable to access password file': 'admin desabilitado, não foi possível ler o arquivo de senha',
|
'admin disabled because not supported on google app engine': 'admin dehabilitado, não é soportado no GAE',
|
||||||
'Admin is disabled because insecure channel': 'Admin desabilitado pois o canal não é seguro',
|
'admin disabled because unable to access password file': 'admin desabilitado, não foi possível ler o arquivo de senha',
|
||||||
'Admin is disabled because unsecure channel': 'Admin desabilitado pois o canal não é seguro',
|
'Admin is disabled because insecure channel': 'Admin desabilitado pois o canal não é seguro',
|
||||||
'Admin language': 'Linguagem do Admin',
|
'Admin is disabled because unsecure channel': 'Admin desabilitado pois o canal não é seguro',
|
||||||
'administrative interface': 'interface administrativa',
|
'Admin language': 'Linguagem do Admin',
|
||||||
'Administrator Password:': 'Senha de administrador:',
|
'administrative interface': 'interface administrativa',
|
||||||
'and rename it (required):': 'e renomeie (requerido):',
|
'Administrator Password:': 'Senha de administrador:',
|
||||||
'and rename it:': ' e renomeie:',
|
'and rename it (required):': 'e renomeie (requerido):',
|
||||||
'appadmin': 'appadmin',
|
'and rename it:': ' e renomeie:',
|
||||||
'appadmin is disabled because insecure channel': 'admin desabilitado, canal inseguro',
|
'appadmin': 'appadmin',
|
||||||
'application "%s" uninstalled': 'aplicação "%s" desinstalada',
|
'appadmin is disabled because insecure channel': 'admin desabilitado, canal inseguro',
|
||||||
'application compiled': 'aplicação compilada',
|
'application "%s" uninstalled': 'aplicação "%s" desinstalada',
|
||||||
'application is compiled and cannot be designed': 'A aplicação está compilada e não pode ser modificada',
|
'application compiled': 'aplicação compilada',
|
||||||
'Application name:': 'Nome da aplicação:',
|
'application is compiled and cannot be designed': 'A aplicação está compilada e não pode ser modificada',
|
||||||
'are not used': 'não usadas',
|
'Application name:': 'Nome da aplicação:',
|
||||||
'are not used yet': 'ainda não usadas',
|
'are not used': 'não usadas',
|
||||||
'Are you sure you want to delete file "%s"?': 'Tem certeza que deseja apagar o arquivo "%s"?',
|
'are not used yet': 'ainda não usadas',
|
||||||
'Are you sure you want to delete plugin "%s"?': 'Tem certeza que deseja apagar o plugin "%s"?',
|
'Are you sure you want to delete file "%s"?': 'Tem certeza que deseja apagar o arquivo "%s"?',
|
||||||
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
'Are you sure you want to delete plugin "%s"?': 'Tem certeza que deseja apagar o plugin "%s"?',
|
||||||
'Are you sure you want to uninstall application "%s"': 'Tem certeza que deseja apagar a aplicação "%s"?',
|
'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?',
|
||||||
'Are you sure you want to uninstall application "%s"?': 'Tem certeza que deseja apagar a aplicação "%s"?',
|
'Are you sure you want to uninstall application "%s"': 'Tem certeza que deseja apagar a aplicação "%s"?',
|
||||||
'Are you sure you want to upgrade web2py now?': 'Tem certeza que deseja atualizar o web2py agora?',
|
'Are you sure you want to uninstall application "%s"?': 'Tem certeza que deseja apagar a aplicação "%s"?',
|
||||||
'arguments': 'argumentos',
|
'Are you sure you want to upgrade web2py now?': 'Tem certeza que deseja atualizar o web2py agora?',
|
||||||
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENÇÃO o login requer uma conexão segura (HTTPS) ou executar de localhost.',
|
'arguments': 'argumentos',
|
||||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENÇÃO OS TESTES NÃO THREAD SAFE, NÃO EFETUE MÚLTIPLOS TESTES AO MESMO TEMPO.',
|
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENÇÃO o login requer uma conexão segura (HTTPS) ou executar de localhost.',
|
||||||
'ATTENTION: you cannot edit the running application!': 'ATENÇÃO: Não pode modificar a aplicação em execução!',
|
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENÇÃO OS TESTES NÃO THREAD SAFE, NÃO EFETUE MÚLTIPLOS TESTES AO MESMO TEMPO.',
|
||||||
'Autocomplete Python Code': 'Autocompletar Código Python',
|
'ATTENTION: you cannot edit the running application!': 'ATENÇÃO: Não pode modificar a aplicação em execução!',
|
||||||
'Available databases and tables': 'Bancos de dados e tabelas disponíveis',
|
'Autocomplete Python Code': 'Autocompletar Código Python',
|
||||||
'back': 'voltar',
|
'Available databases and tables': 'Bancos de dados e tabelas disponíveis',
|
||||||
'browse': 'buscar',
|
'back': 'voltar',
|
||||||
'cache': 'cache',
|
'Begin': 'Begin',
|
||||||
'cache, errors and sessions cleaned': 'cache, erros e sessões eliminadas',
|
'browse': 'buscar',
|
||||||
'can be a git repo': 'can be a git repo',
|
'cache': 'cache',
|
||||||
'Cannot be empty': 'Não pode ser vazio',
|
'cache, errors and sessions cleaned': 'cache, erros e sessões eliminadas',
|
||||||
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Não é possível compilar: Existem erros em sua aplicação. Depure, corrija os errros e tente novamente',
|
'can be a git repo': 'can be a git repo',
|
||||||
'Cannot compile: there are errors in your app:': 'Não é possível compilar: Existem erros em sua aplicação',
|
'Cannot be empty': 'Não pode ser vazio',
|
||||||
'cannot create file': 'Não é possível criar o arquivo',
|
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'Não é possível compilar: Existem erros em sua aplicação. Depure, corrija os errros e tente novamente',
|
||||||
'cannot upload file "%(filename)s"': 'não é possível fazer upload do arquivo "%(filename)s"',
|
'Cannot compile: there are errors in your app:': 'Não é possível compilar: Existem erros em sua aplicação',
|
||||||
'Change admin password': 'mudar senha de administrador',
|
'cannot create file': 'Não é possível criar o arquivo',
|
||||||
'change editor settings': 'mudar definições do editor',
|
'cannot upload file "%(filename)s"': 'não é possível fazer upload do arquivo "%(filename)s"',
|
||||||
'Change Password': 'Trocar Senha',
|
'Change admin password': 'mudar senha de administrador',
|
||||||
'check all': 'marcar todos',
|
'change editor settings': 'mudar definições do editor',
|
||||||
'Check for upgrades': 'checar por atualizações',
|
'Change Password': 'Trocar Senha',
|
||||||
'Check to delete': 'Marque para apagar',
|
'check all': 'marcar todos',
|
||||||
'Checking for upgrades...': 'Buscando atualizações...',
|
'Check for upgrades': 'checar por atualizações',
|
||||||
'Clean': 'limpar',
|
'Check to delete': 'Marque para apagar',
|
||||||
'click here for online examples': 'clique para ver exemplos online',
|
'Checking for upgrades...': 'Buscando atualizações...',
|
||||||
'click here for the administrative interface': 'Clique aqui para acessar a interface administrativa',
|
'Clean': 'limpar',
|
||||||
'Click row to expand traceback': 'Clique em uma coluna para expandir o log do erro',
|
'click here for online examples': 'clique para ver exemplos online',
|
||||||
'click to check for upgrades': 'clique aqui para checar por atualizações',
|
'click here for the administrative interface': 'Clique aqui para acessar a interface administrativa',
|
||||||
'click to open': 'clique para abrir',
|
'Click row to expand traceback': 'Clique em uma coluna para expandir o log do erro',
|
||||||
'Client IP': 'IP do cliente',
|
'click to check for upgrades': 'clique aqui para checar por atualizações',
|
||||||
'code': 'código',
|
'click to open': 'clique para abrir',
|
||||||
'collapse/expand all': 'colapsar/expandir tudo',
|
'Client IP': 'IP do cliente',
|
||||||
'commit (mercurial)': 'commit (mercurial)',
|
'code': 'código',
|
||||||
'Compile': 'compilar',
|
'collapse/expand all': 'colapsar/expandir tudo',
|
||||||
'compiled application removed': 'aplicação compilada removida',
|
'commit (mercurial)': 'commit (mercurial)',
|
||||||
'Controllers': 'Controladores',
|
'Compile': 'compilar',
|
||||||
'controllers': 'controladores',
|
'compiled application removed': 'aplicação compilada removida',
|
||||||
'Count': 'Contagem',
|
'Controllers': 'Controladores',
|
||||||
'Create': 'criar',
|
'controllers': 'controladores',
|
||||||
'create file with filename:': 'criar um arquivo com o nome:',
|
'Count': 'Contagem',
|
||||||
'Create new application using the Wizard': 'Criar nova aplicação utilizando o assistente',
|
'Create': 'criar',
|
||||||
'create new application:': 'nome da nova aplicação:',
|
'create file with filename:': 'criar um arquivo com o nome:',
|
||||||
'Create new simple application': 'Crie uma nova aplicação',
|
'Create new application using the Wizard': 'Criar nova aplicação utilizando o assistente',
|
||||||
'Create/Upload': 'Create/Upload',
|
'create new application:': 'nome da nova aplicação:',
|
||||||
'created by': 'criado por',
|
'Create new simple application': 'Crie uma nova aplicação',
|
||||||
'crontab': 'crontab',
|
'Create/Upload': 'Create/Upload',
|
||||||
'Current request': 'Requisição atual',
|
'created by': 'criado por',
|
||||||
'Current response': 'Resposta atual',
|
'crontab': 'crontab',
|
||||||
'Current session': 'Sessão atual',
|
'Current request': 'Requisição atual',
|
||||||
'currently running': 'Executando',
|
'Current response': 'Resposta atual',
|
||||||
'currently saved or': 'Atualmente salvo ou',
|
'Current session': 'Sessão atual',
|
||||||
'customize me!': 'Modifique-me',
|
'currently running': 'Executando',
|
||||||
'data uploaded': 'Dados enviados',
|
'currently saved or': 'Atualmente salvo ou',
|
||||||
'database': 'banco de dados',
|
'customize me!': 'Modifique-me',
|
||||||
'database %s select': 'Seleção no banco de dados %s',
|
'data uploaded': 'Dados enviados',
|
||||||
'database administration': 'administração de banco de dados',
|
'database': 'banco de dados',
|
||||||
'Date and Time': 'Data e Hora',
|
'database %s select': 'Seleção no banco de dados %s',
|
||||||
'db': 'db',
|
'database administration': 'administração de banco de dados',
|
||||||
'Debug': 'Debug',
|
'Date and Time': 'Data e Hora',
|
||||||
'defines tables': 'define as tabelas',
|
'db': 'db',
|
||||||
'Delete': 'Apague',
|
'Debug': 'Debug',
|
||||||
'delete': 'apagar',
|
'defines tables': 'define as tabelas',
|
||||||
'delete all checked': 'apagar marcados',
|
'Delete': 'Apague',
|
||||||
'delete plugin': 'apagar plugin',
|
'delete': 'apagar',
|
||||||
'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
|
'delete all checked': 'apagar marcados',
|
||||||
'Delete:': 'Apague:',
|
'delete plugin': 'apagar plugin',
|
||||||
'Deploy': 'publicar',
|
'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
|
||||||
'Deploy on Google App Engine': 'Publicar no Google App Engine',
|
'Delete:': 'Apague:',
|
||||||
'Deploy to OpenShift': 'Deploy to OpenShift',
|
'Deploy': 'publicar',
|
||||||
'Description': 'Descrição',
|
'Deploy on Google App Engine': 'Publicar no Google App Engine',
|
||||||
'design': 'modificar',
|
'Deploy to OpenShift': 'Deploy to OpenShift',
|
||||||
'DESIGN': 'Projeto',
|
'Deploy to pythonanywhere': 'Deploy to pythonanywhere',
|
||||||
'Design for': 'Projeto de',
|
'Deploy to PythonAnywhere': 'Deploy to PythonAnywhere',
|
||||||
'Detailed traceback description': 'Detailed traceback description',
|
'Deployment Interface': 'Deployment Interface',
|
||||||
'direction: ltr': 'direção: ltr',
|
'Description': 'Descrição',
|
||||||
'Disable': 'Disable',
|
'design': 'modificar',
|
||||||
'docs': 'docs',
|
'DESIGN': 'Projeto',
|
||||||
'done!': 'feito!',
|
'Design for': 'Projeto de',
|
||||||
'download layouts': 'download layouts',
|
'Detailed traceback description': 'Detailed traceback description',
|
||||||
'Download layouts from repository': 'Download layouts from repository',
|
'details': 'details',
|
||||||
'download plugins': 'download plugins',
|
'direction: ltr': 'direção: ltr',
|
||||||
'Download plugins from repository': 'Download plugins from repository',
|
'Disable': 'Disable',
|
||||||
'E-mail': 'E-mail',
|
'docs': 'docs',
|
||||||
'EDIT': 'EDITAR',
|
'done!': 'feito!',
|
||||||
'Edit': 'editar',
|
'download layouts': 'download layouts',
|
||||||
'Edit application': 'Editar aplicação',
|
'Download layouts from repository': 'Download layouts from repository',
|
||||||
'edit controller': 'editar controlador',
|
'download plugins': 'download plugins',
|
||||||
'Edit current record': 'Editar o registro atual',
|
'Download plugins from repository': 'Download plugins from repository',
|
||||||
'Edit Profile': 'Editar Perfil',
|
'E-mail': 'E-mail',
|
||||||
'edit views:': 'editar visões:',
|
'EDIT': 'EDITAR',
|
||||||
'Editing %s': 'A Editar %s',
|
'Edit': 'editar',
|
||||||
'Editing file': 'Editando arquivo',
|
'Edit application': 'Editar aplicação',
|
||||||
'Editing file "%s"': 'Editando arquivo "%s"',
|
'edit controller': 'editar controlador',
|
||||||
'Editing Language file': 'Editando arquivo de linguagem',
|
'Edit current record': 'Editar o registro atual',
|
||||||
'Enterprise Web Framework': 'Framework web empresarial',
|
'Edit Profile': 'Editar Perfil',
|
||||||
'Error': 'Erro',
|
'edit views:': 'editar visões:',
|
||||||
'Error logs for "%(app)s"': 'Logs de erro para "%(app)s"',
|
'Editing %s': 'A Editar %s',
|
||||||
'Error snapshot': 'Error snapshot',
|
'Editing file': 'Editando arquivo',
|
||||||
'Error ticket': 'Error ticket',
|
'Editing file "%s"': 'Editando arquivo "%s"',
|
||||||
'Errors': 'erros',
|
'Editing Language file': 'Editando arquivo de linguagem',
|
||||||
'Exception instance attributes': 'Atributos da instancia de excessão',
|
'Email Address': 'Email Address',
|
||||||
'Exit Fullscreen': 'Sair de Ecrã Inteiro',
|
'Enterprise Web Framework': 'Framework web empresarial',
|
||||||
'Expand Abbreviation (html files only)': 'Expandir Abreviação (só para ficheiros html)',
|
'Error': 'Erro',
|
||||||
'export as csv file': 'exportar como arquivo CSV',
|
'Error logs for "%(app)s"': 'Logs de erro para "%(app)s"',
|
||||||
'exposes': 'expõe',
|
'Error snapshot': 'Error snapshot',
|
||||||
'extends': 'estende',
|
'Error ticket': 'Error ticket',
|
||||||
'failed to reload module': 'Falha ao recarregar o módulo',
|
'Errors': 'erros',
|
||||||
'failed to reload module because:': 'falha ao recarregar o módulo por:',
|
'Exception instance attributes': 'Atributos da instancia de excessão',
|
||||||
'File': 'Arquivo',
|
'Exit Fullscreen': 'Sair de Ecrã Inteiro',
|
||||||
'file "%(filename)s" created': 'arquivo "%(filename)s" criado',
|
'Expand Abbreviation (html files only)': 'Expandir Abreviação (só para ficheiros html)',
|
||||||
'file "%(filename)s" deleted': 'arquivo "%(filename)s" apagado',
|
'export as csv file': 'exportar como arquivo CSV',
|
||||||
'file "%(filename)s" uploaded': 'arquivo "%(filename)s" enviado',
|
'exposes': 'expõe',
|
||||||
'file "%(filename)s" was not deleted': 'arquivo "%(filename)s" não foi apagado',
|
'exposes:': 'exposes:',
|
||||||
'file "%s" of %s restored': 'arquivo "%s" de %s restaurado',
|
'extends': 'estende',
|
||||||
'file changed on disk': 'arquivo modificado no disco',
|
'failed to reload module': 'Falha ao recarregar o módulo',
|
||||||
'file does not exist': 'arquivo não existe',
|
'failed to reload module because:': 'falha ao recarregar o módulo por:',
|
||||||
'file saved on %(time)s': 'arquivo salvo em %(time)s',
|
'File': 'Arquivo',
|
||||||
'file saved on %s': 'arquivo salvo em %s',
|
'file "%(filename)s" created': 'arquivo "%(filename)s" criado',
|
||||||
'filter': 'filtro',
|
'file "%(filename)s" deleted': 'arquivo "%(filename)s" apagado',
|
||||||
'Find Next': 'Localizar Seguinte',
|
'file "%(filename)s" uploaded': 'arquivo "%(filename)s" enviado',
|
||||||
'Find Previous': 'Localizar Anterior',
|
'file "%(filename)s" was not deleted': 'arquivo "%(filename)s" não foi apagado',
|
||||||
'First name': 'Nome',
|
'file "%s" of %s restored': 'arquivo "%s" de %s restaurado',
|
||||||
'Frames': 'Frames',
|
'file changed on disk': 'arquivo modificado no disco',
|
||||||
'Functions with no doctests will result in [passed] tests.': 'Funções sem doctests resultarão em testes [aceitos].',
|
'file does not exist': 'arquivo não existe',
|
||||||
'graph model': 'graph model',
|
'file saved on %(time)s': 'arquivo salvo em %(time)s',
|
||||||
'Group ID': 'ID do Grupo',
|
'file saved on %s': 'arquivo salvo em %s',
|
||||||
'Hello World': 'Olá Mundo',
|
'filter': 'filtro',
|
||||||
'Help': 'ajuda',
|
'Find Next': 'Localizar Seguinte',
|
||||||
'Hide/Show Translated strings': '',
|
'Find Previous': 'Localizar Anterior',
|
||||||
'htmledit': 'htmledit',
|
'First name': 'Nome',
|
||||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Se o relatório acima contém um número de ticket, isso indica uma falha no controlador em execução, antes de tantar executar os doctests. Isto acontece geralmente por erro de endentação ou erro fora do código da função.\r\nO titulo em verde indica que os testes (se definidos) passaram. Neste caso os testes não são mostrados.',
|
'Form has errors': 'Form has errors',
|
||||||
'Import/Export': 'Importar/Exportar',
|
'Frames': 'Frames',
|
||||||
'includes': 'inclui',
|
'Functions with no doctests will result in [passed] tests.': 'Funções sem doctests resultarão em testes [aceitos].',
|
||||||
'insert new': 'inserir novo',
|
'graph model': 'graph model',
|
||||||
'insert new %s': 'inserir novo %s',
|
'Group ID': 'ID do Grupo',
|
||||||
'inspect attributes': 'inspecionar atributos',
|
'Hello World': 'Olá Mundo',
|
||||||
'Install': 'instalar',
|
'Help': 'ajuda',
|
||||||
'Installed applications': 'Aplicações instaladas',
|
'Hide/Show Translated strings': '',
|
||||||
'internal error': 'erro interno',
|
'htmledit': 'htmledit',
|
||||||
'Internal State': 'Estado Interno',
|
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'Se o relatório acima contém um número de ticket, isso indica uma falha no controlador em execução, antes de tantar executar os doctests. Isto acontece geralmente por erro de endentação ou erro fora do código da função.\r\nO titulo em verde indica que os testes (se definidos) passaram. Neste caso os testes não são mostrados.',
|
||||||
'Invalid action': 'Ação inválida',
|
'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.': 'if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.',
|
||||||
'Invalid email': 'E-mail inválido',
|
'Import/Export': 'Importar/Exportar',
|
||||||
'invalid password': 'senha inválida',
|
'includes': 'inclui',
|
||||||
'Invalid Query': 'Consulta inválida',
|
'insert new': 'inserir novo',
|
||||||
'invalid request': 'solicitação inválida',
|
'insert new %s': 'inserir novo %s',
|
||||||
'invalid ticket': 'ticket inválido',
|
'inspect attributes': 'inspecionar atributos',
|
||||||
'Keyboard shortcuts': 'Atalhos de teclado',
|
'Install': 'instalar',
|
||||||
'language file "%(filename)s" created/updated': 'arquivo de linguagem "%(filename)s" criado/atualizado',
|
'Installed applications': 'Aplicações instaladas',
|
||||||
'Language files (static strings) updated': 'Arquivos de linguagem (textos estáticos) atualizados',
|
'internal error': 'erro interno',
|
||||||
'languages': 'linguagens',
|
'Internal State': 'Estado Interno',
|
||||||
'Languages': 'Linguagens',
|
'Invalid action': 'Ação inválida',
|
||||||
'languages updated': 'linguagens atualizadas',
|
'Invalid email': 'E-mail inválido',
|
||||||
'Last name': 'Sobrenome',
|
'invalid password': 'senha inválida',
|
||||||
'Last saved on:': 'Salvo em:',
|
'Invalid Query': 'Consulta inválida',
|
||||||
'License for': 'Licença para',
|
'invalid request': 'solicitação inválida',
|
||||||
'loading...': 'carregando...',
|
'invalid ticket': 'ticket inválido',
|
||||||
'locals': 'locals',
|
'Keyboard shortcuts': 'Atalhos de teclado',
|
||||||
'Login': 'Entrar',
|
'language file "%(filename)s" created/updated': 'arquivo de linguagem "%(filename)s" criado/atualizado',
|
||||||
'login': 'inicio de sessão',
|
'Language files (static strings) updated': 'Arquivos de linguagem (textos estáticos) atualizados',
|
||||||
'Login to the Administrative Interface': 'Entrar na interface adminitrativa',
|
'languages': 'linguagens',
|
||||||
'Logout': 'finalizar sessão',
|
'Languages': 'Linguagens',
|
||||||
'Lost Password': 'Senha perdida',
|
'languages updated': 'linguagens atualizadas',
|
||||||
'Manage': 'Manage',
|
'Last name': 'Sobrenome',
|
||||||
'manage': 'gerenciar',
|
'Last saved on:': 'Salvo em:',
|
||||||
'merge': 'juntar',
|
'License for': 'Licença para',
|
||||||
'Models': 'Modelos',
|
'lists by ticket': 'lists by ticket',
|
||||||
'models': 'modelos',
|
'Loading...': 'Loading...',
|
||||||
'Modules': 'Módulos',
|
'loading...': 'carregando...',
|
||||||
'modules': 'módulos',
|
'Local Apps': 'Local Apps',
|
||||||
'Name': 'Nome',
|
'locals': 'locals',
|
||||||
'new application "%s" created': 'nova aplicação "%s" criada',
|
'Login': 'Entrar',
|
||||||
'New application wizard': 'Assistente para novas aplicações ',
|
'login': 'inicio de sessão',
|
||||||
'new plugin installed': 'novo plugin instalado',
|
'Login successful': 'Login successful',
|
||||||
'New Record': 'Novo registro',
|
'Login to the Administrative Interface': 'Entrar na interface adminitrativa',
|
||||||
'new record inserted': 'novo registro inserido',
|
'Login/Register': 'Login/Register',
|
||||||
'New simple application': 'Nova aplicação básica',
|
'Logout': 'finalizar sessão',
|
||||||
'next 100 rows': 'próximos 100 registros',
|
'Lost Password': 'Senha perdida',
|
||||||
'NO': 'NÃO',
|
'manage': 'gerenciar',
|
||||||
'No databases in this application': 'Não existem bancos de dados nesta aplicação',
|
'Manage': 'Manage',
|
||||||
'no match': 'não encontrado',
|
'merge': 'juntar',
|
||||||
'no package selected': 'nenhum pacote selecionado',
|
'models': 'modelos',
|
||||||
'online designer': 'online designer',
|
'Models': 'Modelos',
|
||||||
'or alternatively': 'or alternatively',
|
'Modules': 'Módulos',
|
||||||
'Or Get from URL:': 'Ou Obtenha do URL:',
|
'modules': 'módulos',
|
||||||
'or import from csv file': 'ou importar de um arquivo CSV',
|
'Name': 'Nome',
|
||||||
'or provide app url:': 'ou forneça a url de uma aplicação:',
|
'new application "%s" created': 'nova aplicação "%s" criada',
|
||||||
'or provide application url:': 'ou forneça a url de uma aplicação:',
|
'New Application Wizard': 'New Application Wizard',
|
||||||
'Origin': 'Origem',
|
'New application wizard': 'Assistente para novas aplicações ',
|
||||||
'Original/Translation': 'Original/Tradução',
|
'new plugin installed': 'novo plugin instalado',
|
||||||
'Overwrite installed app': 'sobrescrever aplicação instalada',
|
'New Record': 'Novo registro',
|
||||||
'Pack all': 'criar pacote',
|
'new record inserted': 'novo registro inserido',
|
||||||
'Pack compiled': 'criar pacote compilado',
|
'New simple application': 'Nova aplicação básica',
|
||||||
'Pack custom': 'Pack custom',
|
'next 100 rows': 'próximos 100 registros',
|
||||||
'pack plugin': 'empacotar plugin',
|
'NO': 'NÃO',
|
||||||
'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, não pode alterar a senha por aqui',
|
'No databases in this application': 'Não existem bancos de dados nesta aplicação',
|
||||||
'Password': 'Senha',
|
'no match': 'não encontrado',
|
||||||
'password changed': 'senha alterada',
|
'no package selected': 'nenhum pacote selecionado',
|
||||||
'Peeking at file': 'Visualizando arquivo',
|
'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder',
|
||||||
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" eliminado',
|
'online designer': 'online designer',
|
||||||
'Plugin "%s" in application': 'Plugin "%s" na aplicação',
|
'or alternatively': 'or alternatively',
|
||||||
'plugins': 'plugins',
|
'Or Get from URL:': 'Ou Obtenha do URL:',
|
||||||
'Plugins': 'Plugins',
|
'or import from csv file': 'ou importar de um arquivo CSV',
|
||||||
'Plural-Forms:': 'Plural-Forms:',
|
'or provide app url:': 'ou forneça a url de uma aplicação:',
|
||||||
'Powered by': 'Este site utiliza',
|
'or provide application url:': 'ou forneça a url de uma aplicação:',
|
||||||
'previous 100 rows': '100 registros anteriores',
|
'Origin': 'Origem',
|
||||||
'Private files': 'Private files',
|
'Original/Translation': 'Original/Tradução',
|
||||||
'private files': 'private files',
|
'Overwrite installed app': 'sobrescrever aplicação instalada',
|
||||||
'Query:': 'Consulta:',
|
'Pack all': 'criar pacote',
|
||||||
'Rapid Search': 'Rapid Search',
|
'Pack compiled': 'criar pacote compilado',
|
||||||
'record': 'registro',
|
'Pack custom': 'Pack custom',
|
||||||
'record does not exist': 'o registro não existe',
|
'pack plugin': 'empacotar plugin',
|
||||||
'record id': 'id do registro',
|
'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, não pode alterar a senha por aqui',
|
||||||
'Record ID': 'ID do Registro',
|
'Password': 'Senha',
|
||||||
'Register': 'Registrar-se',
|
'password changed': 'senha alterada',
|
||||||
'Registration key': 'Chave de registro',
|
'Peeking at file': 'Visualizando arquivo',
|
||||||
'Reload routes': 'Reload routes',
|
'Please wait, giving pythonanywhere a moment...': 'Please wait, giving pythonanywhere a moment...',
|
||||||
'Remove compiled': 'eliminar compilados',
|
'plugin "%(plugin)s" deleted': 'plugin "%(plugin)s" eliminado',
|
||||||
'Replace': 'Substituir',
|
'Plugin "%s" in application': 'Plugin "%s" na aplicação',
|
||||||
'Replace All': 'Substituir Tudo',
|
'plugins': 'plugins',
|
||||||
'request': 'request',
|
'Plugins': 'Plugins',
|
||||||
'Resolve Conflict file': 'Arquivo de resolução de conflito',
|
'Plural-Forms:': 'Plural-Forms:',
|
||||||
'response': 'response',
|
'Powered by': 'Este site utiliza',
|
||||||
'restore': 'restaurar',
|
'previous 100 rows': '100 registros anteriores',
|
||||||
'revert': 'reverter',
|
'Private files': 'Private files',
|
||||||
'Role': 'Papel',
|
'private files': 'private files',
|
||||||
'Rows in table': 'Registros na tabela',
|
'PythonAnywhere Apps': 'PythonAnywhere Apps',
|
||||||
'Rows selected': 'Registros selecionados',
|
'PythonAnywhere Password': 'PythonAnywhere Password',
|
||||||
'rules are not defined': 'rules are not defined',
|
'Query:': 'Consulta:',
|
||||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
|
'Rapid Search': 'Rapid Search',
|
||||||
'Running on %s': 'A correr em %s',
|
'Read': 'Read',
|
||||||
'Save': 'Save',
|
'record': 'registro',
|
||||||
'save': 'salvar',
|
'record does not exist': 'o registro não existe',
|
||||||
'Save file:': 'Gravar ficheiro:',
|
'record id': 'id do registro',
|
||||||
'Save file: %s': 'Gravar ficheiro: %s',
|
'Record ID': 'ID do Registro',
|
||||||
'Save via Ajax': 'Gravar via Ajax',
|
'Register': 'Registrar-se',
|
||||||
'Saved file hash:': 'Hash do arquivo salvo:',
|
'Registration key': 'Chave de registro',
|
||||||
'selected': 'selecionado(s)',
|
'Reload routes': 'Reload routes',
|
||||||
'session': 'session',
|
'Remove compiled': 'eliminar compilados',
|
||||||
'session expired': 'sessão expirada',
|
'Replace': 'Substituir',
|
||||||
'shell': 'Terminal',
|
'Replace All': 'Substituir Tudo',
|
||||||
'Site': 'site',
|
'request': 'request',
|
||||||
'some files could not be removed': 'alguns arquicos não puderam ser removidos',
|
'requires python-git, but not installed': 'requires python-git, but not installed',
|
||||||
'Start searching': 'Start searching',
|
'Resolve Conflict file': 'Arquivo de resolução de conflito',
|
||||||
'Start wizard': 'iniciar assistente',
|
'response': 'response',
|
||||||
'state': 'estado',
|
'restore': 'restaurar',
|
||||||
'Static': 'Static',
|
'revert': 'reverter',
|
||||||
'static': 'estáticos',
|
'Role': 'Papel',
|
||||||
'Static files': 'Arquivos estáticos',
|
'Rows in table': 'Registros na tabela',
|
||||||
'Submit': 'Submit',
|
'Rows selected': 'Registros selecionados',
|
||||||
'submit': 'enviar',
|
'rules are not defined': 'rules are not defined',
|
||||||
'Sure you want to delete this object?': 'Tem certeza que deseja apaagr este objeto?',
|
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Run tests in this file (to run all files, you may also use the button labelled 'test')",
|
||||||
'table': 'tabela',
|
'Running on %s': 'A correr em %s',
|
||||||
'Table name': 'Nome da tabela',
|
'Save': 'Save',
|
||||||
'test': 'testar',
|
'save': 'salvar',
|
||||||
'Testing application': 'Testando a aplicação',
|
'Save file:': 'Gravar ficheiro:',
|
||||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'A "consulta" é uma condição como "db.tabela.campo1==\'valor\'". Algo como "db.tabela1.campo1==db.tabela2.campo2" resulta em um JOIN SQL.',
|
'Save file: %s': 'Gravar ficheiro: %s',
|
||||||
'the application logic, each URL path is mapped in one exposed function in the controller': 'A lógica da aplicação, cada URL é mapeada para uma função exposta pelo controlador',
|
'Save via Ajax': 'Gravar via Ajax',
|
||||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
|
'Saved file hash:': 'Hash do arquivo salvo:',
|
||||||
'the data representation, define database tables and sets': 'A representação dos dadps, define tabelas e estruturas de dados',
|
'selected': 'selecionado(s)',
|
||||||
'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
|
'session': 'session',
|
||||||
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
|
'session expired': 'sessão expirada',
|
||||||
'the presentations layer, views are also known as templates': 'A camada de apresentação, As visões também são chamadas de templates',
|
'shell': 'Terminal',
|
||||||
'There are no controllers': 'Não existem controllers',
|
'Site': 'site',
|
||||||
'There are no models': 'Não existem modelos',
|
'some files could not be removed': 'alguns arquicos não puderam ser removidos',
|
||||||
'There are no modules': 'Não existem módulos',
|
'Something went wrong please wait a few minutes before retrying': 'Something went wrong please wait a few minutes before retrying',
|
||||||
'There are no plugins': 'There are no plugins',
|
'source : filesystem': 'source : filesystem',
|
||||||
'There are no private files': '',
|
'Start a new app': 'Start a new app',
|
||||||
'There are no static files': 'Não existem arquicos estáticos',
|
'Start searching': 'Start searching',
|
||||||
'There are no translators, only default language is supported': 'Não há traduções, somente a linguagem padrão é suportada',
|
'Start wizard': 'iniciar assistente',
|
||||||
'There are no views': 'Não existem visões',
|
'state': 'estado',
|
||||||
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app',
|
'Static': 'Static',
|
||||||
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
|
'static': 'estáticos',
|
||||||
'these files are served without processing, your images go here': 'Estes arquivos são servidos sem processamento, suas imagens ficam aqui',
|
'Static files': 'Arquivos estáticos',
|
||||||
'This is the %(filename)s template': 'Este é o template %(filename)s',
|
'Submit': 'Submit',
|
||||||
'Ticket': 'Ticket',
|
'submit': 'enviar',
|
||||||
'Ticket ID': 'Ticket ID',
|
'Sure you want to delete this object?': 'Tem certeza que deseja apaagr este objeto?',
|
||||||
'Timestamp': 'Data Atual',
|
'switch to : db': 'switch to : db',
|
||||||
'TM': 'MR',
|
'table': 'tabela',
|
||||||
'to previous version.': 'para a versão anterior.',
|
'Table name': 'Nome da tabela',
|
||||||
'To create a plugin, name a file/folder plugin_[name]': 'Para criar um plugin, nomeio um arquivo/pasta como plugin_[nome]',
|
'test': 'testar',
|
||||||
'toggle breakpoint': 'toggle breakpoint',
|
'Testing application': 'Testando a aplicação',
|
||||||
'Toggle comment': 'Toggle comment',
|
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'A "consulta" é uma condição como "db.tabela.campo1==\'valor\'". Algo como "db.tabela1.campo1==db.tabela2.campo2" resulta em um JOIN SQL.',
|
||||||
'Toggle Fullscreen': 'Toggle Fullscreen',
|
'the application logic, each URL path is mapped in one exposed function in the controller': 'A lógica da aplicação, cada URL é mapeada para uma função exposta pelo controlador',
|
||||||
'Traceback': 'Traceback',
|
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
|
||||||
'translation strings for the application': 'textos traduzidos para a aplicação',
|
'the data representation, define database tables and sets': 'A representação dos dadps, define tabelas e estruturas de dados',
|
||||||
'Translation strings for the application': 'Translation strings for the application',
|
'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
|
||||||
'try': 'tente',
|
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
|
||||||
'try something like': 'tente algo como',
|
'the presentations layer, views are also known as templates': 'A camada de apresentação, As visões também são chamadas de templates',
|
||||||
'Try the mobile interface': 'Try the mobile interface',
|
'There are no controllers': 'Não existem controllers',
|
||||||
'Unable to check for upgrades': 'Não é possível checar as atualizações',
|
'There are no models': 'Não existem modelos',
|
||||||
'unable to create application "%s"': 'não é possível criar a aplicação "%s"',
|
'There are no modules': 'Não existem módulos',
|
||||||
'unable to delete file "%(filename)s"': 'não é possível criar o arquico "%(filename)s"',
|
'There are no plugins': 'There are no plugins',
|
||||||
'unable to delete file plugin "%(plugin)s"': 'não é possível criar o plugin "%(plugin)s"',
|
'There are no private files': '',
|
||||||
'Unable to download': 'Não é possível efetuar o download',
|
'There are no static files': 'Não existem arquicos estáticos',
|
||||||
'Unable to download app': 'Não é possível baixar a aplicação',
|
'There are no translators, only default language is supported': 'Não há traduções, somente a linguagem padrão é suportada',
|
||||||
'Unable to download app because:': 'Não é possível baixar a aplicação porque:',
|
'There are no views': 'Não existem visões',
|
||||||
'Unable to download because': 'Não é possível baixar porque',
|
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app',
|
||||||
'unable to parse csv file': 'não é possível analisar o arquivo CSV',
|
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
|
||||||
'unable to uninstall "%s"': 'não é possível instalar "%s"',
|
'these files are served without processing, your images go here': 'Estes arquivos são servidos sem processamento, suas imagens ficam aqui',
|
||||||
'unable to upgrade because "%s"': 'não é possível atualizar porque "%s"',
|
'This is the %(filename)s template': 'Este é o template %(filename)s',
|
||||||
'uncheck all': 'desmarcar todos',
|
'Ticket': 'Ticket',
|
||||||
'Uninstall': 'desinstalar',
|
'Ticket ID': 'Ticket ID',
|
||||||
'update': 'atualizar',
|
'Timestamp': 'Data Atual',
|
||||||
'update all languages': 'atualizar todas as linguagens',
|
'TM': 'MR',
|
||||||
'Update:': 'Atualizar:',
|
'to previous version.': 'para a versão anterior.',
|
||||||
'upgrade web2py now': 'atualize o web2py agora',
|
'To create a plugin, name a file/folder plugin_[name]': 'Para criar um plugin, nomeio um arquivo/pasta como plugin_[nome]',
|
||||||
'upload': 'upload',
|
'toggle breakpoint': 'toggle breakpoint',
|
||||||
'Upload': 'Upload',
|
'Toggle comment': 'Toggle comment',
|
||||||
'Upload & install packed application': 'Faça upload e instale uma aplicação empacotada',
|
'Toggle Fullscreen': 'Toggle Fullscreen',
|
||||||
'Upload a package:': 'Faça upload de um pacote:',
|
'Traceback': 'Traceback',
|
||||||
'Upload and install packed application': 'Upload and install packed application',
|
'translation strings for the application': 'textos traduzidos para a aplicação',
|
||||||
'upload application:': 'Fazer upload de uma aplicação:',
|
'Translation strings for the application': 'Translation strings for the application',
|
||||||
'Upload existing application': 'Faça upload de uma aplicação existente',
|
'try': 'tente',
|
||||||
'upload file:': 'Enviar arquivo:',
|
'try something like': 'tente algo como',
|
||||||
'upload plugin file:': 'Enviar arquivo de plugin:',
|
'Try the mobile interface': 'Try the mobile interface',
|
||||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para criar consultas mais complexas.',
|
'Unable to check for upgrades': 'Não é possível checar as atualizações',
|
||||||
'Use an url:': 'Use uma url:',
|
'unable to create application "%s"': 'não é possível criar a aplicação "%s"',
|
||||||
'User ID': 'ID do Usuario',
|
'unable to delete file "%(filename)s"': 'não é possível criar o arquico "%(filename)s"',
|
||||||
'variables': 'variáveis',
|
'unable to delete file plugin "%(plugin)s"': 'não é possível criar o plugin "%(plugin)s"',
|
||||||
'Version': 'Versão',
|
'Unable to download': 'Não é possível efetuar o download',
|
||||||
'versioning': 'versionamento',
|
'Unable to download app': 'Não é possível baixar a aplicação',
|
||||||
'Versioning': 'Versioning',
|
'Unable to download app because:': 'Não é possível baixar a aplicação porque:',
|
||||||
'view': 'visão',
|
'Unable to download because': 'Não é possível baixar porque',
|
||||||
'Views': 'Visões',
|
'unable to parse csv file': 'não é possível analisar o arquivo CSV',
|
||||||
'views': 'visões',
|
'unable to uninstall "%s"': 'não é possível instalar "%s"',
|
||||||
'Web Framework': 'Web Framework',
|
'unable to upgrade because "%s"': 'não é possível atualizar porque "%s"',
|
||||||
'web2py is up to date': 'web2py está atualizado',
|
'uncheck all': 'desmarcar todos',
|
||||||
'web2py Recent Tweets': 'Tweets Recentes de @web2py',
|
'Uninstall': 'desinstalar',
|
||||||
'web2py upgraded; please restart it': 'web2py atualizado; favor reiniciar',
|
'update': 'atualizar',
|
||||||
'Welcome to web2py': 'Bem-vindo ao web2py',
|
'update all languages': 'atualizar todas as linguagens',
|
||||||
'YES': 'SIM',
|
'Update:': 'Atualizar:',
|
||||||
}
|
'upgrade now to %s': 'upgrade now to %s',
|
||||||
|
'upgrade web2py now': 'atualize o web2py agora',
|
||||||
|
'upload': 'upload',
|
||||||
|
'Upload': 'Upload',
|
||||||
|
'Upload & install packed application': 'Faça upload e instale uma aplicação empacotada',
|
||||||
|
'Upload a package:': 'Faça upload de um pacote:',
|
||||||
|
'Upload and install packed application': 'Upload and install packed application',
|
||||||
|
'upload application:': 'Fazer upload de uma aplicação:',
|
||||||
|
'Upload existing application': 'Faça upload de uma aplicação existente',
|
||||||
|
'upload file:': 'Enviar arquivo:',
|
||||||
|
'upload plugin file:': 'Enviar arquivo de plugin:',
|
||||||
|
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Use (...)&(...) para AND, (...)|(...) para OR, y ~(...) para NOT, para criar consultas mais complexas.',
|
||||||
|
'Use an url:': 'Use uma url:',
|
||||||
|
'User ID': 'ID do Usuario',
|
||||||
|
'Username': 'Username',
|
||||||
|
'variables': 'variáveis',
|
||||||
|
'Version': 'Versão',
|
||||||
|
'versioning': 'versionamento',
|
||||||
|
'Versioning': 'Versioning',
|
||||||
|
'view': 'visão',
|
||||||
|
'Views': 'Visões',
|
||||||
|
'views': 'visões',
|
||||||
|
'Warning!': 'Warning!',
|
||||||
|
'Web Framework': 'Web Framework',
|
||||||
|
'web2py Admin Password': 'web2py Admin Password',
|
||||||
|
'web2py is up to date': 'web2py está atualizado',
|
||||||
|
'web2py Recent Tweets': 'Tweets Recentes de @web2py',
|
||||||
|
'web2py upgraded; please restart it': 'web2py atualizado; favor reiniciar',
|
||||||
|
'Welcome to web2py': 'Bem-vindo ao web2py',
|
||||||
|
'YES': 'SIM',
|
||||||
|
'You only need these if you have already registered': 'You only need these if you have already registered',
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import time
|
|||||||
from gluon import portalocker
|
from gluon import portalocker
|
||||||
from gluon.admin import apath
|
from gluon.admin import apath
|
||||||
from gluon.fileutils import read_file
|
from gluon.fileutils import read_file
|
||||||
|
from gluon.utils import web2py_uuid
|
||||||
# ###########################################################
|
# ###########################################################
|
||||||
# ## make sure administrator is on localhost or https
|
# ## make sure administrator is on localhost or https
|
||||||
# ###########################################################
|
# ###########################################################
|
||||||
@@ -49,15 +50,18 @@ except IOError:
|
|||||||
def verify_password(password):
|
def verify_password(password):
|
||||||
session.pam_user = None
|
session.pam_user = None
|
||||||
if DEMO_MODE:
|
if DEMO_MODE:
|
||||||
return True
|
ret = True
|
||||||
elif not _config.get('password'):
|
elif not _config.get('password'):
|
||||||
return False
|
ret - False
|
||||||
elif _config['password'].startswith('pam_user:'):
|
elif _config['password'].startswith('pam_user:'):
|
||||||
session.pam_user = _config['password'][9:].strip()
|
session.pam_user = _config['password'][9:].strip()
|
||||||
import gluon.contrib.pam
|
import gluon.contrib.pam
|
||||||
return gluon.contrib.pam.authenticate(session.pam_user, password)
|
ret = gluon.contrib.pam.authenticate(session.pam_user, password)
|
||||||
else:
|
else:
|
||||||
return _config['password'] == CRYPT()(password)[0]
|
ret = _config['password'] == CRYPT()(password)[0]
|
||||||
|
if ret:
|
||||||
|
session.hmac_key = web2py_uuid()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
# ###########################################################
|
# ###########################################################
|
||||||
@@ -100,13 +104,12 @@ def write_hosts_deny(denied_hosts):
|
|||||||
portalocker.unlock(f)
|
portalocker.unlock(f)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
def login_record(success=True):
|
def login_record(success=True):
|
||||||
denied_hosts = read_hosts_deny()
|
denied_hosts = read_hosts_deny()
|
||||||
val = (0, 0)
|
val = (0, 0)
|
||||||
if success and request.client in denied_hosts:
|
if success and request.client in denied_hosts:
|
||||||
del denied_hosts[request.client]
|
del denied_hosts[request.client]
|
||||||
elif not success and not request.is_local:
|
elif not success:
|
||||||
val = denied_hosts.get(request.client, (0, 0))
|
val = denied_hosts.get(request.client, (0, 0))
|
||||||
if time.time() - val[1] < expiration_failed_logins \
|
if time.time() - val[1] < expiration_failed_logins \
|
||||||
and val[0] >= allowed_number_of_attempts:
|
and val[0] >= allowed_number_of_attempts:
|
||||||
@@ -117,6 +120,11 @@ def login_record(success=True):
|
|||||||
write_hosts_deny(denied_hosts)
|
write_hosts_deny(denied_hosts)
|
||||||
return val[0]
|
return val[0]
|
||||||
|
|
||||||
|
def failed_login_count():
|
||||||
|
denied_hosts = read_hosts_deny()
|
||||||
|
val = denied_hosts.get(request.client, (0, 0))
|
||||||
|
return val[0]
|
||||||
|
|
||||||
|
|
||||||
# ###########################################################
|
# ###########################################################
|
||||||
# ## session expiration
|
# ## session expiration
|
||||||
|
|||||||
@@ -1,579 +0,0 @@
|
|||||||
/*=============================================================
|
|
||||||
GENERAL
|
|
||||||
==============================================================*/
|
|
||||||
html,body{height:auto;background:transparent;}
|
|
||||||
/*=============================================================
|
|
||||||
CONTROLS
|
|
||||||
==============================================================*/
|
|
||||||
label,
|
|
||||||
input,
|
|
||||||
button,
|
|
||||||
select,
|
|
||||||
textarea,
|
|
||||||
button.btn
|
|
||||||
{
|
|
||||||
font-size:13px;
|
|
||||||
font-weight:normal;
|
|
||||||
line-height:18px;
|
|
||||||
}
|
|
||||||
textarea,
|
|
||||||
select
|
|
||||||
{
|
|
||||||
margin-bottom:9px;
|
|
||||||
}
|
|
||||||
select,
|
|
||||||
/*textarea,*/
|
|
||||||
input[type="text"],
|
|
||||||
input[type="password"],
|
|
||||||
input[type="datetime"],
|
|
||||||
input[type="datetime-local"],
|
|
||||||
input[type="date"],
|
|
||||||
input[type="month"],
|
|
||||||
input[type="time"],
|
|
||||||
input[type="week"],
|
|
||||||
input[type="number"],
|
|
||||||
input[type="email"],
|
|
||||||
input[type="url"],
|
|
||||||
input[type="search"],
|
|
||||||
input[type="tel"],
|
|
||||||
input[type="color"],
|
|
||||||
.uneditable-input,
|
|
||||||
a.btn-lnk
|
|
||||||
{
|
|
||||||
height:18px;
|
|
||||||
padding:4px;
|
|
||||||
font-size:13px;
|
|
||||||
line-height:18px;
|
|
||||||
}
|
|
||||||
.design h3,
|
|
||||||
.plugin h3
|
|
||||||
{
|
|
||||||
background-position:0 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
select,
|
|
||||||
input[type="file"]
|
|
||||||
{
|
|
||||||
height:28px;
|
|
||||||
line-height:28px;
|
|
||||||
}
|
|
||||||
input[type="submit"],
|
|
||||||
input[type="button"]
|
|
||||||
{
|
|
||||||
font-size:13px;
|
|
||||||
height:28px;
|
|
||||||
line-height:18px;
|
|
||||||
padding:4px 10px;
|
|
||||||
}
|
|
||||||
input[type="radio"],
|
|
||||||
input[type="checkbox"]
|
|
||||||
{
|
|
||||||
margin-top:2px;
|
|
||||||
}
|
|
||||||
.button.btn
|
|
||||||
{
|
|
||||||
line-height:1.25em;
|
|
||||||
font-size:inherit;
|
|
||||||
border:none;
|
|
||||||
text-shadow:none;
|
|
||||||
margin-bottom:0px;
|
|
||||||
-webkit-border-radius:0px;
|
|
||||||
-moz-border-radius:0px;
|
|
||||||
border-radius:0px;
|
|
||||||
-webkit-box-shadow:none;
|
|
||||||
-moz-box-shadow:none;
|
|
||||||
box-shadow:none);
|
|
||||||
}
|
|
||||||
.button.btn:hover
|
|
||||||
{
|
|
||||||
background-color:transparent;
|
|
||||||
-webkit-transition: background-position 0s linear;
|
|
||||||
-moz-transition: background-position 0s linear;
|
|
||||||
-o-transition: background-position 0s linear;
|
|
||||||
transition: background-position 0s linear;
|
|
||||||
}
|
|
||||||
form label
|
|
||||||
{
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.help
|
|
||||||
{
|
|
||||||
border-color:transparent;
|
|
||||||
}
|
|
||||||
/* tree menu */
|
|
||||||
.folder
|
|
||||||
{
|
|
||||||
border:none;
|
|
||||||
}
|
|
||||||
.folder>i
|
|
||||||
{
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
.celled
|
|
||||||
{
|
|
||||||
padding-top: 2px;
|
|
||||||
}
|
|
||||||
.celled-one
|
|
||||||
{
|
|
||||||
padding-top: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.test h3
|
|
||||||
{
|
|
||||||
border:0;
|
|
||||||
padding-left:18px;
|
|
||||||
}
|
|
||||||
/*=============================================================
|
|
||||||
FLASH MESSAGEBOX
|
|
||||||
==============================================================*/
|
|
||||||
.flash
|
|
||||||
{
|
|
||||||
position:fixed;
|
|
||||||
width:50%;
|
|
||||||
top:49px;
|
|
||||||
left:25%;
|
|
||||||
right:25%;
|
|
||||||
cursor:default;
|
|
||||||
text-align:center;
|
|
||||||
padding:8px 35px 8px 14px;
|
|
||||||
z-index:5620;
|
|
||||||
}
|
|
||||||
.flash>.close
|
|
||||||
{
|
|
||||||
color:inherit;
|
|
||||||
opacity:0.7;
|
|
||||||
}
|
|
||||||
.flash>.close:hover
|
|
||||||
{
|
|
||||||
opacity:0.9;
|
|
||||||
}
|
|
||||||
/*=============================================================
|
|
||||||
NAVBAR
|
|
||||||
==============================================================*/
|
|
||||||
.navbar-fixed-top .navbar-inner,
|
|
||||||
.navbar-static-top .navbar-inner
|
|
||||||
{
|
|
||||||
/* in place of shadow image */
|
|
||||||
-webkit-box-shadow:0px 10px 20px rgba(195,195,195,1.0);
|
|
||||||
-moz-box-shadow: 0px 10px 20px rgba(195,195,195,1.0);
|
|
||||||
box-shadow: 0px 10px 20px rgba(195,195,195,1.0);
|
|
||||||
//zoom:1; /* IE6-9 */
|
|
||||||
filter:progid:DXImageTransform.Microsoft.DropShadow(OffX=0, OffY=10, Color=#000000); /* IE6-9 */
|
|
||||||
padding:0;
|
|
||||||
}
|
|
||||||
.navbar-inverse .navbar-inner
|
|
||||||
{
|
|
||||||
min-height:33px; /* required - override */
|
|
||||||
height:33px;
|
|
||||||
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
|
|
||||||
background:#292929 url(../images/header_bg.png) repeat-x;
|
|
||||||
border:none;
|
|
||||||
}
|
|
||||||
#header
|
|
||||||
{
|
|
||||||
background:transparent;
|
|
||||||
}
|
|
||||||
#header.navbar
|
|
||||||
{
|
|
||||||
overflow:visible;
|
|
||||||
}
|
|
||||||
.navbar-inverse .nav > li > a
|
|
||||||
{
|
|
||||||
padding:0;
|
|
||||||
line-height:1.25;
|
|
||||||
text-shadow:none;
|
|
||||||
}
|
|
||||||
.navbar .btn-navbar
|
|
||||||
{
|
|
||||||
padding:4px;
|
|
||||||
margin:5px 5px 0 5px;
|
|
||||||
}
|
|
||||||
#menu{margin-right:-7px;}
|
|
||||||
/*=============================================================
|
|
||||||
FOOTER
|
|
||||||
==============================================================*/
|
|
||||||
#footer
|
|
||||||
{
|
|
||||||
padding-bottom:0;
|
|
||||||
}
|
|
||||||
/*=============================================================
|
|
||||||
MAIN
|
|
||||||
==============================================================*/
|
|
||||||
#main
|
|
||||||
{
|
|
||||||
position:static;
|
|
||||||
padding-top:0;
|
|
||||||
padding-bottom:0;
|
|
||||||
}
|
|
||||||
/*=============================================================
|
|
||||||
SIDEBAR
|
|
||||||
==============================================================*/
|
|
||||||
.sidebar_inner
|
|
||||||
{
|
|
||||||
background:transparent;
|
|
||||||
padding:0;
|
|
||||||
min-width:auto;
|
|
||||||
}
|
|
||||||
.sidebar .box {
|
|
||||||
border-top:1px solid #EEE;
|
|
||||||
}
|
|
||||||
/*=============================================================
|
|
||||||
WIZARD
|
|
||||||
==============================================================*/
|
|
||||||
.step div.help li
|
|
||||||
{
|
|
||||||
line-height:inherit;
|
|
||||||
}
|
|
||||||
.ms-container .ms-selectable li.ms-elem-selectable,
|
|
||||||
.ms-container .ms-selection li.ms-elem-selected
|
|
||||||
{
|
|
||||||
font-size:13px;
|
|
||||||
}
|
|
||||||
.input-append a.btn
|
|
||||||
{
|
|
||||||
padding:4px;
|
|
||||||
height:18px;
|
|
||||||
font-size:13px;
|
|
||||||
line-height:18px;
|
|
||||||
}
|
|
||||||
/*=============================================================
|
|
||||||
ERRORS TABLE
|
|
||||||
==============================================================*/
|
|
||||||
.errors .table th
|
|
||||||
{
|
|
||||||
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.tablebar span.help
|
|
||||||
{
|
|
||||||
font-weight:normal;
|
|
||||||
line-height:1.25em;
|
|
||||||
text-shadow:none;
|
|
||||||
width:auto;
|
|
||||||
}
|
|
||||||
/*=============================================================
|
|
||||||
TOOLTIP
|
|
||||||
==============================================================*/
|
|
||||||
.tooltip.in
|
|
||||||
{
|
|
||||||
opacity:1;
|
|
||||||
filter:alpha(opacity=100);
|
|
||||||
}
|
|
||||||
.tooltip-inner
|
|
||||||
{
|
|
||||||
opacity:1;
|
|
||||||
text-align:left;
|
|
||||||
background:#9fb364;
|
|
||||||
color:#eef1d9;
|
|
||||||
border:1px solid #eef1d9;
|
|
||||||
font-style:italic;
|
|
||||||
padding:0.3em;
|
|
||||||
-moz-border-radius:0.5em;
|
|
||||||
border-radius:0.5em;
|
|
||||||
font-size:13px;
|
|
||||||
text-transform:none;
|
|
||||||
}
|
|
||||||
.tooltip.right .tooltip-arrow,
|
|
||||||
.tooltip.left .tooltip-arrow
|
|
||||||
{
|
|
||||||
border-color:transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
THE GRID
|
|
||||||
==============================================================*/
|
|
||||||
.w2p_grid_bottom_bar .w2p_export_menu
|
|
||||||
{
|
|
||||||
line-height:18px;
|
|
||||||
margin-left:0;
|
|
||||||
}
|
|
||||||
.w2p_export_menu .dropdown-toggle
|
|
||||||
{
|
|
||||||
cursor:pointer;
|
|
||||||
margin:0;
|
|
||||||
padding:0;
|
|
||||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#E6E6E6));
|
|
||||||
background-image: -webkit-linear-gradient(top, white, #E6E6E6);
|
|
||||||
background-image: -o-linear-gradient(top, white, #E6E6E6);
|
|
||||||
background-image: linear-gradient(to bottom, white, #E6E6E6);
|
|
||||||
background-image: -moz-linear-gradient(top, white, #E6E6E6);
|
|
||||||
}
|
|
||||||
.w2p_export_menu ul
|
|
||||||
{
|
|
||||||
margin-top:2px;
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
.w2p_export_menu li
|
|
||||||
{
|
|
||||||
display:list-item;
|
|
||||||
margin:0;
|
|
||||||
}
|
|
||||||
div.web2py_grid
|
|
||||||
{
|
|
||||||
font-size:13px;
|
|
||||||
line-height:18px;
|
|
||||||
}
|
|
||||||
.web2py_grid a.btn
|
|
||||||
{
|
|
||||||
font-size:13px;
|
|
||||||
line-height:18px;
|
|
||||||
padding:4px 10px;
|
|
||||||
margin-left:0;
|
|
||||||
margin-right:4px;
|
|
||||||
|
|
||||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
|
|
||||||
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
|
|
||||||
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
|
|
||||||
background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
|
|
||||||
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
|
|
||||||
}
|
|
||||||
.web2py_grid .input-append .btn
|
|
||||||
{
|
|
||||||
padding:4px 10px;
|
|
||||||
margin-right:0;
|
|
||||||
font-family:inherit;
|
|
||||||
color:#333;
|
|
||||||
text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);
|
|
||||||
border:1px solid #c5c5c5;
|
|
||||||
}
|
|
||||||
.web2py_grid select:focus
|
|
||||||
{
|
|
||||||
border-color:rgba(232,149,60,0.8);
|
|
||||||
outline:0;
|
|
||||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
|
||||||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(232,149,60,0.6);
|
|
||||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(232, 149, 60, 0.6);
|
|
||||||
}
|
|
||||||
.web2py_console input[type="button"],
|
|
||||||
.web2py_grid .row_buttons a.btn
|
|
||||||
{
|
|
||||||
color:#333;
|
|
||||||
line-height:18px;
|
|
||||||
padding:4px 10px;
|
|
||||||
text-shadow:rgba(255, 255, 255, 0.74902) 0px 1px 1px;
|
|
||||||
border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
-moz-border-radius: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
.web2py_console input[type="button"]:hover,
|
|
||||||
.web2py_grid .row_buttons a.btn:hover
|
|
||||||
{
|
|
||||||
color:#333;
|
|
||||||
border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
|
|
||||||
background:#E6E6E6;
|
|
||||||
background-position: 0 -15px !important;
|
|
||||||
-webkit-transition: background-position .1s linear;
|
|
||||||
-moz-transition: background-position .1s linear;
|
|
||||||
-o-transition: background-position .1s linear;
|
|
||||||
transition: background-position .1s linear;
|
|
||||||
}
|
|
||||||
.web2py_table
|
|
||||||
{
|
|
||||||
border:none;
|
|
||||||
}
|
|
||||||
.web2py_table table
|
|
||||||
{
|
|
||||||
/*table-layout:fixed;*/
|
|
||||||
margin-bottom:4px;
|
|
||||||
}
|
|
||||||
.web2py_table table td
|
|
||||||
{
|
|
||||||
/*word-wrap:break-word;*/ /*uncomment when "table-layout:fixed" is applied */
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_grid thead th
|
|
||||||
{
|
|
||||||
background-color:transparent;
|
|
||||||
padding:4px 5px;
|
|
||||||
line-height:18px;
|
|
||||||
vertical-align:bottom;
|
|
||||||
border-right:0;
|
|
||||||
border-bottom:0;
|
|
||||||
word-wrap:break-word;
|
|
||||||
}
|
|
||||||
.web2py_grid .btn-group > .dropdown-menu
|
|
||||||
{
|
|
||||||
font-size:13px;
|
|
||||||
}
|
|
||||||
.web2py_grid .dropdown-menu li > a:hover,
|
|
||||||
.web2py_grid .dropdown-menu li > a:focus
|
|
||||||
{
|
|
||||||
filter:progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */
|
|
||||||
background-image:none;
|
|
||||||
background-color:#E8953C;
|
|
||||||
}
|
|
||||||
.pagination
|
|
||||||
{
|
|
||||||
margin:0;
|
|
||||||
height:30px;
|
|
||||||
}
|
|
||||||
.pagination ul > li > a
|
|
||||||
{
|
|
||||||
line-height:28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#w2p_grid_addbtn:focus,
|
|
||||||
#w2p_search-form :focus,
|
|
||||||
.btn:focus
|
|
||||||
{
|
|
||||||
outline:none;
|
|
||||||
}
|
|
||||||
.web2py_console input[type="button"]:focus,
|
|
||||||
.web2py_grid .row_buttons a.btn:focus
|
|
||||||
{
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15) inset, 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
div.web2py_counter.span6
|
|
||||||
{
|
|
||||||
min-height:20px;
|
|
||||||
}
|
|
||||||
.web2py_paginator
|
|
||||||
{
|
|
||||||
border:0;
|
|
||||||
margin:0;
|
|
||||||
padding:0;
|
|
||||||
background-color:transparent;
|
|
||||||
}
|
|
||||||
.web2py_paginator ul li a
|
|
||||||
{
|
|
||||||
margin-right:0;
|
|
||||||
padding:0 14px;
|
|
||||||
border:1px solid #DDD;
|
|
||||||
border-left-width:0;
|
|
||||||
color:#E8953C;
|
|
||||||
}
|
|
||||||
.web2py_paginator ul li a:hover
|
|
||||||
{
|
|
||||||
background: whiteSmoke;
|
|
||||||
border: 1px solid #DDD;
|
|
||||||
border-left-width:0;
|
|
||||||
color:#e2821b;
|
|
||||||
}
|
|
||||||
.web2py_paginator ul li:first-child a,
|
|
||||||
.web2py_paginator ul li:first-child a:hover
|
|
||||||
{
|
|
||||||
border-left-width:1px;
|
|
||||||
}
|
|
||||||
.web2py_paginator .current
|
|
||||||
{
|
|
||||||
font-weight:normal;
|
|
||||||
}
|
|
||||||
.web2py_paginator ul li.current a:hover
|
|
||||||
{
|
|
||||||
color:#999;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.editor-bar-column a[name="save"]
|
|
||||||
{
|
|
||||||
background-color: whiteSmoke;
|
|
||||||
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
|
|
||||||
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-image: -o-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-image: linear-gradient(to bottom,white,#E6E6E6);
|
|
||||||
background-image: -moz-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
padding:2px 6px;
|
|
||||||
font-size:11px;
|
|
||||||
line-height:17px;
|
|
||||||
margin:0;
|
|
||||||
}
|
|
||||||
.editor-bar-column a[name="save"]:hover
|
|
||||||
{
|
|
||||||
background-color: #E6E6E6;
|
|
||||||
background-position: 0 -15px;
|
|
||||||
-webkit-transition: background-position .1s linear;
|
|
||||||
-moz-transition: background-position .1s linear;
|
|
||||||
-o-transition: background-position .1s linear;
|
|
||||||
transition: background-position .1s linear;
|
|
||||||
}
|
|
||||||
.keybindings
|
|
||||||
{
|
|
||||||
padding:0 18px 10px;
|
|
||||||
}
|
|
||||||
.keybindings li
|
|
||||||
{
|
|
||||||
margin-bottom:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*----- translate page ---*/
|
|
||||||
|
|
||||||
.languageform input
|
|
||||||
{
|
|
||||||
margin-bottom:0;
|
|
||||||
}
|
|
||||||
.languageform div
|
|
||||||
{
|
|
||||||
margin-bottom:9px;
|
|
||||||
}
|
|
||||||
.languageform input.untranslated
|
|
||||||
{
|
|
||||||
background-color:#FC0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.step #wizard_nav .first-box
|
|
||||||
{
|
|
||||||
padding-top:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
MEDIA QUERIES
|
|
||||||
==============================================================*/
|
|
||||||
@media (max-width: 979px)
|
|
||||||
{
|
|
||||||
/*-----------------------------------
|
|
||||||
Navbar
|
|
||||||
-------------------------------------*/
|
|
||||||
#header .navbar-inner
|
|
||||||
{
|
|
||||||
padding:0;
|
|
||||||
}
|
|
||||||
/*collapsed menu*/
|
|
||||||
.navbar .nav-collapse .nav
|
|
||||||
{
|
|
||||||
background:#222;
|
|
||||||
padding:8px 2px 8px 8px;
|
|
||||||
-webkit-border-bottom-right-radius:8px;
|
|
||||||
-webkit-border-bottom-left-radius:8px;
|
|
||||||
-moz-border-radius-bottomright:8px;
|
|
||||||
-moz-border-radius-bottomleft:8px;
|
|
||||||
border-bottom-right-radius:8px;
|
|
||||||
border-bottom-left-radius:8px;
|
|
||||||
}
|
|
||||||
#menu
|
|
||||||
{
|
|
||||||
margin-right:0;
|
|
||||||
}
|
|
||||||
#menu li
|
|
||||||
{
|
|
||||||
float:none;
|
|
||||||
}
|
|
||||||
#menu a.button,
|
|
||||||
#menu a.button span
|
|
||||||
{
|
|
||||||
background-image:url(../images/menu_responsive.png);
|
|
||||||
}
|
|
||||||
#menu a.button
|
|
||||||
{
|
|
||||||
padding:0 1em 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media(max-width:632px)
|
|
||||||
{
|
|
||||||
/*-----------------------------------
|
|
||||||
footer
|
|
||||||
-------------------------------------*/
|
|
||||||
#footer
|
|
||||||
{
|
|
||||||
height:auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer select
|
|
||||||
{
|
|
||||||
margin-top:8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -476,7 +476,7 @@ h4.editableapp { background: #fff url(../images/folder.png) no-repeat; }
|
|||||||
|
|
||||||
h4.currentapp { background: #fff url(../images/folder_locked.png) no-repeat; }
|
h4.currentapp { background: #fff url(../images/folder_locked.png) no-repeat; }
|
||||||
|
|
||||||
.flash { position:fixed; width:50%; top:49px; left:25%; right:25%; cursor:default; text-align:center; z-index:5620; }
|
.w2p_flash { position:fixed; width:50%; top:49px; left:25%; right:25%; cursor:default; text-align:center; z-index:5620; }
|
||||||
span#closeflash {position:absolute; top:1px; right:-1px; font-size:150%; border:1px solid black; border-color: transparent transparent #fbeed5 #fbeed5; border-radius: 0 0 0 4px; width:22px; }
|
span#closeflash {position:absolute; top:1px; right:-1px; font-size:150%; border:1px solid black; border-color: transparent transparent #fbeed5 #fbeed5; border-radius: 0 0 0 4px; width:22px; }
|
||||||
span#closeflash:hover {font-weight:bold; cursor:pointer; }
|
span#closeflash:hover {font-weight:bold; cursor:pointer; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,322 +0,0 @@
|
|||||||
/** these MUST stay **/
|
|
||||||
a {text-decoration:none; white-space:nowrap}
|
|
||||||
a:hover {text-decoration:underline}
|
|
||||||
a.button {text-decoration:none}
|
|
||||||
h1,h2,h3,h4,h5,h6 {margin:0.5em 0 0.25em 0; display:block;
|
|
||||||
font-family:Helvetica}
|
|
||||||
h1 {font-size:4.00em}
|
|
||||||
h2 {font-size:3.00em}
|
|
||||||
h3 {font-size:2.00em}
|
|
||||||
h4 {font-size:1.50em}
|
|
||||||
h5 {font-size:1.25em}
|
|
||||||
h6 {font-size:1.12em}
|
|
||||||
th,label {font-weight:bold; white-space:nowrap;}
|
|
||||||
td,th {text-align:left; padding:2px 5px 2px 5px}
|
|
||||||
th {vertical-align:middle; border-right:1px solid white}
|
|
||||||
td {vertical-align:top}
|
|
||||||
form table tr td label {text-align:left}
|
|
||||||
p,table,ol,ul {padding:0; margin: 0.75em 0}
|
|
||||||
p {text-align:justify}
|
|
||||||
ol, ul {list-style-position:outside; margin-left:2em}
|
|
||||||
li {margin-bottom:0.5em}
|
|
||||||
span,input,select,textarea,button,label,a {display:inline}
|
|
||||||
img {border:0}
|
|
||||||
blockquote,blockquote p,p blockquote {
|
|
||||||
font-style:italic; margin:0.5em 30px 0.5em 30px; font-size:0.9em}
|
|
||||||
i,em {font-style:italic}
|
|
||||||
strong {font-weight:bold}
|
|
||||||
small {font-size:0.8em}
|
|
||||||
code {font-family:Courier}
|
|
||||||
textarea {width:100%}
|
|
||||||
video {width:400px}
|
|
||||||
audio {width:200px}
|
|
||||||
[type="text"], [type="password"], select {
|
|
||||||
margin-right: 5px; width: 300px;
|
|
||||||
}
|
|
||||||
.hidden {display:none;visibility:visible}
|
|
||||||
.right {float:right; text-align:right}
|
|
||||||
.left {float:left; text-align:left}
|
|
||||||
.center {width:100%; text-align:center; vertical-align:middle}
|
|
||||||
/** end **/
|
|
||||||
|
|
||||||
/* Sticky footer begin */
|
|
||||||
|
|
||||||
.main {
|
|
||||||
padding:20px 0 50px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer,.push {
|
|
||||||
height:6em;
|
|
||||||
padding:1em 0;
|
|
||||||
clear:both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-content {position:relative; bottom:-4em; width:100%}
|
|
||||||
|
|
||||||
.auth_navbar {
|
|
||||||
white-space:nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sticky footer end */
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
border-top:1px #DEDEDE solid;
|
|
||||||
}
|
|
||||||
.header {
|
|
||||||
/* background:<fill here for header image>; */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fieldset {padding:16px; border-top:1px #DEDEDE solid}
|
|
||||||
fieldset legend {text-transform:uppercase; font-weight:bold; padding:4px 16px 4px 16px; background:#f1f1f1}
|
|
||||||
|
|
||||||
/* fix ie problem with menu */
|
|
||||||
|
|
||||||
td.w2p_fw {padding-bottom:1px}
|
|
||||||
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
|
|
||||||
td.w2p_fl {text-align:left}
|
|
||||||
td.w2p_fl, td.w2p_fw {padding-right:7px}
|
|
||||||
td.w2p_fl,td.w2p_fc {padding-top:4px}
|
|
||||||
div.w2p_export_menu {margin:5px 0}
|
|
||||||
div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; padding:2px 5px; background-color:#f1f1f1; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px;}
|
|
||||||
|
|
||||||
/* tr#submit_record__row {border-top:1px solid #E5E5E5} */
|
|
||||||
#submit_record__row td {padding-top:.5em}
|
|
||||||
|
|
||||||
/* Fix */
|
|
||||||
#auth_user_remember__row label {display:inline}
|
|
||||||
#web2py_user_form td {vertical-align:top}
|
|
||||||
|
|
||||||
/*********** web2py specific ***********/
|
|
||||||
div.flash {
|
|
||||||
font-weight:bold;
|
|
||||||
display:none;
|
|
||||||
position:fixed;
|
|
||||||
padding:10px;
|
|
||||||
top:48px;
|
|
||||||
right:250px;
|
|
||||||
min-width:280px;
|
|
||||||
opacity:0.95;
|
|
||||||
margin:0px 0px 10px 10px;
|
|
||||||
vertical-align:middle;
|
|
||||||
cursor:pointer;
|
|
||||||
color:#fff;
|
|
||||||
background-color:#000;
|
|
||||||
border:2px solid #fff;
|
|
||||||
border-radius:8px;
|
|
||||||
-o-border-radius: 8px;
|
|
||||||
-moz-border-radius:8px;
|
|
||||||
-webkit-border-radius:8px;
|
|
||||||
background-image: -webkit-linear-gradient(top,#222,#000);
|
|
||||||
background-image: -o-linear-gradient(top,#222,#000);
|
|
||||||
background-image: -moz-linear-gradient(90deg, #222, #000);
|
|
||||||
background-image: linear-gradient(top,#222,#000);
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
z-index:2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.flash #closeflash{color:inherit; float:right; margin-left:15px;}
|
|
||||||
.ie-lte7 div.flash #closeflash
|
|
||||||
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
|
|
||||||
|
|
||||||
div.flash:hover { opacity:0.25; }
|
|
||||||
|
|
||||||
div.error_wrapper {display:block}
|
|
||||||
div.error {
|
|
||||||
width: 298px;
|
|
||||||
background:red;
|
|
||||||
border: 2px solid #d00;
|
|
||||||
color:white;
|
|
||||||
padding:5px;
|
|
||||||
display:inline-block;
|
|
||||||
background-image: -webkit-linear-gradient(left,#f00,#fdd);
|
|
||||||
background-image: -o-linear-gradient(left,#f00,#fdd);
|
|
||||||
background-image: -moz-linear-gradient(0deg, #f00, #fdd);
|
|
||||||
background-image: linear-gradient(left,#f00,#fdd);
|
|
||||||
background-repeat: repeat-y;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar {
|
|
||||||
padding:10px 0;
|
|
||||||
width:100%;
|
|
||||||
color:#959595;
|
|
||||||
vertical-align:middle;
|
|
||||||
padding:auto;
|
|
||||||
background-image:-khtml-gradient(linear,left top,left bottom,from(#333333),to(#222222));
|
|
||||||
background-image:-moz-linear-gradient(top,#333333,#222222);
|
|
||||||
background-image:-ms-linear-gradient(top,#333333,#222222);
|
|
||||||
background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#333333),color-stop(100%,#222222));
|
|
||||||
background-image:-webkit-linear-gradient(top,#333333,#222222);
|
|
||||||
background-image:-o-linear-gradient(top,#333333,#222222);
|
|
||||||
background-image:linear-gradient(top,#333333,#222222);
|
|
||||||
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333',endColorstr='#222222',GradientType=0);
|
|
||||||
-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);
|
|
||||||
-moz-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);
|
|
||||||
box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar a {
|
|
||||||
color:#e1e1e1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navbar {float:right; padding:5px; /* same as superfish */}
|
|
||||||
|
|
||||||
.statusbar {
|
|
||||||
background-color:#F5F5F5;
|
|
||||||
margin-top:1em;
|
|
||||||
margin-bottom:1em;
|
|
||||||
padding:.5em 1em;
|
|
||||||
border:1px solid #ddd;
|
|
||||||
border-radius:5px;
|
|
||||||
-moz-border-radius:5px;
|
|
||||||
-webkit-border-radius:5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumbs {float:left}
|
|
||||||
|
|
||||||
.copyright {float:left}
|
|
||||||
#poweredBy {float:right}
|
|
||||||
|
|
||||||
/* #MEDIA QUERIES SECTION */
|
|
||||||
|
|
||||||
/*
|
|
||||||
*Grid
|
|
||||||
*
|
|
||||||
* The default style for SQLFORM.grid even using jquery-iu or another ui framework
|
|
||||||
* will look better with the declarations below
|
|
||||||
* if needed to remove base.css consider keeping these following lines in some css file.
|
|
||||||
*/
|
|
||||||
/* .web2py_table {border:1px solid #ccc} */
|
|
||||||
.web2py_paginator {}
|
|
||||||
.web2py_grid {width:100%}
|
|
||||||
.web2py_grid table {width:100%}
|
|
||||||
.web2py_grid tbody td {padding:2px 5px 2px 5px; vertical-align: middle;}
|
|
||||||
.web2py_grid .web2py_form td {vertical-align: top;}
|
|
||||||
|
|
||||||
.web2py_grid thead th,.web2py_grid tfoot td {
|
|
||||||
background-color:#EAEAEA;
|
|
||||||
padding:10px 5px 10px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_grid tr.odd {background-color:#F9F9F9}
|
|
||||||
.web2py_grid tr:hover {background-color:#F5F5F5}
|
|
||||||
|
|
||||||
/*
|
|
||||||
.web2py_breadcrumbs a {
|
|
||||||
line-height:20px; margin-right:5px; display:inline-block;
|
|
||||||
padding:3px 5px 3px 5px;
|
|
||||||
font-family:'lucida grande',tahoma,verdana,arial,sans-serif;
|
|
||||||
color:#3C3C3D;
|
|
||||||
text-shadow:1px 1px 0 #FFFFFF;
|
|
||||||
white-space:nowrap; overflow:visible; cursor:pointer;
|
|
||||||
background:#ECECEC;
|
|
||||||
border:1px solid #CACACA;
|
|
||||||
-webkit-border-radius:2px; -moz-border-radius:2px;
|
|
||||||
-webkit-background-clip:padding-box; border-radius:2px;
|
|
||||||
outline:none; position:relative; zoom:1; *display:inline;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
.web2py_console form {
|
|
||||||
width: 100%;
|
|
||||||
display: inline;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin: 0 0 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_console form select {
|
|
||||||
margin:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_search_actions {
|
|
||||||
float:left;
|
|
||||||
text-align:left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_grid .row_buttons {
|
|
||||||
min-height:25px;
|
|
||||||
vertical-align:middle;
|
|
||||||
}
|
|
||||||
.web2py_grid .row_buttons a {
|
|
||||||
margin:3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_search_actions {
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_grid .row_buttons a,
|
|
||||||
.web2py_paginator ul li a,
|
|
||||||
.web2py_search_actions a,
|
|
||||||
.web2py_console input[type=submit],
|
|
||||||
.web2py_console input[type=button],
|
|
||||||
.web2py_console button {
|
|
||||||
line-height:20px;
|
|
||||||
margin-right:2px; display:inline-block;
|
|
||||||
padding:3px 5px 3px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_counter {
|
|
||||||
margin-top:5px;
|
|
||||||
margin-right:2px;
|
|
||||||
width:35%;
|
|
||||||
float:right;
|
|
||||||
text-align:right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*Fix firefox problem*/
|
|
||||||
.web2py_table {clear:both; display:block}
|
|
||||||
|
|
||||||
.web2py_paginator {
|
|
||||||
padding:5px;
|
|
||||||
text-align:right;
|
|
||||||
background-color:#f2f2f2;
|
|
||||||
|
|
||||||
}
|
|
||||||
.web2py_paginator ul {
|
|
||||||
list-style-type:none;
|
|
||||||
margin:0px;
|
|
||||||
padding:0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_paginator ul li {
|
|
||||||
display:inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_paginator .current {
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_breadcrumbs ul {
|
|
||||||
list-style:none;
|
|
||||||
margin-bottom:18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.w2p_grid_breadcrumb_elem {
|
|
||||||
display:inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_console form { vertical-align: middle; }
|
|
||||||
.web2py_console input, .web2py_console select,
|
|
||||||
.web2py_console a { margin: 2px; }
|
|
||||||
|
|
||||||
.web2py_htmltable {
|
|
||||||
width: 100%;
|
|
||||||
overflow-x: auto;
|
|
||||||
-ms-overflow-x:scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
#wiki_page_body {
|
|
||||||
width: 600px;
|
|
||||||
height: auto;
|
|
||||||
min-height: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fix some IE problems */
|
|
||||||
|
|
||||||
.ie-lte7 .topbar .container {z-index:2}
|
|
||||||
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
|
||||||
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
|
|
||||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
/*=============================================================
|
|
||||||
CUSTOM RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
body{height:auto;} /* to avoid vertical scroll bar */
|
|
||||||
|
|
||||||
a{}
|
|
||||||
a:visited{}
|
|
||||||
a:hover{}
|
|
||||||
a:focus{}
|
|
||||||
a:active{}
|
|
||||||
|
|
||||||
h1{}
|
|
||||||
h2{}
|
|
||||||
h3{}
|
|
||||||
h4{}
|
|
||||||
h5{}
|
|
||||||
h6{}
|
|
||||||
|
|
||||||
div.flash.flash-center{left:25%;right:25%;}
|
|
||||||
div.flash.flash-top,div.flash.flash-top:hover{
|
|
||||||
position:relative;
|
|
||||||
display:block;
|
|
||||||
margin:0;
|
|
||||||
padding:1em;
|
|
||||||
top:0;
|
|
||||||
left:0;
|
|
||||||
width:100%;
|
|
||||||
text-align:center;
|
|
||||||
text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
|
|
||||||
color:#865100;
|
|
||||||
background:#feea9a;
|
|
||||||
border:1px solid;
|
|
||||||
border-top:0px;
|
|
||||||
border-left:0px;
|
|
||||||
border-right:0px;
|
|
||||||
border-radius:0;
|
|
||||||
opacity:1;
|
|
||||||
}
|
|
||||||
#header{margin-top:60px;}
|
|
||||||
.mastheader h1 {
|
|
||||||
margin-bottom:9px;
|
|
||||||
font-size:81px;
|
|
||||||
font-weight:bold;
|
|
||||||
letter-spacing:-1px;
|
|
||||||
line-height:1;
|
|
||||||
font-size:54px;
|
|
||||||
}
|
|
||||||
.mastheader small {
|
|
||||||
font-size:20px;
|
|
||||||
font-weight:300;
|
|
||||||
}
|
|
||||||
/* auth navbar - primitive style */
|
|
||||||
.auth_navbar,.auth_navbar a{color:inherit;}
|
|
||||||
.navbar-inner {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
|
|
||||||
.ie-lte7 .auth_navbar,.auth_navbar a{color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */}
|
|
||||||
.auth_navbar a{white-space:nowrap;} /* to avoid the nav split on more lines */
|
|
||||||
.auth_navbar a:hover{color:white;text-decoration:none;}
|
|
||||||
ul#navbar>.auth_navbar{
|
|
||||||
display:inline-block;
|
|
||||||
padding:5px;
|
|
||||||
}
|
|
||||||
/* form errors message box customization */
|
|
||||||
div.error_wrapper{margin-bottom:9px;}
|
|
||||||
div.error_wrapper .error{
|
|
||||||
border-radius: 4px;
|
|
||||||
-o-border-radius: 4px;
|
|
||||||
-moz-border-radius: 4px;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
}
|
|
||||||
/* below rules are only for formstyle = bootstrap
|
|
||||||
trying to make errors look like bootstrap ones */
|
|
||||||
div.controls .error_wrapper{
|
|
||||||
display:inline-block;
|
|
||||||
margin-bottom:0;
|
|
||||||
vertical-align:middle;
|
|
||||||
}
|
|
||||||
div.controls .error{
|
|
||||||
min-width:5px;
|
|
||||||
background:inherit;
|
|
||||||
color:#B94A48;
|
|
||||||
border:none;
|
|
||||||
padding:0;
|
|
||||||
margin:0;
|
|
||||||
/*display:inline;*/ /* uncommenting this, the animation effect is lost */
|
|
||||||
}
|
|
||||||
div.controls .help-inline{color:#3A87AD;}
|
|
||||||
div.controls .error_wrapper +.help-inline {margin-left:-99999px;}
|
|
||||||
div.controls select +.error_wrapper {margin-left:5px;}
|
|
||||||
.ie-lte7 div.error{color:#fff;}
|
|
||||||
|
|
||||||
/* beautify brand */
|
|
||||||
.navbar {margin-bottom:0}
|
|
||||||
.navbar-inverse .brand{color:#c6cecc;}
|
|
||||||
.navbar-inverse .brand b{display:inline-block;margin-top:-1px;}
|
|
||||||
.navbar-inverse .brand b>span{font-size:22px;color:white}
|
|
||||||
.navbar-inverse .brand:hover b>span{color:white}
|
|
||||||
/* beautify web2py link in navbar */
|
|
||||||
span.highlighted{color:#d8d800;}
|
|
||||||
.open span.highlighted{color:#ffff00;}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OVERRIDING WEB2PY.CSS RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/* reset to default */
|
|
||||||
a{white-space:normal;}
|
|
||||||
li{margin-bottom:0;}
|
|
||||||
textarea,button{display:block;}
|
|
||||||
/*reset ul padding */
|
|
||||||
ul#navbar{padding:0;}
|
|
||||||
/* label aligned to related input */
|
|
||||||
td.w2p_fl,td.w2p_fc {padding:0;}
|
|
||||||
#web2py_user_form td{vertical-align:middle;}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OVERRIDING BOOTSTRAP.CSS RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/* because web2py handles this via js */
|
|
||||||
textarea { width:90%}
|
|
||||||
.hidden{visibility:visible;}
|
|
||||||
/* right folder for bootstrap black images/icons */
|
|
||||||
[class^="icon-"],[class*=" icon-"]{
|
|
||||||
background-image:url("../images/glyphicons-halflings.png")
|
|
||||||
}
|
|
||||||
/* right folder for bootstrap white images/icons */
|
|
||||||
.icon-white,
|
|
||||||
.nav-tabs > .active > a > [class^="icon-"],
|
|
||||||
.nav-tabs > .active > a > [class*=" icon-"],
|
|
||||||
.nav-pills > .active > a > [class^="icon-"],
|
|
||||||
.nav-pills > .active > a > [class*=" icon-"],
|
|
||||||
.nav-list > .active > a > [class^="icon-"],
|
|
||||||
.nav-list > .active > a > [class*=" icon-"],
|
|
||||||
.navbar-inverse .nav > .active > a > [class^="icon-"],
|
|
||||||
.navbar-inverse .nav > .active > a > [class*=" icon-"],
|
|
||||||
.dropdown-menu > li > a:hover > [class^="icon-"],
|
|
||||||
.dropdown-menu > li > a:hover > [class*=" icon-"],
|
|
||||||
.dropdown-menu > .active > a > [class^="icon-"],
|
|
||||||
.dropdown-menu > .active > a > [class*=" icon-"] {
|
|
||||||
background-image:url("../images/glyphicons-halflings-white.png");
|
|
||||||
}
|
|
||||||
/* bootstrap has a label as input's wrapper while web2py has a div */
|
|
||||||
div>input[type="radio"],div>input[type="checkbox"]{margin:0;}
|
|
||||||
/* bootstrap has button instead of input */
|
|
||||||
input[type="button"], input[type="submit"]{margin-right:8px;}
|
|
||||||
|
|
||||||
/* web2py radio widget adjustment */
|
|
||||||
.generic-widget input[type='radio'] {margin:-1px 0 0 0; vertical-align: middle;}
|
|
||||||
.generic-widget input[type='radio'] + label {display:inline-block; margin:0 0 0 6px; vertical-align: middle;}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
RULES FOR SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/*when formstyle=table3cols*/
|
|
||||||
tr#auth_user_remember__row>td.w2p_fw>div{padding-bottom:8px;}
|
|
||||||
td.w2p_fw div>label{vertical-align:middle;}
|
|
||||||
td.w2p_fc {padding-bottom:5px;}
|
|
||||||
/*when formstyle=divs*/
|
|
||||||
div#auth_user_remember__row{margin-top:4px;}
|
|
||||||
div#auth_user_remember__row>.w2p_fl{display:none;}
|
|
||||||
div#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
|
||||||
div.w2p_fw,div.w2p_fc{
|
|
||||||
display:inline-block;
|
|
||||||
vertical-align:middle;
|
|
||||||
margin-bottom:0;
|
|
||||||
}
|
|
||||||
div.w2p_fc{
|
|
||||||
padding-left:5px;
|
|
||||||
margin-top:-8px;
|
|
||||||
}
|
|
||||||
/*when formstyle=ul*/
|
|
||||||
form>ul{
|
|
||||||
list-style:none;
|
|
||||||
margin:0;
|
|
||||||
}
|
|
||||||
li#auth_user_remember__row{margin-top:4px;}
|
|
||||||
li#auth_user_remember__row>.w2p_fl{display:none;}
|
|
||||||
li#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
|
||||||
/*when formstyle=bootstrap*/
|
|
||||||
#auth_user_remember__row label.checkbox{display:block;}
|
|
||||||
span.inline-help{display:inline-block;}
|
|
||||||
input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px;}
|
|
||||||
/*when recaptcha is used*/
|
|
||||||
#recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;}
|
|
||||||
td>#recaptcha{margin-bottom:6px;}
|
|
||||||
div>#recaptcha{margin-bottom:9px;}
|
|
||||||
div.control-group.error{
|
|
||||||
width:auto;
|
|
||||||
background:transparent;
|
|
||||||
border:0;
|
|
||||||
color:inherit;
|
|
||||||
padding:0;
|
|
||||||
background-repeat:repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OTHER RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/* Massimo Di Pierro fixed alignment in forms with list:string */
|
|
||||||
form table tr{margin-bottom:9px;}
|
|
||||||
td.w2p_fw ul{margin-left:0px;}
|
|
||||||
|
|
||||||
/* web2py_console in grid and smartgrid */
|
|
||||||
.hidden{visibility:visible;}
|
|
||||||
.web2py_console input{
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.web2py_console input[type="submit"],
|
|
||||||
.web2py_console input[type="button"],
|
|
||||||
.web2py_console button{
|
|
||||||
padding-top:4px;
|
|
||||||
padding-bottom:4px;
|
|
||||||
margin:3px 0 0 2px;
|
|
||||||
}
|
|
||||||
.web2py_console a,
|
|
||||||
.web2py_console select,
|
|
||||||
.web2py_console input
|
|
||||||
{
|
|
||||||
margin:3px 0 0 2px;
|
|
||||||
}
|
|
||||||
.web2py_grid form table{width:auto;}
|
|
||||||
/* auth_user_remember checkbox extrapadding in IE fix */
|
|
||||||
.ie-lte9 input#auth_user_remember.checkbox {padding-left:0;}
|
|
||||||
|
|
||||||
div.controls .error {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
MEDIA QUERIES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
@media only screen and (max-width:979px){
|
|
||||||
body{padding-top:0px;}
|
|
||||||
#navbar{/*top:5px;*/}
|
|
||||||
div.flash{right:5px;}
|
|
||||||
.dropdown-menu ul{visibility:visible;}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width:479px){
|
|
||||||
body{
|
|
||||||
padding-left:10px;
|
|
||||||
padding-right:10px;
|
|
||||||
}
|
|
||||||
.navbar-fixed-top,.navbar-fixed-bottom {
|
|
||||||
margin-left:-10px;
|
|
||||||
margin-right:-10px;
|
|
||||||
}
|
|
||||||
input[type="text"],input[type="password"],select{
|
|
||||||
width:95%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
.navbar {
|
|
||||||
margin-right: -20px;
|
|
||||||
margin-left: -20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
/*=============================================================
|
|
||||||
BOOTSTRAP DROPDOWN MENU
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
.dropdown-menu ul{
|
|
||||||
left:100%;
|
|
||||||
position:absolute;
|
|
||||||
top:0;
|
|
||||||
visibility:hidden;
|
|
||||||
margin-top:-1px;
|
|
||||||
}
|
|
||||||
.dropdown-menu li:hover ul{visibility:visible;}
|
|
||||||
.navbar .dropdown-menu ul:before{
|
|
||||||
border-bottom:7px solid transparent;
|
|
||||||
border-left:none;
|
|
||||||
border-right:7px solid rgba(0, 0, 0, 0.2);
|
|
||||||
border-top:7px solid transparent;
|
|
||||||
left:-7px;
|
|
||||||
top:5px;
|
|
||||||
}
|
|
||||||
.nav > li.dropdown > a:after {
|
|
||||||
border-left: 4px solid transparent;
|
|
||||||
border-right: 4px solid transparent;
|
|
||||||
border-top: 4px solid #000000;
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
height: 0;
|
|
||||||
opacity: 0.7;
|
|
||||||
vertical-align: top;
|
|
||||||
width: 0;
|
|
||||||
|
|
||||||
margin-left: 2px;
|
|
||||||
margin-top: 8px;
|
|
||||||
|
|
||||||
border-bottom-color: #FFFFFF;
|
|
||||||
border-top-color: #FFFFFF;
|
|
||||||
}
|
|
||||||
.dropdown-menu span{display:inline-block;}
|
|
||||||
ul.dropdown-menu li.dropdown > a:after {
|
|
||||||
border-left: 4px solid #000;
|
|
||||||
border-right: 4px solid transparent;
|
|
||||||
border-bottom: 4px solid transparent;
|
|
||||||
border-top: 4px solid transparent;
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
height: 0;
|
|
||||||
opacity: 0.7;
|
|
||||||
vertical-align: top;
|
|
||||||
width: 0;
|
|
||||||
|
|
||||||
margin-left: 8px;
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li.dropdown:hover ul.dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.open >.dropdown-menu ul{display:block;} /* fix menu issue when BS2.0.4 is applied */
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
BOOTSTRAP SUBMIT BUTTON
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
input[type='submit']:not(.btn) {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 4px 14px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #333;
|
|
||||||
text-align: center;
|
|
||||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
|
|
||||||
vertical-align: middle;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: whiteSmoke;
|
|
||||||
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
|
|
||||||
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-image: -o-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-image: linear-gradient(to bottom,white,#E6E6E6);
|
|
||||||
background-image: -moz-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
border: 1px solid #BBB;
|
|
||||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
|
||||||
border-bottom-color: #A2A2A2;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
-moz-border-radius: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
|
|
||||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
|
||||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
|
|
||||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='submit']:not(.btn):hover {
|
|
||||||
color: #333;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #E6E6E6;
|
|
||||||
background-position: 0 -15px;
|
|
||||||
-webkit-transition: background-position .1s linear;
|
|
||||||
-moz-transition: background-position .1s linear;
|
|
||||||
-o-transition: background-position .1s linear;
|
|
||||||
transition: background-position .1s linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='submit']:not(.btn).active, input[type='submit']:not(.btn):active {
|
|
||||||
background-color: #E6E6E6;
|
|
||||||
background-color: #D9D9D9 9;
|
|
||||||
background-image: none;
|
|
||||||
outline: 0;
|
|
||||||
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
|
||||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OTHER
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
.ie-lte8 .navbar-fixed-top {position:static;}
|
|
||||||
|
|
||||||
@@ -77,10 +77,10 @@ function doClickSave() {
|
|||||||
t.attr('disabled', '');
|
t.attr('disabled', '');
|
||||||
var flash = xhr.getResponseHeader('web2py-component-flash');
|
var flash = xhr.getResponseHeader('web2py-component-flash');
|
||||||
if(flash) {
|
if(flash) {
|
||||||
$('.flash').html(decodeURIComponent(flash))
|
$('.w2p_flash').html(decodeURIComponent(flash))
|
||||||
.append('<a href="#" class="close">×</a>')
|
.append('<a href="#" class="close">×</a>')
|
||||||
.slideDown();
|
.slideDown();
|
||||||
} else $('.flash').hide();
|
} else $('.w2p_flash').hide();
|
||||||
try {
|
try {
|
||||||
if(json.error) {
|
if(json.error) {
|
||||||
window.location.href = json.redirect;
|
window.location.href = json.redirect;
|
||||||
@@ -158,10 +158,10 @@ function doToggleBreakpoint(filename, url, sel) {
|
|||||||
// show flash message (if any)
|
// show flash message (if any)
|
||||||
var flash = xhr.getResponseHeader('web2py-component-flash');
|
var flash = xhr.getResponseHeader('web2py-component-flash');
|
||||||
if(flash) {
|
if(flash) {
|
||||||
$('.flash').html(decodeURIComponent(flash))
|
$('.w2p_flash').html(decodeURIComponent(flash))
|
||||||
.append('<a href="#" class="close">×</a>')
|
.append('<a href="#" class="close">×</a>')
|
||||||
.slideDown();
|
.slideDown();
|
||||||
} else $('.flash').hide();
|
} else $('.w2p_flash').hide();
|
||||||
try {
|
try {
|
||||||
if(json.error) {
|
if(json.error) {
|
||||||
window.location.href = json.redirect;
|
window.location.href = json.redirect;
|
||||||
|
|||||||
+5
-4
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -18,7 +18,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active" id="alltables">
|
<div class="tab-pane active" id="alltables">
|
||||||
<table>
|
<table class="table">
|
||||||
{{for db in sorted(databases):}}
|
{{for db in sorted(databases):}}
|
||||||
{{for table in databases[db].tables:}}
|
{{for table in databases[db].tables:}}
|
||||||
{{qry='%s.%s.id>0'%(db,table)}}
|
{{qry='%s.%s.id>0'%(db,table)}}
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
|
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
|
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn btn-default")}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
</pre>
|
</pre>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{if table:}}
|
{{if table:}}
|
||||||
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
|
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn btn-default")}}<br/><br/>
|
||||||
<h3>{{=T("Rows in Table")}}</h3><br/>
|
<h3>{{=T("Rows in Table")}}</h3><br/>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<h3>{{=T("Rows selected")}}</h3><br/>
|
<h3>{{=T("Rows selected")}}</h3><br/>
|
||||||
@@ -72,8 +72,8 @@
|
|||||||
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
|
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<h4>{{=T("%s selected", nrows)}}</h4>
|
<h4>{{=T("%s selected", nrows)}}</h4>
|
||||||
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn")}}{{pass}}
|
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn btn-default")}}{{pass}}
|
||||||
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn")}}{{pass}}
|
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn btn-default")}}{{pass}}
|
||||||
{{if rows:}}
|
{{if rows:}}
|
||||||
<div style="overflow:auto; width:80%;">
|
<div style="overflow:auto; width:80%;">
|
||||||
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
|
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
|
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
|
||||||
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn">{{=T("export as csv file")}}</a>
|
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn btn-default">{{=T("export as csv file")}}</a>
|
||||||
{{=formcsv or ''}}
|
{{=formcsv or ''}}
|
||||||
|
|
||||||
{{elif request.function=='insert':}}
|
{{elif request.function=='insert':}}
|
||||||
@@ -137,9 +137,9 @@
|
|||||||
<h4>{{=T("Overview")}}</h4>
|
<h4>{{=T("Overview")}}</h4>
|
||||||
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
|
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
|
||||||
{{if total['entries'] > 0:}}
|
{{if total['entries'] > 0:}}
|
||||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses})",
|
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||||
dict(ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
|
dict( ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{=T("Size of cache:")}}
|
{{=T("Size of cache:")}}
|
||||||
{{if object_stats:}}
|
{{if object_stats:}}
|
||||||
@@ -155,8 +155,8 @@
|
|||||||
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
|
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle();')}}
|
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="all_keys">
|
<div class="w2p_hidden" id="all_keys">
|
||||||
{{=total['keys']}}
|
{{=total['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -183,8 +183,8 @@
|
|||||||
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
|
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle();')}}
|
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="ram_keys">
|
<div class="w2p_hidden" id="ram_keys">
|
||||||
{{=ram['keys']}}
|
{{=ram['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -212,8 +212,8 @@
|
|||||||
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
|
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle();')}}
|
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="disk_keys">
|
<div class="w2p_hidden" id="disk_keys">
|
||||||
{{=disk['keys']}}
|
{{=disk['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -249,8 +249,8 @@
|
|||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{{extend 'layout.html'}}
|
{{extend 'layout.html'}}
|
||||||
{{
|
{{
|
||||||
|
import re
|
||||||
|
regex_space = re.compile('\s+')
|
||||||
def all(items):
|
def all(items):
|
||||||
return reduce(lambda a,b:a and b,items,True)
|
return reduce(lambda a,b:a and b,items,True)
|
||||||
def peekfile(path,file,vars={},title=None):
|
def peekfile(path,file,vars={},title=None):
|
||||||
@@ -205,7 +207,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
|||||||
{{=peekfile('views',c, dict(id=id))}}
|
{{=peekfile('views',c, dict(id=id))}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras celled celled-one">
|
<span class="extras celled celled-one">
|
||||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
{{if c in extend:}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
@@ -304,7 +306,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
|||||||
while path!=file_path:
|
while path!=file_path:
|
||||||
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
if len(file_path)>=len(path) and all([v==file_path[k] for k,v in enumerate(path)]):
|
||||||
path.append(file_path[len(path)])
|
path.append(file_path[len(path)])
|
||||||
thispath='static__'+'__'.join(path)
|
thispath = regex_space.sub('-', 'static__'+'__'.join(path))
|
||||||
}}
|
}}
|
||||||
<li class="folder"><i> </i>
|
<li class="folder"><i> </i>
|
||||||
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
<a href="javascript:collapse('{{=thispath}}');" class="file">{{=path[-1]}}/</a>
|
||||||
@@ -475,11 +477,11 @@ function filter_files() {
|
|||||||
message=data['message'];
|
message=data['message'];
|
||||||
for(var i=0; i<files.length; i++)
|
for(var i=0; i<files.length; i++)
|
||||||
jQuery('li#_'+files[i].replace(/\//g,'__').replace('.','__')).slideDown();
|
jQuery('li#_'+files[i].replace(/\//g,'__').replace('.','__')).slideDown();
|
||||||
jQuery('.flash').html(message).slideDown();
|
jQuery('.w2p_flash').html(message).slideDown();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
jQuery('.component_contents li, .formfield, .comptools').slideDown();
|
jQuery('.component_contents li, .formfield, .comptools').slideDown();
|
||||||
jQuery('.flash').html('').hide();
|
jQuery('.w2p_flash').html('').hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jQuery(document).ready(function(){
|
jQuery(document).ready(function(){
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
<form action="{{=URL(args=request.args)}}" method="POST">
|
<form action="{{=URL(args=request.args)}}" method="POST">
|
||||||
<h2>{{=T('Select Files to Package')}}</h2>
|
<h2>{{=T('Select Files to Package')}}</h2>
|
||||||
<input type="submit" value="{{=T('Download .w2p')}}" class="btn"/>
|
<input type="submit" value="{{=T('Download .w2p')}}" class="btn"/>
|
||||||
|
<input type="submit" name="doexe" value="{{=T('Download as .exe')}}" class="btn"/>
|
||||||
<div style="margin-top:20px">
|
<div style="margin-top:20px">
|
||||||
{{tree(base)}}
|
{{tree(base)}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ for c in controllers: controller_functions+=[c[:-3]+'/%s.html'%x for x in functi
|
|||||||
{{=peekfile('views',c)}}
|
{{=peekfile('views',c)}}
|
||||||
</span>
|
</span>
|
||||||
<span class="extras celled">
|
<span class="extras celled">
|
||||||
{{if extend.has_key(c):}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
{{if c in extend:}}{{=T("extends")}} <b>{{=extend[c]}}</b> {{pass}}
|
||||||
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
{{if include[c]:}}{{=T("includes")}} {{pass}}{{=XML(', '.join([B(f).xml() for f in include[c]]))}}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -27,7 +27,9 @@
|
|||||||
{{buttons.append((URL('pack',args=a), T("Pack all")))}}
|
{{buttons.append((URL('pack',args=a), T("Pack all")))}}
|
||||||
{{buttons.append((URL('pack_custom',args=a), T("Pack custom")))}}
|
{{buttons.append((URL('pack_custom',args=a), T("Pack custom")))}}
|
||||||
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
{{if not os.path.exists('applications/%s/compiled' % a):}}
|
||||||
{{buttons.append((URL('compile_app',args=a), T("Compile")))}}
|
{{buttons.append((URL('compile_app',args=[a, 'skip_failed_views']),
|
||||||
|
T("Compile (skip failed views)")))}}
|
||||||
|
{{buttons.append((URL('compile_app',args=a), T("Compile (all or nothing)")))}}
|
||||||
{{else:}}
|
{{else:}}
|
||||||
{{buttons.append((URL('pack',args=(a, 'compiled')), T("Pack compiled")))}}
|
{{buttons.append((URL('pack',args=(a, 'compiled')), T("Pack compiled")))}}
|
||||||
{{if glob.glob('applications/%s/controllers/*.py' % a):}}
|
{{if glob.glob('applications/%s/controllers/*.py' % a):}}
|
||||||
@@ -54,7 +56,7 @@
|
|||||||
{{pass}}
|
{{pass}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{{=button_enable(URL('enable',args=a), a) if a!='admin' else ''}}
|
{{=button_enable(URL('enable',args=a, hmac_key=session.hmac_key), a) if a!='admin' else ''}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
@@ -138,6 +140,7 @@
|
|||||||
<p class="row-buttons">
|
<p class="row-buttons">
|
||||||
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
{{=button(URL('gae','deploy'), T('Deploy on Google App Engine'))}}
|
||||||
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
{{=button(URL('openshift','deploy'),T('Deploy to OpenShift'))}}
|
||||||
|
{{=button(URL('pythonanywhere','deploy'), T('Deploy to PythonAnywhere'))}}
|
||||||
</p>
|
</p>
|
||||||
</div> <!-- /DEPLOY ON GAE -->
|
</div> <!-- /DEPLOY ON GAE -->
|
||||||
<!-- APP WIZARD -->
|
<!-- APP WIZARD -->
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
<div id="{{=globals().get('main_id', 'main')}}" class="container-fluid">
|
<div id="{{=globals().get('main_id', 'main')}}" class="container-fluid">
|
||||||
<div id="main_inner" class="row-fluid">
|
<div id="main_inner" class="row-fluid">
|
||||||
<div class="span12">
|
<div class="span12">
|
||||||
<div class="flash alert">{{=response.flash or ''}}</div>
|
<div class="w2p_flash alert">{{=response.flash or ''}}</div>
|
||||||
{{include}}
|
{{include}}
|
||||||
</div><!-- /main span12 -->
|
</div><!-- /main span12 -->
|
||||||
</div><!-- /main row-fluid -->
|
</div><!-- /main row-fluid -->
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(document).ready(function(){
|
jQuery(document).ready(function(){
|
||||||
jQuery("[rel=tooltip]").tooltip();
|
jQuery("[rel=tooltip]").tooltip();
|
||||||
|
jQuery(":input").attr("autocomplete","off");
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
{{extend 'layout.html'}}
|
||||||
|
<h2><span style="color:#139FD7">python</span>anywhere {{=T('Deployment Interface')}}</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="register_form">
|
||||||
|
<h3>{{=T('Login/Register')}}</h3>
|
||||||
|
<form class="form-horizontal" id="palogin">
|
||||||
|
|
||||||
|
<div class="control-group" id="username__row">
|
||||||
|
<label class="control-label" for="username">{{=T('Username')}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="username" id="username"><span class="help-inline">*</span>
|
||||||
|
<span class="help-block"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" id="email_address__row">
|
||||||
|
<label class="control-label" for="email_address">{{=T('Email Address')}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="text" name="email_address" id="email_address">
|
||||||
|
<span class="help-block"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" id="pythonanywhere_password__row">
|
||||||
|
<label class="control-label" for="pythonanywhere_password">{{=T('PythonAnywhere Password')}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="password" name="pythonanywhere_password" id="pythonanywhere_password">
|
||||||
|
<span class="help-block"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" id="web2py_admin_password__row">
|
||||||
|
<label class="control-label" for="web2py_admin_password">{{=T('web2py Admin Password')}}</label>
|
||||||
|
<div class="controls">
|
||||||
|
<input type="password" name="web2py_admin_password" id="web2py_admin_password"><span class="help-inline">*</span>
|
||||||
|
<span class="help-block"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group" id="accepts_terms__row">
|
||||||
|
<div class="controls">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" name="accepts_terms" id="accepts_terms"><a target="_blank" href="https://www.pythonanywhere.com/terms/">{{=T('Accept Terms')}}</a>
|
||||||
|
</label>
|
||||||
|
<span class="help-block"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-group">
|
||||||
|
<div class="controls">
|
||||||
|
<button type="submit" class="btn btn-primary" id="submit_palogin">{{=T('Submit')}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
<p>* {{=T('You only need these if you have already registered')}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row-fluid" id="app_manager" style="display:none;">
|
||||||
|
<div class="span6">
|
||||||
|
<h3>{{=T('Local Apps')}}</h3>
|
||||||
|
<form id="apppicker">
|
||||||
|
<select name="apps" class="form-control" id="local" multiple>
|
||||||
|
<option>{{=T('Loading...')}}</option>
|
||||||
|
</select>
|
||||||
|
<input type="submit" value="Deploy" id="deploy_button" class="btn btn-primary">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<strong>{{=T('Warning!')}}</strong> {{=T('if your application uses a database other than sqlite you will then have to configure its DAL in pythonanywhere.')}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="span6">
|
||||||
|
<h3>{{=T('PythonAnywhere Apps')}}</h3>
|
||||||
|
<ul id="pythonanywhere">
|
||||||
|
<li>{{=T('Loading...')}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
$('#palogin').off('submit');
|
||||||
|
$('#palogin').submit(function(event) {
|
||||||
|
var data = $('#palogin').serialize();
|
||||||
|
$.web2py.disableElement($('#submit_palogin'));
|
||||||
|
$.web2py.disableFormElements($('#palogin'));
|
||||||
|
$.ajax({
|
||||||
|
url: '{{=URL("pythonanywhere", "create_account")}}',
|
||||||
|
type: 'POST',
|
||||||
|
data: data,
|
||||||
|
dataType: 'json',
|
||||||
|
}).done(function(data, textStatus, jqXHR) {
|
||||||
|
$('#palogin .error').removeClass('error');
|
||||||
|
$('#palogin .help-block').text('');
|
||||||
|
if(data.status == 'error') {
|
||||||
|
for(var error in data.errors) {
|
||||||
|
$('#' + error + '__row').addClass('error');
|
||||||
|
$('#' + error + '__row .help-block').text(data.errors[error][0]);
|
||||||
|
}
|
||||||
|
$.web2py.enableElement($('#submit_palogin'));
|
||||||
|
$.web2py.enableFormElements($('#palogin'));
|
||||||
|
$.web2py.flash("{{=T('Form has errors')}}");
|
||||||
|
} else {
|
||||||
|
$.web2py.flash("{{=T('Login successful')}}");
|
||||||
|
$('#register_form').hide();
|
||||||
|
$('#app_manager').show();
|
||||||
|
refresh_apps();
|
||||||
|
}
|
||||||
|
}).fail(function(){
|
||||||
|
$.web2py.flash("{{=T('Something went wrong please wait a few minutes before retrying')}}");
|
||||||
|
$.web2py.enableElement($('#submit_palogin'));
|
||||||
|
$.web2py.enableFormElements($('#palogin'));
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#apppicker').off('submit');
|
||||||
|
$('#apppicker').submit(function(event) {
|
||||||
|
var data = $('#apppicker').serialize();
|
||||||
|
$.web2py.disableElement($('#deploy_button'));
|
||||||
|
$.ajax({
|
||||||
|
url: '{{=URL("pythonanywhere", "bulk_install")}}',
|
||||||
|
type: 'POST',
|
||||||
|
data: {username: $('#username').val(), password: $('#web2py_admin_password').val(), apps: $('#local').val()},
|
||||||
|
dataType: 'json',
|
||||||
|
}).done(function(data, textStatus, jqXHR) {
|
||||||
|
refresh_apps();
|
||||||
|
$.web2py.enableElement($('#deploy_button'));
|
||||||
|
}).fail(function(){
|
||||||
|
$.web2py.flash("{{=T('Something went wrong please wait a few minutes before retrying')}}");
|
||||||
|
$.web2py.enableElement($('#deploy_button'));
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function refresh_apps() {
|
||||||
|
// Refresh List of Apps
|
||||||
|
$('#deploy_button').prop('disabled', true);
|
||||||
|
$.ajax({
|
||||||
|
url: '{{=URL("pythonanywhere", "list_apps")}}',
|
||||||
|
type: 'GET',
|
||||||
|
data: {username: $('#username').val(), password: $('#web2py_admin_password').val()},
|
||||||
|
dataType: 'json',
|
||||||
|
}).done(function(data, textStatus, jqXHR) {
|
||||||
|
var i = 0;
|
||||||
|
$('#local').html('')
|
||||||
|
for(i = 0; i < data.local.length; i++) {
|
||||||
|
$('#local').append($('<option>', {
|
||||||
|
value: data.local[i],
|
||||||
|
text: data.local[i]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
$('#local').multiSelect('refresh');
|
||||||
|
$('#pythonanywhere').html('')
|
||||||
|
for(i = 0; i < data.pythonanywhere.length; i++) {
|
||||||
|
$('#pythonanywhere').append($('<li>', {
|
||||||
|
text: data.pythonanywhere[i]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
$('#deploy_button').prop('disabled', false);
|
||||||
|
$.web2py.hide_flash();
|
||||||
|
}).fail(function(){
|
||||||
|
// Mostly this happens if it's a new account, just waiting a bit should be enough.
|
||||||
|
$.get('http://' + $('#username').val() + '.pythonanywhere.com'); // Kickstart the instance
|
||||||
|
$.web2py.flash("{{=T('Please wait, giving pythonanywhere a moment...')}}");
|
||||||
|
setTimeout(refresh_apps, 30000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
var w2p_ajax_confirm_message = "{{=T('Are you sure you want to delete this object?')}}";
|
var w2p_ajax_confirm_message = "{{=T('Are you sure you want to delete this object?')}}";
|
||||||
var w2p_ajax_date_format = "{{=T('%Y-%m-%d')}}";
|
var w2p_ajax_date_format = "{{=T('%Y-%m-%d')}}";
|
||||||
var w2p_ajax_datetime_format = "{{=T('%Y-%m-%d %H:%M:%S')}}";
|
var w2p_ajax_datetime_format = "{{=T('%Y-%m-%d %H:%M:%S')}}";
|
||||||
|
var w2p_ajax_disable_with_message = "{{=T('Working...')}}";
|
||||||
var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}'
|
var ajax_error_500 = '{{=T.M('An error occured, please [[reload %s]] the page') % URL(args=request.args, vars=request.get_vars) }}'
|
||||||
//--></script>
|
//--></script>
|
||||||
{{
|
{{
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ if request.function == 'manage':
|
|||||||
auth.table_group(),
|
auth.table_group(),
|
||||||
auth.table_permission()])
|
auth.table_permission()])
|
||||||
manager_role = manager_action.get('role', None) if manager_action else None
|
manager_role = manager_action.get('role', None) if manager_action else None
|
||||||
auth.requires_membership(manager_role)(lambda: None)()
|
if not (gluon.fileutils.check_credentials(request) or auth.has_membership(manager_role)):
|
||||||
|
raise HTTP(403, "Not authorized")
|
||||||
menu = False
|
menu = False
|
||||||
elif (request.application == 'admin' and not session.authorized) or \
|
elif (request.application == 'admin' and not session.authorized) or \
|
||||||
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||||
@@ -80,7 +81,6 @@ if False and request.tickets_db:
|
|||||||
def get_databases(request):
|
def get_databases(request):
|
||||||
dbs = {}
|
dbs = {}
|
||||||
for (key, value) in global_env.items():
|
for (key, value) in global_env.items():
|
||||||
cond = False
|
|
||||||
try:
|
try:
|
||||||
cond = isinstance(value, GQLDB)
|
cond = isinstance(value, GQLDB)
|
||||||
except:
|
except:
|
||||||
@@ -420,7 +420,7 @@ def ccache():
|
|||||||
'oldest': time.time(),
|
'oldest': time.time(),
|
||||||
'keys': []
|
'keys': []
|
||||||
}
|
}
|
||||||
|
|
||||||
disk = copy.copy(ram)
|
disk = copy.copy(ram)
|
||||||
total = copy.copy(ram)
|
total = copy.copy(ram)
|
||||||
disk['keys'] = []
|
disk['keys'] = []
|
||||||
@@ -445,30 +445,31 @@ def ccache():
|
|||||||
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
||||||
total.update(gae_stats)
|
total.update(gae_stats)
|
||||||
else:
|
else:
|
||||||
|
# get ram stats directly from the cache object
|
||||||
|
ram_stats = cache.ram.stats[request.application]
|
||||||
|
ram['hits'] = ram_stats['hit_total'] - ram_stats['misses']
|
||||||
|
ram['misses'] = ram_stats['misses']
|
||||||
|
try:
|
||||||
|
ram['ratio'] = ram['hits'] * 100 / ram_stats['hit_total']
|
||||||
|
except (KeyError, ZeroDivisionError):
|
||||||
|
ram['ratio'] = 0
|
||||||
|
|
||||||
for key, value in cache.ram.storage.iteritems():
|
for key, value in cache.ram.storage.iteritems():
|
||||||
if isinstance(value, dict):
|
if hp:
|
||||||
ram['hits'] = value['hit_total'] - value['misses']
|
ram['bytes'] += hp.iso(value[1]).size
|
||||||
ram['misses'] = value['misses']
|
ram['objects'] += hp.iso(value[1]).count
|
||||||
try:
|
ram['entries'] += 1
|
||||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
if value[0] < ram['oldest']:
|
||||||
except (KeyError, ZeroDivisionError):
|
ram['oldest'] = value[0]
|
||||||
ram['ratio'] = 0
|
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
else:
|
|
||||||
if hp:
|
|
||||||
ram['bytes'] += hp.iso(value[1]).size
|
|
||||||
ram['objects'] += hp.iso(value[1]).count
|
|
||||||
ram['entries'] += 1
|
|
||||||
if value[0] < ram['oldest']:
|
|
||||||
ram['oldest'] = value[0]
|
|
||||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
|
||||||
|
|
||||||
for key in cache.disk.storage:
|
for key in cache.disk.storage:
|
||||||
value = cache.disk.storage[key]
|
value = cache.disk.storage[key]
|
||||||
if isinstance(value, dict):
|
if isinstance(value[1], dict):
|
||||||
disk['hits'] = value['hit_total'] - value['misses']
|
disk['hits'] = value[1]['hit_total'] - value[1]['misses']
|
||||||
disk['misses'] = value['misses']
|
disk['misses'] = value[1]['misses']
|
||||||
try:
|
try:
|
||||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
disk['ratio'] = disk['hits'] * 100 / value[1]['hit_total']
|
||||||
except (KeyError, ZeroDivisionError):
|
except (KeyError, ZeroDivisionError):
|
||||||
disk['ratio'] = 0
|
disk['ratio'] = 0
|
||||||
else:
|
else:
|
||||||
@@ -480,12 +481,12 @@ def ccache():
|
|||||||
disk['oldest'] = value[0]
|
disk['oldest'] = value[0]
|
||||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
|
|
||||||
total['entries'] = ram['entries'] + disk['entries']
|
ram_keys = ram.keys() # ['hits', 'objects', 'ratio', 'entries', 'keys', 'oldest', 'bytes', 'misses']
|
||||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
ram_keys.remove('ratio')
|
||||||
total['objects'] = ram['objects'] + disk['objects']
|
ram_keys.remove('oldest')
|
||||||
total['hits'] = ram['hits'] + disk['hits']
|
for key in ram_keys:
|
||||||
total['misses'] = ram['misses'] + disk['misses']
|
total[key] = ram[key] + disk[key]
|
||||||
total['keys'] = ram['keys'] + disk['keys']
|
|
||||||
try:
|
try:
|
||||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||||
total['misses'])
|
total['misses'])
|
||||||
@@ -575,11 +576,9 @@ def bg_graph_model():
|
|||||||
meta_graphmodel = dict(group=request.application, color='#ECECEC')
|
meta_graphmodel = dict(group=request.application, color='#ECECEC')
|
||||||
|
|
||||||
group = meta_graphmodel['group'].replace(' ', '')
|
group = meta_graphmodel['group'].replace(' ', '')
|
||||||
if not subgraphs.has_key(group):
|
if group not in subgraphs:
|
||||||
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
|
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
|
||||||
subgraphs[group]['tables'].append(tablename)
|
subgraphs[group]['tables'].append(tablename)
|
||||||
else:
|
|
||||||
subgraphs[group]['tables'].append(tablename)
|
|
||||||
|
|
||||||
graph.add_node(tablename, name=tablename, shape='plaintext',
|
graph.add_node(tablename, name=tablename, shape='plaintext',
|
||||||
label=table_template(tablename))
|
label=table_template(tablename))
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ session.forget()
|
|||||||
cache_expire = not request.is_local and 300 or 0
|
cache_expire = not request.is_local and 300 or 0
|
||||||
|
|
||||||
|
|
||||||
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
# @cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
||||||
def index():
|
def index():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
@@ -19,14 +19,13 @@ def index():
|
|||||||
def what():
|
def what():
|
||||||
import urllib
|
import urllib
|
||||||
try:
|
try:
|
||||||
images = XML(urllib.urlopen(
|
images = XML(urllib.urlopen('http://www.web2py.com/poweredby/default/images').read())
|
||||||
'http://www.web2py.com/poweredby/default/images').read())
|
|
||||||
except:
|
except:
|
||||||
images = []
|
images = []
|
||||||
return response.render(images=images)
|
return response.render(images=images)
|
||||||
|
|
||||||
|
|
||||||
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
# @cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
||||||
def download():
|
def download():
|
||||||
return response.render()
|
return response.render()
|
||||||
|
|
||||||
@@ -74,14 +73,15 @@ def license():
|
|||||||
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
|
filename = os.path.join(request.env.gluon_parent, 'LICENSE')
|
||||||
return response.render(dict(license=MARKMIN(read_file(filename))))
|
return response.render(dict(license=MARKMIN(read_file(filename))))
|
||||||
|
|
||||||
|
|
||||||
def version():
|
def version():
|
||||||
if request.args(0)=='raw':
|
if request.args(0) == 'raw':
|
||||||
return request.env.web2py_version
|
return request.env.web2py_version
|
||||||
from gluon.fileutils import parse_version
|
from gluon.fileutils import parse_version
|
||||||
(a, b, c, pre_release, build) = parse_version(request.env.web2py_version)
|
(a, b, c, pre_release, build) = parse_version(request.env.web2py_version)
|
||||||
return 'Version %i.%i.%i (%.4i-%.2i-%.2i %.2i:%.2i:%.2i) %s' % (
|
return 'Version %i.%i.%i (%.4i-%.2i-%.2i %.2i:%.2i:%.2i) %s' % \
|
||||||
a,b,c,build.year,build.month,build.day,
|
(a, b, c, build.year, build.month, build.day, build.hour, build.minute, build.second, pre_release)
|
||||||
build.hour,build.minute,build.second,pre_release)
|
|
||||||
|
|
||||||
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
@cache.action(time_expire=300, cache_model=cache.ram, quick='P')
|
||||||
def examples():
|
def examples():
|
||||||
|
|||||||
@@ -35,12 +35,6 @@ def hello6():
|
|||||||
response.flash = 'Hello World in a flash!'
|
response.flash = 'Hello World in a flash!'
|
||||||
return dict(message=T('Hello World'))
|
return dict(message=T('Hello World'))
|
||||||
|
|
||||||
|
|
||||||
def status():
|
|
||||||
""" page that shows internal status"""
|
|
||||||
return dict(toolbar=response.toolbar())
|
|
||||||
|
|
||||||
|
|
||||||
def redirectme():
|
def redirectme():
|
||||||
""" redirects to /{{=request.application}}/{{=request.controller}}/hello3 """
|
""" redirects to /{{=request.application}}/{{=request.controller}}/hello3 """
|
||||||
|
|
||||||
|
|||||||
@@ -27,4 +27,4 @@ def xml():
|
|||||||
|
|
||||||
|
|
||||||
def beautify():
|
def beautify():
|
||||||
return dict(message=BEAUTIFY(request))
|
return dict(message=BEAUTIFY(dict(a=1,b=[2,3,dict(hello='world')])))
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
response.menu = [
|
response.menu = [
|
||||||
(T('Home'), False, URL('default', 'index')),
|
(T('Home'), request.controller == 'default' and request.function == 'index', URL('default', 'index')),
|
||||||
(T('About'), False, URL('default', 'what')),
|
(T('About'), request.controller == 'default' and request.function == 'what', URL('default', 'what')),
|
||||||
(T('Download'), False, URL('default', 'download')),
|
(T('Download'), request.controller == 'default' and request.function == 'download', URL('default', 'download')),
|
||||||
(T('Docs & Resources'), False, URL('default', 'documentation')),
|
(T('Docs & Resources'), request.controller == 'default' and request.function == 'documentation', URL('default', 'documentation')),
|
||||||
(T('Support'), False, URL('default', 'support')),
|
(T('Support'), request.controller == 'default' and request.function == 'support', URL('default', 'support')),
|
||||||
(T('Contributors'), False, URL('default', 'who'))]
|
(T('Contributors'), request.controller == 'default' and request.function == 'who', URL('default', 'who'))]
|
||||||
|
|
||||||
#########################################################################
|
#########################################################################
|
||||||
## Changes the menu active item
|
## Changes the menu active item
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
session.connect(request,response,cookie_key='yoursecret')
|
from gluon.utils import web2py_uuid
|
||||||
|
cookie_key = cache.ram('cookie_key',lambda: web2py_uuid(),None)
|
||||||
|
session.connect(request,response,cookie_key=cookie_key)
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#### Learning and Demos
|
#### Learning and Demos
|
||||||
- [[Intro video http://www.youtube.com/watch?v=BXzqmHx6edY]] and [[code examples https://github.com/mjhea0/web2py]]
|
- [[Intro video http://www.youtube.com/watch?v=BXzqmHx6edY]] and [[code examples https://github.com/mjhea0/web2py]]
|
||||||
|
- [[Step by step tutorial https://milesm.pythonanywhere.com/wiki]]
|
||||||
|
- [[web2py Reference Project http://www.web2pyref.com/]]
|
||||||
|
- [[An advanced tutorial https://milesm.pythonanywhere.com/wiki]]
|
||||||
- [[Killer Web Development Tutorial http://killer-web-development.com/]]
|
- [[Killer Web Development Tutorial http://killer-web-development.com/]]
|
||||||
- [[Real Python for the Web http://www.realpython.com]] (web development with web2py and more!)
|
- [[Real Python for the Web http://www.realpython.com]] (web development with web2py and more!)
|
||||||
- [[Admin Demo http://www.web2py.com/demo_admin popup]] (web-based IDE)
|
- [[Admin Demo http://www.web2py.com/demo_admin popup]] (web-based IDE)
|
||||||
@@ -17,10 +20,11 @@
|
|||||||
|
|
||||||
#### Code
|
#### Code
|
||||||
- [[web2pyslices (recipes) http://www.web2pyslices.com popup]]
|
- [[web2pyslices (recipes) http://www.web2pyslices.com popup]]
|
||||||
- [[Layouts http://www.web2py.com/layouts popup]]
|
- [[Dashboard welcome app https://github.com/mjbeller/web2py-starter]]
|
||||||
|
- [[stupid.css theme https://github.com/mdipierro/web2py-welcome-theme-stupid]]
|
||||||
- [[Plugins http://www.web2py.com/plugins popup]]
|
- [[Plugins http://www.web2py.com/plugins popup]]
|
||||||
- [[More Plugins http://dev.s-cubism.com/web2py_plugins]]
|
|
||||||
- [[Appliances http://www.web2py.com/appliances popup]]
|
- [[Appliances http://www.web2py.com/appliances popup]]
|
||||||
- [[web2py utils http://packages.python.org/web2py_utils/ popup]]
|
- [[web2py utils http://packages.python.org/web2py_utils/ popup]]
|
||||||
|
- [[Sublime text 3 plugin https://bitbucket.org/kfog/w2p popup]]
|
||||||
|
|
||||||
#### [[Sites Powered by web2py http://www.web2py.com/poweredby popup]]
|
#### [[Sites Powered by web2py http://www.web2py.com/poweredby popup]]
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ French speakers group
|
|||||||
|
|
||||||
``web2py-fr``:groupdates
|
``web2py-fr``:groupdates
|
||||||
|
|
||||||
|
## Italian Group
|
||||||
|
|
||||||
|
- [[https://groups.google.com/forum/?fromgroups#!forum/web2py-it https://groups.google.com/forum/?fromgroups#!forum/web2py-it popup]]
|
||||||
|
|
||||||
## Japanese Group
|
## Japanese Group
|
||||||
|
|
||||||
Japanese speakers group
|
Japanese speakers group
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,7 +1,11 @@
|
|||||||
.calendar{z-index:99;position:relative;display:none;background:#fff;border:2px solid #000;font-size:11px;color:#000;cursor:default;font-family:Arial,Helvetica,sans-serif;
|
.calendar {z-index:2000;position:relative;margin-top:140px;display:none;background-color:white;border:1px solid #000;color:#000;cursor:default;box-shadow:0 0 10px #666}.calendar * {text-align: center;font-size:10px!important}
|
||||||
border-radius: 10px;
|
.calendar table {border-collapse:collapse}
|
||||||
-moz-border-radius: 10px;
|
.calendar tbody tr:hover {background-color:#fbf6d9}
|
||||||
-webkit-border-radius: 10px;
|
.calendar td, th {padding:5px; vertical-align:top; text-align:left; border:0}
|
||||||
}.calendar table{margin:0px;font-size:11px;color:#000;cursor:default;font-family:tahoma,verdana,sans-serif;}.calendar .button{text-align:center;padding:1px;color:#fff;background:#000;}.calendar .nav{background:#000;color:#fff}.calendar thead .title{font-weight:bold;padding:1px;background:#000;color:#fff;text-align:center;}.calendar thead .name{padding:2px;text-align:center;background:#bbb;}.calendar thead .weekend{color:#f00;}.calendar thead .hilite {background-color:#666;}.calendar thead .active{padding:2px 0 0 2px;background-color:#c4c0b8;}.calendar tbody .day{width:2em;text-align:right;padding:2px 4px 2px 2px;}.calendar tbody .day.othermonth{color:#aaa;}.calendar tbody .day.othermonth.oweekend{color:#faa;}.calendar table .wn{padding:2px 3px 2px 2px;background:#bbb;}.calendar tbody .rowhilite td{background:#ddd;}.calendar tbody td.hilite{background:#bbb;}.calendar tbody td.active{background:#bbb;}.calendar tbody td.selected{font-weight:bold;background:#ddd;}.calendar tbody td.weekend{color:#f00;}.calendar tbody td.today{font-weight:bold;color:#00f;}.calendar tbody .disabled{color:#999;}.calendar tbody .emptycell{visibility:hidden;}.calendar tbody .emptyrow{display:none;}.calendar tfoot .ttip{background:#bbb;padding:1px;background:#000;color:#fff;text-align:center;}.calendar tfoot .hilite{background:#ddd;}.calendar tfoot .active{}.calendar .combo{position:absolute;display:none;width:4em;top:0;left:0;cursor:default;background:#e4e0d8;padding:1px;z-index:100;}.calendar .combo .label,.calendar .combo .label-IEfix{text-align:center;padding:1px;}.calendar .combo .label-IEfix{width:4em;}.calendar .combo .active{background:#c4c0b8;}.calendar .combo .hilite{background:#048;color:#fea;}.calendar td.time{padding:1px 0;text-align:center;background-color:#bbb;}.calendar td.time .hour,.calendar td.time .minute,.calendar td.time .ampm{padding:0 3px 0 4px;font-weight:bold;}.calendar td.time .ampm{text-align:center;}.calendar td.time .colon{padding:0 2px 0 3px;font-weight:bold;}.calendar td.time span.hilite{}.calendar td.time span.active{border-color:#f00;background-color:#000;color:#0f0;}.hour,.minute{font-size:2em;}
|
.calendar thead tr {background-color:#f1f1f1}
|
||||||
|
.calendar tbody tr {border-bottom:2px solid #f1f1f1}
|
||||||
|
.calendar th {font-weight:string; padding:5px; vertical-align:bottom; text-align:left}
|
||||||
|
.calendar thead th {vertical-align:bottom}
|
||||||
|
.calendar tbody th {vertical-align:top}
|
||||||
|
|
||||||
#CP_hourcont{z-index:99;padding:0;position:absolute;border:1px dashed #666;background-color:#eee;display:none;}#CP_minutecont{z-index:99;background-color:#ddd;padding:1px;position:absolute;width:45px;display:none;}.floatleft{float:left;}.CP_hour{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:35px;}.CP_minute{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:auto;}.CP_over{background-color:#fff;z-index:99}
|
#CP_hourcont{z-index:2000;padding:0;position:absolute;border:1px dashed #666;background-color:#eee;display:none;}#CP_minutecont{z-index:2000;background-color:#ddd;padding:1px;position:absolute;width:45px;display:none;}.floatleft{float:left;}.CP_hour{z-index:2000;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:35px;}.CP_minute{z-index:2000;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:auto;}.CP_over{background-color:#fff;z-index:2000}
|
||||||
|
|||||||
@@ -1,20 +1,69 @@
|
|||||||
@import url(http://fonts.googleapis.com/css?family=Economica);
|
/* Gray the black as suggested by Anthony */
|
||||||
@@import url(http://fonts.googleapis.com/css?family=Belleza);
|
h1,h2,h3,h4,h5,h6 {color: rgb(35, 35, 35); text-transform:none}
|
||||||
|
.black {
|
||||||
body { font-family: Arial, Helvetica; }
|
color: rgb(35, 35, 35);
|
||||||
a, a:visited, a:hover, h1,h2,h3,h4,h5 {color: #658883}
|
background-color: rgb(35, 35, 35);
|
||||||
a.btn-danger, a.btn-warning, a.btn-success {color:white}
|
}
|
||||||
h1,h2,h3,h4,h5 { font-family: "Economica", Arial, Helevtica; }
|
|
||||||
body {
|
/* Spacing between thead and tbody */
|
||||||
background: url('../images/stripes.png') repeat-x;
|
/* Ref: http://stackoverflow.com/questions/9258754/spacing-between-thead-and-tbody */
|
||||||
}
|
tbody:before {
|
||||||
#header {
|
content: "-";
|
||||||
margin-top: 40px;
|
display: block;
|
||||||
}
|
line-height: 1em;
|
||||||
.btn-180 {
|
color: transparent;
|
||||||
width: 180px;
|
}
|
||||||
}
|
|
||||||
.page-header {
|
/* Improve buttons in download page */
|
||||||
border-bottom: 0;
|
th, td {padding: 0}
|
||||||
}
|
|
||||||
|
|
||||||
|
tbody tr:hover {background-color:transparent}
|
||||||
|
tbody tr {border-bottom: none}
|
||||||
|
p {text-align: left}
|
||||||
|
p, li { line-height: 1.6em}
|
||||||
|
|
||||||
|
/* Improve CODE() display though padding has no effect as some PRE are hardcoded somewhere can't find it */
|
||||||
|
/* padding of 10px should make it... */
|
||||||
|
pre {background-color: rgb(35, 35, 35)!important; border-radius:5px; color:white; padding: 10px}
|
||||||
|
|
||||||
|
/* Improve buttons in download page */
|
||||||
|
a.btn.btn180 {padding:10px; font-size:1.2em; width:200px}
|
||||||
|
|
||||||
|
.menu .web2py-menu-active a {
|
||||||
|
color: #26a69a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spaced-vertical {
|
||||||
|
margin: 0 0.5em 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover,
|
||||||
|
a.noeffect img:hover {
|
||||||
|
transition: scale .5s;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn,
|
||||||
|
a.noeffect img {
|
||||||
|
transition: all .2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lower saturation of color #26a69a - 20 points lower */
|
||||||
|
/* The below change to color #26a69a should come before other color change or they override all buttons background-color */
|
||||||
|
/* The color should maybe change at stupid.css level as it herited from there also in stupid.css it would be better
|
||||||
|
to define this color at one place actually color is defined all over the place */
|
||||||
|
a {color:#47a69d}
|
||||||
|
.btn, button, [type=button], [type=submit] {background-color:#47a69d}
|
||||||
|
.progress .determinate {background-color:#47a69d}
|
||||||
|
.progress .indeterminate {background-color:#47a69d}
|
||||||
|
a:not(.btn):not(.noeffect):hover {color:#47a69d}
|
||||||
|
a:not(.btn):not(.noeffect):after {background-color:#47a69d}
|
||||||
|
.tags > span {background-color:#47a69d}
|
||||||
|
.tags.dismissible > span.off:hover {background-color:#47a69d}
|
||||||
|
.aquamarine{background-color:#47a69d}
|
||||||
|
|
||||||
|
/* Lower the saturation of 20 points */
|
||||||
|
.green {background-color: #58cc65}
|
||||||
|
.yellow {background-color: #ffe333}
|
||||||
|
.red {background-color: #cc4229}
|
||||||
|
|||||||
@@ -0,0 +1,359 @@
|
|||||||
|
/************
|
||||||
|
Created by Massimo Di Pierro
|
||||||
|
Stupid.css is what the names says, take it with a grain of salt
|
||||||
|
License: BSD
|
||||||
|
************/
|
||||||
|
|
||||||
|
/*** basic styles ***/
|
||||||
|
html {box-sizing:border-box;}
|
||||||
|
*, *:after, *:before {border:0; margin:0; padding:0; box-sizing:inherit;}
|
||||||
|
html, body {max-width: 100vw; overflow-x: hidden}
|
||||||
|
body {font-family:"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif}
|
||||||
|
p, li {margin-bottom:0.5em}
|
||||||
|
p {text-align:justify}
|
||||||
|
label, strong {font-weight:bold}
|
||||||
|
ul {list-style-type:none; padding-left:20px}
|
||||||
|
a {text-decoration:none; color:#26a69a; white-space:nowrap}
|
||||||
|
a:hover {cursor:pointer}
|
||||||
|
h1,h2,h3,h4,h5,h6{font-weight:bold; text-transform:uppercase}
|
||||||
|
h1{font-size:4em; margin:1.0em 0 0.25em 0}
|
||||||
|
h2{font-size:2.4em; margin:0.9em 0 0.25em 0}
|
||||||
|
h3{font-size:1.8em; margin:0.8em 0 0.25em 0}
|
||||||
|
h4{font-size:1.6em; margin:0.7em 0 0.25em 0}
|
||||||
|
h5{font-size:1.4em; margin:0.6em 0 0.25em 0}
|
||||||
|
h6{font-size:1.2em; margin:0.5em 0 0.25em 0}
|
||||||
|
table {border-collapse:collapse}
|
||||||
|
tbody tr:hover {background-color:#fbf6d9}
|
||||||
|
thead tr {background-color:#f1f1f1}
|
||||||
|
tbody tr {border-bottom:2px solid #f1f1f1}
|
||||||
|
td, th {padding: 5px; text-align: left; vertical-align:top}
|
||||||
|
thead th {vertical-align:bottom}
|
||||||
|
header, main, footer {display:block; with:100%} /* IE fix */
|
||||||
|
|
||||||
|
@media all and (max-width:599px) {
|
||||||
|
h1{font-size:2em}
|
||||||
|
h2{font-size:1.8em}
|
||||||
|
h3{font-size:1.6em}
|
||||||
|
h4{font-size:1.4em}
|
||||||
|
h5{font-size:1.2em}
|
||||||
|
h6{font-size:1.0em}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** buttons ***/
|
||||||
|
.btn, button, [type=button], [type=submit] {padding:0.5em 1em; margin:0 0.5em 0.5em 0; display:inline-block; background-color:#26a69a; color:white}
|
||||||
|
.btn:hover, button:hover, [type=button]:hover, [type=submit]:hover {box-shadow:0 0 10px #666; text-decoration:none; cursor:pointer}
|
||||||
|
.btn.small, table .btn {padding:0.25em 0.5em; font-size:0.8em}
|
||||||
|
.btn.large {padding:1em 2em; font-size:1.2em}
|
||||||
|
.btn.oval {border-radius:50%}
|
||||||
|
|
||||||
|
/*** helpers ***/
|
||||||
|
.rounded {-moz-border-radius:5px; border-radius:5px}
|
||||||
|
.padded {padding:10px 20px}
|
||||||
|
.center {text-align:center; margin-left:auto; margin-right:auto}
|
||||||
|
.center>div {text-align:left}
|
||||||
|
.right {right:0; text-align:right}
|
||||||
|
.middle div {vertical-align:middle}
|
||||||
|
.bottom div {vertical-align:bottom}
|
||||||
|
.xscroll {overflow-x:scroll}
|
||||||
|
.yscroll {overflow-y:scroll}
|
||||||
|
.nowrap {white-space:nowrap; overflow-x:hidden}
|
||||||
|
.fill {width:100%}
|
||||||
|
.lifted {box-shadow:5px 5px 10px #666}
|
||||||
|
.relative {position:relative}
|
||||||
|
.relative>div {position:absolute}
|
||||||
|
.spaced {margin-bottom:20px; margin-top:20px}
|
||||||
|
.hidden {display:none}
|
||||||
|
|
||||||
|
/*** forms ***/
|
||||||
|
input:not([type]), input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]), [type=file]:before {outline:none; padding:0.5em 1em; margin:0.5px; border-bottom:1px solid #ddd; width:100%}
|
||||||
|
textarea {width:100%; border:1px solid #ddd; padding:4px 8px; outline:none; outline:none}
|
||||||
|
select {-webkit-appearance:none; outline:none; padding:0.5em 1em; border-radius:0; margin:0.5px; border-bottom:1px solid #ddd; width:100%;background-color:transparent}
|
||||||
|
input, textarea, select, button, .btn {font-size:12px}
|
||||||
|
input:not([type]):hover, input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]):hover, select:hover, textarea:hover {background-color:#fbf6d9; transition:background-color 1s ease}
|
||||||
|
input:invalid, input.error {background:#cc1f00;color:white}
|
||||||
|
|
||||||
|
/*** grid ***/
|
||||||
|
.container {margin-right:-20px}
|
||||||
|
.container>.quarter, .container>.half, .container>.third, .container>.twothirds, .container>.threequarters {display:inline-block; padding: 0 20px 0 0; vertical-align:top}
|
||||||
|
.container>.fill{display: inline-block}
|
||||||
|
.container img, .container video {max-width:100%}
|
||||||
|
|
||||||
|
@media all and (min-width:800px) {
|
||||||
|
.max900 {max-width:900px; margin-left:auto; margin-right:auto}
|
||||||
|
.quarter {width:25%; margin-right:-5px}
|
||||||
|
.half {width:50%; margin-right:-10px}
|
||||||
|
.third {width:33.33%; margin-right:-6.66px}
|
||||||
|
.twothirds {width:66.66%; margin-right:-13.33px}
|
||||||
|
.threequarters {width:75%; margin-right:-15px}
|
||||||
|
}
|
||||||
|
@media all and (min-width:600px) and (max-width:799px) {
|
||||||
|
.quarter.compressible {width:25%; margin-right:-5px}
|
||||||
|
.half.compressible {width:50%; margin-right:-10px}
|
||||||
|
.threequarters.compressible {width:75%; margin-right:-15px}
|
||||||
|
.quarter:not(.compressible), .half:not(.compressible), .threequarters:not(.compressible) {width:100%; margin-right:-20px}
|
||||||
|
.third {width:33.33%; margin-right:-6.66px}
|
||||||
|
.twothirds {width:66.66%; margin-right:-13.33px}
|
||||||
|
label.quarter:not(.compressible).right, label.half:not(.compressible).right, label.threequarters:not(.compressible).right {float:left; text-align:left}
|
||||||
|
}
|
||||||
|
@media all and (max-width:599px) {
|
||||||
|
.quarter:not(.compressible), .half:not(.compressible), .third:not(.compressible), .twothirds:not(.compressible), .threequarters:not(.compressible) {width:100%;}
|
||||||
|
label.quarter:not(.compressible).right, label.half:not(.compressible).right, label.threequarters:not(.compressible).right,
|
||||||
|
label.third:not(.compressible).right, label.twothirds:not(.compressible).right {float:left; text-align:left}
|
||||||
|
.quarter.compressible {width:25%; margin-right:-5px}
|
||||||
|
.half.compressible {width:50%; margin-right:-10px}
|
||||||
|
.third.compressible {width:33.33%; margin-right:-6.66px}
|
||||||
|
.twothirds.compressible {width:66.66%; margin-right:-13.33px}
|
||||||
|
.threequarters.compressible {width:75%; margin-right:-15px}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** progress bar from http://codepen.io/holdencreative/details/pvxGxy ***/
|
||||||
|
.progress {
|
||||||
|
margin-left:-15px;
|
||||||
|
margin-right:-15px;
|
||||||
|
position:relative;
|
||||||
|
height:8px;
|
||||||
|
display:block;
|
||||||
|
width:120%;
|
||||||
|
background-color:#acece6;
|
||||||
|
border-radius:0;
|
||||||
|
background-clip:padding-box;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
.progress .determinate {
|
||||||
|
position:absolute;
|
||||||
|
background-color:inherit;
|
||||||
|
top:0;
|
||||||
|
bottom:0;
|
||||||
|
background-color:#26a69a;
|
||||||
|
transition:width .3s linear;
|
||||||
|
}
|
||||||
|
.progress .indeterminate {
|
||||||
|
background-color:#26a69a;
|
||||||
|
}
|
||||||
|
.progress .indeterminate:before {
|
||||||
|
content:'';
|
||||||
|
position:absolute;
|
||||||
|
background-color:inherit;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
bottom:0;
|
||||||
|
will-change:left, right;
|
||||||
|
animation:indeterminate 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||||
|
}
|
||||||
|
.progress .indeterminate:after {
|
||||||
|
content:'';
|
||||||
|
position:absolute;
|
||||||
|
background-color:inherit;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
bottom:0;
|
||||||
|
will-change:left, right;
|
||||||
|
animation:indeterminate-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
|
||||||
|
animation-delay:1.15s;
|
||||||
|
}
|
||||||
|
@-webkit-keyframes indeterminate {
|
||||||
|
0% {left:-35%; right:100%}
|
||||||
|
60% {left:100%; right:-90%}
|
||||||
|
100% {left:100%; right:-90%}
|
||||||
|
}
|
||||||
|
@-moz-keyframes indeterminate {
|
||||||
|
0% {left:-35%; right:100%}
|
||||||
|
60% {left:100%; right:-90%}
|
||||||
|
100% {left:100%; right:-90%}
|
||||||
|
}
|
||||||
|
@keyframes indeterminate {
|
||||||
|
0% {left:-35%; right:100%}
|
||||||
|
60% {left:100%; right:-90%}
|
||||||
|
100% {left:100%; right:-90%}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes indeterminate-short {
|
||||||
|
0% {left:-200%; right:100%}
|
||||||
|
60% {left:107%; right:-8%}
|
||||||
|
100% {left:107%; right:-8%}
|
||||||
|
}
|
||||||
|
@-moz-keyframes indeterminate-short {
|
||||||
|
0% {left:-200%; right:100%}
|
||||||
|
60% {left:107%; right:-8%}
|
||||||
|
100% {left:107%; right:-8%}
|
||||||
|
}
|
||||||
|
@keyframes indeterminate-short {
|
||||||
|
0% {left:-200%; right:100%}
|
||||||
|
60% {left:107%; right:-8%}
|
||||||
|
100% {left:107%; right:-8%}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** dropdown menu from http://codepen.io/philhoyt/pen/ujHzd ***/
|
||||||
|
.menu {list-style:none; position:relative; margin:0; padding:0}
|
||||||
|
.menu.right {float:right}
|
||||||
|
.menu a {padding:0 15px; text-decoration:none;text-align:left;font-family:"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; text-align:left}
|
||||||
|
.menu li {position:relative; float:left; margin:0; padding:0}
|
||||||
|
.menu ul {background:white; border:1px solid #e1e1e1; visibility:hidden; opacity:0; position:absolute; top:110%; padding:0; z-index:1000; transition:all 0.2s ease-out; list-style-type:none; box-shadow:5px 5px 10px #666}
|
||||||
|
.menu ul a {padding:10px 15px; color:#333; font-weight:700; font-size:12px; line-height:16px; display: block}
|
||||||
|
.menu ul li {float:none; width:200px}
|
||||||
|
.menu ul ul {top:0; left:80%; z-index:1100}
|
||||||
|
.menu li:hover > ul {visibility:visible; opacity:1}
|
||||||
|
.menu>li>ul>li:first-child:before{content:''; position:absolute; width:1px; height:1px; border:10px solid transparent; left:50px; top:-20px; margin-left:-10px; border-bottom-color:white}
|
||||||
|
.menu.dark ul {background:#111111; border:1px solid #111111}
|
||||||
|
.menu.dark ul a {color:white}
|
||||||
|
.menu.dark>li>ul>li:first-child:before{border-bottom-color:#111111}
|
||||||
|
|
||||||
|
@media all and (max-width:599px) {
|
||||||
|
header .menu li, header .menu ul {width: 100%}
|
||||||
|
header .menu.right {float:left; text-align:left}
|
||||||
|
header .menu ul ul {top:2.5em; left:-1px}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (min-width:600px) {
|
||||||
|
.ham {display:none!important}
|
||||||
|
.burger.accordion * {max-height:1000px; overflow:visible}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** pulsating ring from https://jsfiddle.net/mandynicole/7xrKP/ *******/
|
||||||
|
.pulse:after {
|
||||||
|
content:"";
|
||||||
|
border:3px solid #00e6ac;
|
||||||
|
-webkit-border-radius:30px;
|
||||||
|
height:40px;
|
||||||
|
width:40px;
|
||||||
|
position:absolute;
|
||||||
|
margin-left:-20px;
|
||||||
|
margin-top:-20px;
|
||||||
|
-webkit-animation:pulsate 1s ease-out;
|
||||||
|
-webkit-animation-iteration-count:infinite;
|
||||||
|
opacity:0.0
|
||||||
|
}
|
||||||
|
@-webkit-keyframes pulsate {
|
||||||
|
0% {-webkit-transform:scale(0.1, 0.1); opacity:0.0}
|
||||||
|
50% {opacity:1.0}
|
||||||
|
100% {-webkit-transform:scale(1.2, 1.2); opacity:0.0}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** underline effect ***/
|
||||||
|
a:not(.btn):not(.noeffect) {position:relative}
|
||||||
|
a:not(.btn):not(.noeffect):hover {color:#26a69a}
|
||||||
|
a:not(.btn):not(.noeffect):hover:after {width:100%}
|
||||||
|
a:not(.btn):not(.noeffect):after {
|
||||||
|
display:block;
|
||||||
|
position:absolute;
|
||||||
|
left:0;
|
||||||
|
bottom:-1px;
|
||||||
|
width:0;
|
||||||
|
height:2px;
|
||||||
|
background-color:#26a69a;
|
||||||
|
content:"";
|
||||||
|
transition:width 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** modal ***/
|
||||||
|
.modal {
|
||||||
|
position:fixed;
|
||||||
|
z-index:9999;
|
||||||
|
top:0;
|
||||||
|
bottom:0;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
background-color:rgba(0,0,0,0.8);
|
||||||
|
padding-top:20vh;
|
||||||
|
transition:opacity 500ms;
|
||||||
|
visibility:hidden;
|
||||||
|
opacity:0;
|
||||||
|
}
|
||||||
|
.modal:target {visibility:visible; opacity:1}
|
||||||
|
.modal div {margin-left:auto; margin-right:auto}
|
||||||
|
.modal .close:not(.btn) {position:absolute; top:10px; right:10px; font-size:20px}
|
||||||
|
.modal .close {transition:all 200ms}
|
||||||
|
|
||||||
|
/*** tooltips from http://codepen.io/trezy/pen/Khnzy ***/
|
||||||
|
[data-tooltip] {position:relative}
|
||||||
|
[data-tooltip]:before, [data-tooltip]:after {display:none; position:absolute; top:0}
|
||||||
|
[data-tooltip]:hover:after,[data-tooltip]:hover:before {display:block}
|
||||||
|
[data-tooltip]:hover:before {
|
||||||
|
border-bottom:.6em solid #111111;
|
||||||
|
border-bottom:.6em solid #111111;
|
||||||
|
border-left:7px solid transparent;
|
||||||
|
border-right:7px solid transparent;
|
||||||
|
content:"";
|
||||||
|
left:0;
|
||||||
|
margin-top:12px;
|
||||||
|
z-index:2000;
|
||||||
|
}
|
||||||
|
[data-tooltip]:hover:after {
|
||||||
|
z-index:2000;
|
||||||
|
background-color:rgba(0,0,0,0.8);
|
||||||
|
border:4px solid rgba(0,0,0,0.8);
|
||||||
|
border-radius:7px;
|
||||||
|
color:white;
|
||||||
|
text-transform:none;
|
||||||
|
font-size: 12px;
|
||||||
|
content:attr(data-tooltip);
|
||||||
|
left:0;
|
||||||
|
top:2px;
|
||||||
|
margin-left:-20px;
|
||||||
|
margin-top:1.5em;
|
||||||
|
padding:5px 15px;
|
||||||
|
white-space:pre-wrap;
|
||||||
|
width:100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** accordion ***/
|
||||||
|
.accordion>input ~ label:before {content:"▲ "; color:#ddd}
|
||||||
|
.accordion>input:checked ~ label:before {content:"▼ "; color:#ddd}
|
||||||
|
.accordion>input {display:none}
|
||||||
|
.accordion>input:checked ~ *:not(label) {
|
||||||
|
max-height: 1000px !important;
|
||||||
|
overflow:visible !important;
|
||||||
|
-webkit-transition: max-height .3s ease-in;
|
||||||
|
transition: max-height .3s ease-in;
|
||||||
|
}
|
||||||
|
.accordion>*:not(label) {
|
||||||
|
max-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-transition: max-height .3s ease-out;
|
||||||
|
transition: max-height .3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** cards from http://codepen.io/edeesims/pen/iGDzk ***/
|
||||||
|
.card {perspective: 500px; max-width:100%}
|
||||||
|
.card>div {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 15px rgba(0,0,0,0.1);
|
||||||
|
transition: transform 1s;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
.card:hover>div {
|
||||||
|
transform: rotateY( 180deg ) ;
|
||||||
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
.card>div>div {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
}
|
||||||
|
.card>div>div:nth-child(2) {
|
||||||
|
transform: rotateY( 180deg );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**** tags ****/
|
||||||
|
.tags > span {
|
||||||
|
padding: 4px 9px;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: white;
|
||||||
|
background-color: #26a69a;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size:12px;
|
||||||
|
margin: 2px 5px 2px 0;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.tags.dismissible > span:hover {opacity: 0.5}
|
||||||
|
.tags.dismissible > span:not(.off):after {content:" ✕"}
|
||||||
|
.tags > span.off {background-color: #ccc}
|
||||||
|
.tags.dismissible > span.off:hover {background-color:#26a69a}
|
||||||
|
|
||||||
|
/*** colors from http://clrs.cc/ ***/
|
||||||
|
.navy{background-color:#001f3f;color:white}.blue{background-color:#0074d9;color:white}.aqua{background-color:#7fdbff;color:#111111}.teal{background-color:#39cccc;color:white}.olive{background-color:#3d9970;color:white}.green{background-color:#2ecc40;color:white}.aquamarine{background-color:#26a69a;color:white}.lime{background-color:#01ff70;color:#111111}.yellow{background-color:#ffdc00;color:#111111}.orange{background-color:#ff851b;color:white}.red{background-color:#cc1f00;color:white}.fuchsia{background-color:#f012be;color:white}.pink{background-color:#ee6e73;color:white}.purple{background-color:#b10dc9;color:white}.maroon{background-color:#85144b;color:white}.white{background-color:#fff;color:#111111;-webkit-box-shadow:inset 0px 0px 0px 1px #ddd;-moz-box-shadow:inset 0px 0px 0px 1px #ddd;box-shadow:inset 0px 0px 0px 1px #ddd}.gray{background-color:#aaa;color:white}.silver{background-color:#f1f1f1;color:#111111}.black{background-color:#111111;color:white}.glass{background:rgba(255,255,255,0.5);color:#111111}
|
||||||
@@ -1,84 +1,17 @@
|
|||||||
/** these MUST stay **/
|
header a {color: white; font-size:1.1em}
|
||||||
a {text-decoration:none; white-space:nowrap}
|
main {min-height: 70vh}
|
||||||
a:hover {text-decoration:underline}
|
.form-group {padding-bottom: 10px !important;}
|
||||||
a.button {text-decoration:none}
|
.w2p_hidden {display:none;visibility:visible}
|
||||||
h1,h2,h3,h4,h5,h6 {margin:0.5em 0 0.25em 0; display:block;
|
|
||||||
font-family:Helvetica}
|
|
||||||
h1 {font-size:4.00em}
|
|
||||||
h2 {font-size:3.00em}
|
|
||||||
h3 {font-size:2.00em}
|
|
||||||
h4 {font-size:1.50em}
|
|
||||||
h5 {font-size:1.25em}
|
|
||||||
h6 {font-size:1.12em}
|
|
||||||
th,label {font-weight:bold; white-space:nowrap;}
|
|
||||||
td,th {text-align:left; padding:2px 5px 2px 5px}
|
|
||||||
th {vertical-align:middle; border-right:1px solid white}
|
|
||||||
td {vertical-align:top}
|
|
||||||
form table tr td label {text-align:left}
|
|
||||||
p,table,ol,ul {padding:0; margin: 0.75em 0}
|
|
||||||
p {text-align:justify}
|
|
||||||
ol, ul {list-style-position:outside; margin-left:2em}
|
|
||||||
li {margin-bottom:0.5em}
|
|
||||||
span,input,select,textarea,button,label,a {display:inline}
|
|
||||||
img {border:0}
|
|
||||||
blockquote,blockquote p,p blockquote {
|
|
||||||
font-style:italic; margin:0.5em 30px 0.5em 30px; font-size:0.9em}
|
|
||||||
i,em {font-style:italic}
|
|
||||||
strong {font-weight:bold}
|
|
||||||
small {font-size:0.8em}
|
|
||||||
code {font-family:Courier}
|
|
||||||
textarea {width:100%}
|
|
||||||
video {width:400px}
|
|
||||||
audio {width:200px}
|
|
||||||
[type="text"], [type="password"], select {
|
|
||||||
margin-right: 5px; width: 300px;
|
|
||||||
}
|
|
||||||
.hidden {display:none;visibility:visible}
|
|
||||||
.right {float:right; text-align:right}
|
.right {float:right; text-align:right}
|
||||||
.left {float:left; text-align:left}
|
.left {float:left; text-align:left}
|
||||||
.center {width:100%; text-align:center; vertical-align:middle}
|
.center {width:100%; text-align:center; vertical-align:middle}
|
||||||
/** end **/
|
|
||||||
|
|
||||||
/* Sticky footer begin */
|
|
||||||
|
|
||||||
.main {
|
|
||||||
padding:20px 0 50px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer,.push {
|
|
||||||
height:6em;
|
|
||||||
padding:1em 0;
|
|
||||||
clear:both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer-content {position:relative; bottom:-4em; width:100%}
|
|
||||||
|
|
||||||
.auth_navbar {
|
|
||||||
white-space:nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sticky footer end */
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
border-top:1px #DEDEDE solid;
|
|
||||||
}
|
|
||||||
.header {
|
|
||||||
/* background:<fill here for header image>; */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fieldset {padding:16px; border-top:1px #DEDEDE solid}
|
|
||||||
fieldset legend {text-transform:uppercase; font-weight:bold; padding:4px 16px 4px 16px; background:#f1f1f1}
|
|
||||||
|
|
||||||
/* fix ie problem with menu */
|
|
||||||
|
|
||||||
td.w2p_fw {padding-bottom:1px}
|
td.w2p_fw {padding-bottom:1px}
|
||||||
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
|
td.w2p_fl,td.w2p_fw,td.w2p_fc {vertical-align:top}
|
||||||
td.w2p_fl {text-align:left}
|
td.w2p_fl {text-align:left}
|
||||||
td.w2p_fl, td.w2p_fw {padding-right:7px}
|
td.w2p_fl, td.w2p_fw {padding-right:7px}
|
||||||
td.w2p_fl,td.w2p_fc {padding-top:4px}
|
td.w2p_fl,td.w2p_fc {padding-top:4px}
|
||||||
div.w2p_export_menu {margin:5px 0}
|
div.w2p_export_menu {white-space: wrap; margin:5px 0}
|
||||||
div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; padding:2px 5px; background-color:#f1f1f1; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px;}
|
div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; padding:2px 5px; background-color:#f1f1f1; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px; font-size:0.7em; color: black}
|
||||||
|
|
||||||
/* tr#submit_record__row {border-top:1px solid #E5E5E5} */
|
/* tr#submit_record__row {border-top:1px solid #E5E5E5} */
|
||||||
#submit_record__row td {padding-top:.5em}
|
#submit_record__row td {padding-top:.5em}
|
||||||
@@ -88,54 +21,30 @@ div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; pa
|
|||||||
#web2py_user_form td {vertical-align:top}
|
#web2py_user_form td {vertical-align:top}
|
||||||
|
|
||||||
/*********** web2py specific ***********/
|
/*********** web2py specific ***********/
|
||||||
div.flash {
|
div.w2p_flash {
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
display:none;
|
display:none;
|
||||||
position:fixed;
|
padding:20px 20px 20px 50px;
|
||||||
padding:10px;
|
width:100%;
|
||||||
top:48px;
|
|
||||||
right:250px;
|
|
||||||
min-width:280px;
|
|
||||||
opacity:0.95;
|
opacity:0.95;
|
||||||
margin:0px 0px 10px 10px;
|
|
||||||
vertical-align:middle;
|
vertical-align:middle;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
color:#fff;
|
color:#000;
|
||||||
background-color:#000;
|
background-color:#ffdc00;
|
||||||
border:2px solid #fff;
|
|
||||||
border-radius:8px;
|
|
||||||
-o-border-radius: 8px;
|
|
||||||
-moz-border-radius:8px;
|
|
||||||
-webkit-border-radius:8px;
|
|
||||||
background-image: -webkit-linear-gradient(top,#222,#000);
|
|
||||||
background-image: -o-linear-gradient(top,#222,#000);
|
|
||||||
background-image: -moz-linear-gradient(90deg, #222, #000);
|
|
||||||
background-image: linear-gradient(top,#222,#000);
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
z-index:2000;
|
z-index:2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.flash #closeflash{color:inherit; float:right; margin-left:15px;}
|
div.w2p_flash:before{content:"×";float:right; margin-right:100px; color:black;}
|
||||||
.ie-lte7 div.flash #closeflash
|
.ie-lte7 div.flash #closeflash
|
||||||
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
|
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
|
||||||
|
|
||||||
div.flash:hover { opacity:0.25; }
|
div.w2p_flash:hover { opacity:0.80; }
|
||||||
|
|
||||||
div.error_wrapper {display:block}
|
div.error_wrapper {display:block}
|
||||||
div.error {
|
div.error {
|
||||||
width: 298px;
|
color:red;
|
||||||
background:red;
|
|
||||||
border: 2px solid #d00;
|
|
||||||
color:white;
|
|
||||||
padding:5px;
|
padding:5px;
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
background-image: -webkit-linear-gradient(left,#f00,#fdd);
|
|
||||||
background-image: -o-linear-gradient(left,#f00,#fdd);
|
|
||||||
background-image: -moz-linear-gradient(0deg, #f00, #fdd);
|
|
||||||
background-image: linear-gradient(left,#f00,#fdd);
|
|
||||||
background-repeat: repeat-y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
@@ -190,34 +99,8 @@ div.error {
|
|||||||
*/
|
*/
|
||||||
/* .web2py_table {border:1px solid #ccc} */
|
/* .web2py_table {border:1px solid #ccc} */
|
||||||
.web2py_paginator {}
|
.web2py_paginator {}
|
||||||
.web2py_grid {width:100%}
|
|
||||||
.web2py_grid table {width:100%}
|
.web2py_grid table {width:100%}
|
||||||
.web2py_grid tbody td {padding:2px 5px 2px 5px; vertical-align: middle;}
|
.web2py_grid td {color: black;}
|
||||||
.web2py_grid .web2py_form td {vertical-align: top;}
|
|
||||||
|
|
||||||
.web2py_grid thead th,.web2py_grid tfoot td {
|
|
||||||
background-color:#EAEAEA;
|
|
||||||
padding:10px 5px 10px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.web2py_grid tr.odd {background-color:#F9F9F9}
|
|
||||||
.web2py_grid tr:hover {background-color:#F5F5F5}
|
|
||||||
|
|
||||||
/*
|
|
||||||
.web2py_breadcrumbs a {
|
|
||||||
line-height:20px; margin-right:5px; display:inline-block;
|
|
||||||
padding:3px 5px 3px 5px;
|
|
||||||
font-family:'lucida grande',tahoma,verdana,arial,sans-serif;
|
|
||||||
color:#3C3C3D;
|
|
||||||
text-shadow:1px 1px 0 #FFFFFF;
|
|
||||||
white-space:nowrap; overflow:visible; cursor:pointer;
|
|
||||||
background:#ECECEC;
|
|
||||||
border:1px solid #CACACA;
|
|
||||||
-webkit-border-radius:2px; -moz-border-radius:2px;
|
|
||||||
-webkit-background-clip:padding-box; border-radius:2px;
|
|
||||||
outline:none; position:relative; zoom:1; *display:inline;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
.web2py_console form {
|
.web2py_console form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -302,11 +185,6 @@ li.w2p_grid_breadcrumb_elem {
|
|||||||
.web2py_console input, .web2py_console select,
|
.web2py_console input, .web2py_console select,
|
||||||
.web2py_console a { margin: 2px; }
|
.web2py_console a { margin: 2px; }
|
||||||
|
|
||||||
.web2py_htmltable {
|
|
||||||
width: 100%;
|
|
||||||
overflow-x: auto;
|
|
||||||
-ms-overflow-x:scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
#wiki_page_body {
|
#wiki_page_body {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
@@ -317,6 +195,10 @@ li.w2p_grid_breadcrumb_elem {
|
|||||||
/* fix some IE problems */
|
/* fix some IE problems */
|
||||||
|
|
||||||
.ie-lte7 .topbar .container {z-index:2}
|
.ie-lte7 .topbar .container {z-index:2}
|
||||||
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
.ie-lte8 div.w2p_flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
||||||
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
|
.ie-lte8 div.w2p_flash:hover {filter:alpha(opacity=25);}
|
||||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||||
|
|
||||||
|
.web2py_console .form-control {width: 20%; display: inline;}
|
||||||
|
.web2py_console #w2p_keywords {width: 50%;}
|
||||||
|
.web2py_search_actions a, .web2py_console input[type=submit], .web2py_console input[type=button], .web2py_console button { padding: 6px 12px; }
|
||||||
|
|||||||
@@ -1,264 +0,0 @@
|
|||||||
/*=============================================================
|
|
||||||
CUSTOM RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
body{height:auto;} /* to avoid vertical scroll bar */
|
|
||||||
|
|
||||||
a{}
|
|
||||||
a:visited{}
|
|
||||||
a:hover{}
|
|
||||||
a:focus{}
|
|
||||||
a:active{}
|
|
||||||
|
|
||||||
h1{}
|
|
||||||
h2{}
|
|
||||||
h3{}
|
|
||||||
h4{}
|
|
||||||
h5{}
|
|
||||||
h6{}
|
|
||||||
|
|
||||||
div.flash.flash-center{left:25%;right:25%;}
|
|
||||||
div.flash.flash-top,div.flash.flash-top:hover{
|
|
||||||
position:relative;
|
|
||||||
display:block;
|
|
||||||
margin:0;
|
|
||||||
padding:1em;
|
|
||||||
top:0;
|
|
||||||
left:0;
|
|
||||||
width:100%;
|
|
||||||
text-align:center;
|
|
||||||
text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
|
|
||||||
color:#865100;
|
|
||||||
background:#feea9a;
|
|
||||||
border:1px solid;
|
|
||||||
border-top:0px;
|
|
||||||
border-left:0px;
|
|
||||||
border-right:0px;
|
|
||||||
border-radius:0;
|
|
||||||
opacity:1;
|
|
||||||
}
|
|
||||||
#header{margin-top:60px;}
|
|
||||||
.mastheader h1 {
|
|
||||||
margin-bottom:9px;
|
|
||||||
font-size:81px;
|
|
||||||
font-weight:bold;
|
|
||||||
letter-spacing:-1px;
|
|
||||||
line-height:1;
|
|
||||||
font-size:54px;
|
|
||||||
}
|
|
||||||
.mastheader small {
|
|
||||||
font-size:20px;
|
|
||||||
font-weight:300;
|
|
||||||
}
|
|
||||||
/* auth navbar - primitive style */
|
|
||||||
.auth_navbar,.auth_navbar a{color:inherit;}
|
|
||||||
.navbar-inner {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}
|
|
||||||
.ie-lte7 .auth_navbar,.auth_navbar a{color:expression(this.parentNode.currentStyle['color']); /* ie7 doesn't support inherit */}
|
|
||||||
.auth_navbar a{white-space:nowrap;} /* to avoid the nav split on more lines */
|
|
||||||
.auth_navbar a:hover{color:white;text-decoration:none;}
|
|
||||||
ul#navbar>.auth_navbar{
|
|
||||||
display:inline-block;
|
|
||||||
padding:5px;
|
|
||||||
}
|
|
||||||
/* form errors message box customization */
|
|
||||||
div.error_wrapper{margin-bottom:9px;}
|
|
||||||
div.error_wrapper .error{
|
|
||||||
border-radius: 4px;
|
|
||||||
-o-border-radius: 4px;
|
|
||||||
-moz-border-radius: 4px;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
}
|
|
||||||
/* below rules are only for formstyle = bootstrap
|
|
||||||
trying to make errors look like bootstrap ones */
|
|
||||||
div.controls .error_wrapper{
|
|
||||||
display:inline-block;
|
|
||||||
margin-bottom:0;
|
|
||||||
vertical-align:middle;
|
|
||||||
}
|
|
||||||
div.controls .error{
|
|
||||||
min-width:5px;
|
|
||||||
background:inherit;
|
|
||||||
color:#B94A48;
|
|
||||||
border:none;
|
|
||||||
padding:0;
|
|
||||||
margin:0;
|
|
||||||
/*display:inline;*/ /* uncommenting this, the animation effect is lost */
|
|
||||||
}
|
|
||||||
div.controls .help-inline{color:#3A87AD;}
|
|
||||||
div.controls .error_wrapper +.help-inline {margin-left:-99999px;}
|
|
||||||
div.controls select +.error_wrapper {margin-left:5px;}
|
|
||||||
.ie-lte7 div.error{color:#fff;}
|
|
||||||
|
|
||||||
/* beautify brand */
|
|
||||||
.navbar {margin-bottom:0}
|
|
||||||
.navbar-inverse .brand{color:#c6cecc;}
|
|
||||||
.navbar-inverse .brand b{display:inline-block;margin-top:-1px;}
|
|
||||||
.navbar-inverse .brand b>span{font-size:22px;color:white}
|
|
||||||
.navbar-inverse .brand:hover b>span{color:white}
|
|
||||||
/* beautify web2py link in navbar */
|
|
||||||
span.highlighted{color:#d8d800;}
|
|
||||||
.open span.highlighted{color:#ffff00;}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OVERRIDING WEB2PY.CSS RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/* reset to default */
|
|
||||||
a{white-space:normal;}
|
|
||||||
li{margin-bottom:0;}
|
|
||||||
textarea,button{display:block;}
|
|
||||||
/*reset ul padding */
|
|
||||||
ul#navbar{padding:0;}
|
|
||||||
/* label aligned to related input */
|
|
||||||
td.w2p_fl,td.w2p_fc {padding:0;}
|
|
||||||
#web2py_user_form td{vertical-align:middle;}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OVERRIDING BOOTSTRAP.CSS RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/* because web2py handles this via js */
|
|
||||||
textarea { width:90%}
|
|
||||||
.hidden{visibility:visible;}
|
|
||||||
/* right folder for bootstrap black images/icons */
|
|
||||||
[class^="icon-"],[class*=" icon-"]{
|
|
||||||
background-image:url("../images/glyphicons-halflings.png")
|
|
||||||
}
|
|
||||||
/* right folder for bootstrap white images/icons */
|
|
||||||
.icon-white,
|
|
||||||
.nav-tabs > .active > a > [class^="icon-"],
|
|
||||||
.nav-tabs > .active > a > [class*=" icon-"],
|
|
||||||
.nav-pills > .active > a > [class^="icon-"],
|
|
||||||
.nav-pills > .active > a > [class*=" icon-"],
|
|
||||||
.nav-list > .active > a > [class^="icon-"],
|
|
||||||
.nav-list > .active > a > [class*=" icon-"],
|
|
||||||
.navbar-inverse .nav > .active > a > [class^="icon-"],
|
|
||||||
.navbar-inverse .nav > .active > a > [class*=" icon-"],
|
|
||||||
.dropdown-menu > li > a:hover > [class^="icon-"],
|
|
||||||
.dropdown-menu > li > a:hover > [class*=" icon-"],
|
|
||||||
.dropdown-menu > .active > a > [class^="icon-"],
|
|
||||||
.dropdown-menu > .active > a > [class*=" icon-"] {
|
|
||||||
background-image:url("../images/glyphicons-halflings-white.png");
|
|
||||||
}
|
|
||||||
/* bootstrap has a label as input's wrapper while web2py has a div */
|
|
||||||
div>input[type="radio"],div>input[type="checkbox"]{margin:0;}
|
|
||||||
/* bootstrap has button instead of input */
|
|
||||||
input[type="button"], input[type="submit"]{margin-right:8px;}
|
|
||||||
|
|
||||||
/* web2py radio widget adjustment */
|
|
||||||
.generic-widget input[type='radio'] {margin:-1px 0 0 0; vertical-align: middle;}
|
|
||||||
.generic-widget input[type='radio'] + label {display:inline-block; margin:0 0 0 6px; vertical-align: middle;}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
RULES FOR SOLVING CONFLICTS BETWEEN WEB2PY.CSS AND BOOTSTRAP.CSS
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/*when formstyle=table3cols*/
|
|
||||||
tr#auth_user_remember__row>td.w2p_fw>div{padding-bottom:8px;}
|
|
||||||
td.w2p_fw div>label{vertical-align:middle;}
|
|
||||||
td.w2p_fc {padding-bottom:5px;}
|
|
||||||
/*when formstyle=divs*/
|
|
||||||
div#auth_user_remember__row{margin-top:4px;}
|
|
||||||
div#auth_user_remember__row>.w2p_fl{display:none;}
|
|
||||||
div#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
|
||||||
div.w2p_fw,div.w2p_fc{
|
|
||||||
display:inline-block;
|
|
||||||
vertical-align:middle;
|
|
||||||
margin-bottom:0;
|
|
||||||
}
|
|
||||||
div.w2p_fc{
|
|
||||||
padding-left:5px;
|
|
||||||
margin-top:-8px;
|
|
||||||
}
|
|
||||||
/*when formstyle=ul*/
|
|
||||||
form>ul{
|
|
||||||
list-style:none;
|
|
||||||
margin:0;
|
|
||||||
}
|
|
||||||
li#auth_user_remember__row{margin-top:4px;}
|
|
||||||
li#auth_user_remember__row>.w2p_fl{display:none;}
|
|
||||||
li#auth_user_remember__row>.w2p_fw{min-height:39px;}
|
|
||||||
/*when formstyle=bootstrap*/
|
|
||||||
#auth_user_remember__row label.checkbox{display:block;}
|
|
||||||
span.inline-help{display:inline-block;}
|
|
||||||
input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px;}
|
|
||||||
/*when recaptcha is used*/
|
|
||||||
#recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;}
|
|
||||||
td>#recaptcha{margin-bottom:6px;}
|
|
||||||
div>#recaptcha{margin-bottom:9px;}
|
|
||||||
div.control-group.error{
|
|
||||||
width:auto;
|
|
||||||
background:transparent;
|
|
||||||
border:0;
|
|
||||||
color:inherit;
|
|
||||||
padding:0;
|
|
||||||
background-repeat:repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OTHER RULES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
/* Massimo Di Pierro fixed alignment in forms with list:string */
|
|
||||||
form table tr{margin-bottom:9px;}
|
|
||||||
td.w2p_fw ul{margin-left:0px;}
|
|
||||||
|
|
||||||
/* web2py_console in grid and smartgrid */
|
|
||||||
.hidden{visibility:visible;}
|
|
||||||
.web2py_console input{
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.web2py_console input[type="submit"],
|
|
||||||
.web2py_console input[type="button"],
|
|
||||||
.web2py_console button{
|
|
||||||
padding-top:4px;
|
|
||||||
padding-bottom:4px;
|
|
||||||
margin:3px 0 0 2px;
|
|
||||||
}
|
|
||||||
.web2py_console a,
|
|
||||||
.web2py_console select,
|
|
||||||
.web2py_console input
|
|
||||||
{
|
|
||||||
margin:3px 0 0 2px;
|
|
||||||
}
|
|
||||||
.web2py_grid form table{width:auto;}
|
|
||||||
/* auth_user_remember checkbox extrapadding in IE fix */
|
|
||||||
.ie-lte9 input#auth_user_remember.checkbox {padding-left:0;}
|
|
||||||
|
|
||||||
div.controls .error {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
MEDIA QUERIES
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
@media only screen and (max-width:979px){
|
|
||||||
body{padding-top:0px;}
|
|
||||||
#navbar{/*top:5px;*/}
|
|
||||||
div.flash{right:5px;}
|
|
||||||
.dropdown-menu ul{visibility:visible;}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width:479px){
|
|
||||||
body{
|
|
||||||
padding-left:10px;
|
|
||||||
padding-right:10px;
|
|
||||||
}
|
|
||||||
.navbar-fixed-top,.navbar-fixed-bottom {
|
|
||||||
margin-left:-10px;
|
|
||||||
margin-right:-10px;
|
|
||||||
}
|
|
||||||
input[type="text"],input[type="password"],select{
|
|
||||||
width:95%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
.navbar {
|
|
||||||
margin-right: -20px;
|
|
||||||
margin-left: -20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
/*=============================================================
|
|
||||||
BOOTSTRAP DROPDOWN MENU
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
.dropdown-menu ul{
|
|
||||||
left:100%;
|
|
||||||
position:absolute;
|
|
||||||
top:0;
|
|
||||||
visibility:hidden;
|
|
||||||
margin-top:-1px;
|
|
||||||
}
|
|
||||||
.dropdown-menu li:hover ul{visibility:visible;}
|
|
||||||
.navbar .dropdown-menu ul:before{
|
|
||||||
border-bottom:7px solid transparent;
|
|
||||||
border-left:none;
|
|
||||||
border-right:7px solid rgba(0, 0, 0, 0.2);
|
|
||||||
border-top:7px solid transparent;
|
|
||||||
left:-7px;
|
|
||||||
top:5px;
|
|
||||||
}
|
|
||||||
.nav > li.dropdown > a:after {
|
|
||||||
border-left: 4px solid transparent;
|
|
||||||
border-right: 4px solid transparent;
|
|
||||||
border-top: 4px solid #000000;
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
height: 0;
|
|
||||||
opacity: 0.7;
|
|
||||||
vertical-align: top;
|
|
||||||
width: 0;
|
|
||||||
|
|
||||||
margin-left: 2px;
|
|
||||||
margin-top: 8px;
|
|
||||||
|
|
||||||
border-bottom-color: #FFFFFF;
|
|
||||||
border-top-color: #FFFFFF;
|
|
||||||
}
|
|
||||||
.dropdown-menu span{display:inline-block;}
|
|
||||||
ul.dropdown-menu li.dropdown > a:after {
|
|
||||||
border-left: 4px solid #000;
|
|
||||||
border-right: 4px solid transparent;
|
|
||||||
border-bottom: 4px solid transparent;
|
|
||||||
border-top: 4px solid transparent;
|
|
||||||
content: "";
|
|
||||||
display: inline-block;
|
|
||||||
height: 0;
|
|
||||||
opacity: 0.7;
|
|
||||||
vertical-align: top;
|
|
||||||
width: 0;
|
|
||||||
|
|
||||||
margin-left: 8px;
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.nav li.dropdown:hover ul.dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.open >.dropdown-menu ul{display:block;} /* fix menu issue when BS2.0.4 is applied */
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
BOOTSTRAP SUBMIT BUTTON
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
input[type='submit']:not(.btn) {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 4px 14px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 20px;
|
|
||||||
color: #333;
|
|
||||||
text-align: center;
|
|
||||||
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
|
|
||||||
vertical-align: middle;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: whiteSmoke;
|
|
||||||
background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6));
|
|
||||||
background-image: -webkit-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-image: -o-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-image: linear-gradient(to bottom,white,#E6E6E6);
|
|
||||||
background-image: -moz-linear-gradient(top,white,#E6E6E6);
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
border: 1px solid #BBB;
|
|
||||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
|
||||||
border-bottom-color: #A2A2A2;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
-moz-border-radius: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
|
|
||||||
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
|
|
||||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
-moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
|
|
||||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='submit']:not(.btn):hover {
|
|
||||||
color: #333;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #E6E6E6;
|
|
||||||
background-position: 0 -15px;
|
|
||||||
-webkit-transition: background-position .1s linear;
|
|
||||||
-moz-transition: background-position .1s linear;
|
|
||||||
-o-transition: background-position .1s linear;
|
|
||||||
transition: background-position .1s linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type='submit']:not(.btn).active, input[type='submit']:not(.btn):active {
|
|
||||||
background-color: #E6E6E6;
|
|
||||||
background-color: #D9D9D9 9;
|
|
||||||
background-image: none;
|
|
||||||
outline: 0;
|
|
||||||
-webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
|
||||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*=============================================================
|
|
||||||
OTHER
|
|
||||||
==============================================================*/
|
|
||||||
|
|
||||||
.ie-lte8 .navbar-fixed-top {position:static;}
|
|
||||||
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5
-4
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
|||||||
// this code improves bootstrap menus and adds dropdown support
|
|
||||||
jQuery(function(){
|
|
||||||
jQuery('.nav>li>a').each(function(){
|
|
||||||
if(jQuery(this).parent().find('ul').length)
|
|
||||||
jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append('<b class="caret"></b>');
|
|
||||||
});
|
|
||||||
jQuery('.nav li li').each(function(){
|
|
||||||
if(jQuery(this).find('ul').length)
|
|
||||||
jQuery(this).addClass('dropdown-submenu');
|
|
||||||
});
|
|
||||||
function adjust_height_of_collapsed_nav() {
|
|
||||||
var cn = jQuery('div.collapse');
|
|
||||||
if (cn.get(0)) {
|
|
||||||
var cnh = cn.get(0).style.height;
|
|
||||||
if (cnh>'0px'){
|
|
||||||
cn.css('height','auto');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function hoverMenu(){
|
|
||||||
jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){
|
|
||||||
adjust_height_of_collapsed_nav();
|
|
||||||
var mi = jQuery(this).addClass('open');
|
|
||||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400);
|
|
||||||
}, function(){
|
|
||||||
var mi = jQuery(this);
|
|
||||||
mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
hoverMenu(); // first page load
|
|
||||||
jQuery(window).resize(hoverMenu); // on resize event
|
|
||||||
jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');});
|
|
||||||
});
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active" id="alltables">
|
<div class="tab-pane active" id="alltables">
|
||||||
<table>
|
<table class="table">
|
||||||
{{for db in sorted(databases):}}
|
{{for db in sorted(databases):}}
|
||||||
{{for table in databases[db].tables:}}
|
{{for table in databases[db].tables:}}
|
||||||
{{qry='%s.%s.id>0'%(db,table)}}
|
{{qry='%s.%s.id>0'%(db,table)}}
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
|
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}}
|
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn btn-default")}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
</pre>
|
</pre>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
{{if table:}}
|
{{if table:}}
|
||||||
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/>
|
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn btn-default")}}<br/><br/>
|
||||||
<h3>{{=T("Rows in Table")}}</h3><br/>
|
<h3>{{=T("Rows in Table")}}</h3><br/>
|
||||||
{{else:}}
|
{{else:}}
|
||||||
<h3>{{=T("Rows selected")}}</h3><br/>
|
<h3>{{=T("Rows selected")}}</h3><br/>
|
||||||
@@ -72,8 +72,8 @@
|
|||||||
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
|
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<h4>{{=T("%s selected", nrows)}}</h4>
|
<h4>{{=T("%s selected", nrows)}}</h4>
|
||||||
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn")}}{{pass}}
|
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn btn-default")}}{{pass}}
|
||||||
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn")}}{{pass}}
|
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn btn-default")}}{{pass}}
|
||||||
{{if rows:}}
|
{{if rows:}}
|
||||||
<div style="overflow:auto; width:80%;">
|
<div style="overflow:auto; width:80%;">
|
||||||
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
|
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{pass}}
|
{{pass}}
|
||||||
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
|
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
|
||||||
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn">{{=T("export as csv file")}}</a>
|
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn btn-default">{{=T("export as csv file")}}</a>
|
||||||
{{=formcsv or ''}}
|
{{=formcsv or ''}}
|
||||||
|
|
||||||
{{elif request.function=='insert':}}
|
{{elif request.function=='insert':}}
|
||||||
@@ -137,9 +137,9 @@
|
|||||||
<h4>{{=T("Overview")}}</h4>
|
<h4>{{=T("Overview")}}</h4>
|
||||||
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
|
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
|
||||||
{{if total['entries'] > 0:}}
|
{{if total['entries'] > 0:}}
|
||||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses})",
|
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||||
dict(ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
|
dict( ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{=T("Size of cache:")}}
|
{{=T("Size of cache:")}}
|
||||||
{{if object_stats:}}
|
{{if object_stats:}}
|
||||||
@@ -155,8 +155,8 @@
|
|||||||
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
|
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle();')}}
|
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="all_keys">
|
<div class="w2p_hidden" id="all_keys">
|
||||||
{{=total['keys']}}
|
{{=total['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -183,8 +183,8 @@
|
|||||||
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
|
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle();')}}
|
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="ram_keys">
|
<div class="w2p_hidden" id="ram_keys">
|
||||||
{{=ram['keys']}}
|
{{=ram['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -212,8 +212,8 @@
|
|||||||
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
|
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle();')}}
|
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="disk_keys">
|
<div class="w2p_hidden" id="disk_keys">
|
||||||
{{=disk['keys']}}
|
{{=disk['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -249,8 +249,8 @@
|
|||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
{{extend 'layout.html'}}
|
{{extend 'layout.html'}}
|
||||||
|
|
||||||
<iframe src="//player.vimeo.com/hubnut/album/3016728?color=ff6600&background=ffffff&slideshow=1&video_title=1&video_byline=1" width="400" height="300" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
|
<div>
|
||||||
|
{{=get_content('main')}}
|
||||||
<div class="contentleft">
|
<center>
|
||||||
<div >
|
<iframe src="//player.vimeo.com/hubnut/album/3016728?color=ff6600&background=ffffff&slideshow=1&video_title=1&video_byline=1" width="400" height="300" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
|
||||||
{{=get_content('main')}}
|
</center>
|
||||||
</div>
|
{{=get_content('official')}}
|
||||||
{{=get_content('official')}}
|
{{=get_content('community')}}
|
||||||
{{=get_content('community')}}
|
{{=get_content('more')}}
|
||||||
{{=get_content('more')}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,47 +5,73 @@
|
|||||||
|
|
||||||
<h2>web2py<sup style="font-size:0.5em;">TM</sup> Download</h2>
|
<h2>web2py<sup style="font-size:0.5em;">TM</sup> Download</h2>
|
||||||
|
|
||||||
<center style="padding:20px">
|
<center class="spaced">
|
||||||
<table class="downloads">
|
<table class="twothirds">
|
||||||
<tr>
|
<thead>
|
||||||
<th>For Normal Users</th>
|
<tr>
|
||||||
<th>For Testers</th>
|
<th>For Normal Users</th>
|
||||||
<th>For Developers</th>
|
<th>For Testers</th>
|
||||||
</tr>
|
<th>For Developers</th>
|
||||||
<tr>
|
</tr>
|
||||||
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_win.zip">For Windows</a></td>
|
</thead>
|
||||||
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_win.zip">For Windows</a></td>
|
<tbody>
|
||||||
<td><a class="btn btn-180 btn-danger" href="http://github.com/web2py/web2py/">Git Repository</a></td>
|
<tr>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<a class="btn btn180 rounded green" href="http://www.web2py.com/examples/static/web2py_win.zip">For Windows</a>
|
||||||
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_osx.zip">For Mac</a></td>
|
</td>
|
||||||
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_osx.zip">For Mac</a></td>
|
<td>
|
||||||
<td></td>
|
<a class="btn btn180 rounded yellow" href="http://www.web2py.com/examples/static/nightly/web2py_win.zip">For Windows</a>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
<td>
|
||||||
<td><a class="btn btn-180 btn-success" href="http://www.web2py.com/examples/static/web2py_src.zip">Source Code</a></td>
|
<a class="btn btn180 rounded red" href="http://github.com/web2py/web2py/">Git Repository</a>
|
||||||
<td><a class="btn btn-180 btn-warning" href="http://www.web2py.com/examples/static/nightly/web2py_src.zip">Source Code</a></td>
|
</td>
|
||||||
<td><a class="btn btn-180 btn-danger" href="http://web2py.readthedocs.org/en/latest/">Source code docs</a></td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<td>
|
||||||
<td><a class="btn btn-180 btn-success" href="https://dl.dropbox.com/u/18065445/web2py/web2py_manual_5th.pdf">Manual</a></td>
|
<a class="btn btn180 rounded green" href="http://www.web2py.com/examples/static/web2py_osx.zip">For Mac</a>
|
||||||
<td><a class="btn btn-180" href="https://github.com/web2py/web2py/releases">Change Log</a></td>
|
</td>
|
||||||
<td><a class="btn btn-180" href="https://github.com/web2py/web2py/issues">Report a Bug</a></td>
|
<td>
|
||||||
</tr>
|
<a class="btn btn180 rounded yellow" href="http://www.web2py.com/examples/static/nightly/web2py_osx.zip">For Mac</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn180 rounded green" href="http://www.web2py.com/examples/static/web2py_src.zip">Source Code</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn180 rounded yellow" href="http://www.web2py.com/examples/static/nightly/web2py_src.zip">Source Code</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn180 rounded red" href="http://web2py.readthedocs.org/en/latest/">Source code docs</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn180 rounded green" href="https://dl.dropbox.com/u/18065445/web2py/web2py_manual_5th.pdf">Manual</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn180 rounded" href="https://github.com/web2py/web2py/releases">Change Log</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn180 rounded" href="https://github.com/web2py/web2py/issues">Report a Bug</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</center>
|
</center>
|
||||||
|
|
||||||
<p style="text-align:left;">
|
<p style="text-align:left;">
|
||||||
The source code version works on all supported platforms, including Linux, but it requires Python 2.5, 2.6, or 2.7.
|
The source code version works on all supported platforms, including Linux, but it requires Python 2.6, or 2.7 (recommended).
|
||||||
It runs on Windows and most Unix systems, including <b>Linux</b> and <b>BSD</b>.
|
It runs on Windows and most Unix systems, including <b>Linux</b> and <b>BSD</b>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3>Instructions</h3>
|
<h3>Instructions</h3>
|
||||||
<p>After download, unzip it and click on web2py.exe (windows) or web2py.app (osx).
|
<p>After download, unzip it and click on web2py.exe (windows) or web2py.app (osx).
|
||||||
To run from source, type:</p>
|
To run from source, type:</p>
|
||||||
{{=CODE("python2.7 web2py.py",language=None,counter='>',_class='boxCode')}}
|
{{=CODE("python2.7 web2py.py", language=None, counter='>', _class='boxCode')}}
|
||||||
<p>or for more info type:</p>
|
<p>or for more info type:</p>
|
||||||
{{=CODE("python2.7 web2py.py -h",language=None,counter='>',_class='boxCode')}}
|
{{=CODE("python2.7 web2py.py -h", language=None, counter='>', _class='boxCode')}}
|
||||||
|
|
||||||
|
|
||||||
<h3>Caveats</h3>
|
<h3>Caveats</h3>
|
||||||
@@ -58,7 +84,7 @@
|
|||||||
<p>Applications built with web2py can be released under any license the author wishes as long they do not contain web2py code. They can link unmodified web2py libraries and they can be distributed with official web2py binaries. In particular web2py applications can be distributed in closed source. The admin interface provides a button to byte-code compile.</p>
|
<p>Applications built with web2py can be released under any license the author wishes as long they do not contain web2py code. They can link unmodified web2py libraries and they can be distributed with official web2py binaries. In particular web2py applications can be distributed in closed source. The admin interface provides a button to byte-code compile.</p>
|
||||||
<p>It is fine to distribute web2py (source or compiled) with your applications as long as you make it clear in the license where your application ends and web2py starts.</p>
|
<p>It is fine to distribute web2py (source or compiled) with your applications as long as you make it clear in the license where your application ends and web2py starts.</p>
|
||||||
<p>web2py is copyrighted by Massimo Di Pierro. The web2py trademark is owned by Massimo Di Pierro.</p>
|
<p>web2py is copyrighted by Massimo Di Pierro. The web2py trademark is owned by Massimo Di Pierro.</p>
|
||||||
<a class="btn btn-small" href="{{=URL('license')}}">read more</a>
|
<a class="btn btn-small rounded" href="{{=URL('license')}}">read more</a>
|
||||||
|
|
||||||
<h3>Artwork</h3>
|
<h3>Artwork</h3>
|
||||||
<center>
|
<center>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def hello1():
|
|||||||
return "Hello World"
|
return "Hello World"
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
|
|
||||||
<p>If the controller function returns a string, that is the body of the rendered page.<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello1">hello1</a></p>
|
<p>If the controller function returns a string, that is the body of the rendered page.<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello1">hello1</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -40,7 +40,7 @@ def hello2():
|
|||||||
return T("Hello World")
|
return T("Hello World")
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
|
|
||||||
<p>The function T() marks strings that need to be translated. Translation dictionaries can be created at /admin/default/design<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello2">hello2</a></p>
|
<p>The function T() marks strings that need to be translated. Translation dictionaries can be created at /admin/default/design<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello2">hello2</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -51,7 +51,7 @@ def hello3():
|
|||||||
<b>and view: simple_examples/hello3.html</b>
|
<b>and view: simple_examples/hello3.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/simple_examples/hello3.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/simple_examples/hello3.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>If you return a dictionary, the variables defined in the dictionery are visible to the view (template).
|
<p>If you return a dictionary, the variables defined in the dictionery are visible to the view (template).
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello3.html">hello3</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello3.html">hello3</a></p>
|
||||||
|
|
||||||
<p>Actions can also be be rendered in other formsts like JSON, <a href="/{{=request.application}}/simple_examples/hello3.json">hello3.json</a>, and XML, <a href="/{{=request.application}}/simple_examples/hello3.xml">hello3.xml</a></p>
|
<p>Actions can also be be rendered in other formsts like JSON, <a href="/{{=request.application}}/simple_examples/hello3.json">hello3.json</a>, and XML, <a href="/{{=request.application}}/simple_examples/hello3.xml">hello3.xml</a></p>
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ def hello4():
|
|||||||
return dict(message=T("Hello World"))
|
return dict(message=T("Hello World"))
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can change the view, but the default is /[controller]/[function].html. If the default is not found web2py tries to render the page using the generic.html view.
|
<p>You can change the view, but the default is /[controller]/[function].html. If the default is not found web2py tries to render the page using the generic.html view.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello4">hello4</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello4">hello4</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -76,7 +76,7 @@ def hello5():
|
|||||||
<li>named arguments and name starts with '_'. These are mapped blindly into tag attributes and the '_' is removed. attributes without value like "READONLY" can be created with the argument "_readonly=ON".</li>
|
<li>named arguments and name starts with '_'. These are mapped blindly into tag attributes and the '_' is removed. attributes without value like "READONLY" can be created with the argument "_readonly=ON".</li>
|
||||||
<li>named arguments and name does not start with '_'. They have a special meaning. See "value=" for INPUT, TEXTAREA, SELECT tags later.
|
<li>named arguments and name does not start with '_'. They have a special meaning. See "value=" for INPUT, TEXTAREA, SELECT tags later.
|
||||||
</ul>
|
</ul>
|
||||||
<p>Try it here: <a href="/{{=request.application}}/simple_examples/hello5">hello5</a></p>
|
<p>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello5">hello5</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -86,7 +86,7 @@ def hello6():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
|
|
||||||
<p>response.flash allows you to flash a message to the user when the page is returned. Use session.flash instead of response.flash to display a message after redirection. With default layout, you can click on the flash to make it disappear.
|
<p>response.flash allows you to flash a message to the user when the page is returned. Use session.flash instead of response.flash to display a message after redirection. With default layout, you can click on the flash to make it disappear.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/hello6">hello6</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/hello6">hello6</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -94,7 +94,6 @@ def status():
|
|||||||
return dict(toobar=response.toolbar())
|
return dict(toobar=response.toolbar())
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>Here we are showing the request, session and response objects using the generic.html template.
|
<p>Here we are showing the request, session and response objects using the generic.html template.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/status">status</a></p>
|
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -102,7 +101,7 @@ def redirectme():
|
|||||||
redirect(URL('hello3'))
|
redirect(URL('hello3'))
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can do redirect.
|
<p>You can do redirect.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/redirectme">redirectme</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/redirectme">redirectme</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -110,7 +109,7 @@ def raisehttp():
|
|||||||
raise HTTP(400,"internal error")
|
raise HTTP(400,"internal error")
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can raise HTTP exceptions to return an error page.
|
<p>You can raise HTTP exceptions to return an error page.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/raisehttp">raisehttp</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/raisehttp">raisehttp</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -128,7 +127,7 @@ def servejs():
|
|||||||
return 'alert("This is a Javascript document, it is not supposed to run!");'
|
return 'alert("This is a Javascript document, it is not supposed to run!");'
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can serve other than HTML pages by changing the contenttype via the response.headers. The gluon.contenttype module can help you figure the type of the file to be served. NOTICE: this is not necessary for static files unless you want to require authorization.
|
<p>You can serve other than HTML pages by changing the contenttype via the response.headers. The gluon.contenttype module can help you figure the type of the file to be served. NOTICE: this is not necessary for static files unless you want to require authorization.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/servejs">servejs</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/servejs">servejs</a></p>
|
||||||
|
|
||||||
<h3 id="example_json">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3 id="example_json">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -136,7 +135,7 @@ def servejs():
|
|||||||
return response.json(['foo', {'bar': ('baz', None, 1.0, 2)}])
|
return response.json(['foo', {'bar': ('baz', None, 1.0, 2)}])
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>If you are into Ajax, web2py includes gluon.contrib.<a href="http://cheeseshop.python.org/pypi/simplejson">simplejson</a>, developed by Bob Ippolito. This module provides a fast and easy way to serve asynchronous content to your Ajax page. gluon.simplesjson.dumps(...) can serialize most Python types into <a href="http://www.json.org">JSON</a>. gluon.contrib.simplejson.loads(...) performs the reverse operation.
|
<p>If you are into Ajax, web2py includes gluon.contrib.<a href="http://cheeseshop.python.org/pypi/simplejson">simplejson</a>, developed by Bob Ippolito. This module provides a fast and easy way to serve asynchronous content to your Ajax page. gluon.simplesjson.dumps(...) can serialize most Python types into <a href="http://www.json.org">JSON</a>. gluon.contrib.simplejson.loads(...) performs the reverse operation.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/makejson">makejson</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/makejson">makejson</a></p>
|
||||||
|
|
||||||
<p>New in web2py 1.63: Any normal action returning a dict is automatically serialized in JSON if '.json' is appended to the URL.</p>
|
<p>New in web2py 1.63: Any normal action returning a dict is automatically serialized in JSON if '.json' is appended to the URL.</p>
|
||||||
|
|
||||||
@@ -152,7 +151,7 @@ def makertf():
|
|||||||
response.headers['Content-Type']='text/rtf'
|
response.headers['Content-Type']='text/rtf'
|
||||||
return q.dumps(doc)
|
return q.dumps(doc)
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>web2py also includes gluon.contrib.<a href="http://pyrtf.sourceforge.net/">pyrtf</a>, developed by Simon Cusack and revised by Grant Edwards. This module allows you to generate Rich Text Format documents including colored formatted text and pictures.<br/>Try it here: <a href="/{{=request.application}}/simple_examples/makertf">makertf</a></p>
|
<p>web2py also includes gluon.contrib.<a href="http://pyrtf.sourceforge.net/">pyrtf</a>, developed by Simon Cusack and revised by Grant Edwards. This module allows you to generate Rich Text Format documents including colored formatted text and pictures.<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/makertf">makertf</a></p>
|
||||||
|
|
||||||
<h3 id="example_rss">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3 id="example_rss">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -179,7 +178,7 @@ def rss_aggregator():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>web2py includes gluon.contrib.<a href="http://www.dalkescientific.com/Python/PyRSS2Gen.html">rss2</a>, developed by Dalke Scientific Software, which generates RSS2 feeds, and
|
<p>web2py includes gluon.contrib.<a href="http://www.dalkescientific.com/Python/PyRSS2Gen.html">rss2</a>, developed by Dalke Scientific Software, which generates RSS2 feeds, and
|
||||||
gluon.contrib.<a href="http://www.feedparser.org/">feedparser</a>, developed by Mark Pilgrim, which collects RSS and ATOM feeds. The above controller collects a slashdot feed and makes new one.
|
gluon.contrib.<a href="http://www.feedparser.org/">feedparser</a>, developed by Mark Pilgrim, which collects RSS and ATOM feeds. The above controller collects a slashdot feed and makes new one.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/simple_examples/rss_aggregator">rss_aggregator</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/rss_aggregator">rss_aggregator</a></p>
|
||||||
|
|
||||||
|
|
||||||
<h3 id="example_wiki">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
<h3 id="example_wiki">Example {{=c}}{{c+=1}}</h3><b>In controller: simple_examples.py</b>
|
||||||
@@ -194,7 +193,7 @@ def ajaxwiki_onclick():
|
|||||||
return MARKMIN(request.vars.text).xml()
|
return MARKMIN(request.vars.text).xml()
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>The markmin wiki markup is described <a href="{{=URL('static','markmin.html')}}">here</a>.
|
<p>The markmin wiki markup is described <a href="{{=URL('static','markmin.html')}}">here</a>.
|
||||||
web2py also includes gluon.contrib.<a href="http://code.google.com/p/python-markdown2/">markdown</a>.WIKI helper (markdown2) which converts WIKI markup to HTML following <a href="http://en.wikipedia.org/wiki/Markdown">this syntax</a>. In this example we added a fancy ajax effect.<br/>Try it here: <a href="/{{=request.application}}/simple_examples/ajaxwiki">ajaxwiki</a></p>
|
web2py also includes gluon.contrib.<a href="http://code.google.com/p/python-markdown2/">markdown</a>.WIKI helper (markdown2) which converts WIKI markup to HTML following <a href="http://en.wikipedia.org/wiki/Markdown">this syntax</a>. In this example we added a fancy ajax effect.<br/>Try it here: <a class="btn" href="/{{=request.application}}/simple_examples/ajaxwiki">ajaxwiki</a></p>
|
||||||
|
|
||||||
<h2 id="session_examples">Session Examples</h2>
|
<h2 id="session_examples">Session Examples</h2>
|
||||||
|
|
||||||
@@ -207,7 +206,7 @@ def counter():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: session_examples/counter.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: session_examples/counter.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/session_examples/counter.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/session_examples/counter.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>Click to count. The session.counter is persistent for this user and application. Every applicaiton within the system has its own separate session management.
|
<p>Click to count. The session.counter is persistent for this user and application. Every applicaiton within the system has its own separate session management.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/session_examples/counter">counter</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/session_examples/counter">counter</a></p>
|
||||||
|
|
||||||
<h2 id="template_examples">Template Examples</h2>
|
<h2 id="template_examples">Template Examples</h2>
|
||||||
|
|
||||||
@@ -219,7 +218,7 @@ def variables():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/variables.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/variables.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/variables.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/variables.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>A view (also known as template) is just an HTML file with {{...}} tags. You can put ANY python code into the tags, no need to indent but you must use pass to close blocks. The view is transformed into a python code and then executed. {{=a}} prints a.xml() or escape(str(a)).
|
<p>A view (also known as template) is just an HTML file with {{...}} tags. You can put ANY python code into the tags, no need to indent but you must use pass to close blocks. The view is transformed into a python code and then executed. {{=a}} prints a.xml() or escape(str(a)).
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/variables">variables</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/variables">variables</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -228,7 +227,7 @@ def test_for():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_for.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_for.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_for.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_for.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can do for and while loops.
|
<p>You can do for and while loops.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_for">test_for</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_for">test_for</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -237,7 +236,7 @@ def test_if():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_if.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_if.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_if.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_if.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can do if, elif, else.
|
<p>You can do if, elif, else.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_if">test_if</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_if">test_if</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -246,7 +245,7 @@ def test_try():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_try.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_try.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_try.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_try.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can do try, except, finally.
|
<p>You can do try, except, finally.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_try">test_try</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_try">test_try</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -255,7 +254,7 @@ def test_def():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_def.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/test_def.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_def.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/test_def.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can write functions in HTML too.
|
<p>You can write functions in HTML too.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/test_def">test_def</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/test_def">test_def</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -264,7 +263,7 @@ def escape():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/escape.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/escape.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/escape.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/escape.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>The argument of {{=...}} is always escaped unless it is an object with a .xml() method such as link, A(...), a FORM(...), a XML(...) block, etc.
|
<p>The argument of {{=...}} is always escaped unless it is an object with a .xml() method such as link, A(...), a FORM(...), a XML(...) block, etc.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/escape">escape</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/escape">escape</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -273,16 +272,16 @@ def xml():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/xml.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/xml.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/xml.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/xml.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>If you do not want to escape the argument of {{=...}} mark it as XML.
|
<p>If you do not want to escape the argument of {{=...}} mark it as XML.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/xml">xml</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/xml">xml</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: template_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
def beautify():
|
def beautify():
|
||||||
return dict(message=BEAUTIFY(request))
|
dict(message=BEAUTIFY(dict(a=1,b=[2,3,dict(hello='world')])))
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/beautify.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: template_examples/beautify.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/template_examples/beautify.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/template_examples/beautify.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can use BEAUTIFY to turn lists and dictionaries into organized HTML.
|
<p>You can use BEAUTIFY to turn lists and dictionaries into organized HTML.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/template_examples/beautify">beautify</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/template_examples/beautify">beautify</a></p>
|
||||||
|
|
||||||
<h2 id="layout_examples">Layout Examples</h2>
|
<h2 id="layout_examples">Layout Examples</h2>
|
||||||
|
|
||||||
@@ -298,7 +297,7 @@ def civilized():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/civilized.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/civilized.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/civilized.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/civilized.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can specify the layout file at the top of your view. civilized Layout file is a view that somewhere in the body contains {{include}}.
|
<p>You can specify the layout file at the top of your view. civilized Layout file is a view that somewhere in the body contains {{include}}.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/layout_examples/civilized">civilized</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/layout_examples/civilized">civilized</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: layout_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: layout_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -310,7 +309,7 @@ def slick():
|
|||||||
return dict(message="you clicked on slick")
|
return dict(message="you clicked on slick")
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/slick.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/slick.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/slick.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/slick.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>Same here, but using a different template.<br/>Try it here: <a href="/{{=request.application}}/layout_examples/slick">slick</a></p>
|
<p>Same here, but using a different template.<br/>Try it here: <a class="btn" href="/{{=request.application}}/layout_examples/slick">slick</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: layout_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: layout_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -323,7 +322,7 @@ def basic():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/basic.html</b>
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}<b>and view: layout_examples/basic.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/basic.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/layout_examples/basic.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>'layout.html' is the default template, every application has a copy of it.
|
<p>'layout.html' is the default template, every application has a copy of it.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/layout_examples/basic">basic</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/layout_examples/basic">basic</a></p>
|
||||||
|
|
||||||
<h2 id="form_examples">Form Examples</h2>
|
<h2 id="form_examples">Form Examples</h2>
|
||||||
|
|
||||||
@@ -347,7 +346,7 @@ def form():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>You can use HTML helpers like FORM, INPUT, TEXTAREA, OPTION, SELECT to build forms. The "value=" attribute sets the initial value of the field (works for TEXTAREA and OPTION/SELECT too) and the requires attribute sets the validators.
|
<p>You can use HTML helpers like FORM, INPUT, TEXTAREA, OPTION, SELECT to build forms. The "value=" attribute sets the initial value of the field (works for TEXTAREA and OPTION/SELECT too) and the requires attribute sets the validators.
|
||||||
FORM.accepts(..) tries to validate the form and, on success, stores vars into form.vars. On failure the error messages are stored into form.errors and shown in the form.
|
FORM.accepts(..) tries to validate the form and, on success, stores vars into form.vars. On failure the error messages are stored into form.errors and shown in the form.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/form_examples/form">form</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/form_examples/form">form</a></p>
|
||||||
|
|
||||||
<h2 id="database_examples">Database Examples</h2>
|
<h2 id="database_examples">Database Examples</h2>
|
||||||
|
|
||||||
@@ -497,7 +496,7 @@ def cache_in_ram():
|
|||||||
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>The output of <tt>lambda:time.ctime()</tt> is cached in ram for 5 seconds. The string 'time' is used as cache key.
|
<p>The output of <tt>lambda:time.ctime()</tt> is cached in ram for 5 seconds. The string 'time' is used as cache key.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_in_ram">cache_in_ram</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_in_ram">cache_in_ram</a></p>
|
||||||
|
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
||||||
@@ -508,7 +507,7 @@ def cache_on_disk():
|
|||||||
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>The output of <tt>lambda:time.ctime()</tt> is cached on disk (using the shelve module) for 5 seconds.
|
<p>The output of <tt>lambda:time.ctime()</tt> is cached on disk (using the shelve module) for 5 seconds.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_on_disk">cache_on_disk</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_on_disk">cache_on_disk</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -519,7 +518,7 @@ def cache_in_ram_and_disk():
|
|||||||
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>The output of <tt>lambda:time.ctime()</tt> is cached on disk (using the shelve module) and then in ram for 5 seconds. web2py looks in ram first and if not there it looks on disk. If it is not on disk it calls the function. This is useful in a multiprocess type of environment. The two times do not have to be the same.
|
<p>The output of <tt>lambda:time.ctime()</tt> is cached on disk (using the shelve module) and then in ram for 5 seconds. web2py looks in ram first and if not there it looks on disk. If it is not on disk it calls the function. This is useful in a multiprocess type of environment. The two times do not have to be the same.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_in_ram_and_disk">cache_in_ram_and_disk</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_in_ram_and_disk">cache_in_ram_and_disk</a></p>
|
||||||
|
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
||||||
@@ -530,7 +529,7 @@ def cache_in_ram_and_disk():
|
|||||||
t=time.ctime()
|
t=time.ctime()
|
||||||
return dict(time=t,link=A('click to reload',_href=URL(r=request)))""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
return dict(time=t,link=A('click to reload',_href=URL(r=request)))""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>Here the entire controller (dictionary) is cached in ram for 5 seconds. The result of a select cannot be cached unless it is first serialized into a table <tt>lambda:SQLTABLE(db().select(db.user.ALL)).xml()</tt>. You can read below for an even better way to do it.
|
<p>Here the entire controller (dictionary) is cached in ram for 5 seconds. The result of a select cannot be cached unless it is first serialized into a table <tt>lambda:SQLTABLE(db().select(db.user.ALL)).xml()</tt>. You can read below for an even better way to do it.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_controller_in_ram">cache_controller_in_ram</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_controller_in_ram">cache_controller_in_ram</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -541,7 +540,7 @@ def cache_controller_on_disk():
|
|||||||
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
return dict(time=t,link=A('click to reload',_href=URL(r=request)))
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>Here the entire controller (dictionary) is cached on disk for 5 seconds. This will not work if the dictionary contains unpickleable objects.
|
<p>Here the entire controller (dictionary) is cached on disk for 5 seconds. This will not work if the dictionary contains unpickleable objects.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_controller_on_disk">cache_controller_on_disk</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_controller_on_disk">cache_controller_on_disk</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -553,7 +552,7 @@ def cache_controller_and_view():
|
|||||||
return response.render(d)
|
return response.render(d)
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p><tt>response.render(d)</tt> renders the dictionary inside the controller, so everything is cached now for 5 seconds. This is best and fastest way of caching!
|
<p><tt>response.render(d)</tt> renders the dictionary inside the controller, so everything is cached now for 5 seconds. This is best and fastest way of caching!
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/cache_examples/cache_controller_and_view">cache_controller_and_view</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/cache_examples/cache_controller_and_view">cache_controller_and_view</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: cache_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -583,7 +582,7 @@ def data():
|
|||||||
<b>In view: ajax_examples/index.html</b>
|
<b>In view: ajax_examples/index.html</b>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/ajax_examples/index.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/ajax_examples/index.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>The javascript function "ajax" is provided in "web2py_ajax.html" and included by "layout.html". It takes three arguments, a url, a list of ids and a target id. When called, it sends to the url (via a get) the values of the ids and display the response in the value (of innerHTML) of the target id.
|
<p>The javascript function "ajax" is provided in "web2py_ajax.html" and included by "layout.html". It takes three arguments, a url, a list of ids and a target id. When called, it sends to the url (via a get) the values of the ids and display the response in the value (of innerHTML) of the target id.
|
||||||
<br/>Try it here: <a href="/{{=request.application}}/ajax_examples/index">index</a></p>
|
<br/>Try it here: <a class="btn" href="/{{=request.application}}/ajax_examples/index">index</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: ajax_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: ajax_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -591,7 +590,7 @@ def flash():
|
|||||||
response.flash='this text should appear!'
|
response.flash='this text should appear!'
|
||||||
return dict()
|
return dict()
|
||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>Try it here: <a href="/{{=request.application}}/ajax_examples/flash">flash</a></p>
|
<p>Try it here: <a class="btn" href="/{{=request.application}}/ajax_examples/flash">flash</a></p>
|
||||||
|
|
||||||
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: ajax_examples.py </b>
|
<h3>Example {{=c}}{{c+=1}}</h3><b>In controller: ajax_examples.py </b>
|
||||||
{{=CODE("""
|
{{=CODE("""
|
||||||
@@ -600,7 +599,7 @@ def fade():
|
|||||||
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
""".strip(),language='web2py',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<b>In view: ajax_examples/fade.html </b><br/>
|
<b>In view: ajax_examples/fade.html </b><br/>
|
||||||
{{=CODE(open(os.path.join(request.folder,'views/ajax_examples/fade.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
{{=CODE(open(os.path.join(request.folder,'views/ajax_examples/fade.html'),'r').read(),language='html',link=URL('global','vars'),_class='boxCode')}}
|
||||||
<p>Try it here: <a href="/{{=request.application}}/ajax_examples/fade">fade</a></p>
|
<p>Try it here: <a class="btn" href="/{{=request.application}}/ajax_examples/fade">fade</a></p>
|
||||||
|
|
||||||
<h3>Excel-like spreadsheet via Ajax</h3>
|
<h3>Excel-like spreadsheet via Ajax</h3>
|
||||||
Web2py includes a widget that acts like an Excel-like spreadsheet and can be used to build forms
|
Web2py includes a widget that acts like an Excel-like spreadsheet and can be used to build forms
|
||||||
|
|||||||
@@ -1,37 +1,24 @@
|
|||||||
{{extend 'layout.html'}}
|
{{extend 'layout.html'}}
|
||||||
{{
|
|
||||||
import random
|
|
||||||
quotes = [
|
|
||||||
("web2py was the life saver today for me, my blog post: Standalone Usage of web2py's", "caglartoklu", "http://twitter.com/#!/caglartoklu/status/84292131707031553"),
|
|
||||||
("Get Things Done - Faster, Better and More Easily with web2py",
|
|
||||||
"Bruno Rocha", "http://twitter.com/#!/rochacbruno/status/73583156044890112"),
|
|
||||||
("Please use www.web2py.com when using MVC , no PHP/SQL stuff please...its 2011 not 1999", "rabblesoft", "http://twitter.com/#!/rabblesoft/status/79189028431343616"),
|
|
||||||
('web2py rules! as a sysadmin I like the no installation and no configuration approach a lot)', "kjogut", "http://twitter.com/#!/jkogut/status/61414554273447936"),
|
|
||||||
("web2py it is. Compatible with everything under the sun and great interfaces to googleappengine", "comamitc","http://twitter.com/#!/comamitc/status/51744719071477760"),
|
|
||||||
("If you are still learning python, web2py is best tool by far", "pbreit", "http://twitter.com/#!/pbreit/status/48260905775017984")
|
|
||||||
]
|
|
||||||
random.shuffle(quotes)
|
|
||||||
}}
|
|
||||||
|
|
||||||
<div class="row-fluid">
|
<div class="container">
|
||||||
<div class="span12">
|
<div class="twothirds">
|
||||||
<div class="span8">
|
<div class="padded">
|
||||||
<h3>web2py<sup>TM</sup> Web Framework</h3>
|
<h3><img src="{{=URL('static/images', 'web2py_logo.png')}}"> Web Framework</h3>
|
||||||
<p>Free open source full-stack framework for rapid development of fast, scalable, <a href="http://www.web2py.com/book/default/chapter/01#Security" target="_blank">secure</a> and portable database-driven web-based applications. Written and programmable in <a href="http://www.python.org" target="_blank">Python</a>.</p>
|
<p>Free open source full-stack framework for rapid development of fast, scalable, <a href="http://www.web2py.com/book/default/chapter/01#Security" target="_blank">secure</a> and portable database-driven web-based applications. Written and programmable in <a href="http://www.python.org" target="_blank">Python</a>.</p>
|
||||||
<table width="100%">
|
<table width="100%">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="http://web2py.com/book">
|
<a class="noeffect" href="http://web2py.com/book">
|
||||||
<img src="{{=URL('static','images/book-5th.png')}}" />
|
<img src="{{=URL('static','images/book-5th.png')}}" />
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://vimeo.com/album/3016728">
|
<a class="noeffect" href="https://vimeo.com/album/3016728">
|
||||||
<img src="{{=URL('static','images/videos.png')}}" />
|
<img src="{{=URL('static','images/videos.png')}}" />
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="http://link.packtpub.com/SUlnrN">
|
<a class="noeffect" href="http://link.packtpub.com/SUlnrN">
|
||||||
<img src="{{=URL('static','images/book-recipes.png')}}" />
|
<img src="{{=URL('static','images/book-recipes.png')}}" />
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@@ -39,45 +26,44 @@ random.shuffle(quotes)
|
|||||||
</table>
|
</table>
|
||||||
<p>Current version: <a href="{{=URL('download')}}">{{=request.env.web2py_version}} (<a href="http://www.gnu.org/licenses/lgpl.html">LGPLv3 License</a>)</p>
|
<p>Current version: <a href="{{=URL('download')}}">{{=request.env.web2py_version}} (<a href="http://www.gnu.org/licenses/lgpl.html">LGPLv3 License</a>)</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="span4" style="text-align:center">
|
</div>
|
||||||
<a href="http://www.infoworld.com/slideshow/24605/infoworlds-2012-technology-of-the-year-award-winners-183313#slide23"><img src="{{=URL('static','images/infoworld2012.jpeg')}}" width="200px"/></a><br/>
|
<div class="third">
|
||||||
<a class="btn btn-danger" href="{{=URL('download')}}" style="margin-top:10px; width:180px; color:white">Download Now</a><br/>
|
<div class="padded center">
|
||||||
<a class="btn btn-danger" href="https://www.pythonanywhere.com/try-web2py" style="margin-top:10px; width:180px; color:white">Try it now online</a><br/>
|
<a class="noeffect" href="http://www.infoworld.com/slideshow/24605/infoworlds-2012-technology-of-the-year-award-winners-183313#slide23">
|
||||||
<a class="btn btn-danger" href="http://web2py.com/poweredby" style="margin-top:10px; width:180px; color:white">Sites Powered by web2py</a><br/><br/>
|
<img class="spaced-vertical" src="{{=URL('static','images/infoworld2012.jpeg')}}">
|
||||||
<a class="coinbase-button" data-code="df71ec5c2d5bc3b1c18139ab645f352b" data-button-style="donation_large" href="https://coinbase.com/checkouts/df71ec5c2d5bc3b1c18139ab645f352b">Donate Bitcoins</a><script src="https://coinbase.com/assets/button.js" type="text/javascript"></script>
|
</a>
|
||||||
|
<a class="btn rounded red fill" href="{{=URL('download')}}">
|
||||||
|
Download Now
|
||||||
|
</a>
|
||||||
|
<a class="btn rounded red fill" href="{{=URL('examples')}}">
|
||||||
|
Quick Examples
|
||||||
|
</a>
|
||||||
|
<a class="btn rounded red fill" href="https://www.pythonanywhere.com/try-web2py">
|
||||||
|
Try it now online
|
||||||
|
</a>
|
||||||
|
<a class="btn rounded red fill" href="http://web2py.com/poweredby">
|
||||||
|
Sites Powered by web2py
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row-fluid">
|
<div class="container">
|
||||||
<div class="span12">
|
<div class="third">
|
||||||
<div class="span4">
|
<div class="padded">
|
||||||
<h3><a href="{{=URL('what')}}">Batteries Included</a></h3>
|
<h5><a href="{{=URL('what')}}">Batteries Included</a></h5>
|
||||||
<p>Everything you need in one package including fast multi-threaded web server, SQL database and web-based interface. No third party dependencies but works with <a href={{=URL('what')}}>third party tools</a>.</p>
|
<p>Everything you need in one package including fast multi-threaded web server, SQL database and web-based interface. No third party dependencies but works with <a href={{=URL('what')}}>third party tools</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="span4">
|
</div>
|
||||||
<h3><a href="http://web2py.com/demo_admin">Web-Based IDE</a></h3>
|
<div class="third">
|
||||||
|
<div class="padded">
|
||||||
|
<h5><a href="http://web2py.com/demo_admin">Web-Based IDE</a></h5>
|
||||||
<p>Create, modify, deploy and manage application from anywhere using your browser. One web2py instance can run multiple web sites using different databases. Try the <a href="http://www.web2py.com/demo_admin">interactive demo</a>.</p>
|
<p>Create, modify, deploy and manage application from anywhere using your browser. One web2py instance can run multiple web sites using different databases. Try the <a href="http://www.web2py.com/demo_admin">interactive demo</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="span4">
|
</div>
|
||||||
<h3><a href="{{=URL('documentation')}}">Extensive Docs</a></h3>
|
<div class="third">
|
||||||
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://www.web2py.com/book" target="_blank">manual</a> and the <a href="http://web2py.readthedocs.org/en/latest/" target="_blank">Sphinx docs</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://www.web2py.com/layouts" target="_blank">layouts</a>, <a href="http://dev.s-cubism.com/web2py_plugins" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
|
<div class="padded">
|
||||||
|
<h5><a href="{{=URL('documentation')}}">Extensive Docs</a></h5>
|
||||||
|
<p>Start with some <a href="{{=URL('examples')}}">quick examples</a>, then read the <a href="http://www.web2py.com/book" target="_blank">manual</a> and the <a href="http://web2py.readthedocs.org/en/latest/" target="_blank">Sphinx docs</a>, watch <a href="http://vimeo.com/album/178500" target="_blank">videos</a>, and join a <a href="{{=URL('default', 'usergroups')}}">user group</a> for discussion. Take advantage of the <a href="http://www.web2py.com/layouts" target="_blank">layouts</a>, <a href="http://www.web2pyslices.com/home?content_type=Package" target="_blank">plugins</a>, <a href="http://www.web2py.com/appliances" target="_blank">appliances</a>, and <a href="http://web2pyslices.com" target="_blank">recipes</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row-fluid">
|
|
||||||
<div class="span12">
|
|
||||||
<img class="scale-with-grid centered" src="/examples/static/images/shadow-bottom.png">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row-fluid">
|
|
||||||
<div class="span12">
|
|
||||||
{{for k,quote in enumerate(quotes[:3]):}}
|
|
||||||
<div class="span4">
|
|
||||||
<p style="text-align: left"><em>{{=quote[0]}}</em></p>
|
|
||||||
<span class="right">
|
|
||||||
<a href="{{=quote[2]}}">{{=quote[1]}}</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{{pass}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -17,22 +17,26 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a target="_blank" href="http://experts4solutions.com">Experts4Soutions</a> (worldwide)</li>
|
<li><a target="_blank" href="http://experts4solutions.com">Experts4Soutions</a> (worldwide)</li>
|
||||||
<li><a target="_blank" href="http://www.planethost.com">PlanetHost</a> (USA)</li>
|
<li><a target="_blank" href="http://www.planethost.com">PlanetHost</a> (USA)</li>
|
||||||
<li><a target="_blank" href="http://www.formatics.nl">Formatics</a> (Netherlands)</li>
|
<li><a target="_blank" href="http://www.corebyte.nl">Corebyte</a> (Netherlands)</li>
|
||||||
|
<li><a target="_blank" href="http://www.dutveul.nl">Dutveul</a> (Netherlands)</li>
|
||||||
<li><a target="_blank" href="http://www.onemewebservices.com">OneMeWebServices</a> (Canada)</li>
|
<li><a target="_blank" href="http://www.onemewebservices.com">OneMeWebServices</a> (Canada)</li>
|
||||||
<li><a target="_blank" href="http://www.budgetbytes.nl">BudgetBytes</a> (The Netherlands)</li>
|
<li><a target="_blank" href="http://www.budgetbytes.nl">BudgetBytes</a> (The Netherlands)</li>
|
||||||
<li><a target="_blank" href="http://www.androsoft.pl">ANDROSoft</a> (Poland)</li>
|
<li><a target="_blank" href="http://www.androsoft.pl">ANDROSoft</a> (Poland)</li>
|
||||||
|
<li><a target="_blank" href="http://www.sonnetech.com.br">Sonne Tech</a> (Brazil)</li>
|
||||||
<li><a target="_blank" href="www.sonnetech.com.br">Sonne Tech</a> (Brazil)</li>
|
|
||||||
<li><a target="_blank" href="http://www.nrg.com.br">NRG Internet Solutions</a> (Brazil)</li>
|
<li><a target="_blank" href="http://www.nrg.com.br">NRG Internet Solutions</a> (Brazil)</li>
|
||||||
<li><a target="_blank" href="http://itjp.net.br/">ITJP</a> (Brazil)</li>
|
<li><a target="_blank" href="http://itjp.net.br/">ITJP</a> (Brazil)</li>
|
||||||
<li><a target="_blank" href="http://i-am.pt">I am Consultoria</a> (Portugal)</li>
|
<li><a target="_blank" href="http://i-am.pt">I am Consultoria</a> (Portugal)</li>
|
||||||
|
<li><a target="_blank" href="http://www.definescope.com/">DefineScope</a> (Portugal)</li>
|
||||||
<li><a target="_blank" href="http://lpfx.com.br">LPFX</a> (Brazil)</li>
|
<li><a target="_blank" href="http://lpfx.com.br">LPFX</a> (Brazil)</li>
|
||||||
<li><a target="_blank" href="http://emotionull.com">Emotionull</a> (Greece and Cyprus)</li>
|
<li><a target="_blank" href="http://emotionull.com">Emotionull</a> (Greece and Cyprus)</li>
|
||||||
<li><a target="_blank" href="http://www.vsa-services.com/">VSA Services</a> (Singapore)</li>
|
|
||||||
<li><a target="_blank" href="http://www.albendas.com">Albendas</a> (Spain)</li>
|
<li><a target="_blank" href="http://www.albendas.com">Albendas</a> (Spain)</li>
|
||||||
<li><a target="_blank" href="https://loadinfo-net.appspot.com">LoadInfo</a> (Bulgaria)</li>
|
|
||||||
<li><a target="_blank" href="http://www.appliedobjects.com">Applied Objects</a> (New Zealand)</li>
|
<li><a target="_blank" href="http://www.appliedobjects.com">Applied Objects</a> (New Zealand)</li>
|
||||||
<li><a target="_blank" href="http://www.sistemasagiles.com.ar/">Sistemas Ágiles</a> ("Agile Systems") (Argentina)</li>
|
<li><a target="_blank" href="http://www.sistemasagiles.com.ar/">Sistemas Ágiles</a> ("Agile Systems") (Argentina)</li>
|
||||||
|
<li><a target="_blank" href="http://www.tasko.it/">Tasko</a> (Italy)</li>
|
||||||
|
<li><a target="_blank" href="http://www.geekondemand.it/"> GeekOnDemand</a> (Italy)</li>
|
||||||
|
<li><a target="_blank" href="http://stifix.com"> Stifix</a> (Indonesia)</li>
|
||||||
|
<li><a target="_blank" href="http://www.garciac.es"> Garciac</a> (Spain)</li>
|
||||||
|
<li><a target="_blank" href="http://memoriapersistente.pt "> Memoria persistente</a> (Portugal)</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
{{block right_sidebar}}
|
{{block right_sidebar}}
|
||||||
<center>
|
<center>
|
||||||
|
<!--
|
||||||
<h3 class="feature-title">SITES POWERED BY WEB2PY</h3>
|
<h3 class="feature-title">SITES POWERED BY WEB2PY</h3>
|
||||||
<a href="http://web2py.com/poweredby"><img class="frame" id="img1" width="200px"/></a>
|
<a href="http://web2py.com/poweredby"><img class="frame" id="img1" width="200px"/></a>
|
||||||
<a href="http://web2py.com/poweredby"><img class="frame" id="img2" width="200px"/></a>
|
<a href="http://web2py.com/poweredby"><img class="frame" id="img2" width="200px"/></a>
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
<a href="http://web2py.com/poweredby"><img class="frame" id="img6" width="200px"/></a>
|
<a href="http://web2py.com/poweredby"><img class="frame" id="img6" width="200px"/></a>
|
||||||
<a href="http://web2py.com/poweredby"><img class="frame" id="img7" width="200px"/></a>
|
<a href="http://web2py.com/poweredby"><img class="frame" id="img7" width="200px"/></a>
|
||||||
<a href="http://web2py.com/poweredby"><img class="frame" id="img8" width="200px"/></a>
|
<a href="http://web2py.com/poweredby"><img class="frame" id="img8" width="200px"/></a>
|
||||||
</div>
|
-->
|
||||||
</center>
|
</center>
|
||||||
<script>
|
<script>
|
||||||
function showimages() {
|
function showimages() {
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
</li><li>Keith Yang (openid)
|
</li><li>Keith Yang (openid)
|
||||||
</li><li><a href="http://dev.s-cubism.com/web2py_plugins">Kenji Hosoda</a> (plugins)
|
</li><li><a href="http://dev.s-cubism.com/web2py_plugins">Kenji Hosoda</a> (plugins)
|
||||||
</li><li>Kyle Smith (javascript)
|
</li><li>Kyle Smith (javascript)
|
||||||
|
</li><li><a href="https://github.com/leonelcamara">Leonel Câmara</a>
|
||||||
</li><li><a href="http://blog.donews.com/limodou/">Limodou</a> (winservice)
|
</li><li><a href="http://blog.donews.com/limodou/">Limodou</a> (winservice)
|
||||||
</li><li><a href="https://github.com/lucasdavila">Lucas D'Ávila</a>
|
</li><li><a href="https://github.com/lucasdavila">Lucas D'Ávila</a>
|
||||||
</li><li>Marc Abramowitz (tests and travis continuous integration)
|
</li><li>Marc Abramowitz (tests and travis continuous integration)
|
||||||
@@ -99,6 +100,7 @@
|
|||||||
</li><li>Michael Willis (shell)
|
</li><li>Michael Willis (shell)
|
||||||
</li><li>Michele Comitini (facebook)
|
</li><li>Michele Comitini (facebook)
|
||||||
</li><li>Michael Toomim (scheduler)
|
</li><li>Michael Toomim (scheduler)
|
||||||
|
</li><li>Narendra Bhati (security)
|
||||||
</li><li>Nathan Freeze (admin design, IS_STRONG, DAL features, <a href="http://web2pyslices.com">web2pyslices.com</a>)
|
</li><li>Nathan Freeze (admin design, IS_STRONG, DAL features, <a href="http://web2pyslices.com">web2pyslices.com</a>)
|
||||||
</li><li>Niall Sweeny (MSSQL support)
|
</li><li>Niall Sweeny (MSSQL support)
|
||||||
</li><li>Niccolo Polo (epydoc)
|
</li><li>Niccolo Polo (epydoc)
|
||||||
|
|||||||
@@ -1,173 +1,67 @@
|
|||||||
<!--[if HTML5]><![endif]-->
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
|
<html>
|
||||||
<!--[if lt IE 7]><html class="ie ie6 ie-lte9 ie-lte8 ie-lte7 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
<head>
|
||||||
<!--[if IE 7]><html class="ie ie7 ie-lte9 ie-lte8 ie-lte7 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
<meta charset="utf-8">
|
||||||
<!--[if IE 8]><html class="ie ie8 ie-lte9 ie-lte8 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<!--[if IE 9]><html class="ie9 ie-lte9 no-js" lang="{{=T.accepted_language or 'en'}}"> <![endif]-->
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<!--[if (gt IE 9)|!(IE)]><!--> <html class="no-js" lang="{{=T.accepted_language or 'en'}}"> <!--<![endif]-->
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<head>
|
<link href="{{=URL('static','css/calendar.css')}}" rel="stylesheet" type="text/css"/>
|
||||||
<title>{{=response.title or request.application}}</title>
|
<link href="{{=URL('static','css/web2py.css')}}" rel="stylesheet" type="text/css"/>
|
||||||
<!--[if !HTML5]>
|
<link href="{{=URL('static','css/stupid.css')}}" rel="stylesheet" type="text/css"/>
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge{{=not request.is_local and ',chrome=1' or ''}}">
|
<link href="{{=URL('static','css/examples.css')}}" rel="stylesheet" type="text/css"/>
|
||||||
<![endif]-->
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
|
||||||
<!-- www.phpied.com/conditional-comments-block-downloads/ -->
|
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
|
||||||
<!-- Always force latest IE rendering engine
|
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
|
||||||
(even in intranet) & Chrome Frame
|
{{
|
||||||
Remove this if you use the .htaccess -->
|
left_sidebar_enabled = globals().get('left_sidebar_enabled', False)
|
||||||
|
right_sidebar_enabled = globals().get('right_sidebar_enabled', False)
|
||||||
<meta charset="utf-8" />
|
middle_column = {0: 'fill', 1: 'threequarters', 2: 'half'}[
|
||||||
|
|
||||||
<!-- http://dev.w3.org/html5/markup/meta.name.html -->
|
|
||||||
<meta name="application-name" content="{{=request.application}}" />
|
|
||||||
|
|
||||||
<!-- Speaking of Google, don't forget to set your site up:
|
|
||||||
http://google.com/webmasters -->
|
|
||||||
<meta name="google-site-verification" content="" />
|
|
||||||
|
|
||||||
<!-- Mobile Viewport Fix
|
|
||||||
j.mp/mobileviewport & davidbcalhoun.com/2010/viewport-metatag
|
|
||||||
device-width: Occupy full width of the screen in its current orientation
|
|
||||||
initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
|
|
||||||
user-scalable = yes allows the user to zoom in -->
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
|
|
||||||
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
|
|
||||||
|
|
||||||
<!-- All JavaScript at the bottom, except for Modernizr which enables
|
|
||||||
HTML5 elements & feature detects -->
|
|
||||||
<script src="{{=URL('static','js/modernizr.custom.js')}}"></script>
|
|
||||||
|
|
||||||
<!-- include stylesheets -->
|
|
||||||
{{
|
|
||||||
response.files.append(URL('static','css/web2py.css'))
|
|
||||||
response.files.append(URL('static','css/bootstrap.min.css'))
|
|
||||||
response.files.append(URL('static','css/bootstrap-responsive.min.css'))
|
|
||||||
response.files.append(URL('static','css/web2py_bootstrap.css'))
|
|
||||||
response.files.append(URL('static','css/examples.css'))
|
|
||||||
}}
|
|
||||||
|
|
||||||
{{include 'web2py_ajax.html'}}
|
|
||||||
|
|
||||||
{{
|
|
||||||
# using sidebars need to know what sidebar you want to use
|
|
||||||
left_sidebar_enabled = globals().get('left_sidebar_enabled',False)
|
|
||||||
right_sidebar_enabled = globals().get('right_sidebar_enabled',False)
|
|
||||||
middle_columns = {0:'span12',1:'span9',2:'span6'}[
|
|
||||||
(left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)]
|
(left_sidebar_enabled and 1 or 0)+(right_sidebar_enabled and 1 or 0)]
|
||||||
}}
|
}}
|
||||||
|
{{include "web2py_ajax.html"}}
|
||||||
<!-- uncomment here to load jquery-ui
|
</head>
|
||||||
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/base/jquery-ui.css" type="text/css" media="all" />
|
<body class="black">
|
||||||
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js" type="text/javascript"></script>
|
<header class="black padded">
|
||||||
uncomment to load jquery-ui //-->
|
<div class="container middle max900">
|
||||||
<noscript><link href="{{=URL('static', 'css/web2py_bootstrap_nojs.css')}}" rel="stylesheet" type="text/css" /></noscript>
|
<div class="fill middle">
|
||||||
{{block head}}{{end}}
|
<label class="ham" for="menu"><i class="fa fa-bars padded"></i></label>
|
||||||
</head>
|
<div class="burger accordion">
|
||||||
|
<input type="checkbox" id="menu"/>
|
||||||
<body>
|
{{=MENU(response.menu,_class='menu')}}
|
||||||
<!-- Navbar ================================================== -->
|
</div>
|
||||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
|
||||||
<div class="flash">{{=response.flash or ''}}</div>
|
|
||||||
<div class="navbar-inner">
|
|
||||||
<div class="container">
|
|
||||||
<!-- the next tag is necessary for bootstrap menus, do not remove -->
|
|
||||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</button>
|
|
||||||
{{=response.logo or ''}}
|
|
||||||
<ul id="navbar" class="nav pull-right">{{='auth' in globals() and auth.navbar(mode="dropdown") or ''}}</ul>
|
|
||||||
<div class="nav-collapse">
|
|
||||||
{{is_mobile=request.user_agent().is_mobile}}
|
|
||||||
{{if response.menu:}}
|
|
||||||
{{=MENU(response.menu, _class='mobile-menu nav' if is_mobile else 'nav',mobile=is_mobile,li_class='dropdown',ul_class='dropdown-menu')}}
|
|
||||||
{{pass}}
|
|
||||||
</div><!--/.nav-collapse -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div><!--/top navbar -->
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<!-- Masthead ================================================== -->
|
|
||||||
<header class="mastheader" id="header">
|
|
||||||
<div class="span4">
|
|
||||||
<div class="page-header">
|
|
||||||
<img src="{{=URL('static','images/web2py_logo.png')}}" class="logo" alt="web2py logo" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</div>
|
{{if response.flash:}}
|
||||||
<div class="container">
|
<div class="w2p_flash">
|
||||||
|
{{=response.flash}}
|
||||||
<section id="main" class="main row">
|
|
||||||
{{if left_sidebar_enabled:}}
|
|
||||||
<div class="span3 left-sidebar">
|
|
||||||
{{block left_sidebar}}
|
|
||||||
<h3>Left Sidebar</h3>
|
|
||||||
<p></p>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
{{pass}}
|
|
||||||
|
|
||||||
<div class="{{=middle_columns}}">
|
|
||||||
{{block center}}
|
|
||||||
{{include}}
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{if right_sidebar_enabled:}}
|
|
||||||
<div class="span3">
|
|
||||||
{{block right_sidebar}}
|
|
||||||
<h3>Right Sidebar</h3>
|
|
||||||
<p></p>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
{{pass}}
|
|
||||||
</section><!--/main-->
|
|
||||||
|
|
||||||
<!-- Footer ================================================== -->
|
|
||||||
<div class="row">
|
|
||||||
<footer class="footer span12" id="footer">
|
|
||||||
<div class="footer-content">
|
|
||||||
{{block footer}} <!-- this is default footer -->
|
|
||||||
<div id="poweredBy" class="pull-right">
|
|
||||||
{{=T('Copyright')}} © {{=request.now.year}} -
|
|
||||||
{{=T('Powered by')}}
|
|
||||||
<a href="http://www.web2py.com/">web2py</a> -
|
|
||||||
{{=T('Hosted by')}}
|
|
||||||
<a href="http://pythonanywhere.com">PythonAnywhere</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
|
{{pass}}
|
||||||
</div> <!-- /container -->
|
<main class="white">
|
||||||
|
<div class="container max900">
|
||||||
<!-- The javascript =============================================
|
{{if left_sidebar_enabled:}}
|
||||||
(Placed at the end of the document so the pages load faster) -->
|
<div class="quarter padded">{{block left_sidebar}}{{end}}</div>
|
||||||
<script src="{{=URL('static','js/bootstrap.min.js')}}"></script>
|
{{pass}}
|
||||||
<script src="{{=URL('static','js/web2py_bootstrap.js')}}"></script>
|
<div class="{{=middle_column}} padded">{{include}}</div>
|
||||||
<!--[if lt IE 7 ]>
|
{{if right_sidebar_enabled:}}
|
||||||
<script src="{{=URL('static','js/dd_belatedpng.js')}}"></script>
|
<div class="quarter padded">{{block right_sidebar}}{{end}}</div>
|
||||||
<script> DD_belatedPNG.fix('img, .png_bg'); //fix any <img> or .png_bg background-images </script>
|
{{pass}}
|
||||||
<![endif]-->
|
</div>
|
||||||
|
<div class="silver center padded">
|
||||||
{{if response.google_analytics_id:}}
|
<a class="fa fa-twitter" href="https://twitter.com/web2py/"></a>
|
||||||
<script src="{{=URL('static','js/analytics.min.js')}}"></script>
|
<a class="fa fa-facebook" href="https://www.facebook.com/web2py/"></a>
|
||||||
<script type="text/javascript">
|
</div>
|
||||||
analytics.initialize({
|
</main>
|
||||||
'Google Analytics':{trackingId:'{{=response.google_analytics_id}}'}
|
<footer class="black">
|
||||||
});</script>
|
<div class="container padded max900">
|
||||||
{{pass}}
|
<div class="fill">
|
||||||
<script src="{{=URL('static','js/share.js',vars=dict(static=URL('static','images')))}}"></script>
|
Copyright @ 2016 - Powered by Web2py
|
||||||
<a style="position:fixed;bottom:0;left:0;z-index:1000" href="https://groups.google.com/forum/?fromgroups#!forum/web2py" target="_blank">
|
</div>
|
||||||
<img src="{{=URL('static','images/questions.png')}}" />
|
</div>
|
||||||
</a>
|
</footer>
|
||||||
|
</body>
|
||||||
</body>
|
<script>
|
||||||
|
// prevent android horizontal scrolling
|
||||||
|
window.addEventListener("scroll", function(){window.scroll(0, window.pageYOffset);}, false);
|
||||||
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
{{extend 'layout.html'}}
|
|
||||||
|
|
||||||
{{=toolbar}}
|
|
||||||
@@ -49,7 +49,8 @@ if request.function == 'manage':
|
|||||||
auth.table_group(),
|
auth.table_group(),
|
||||||
auth.table_permission()])
|
auth.table_permission()])
|
||||||
manager_role = manager_action.get('role', None) if manager_action else None
|
manager_role = manager_action.get('role', None) if manager_action else None
|
||||||
auth.requires_membership(manager_role)(lambda: None)()
|
if not (gluon.fileutils.check_credentials(request) or auth.has_membership(manager_role)):
|
||||||
|
raise HTTP(403, "Not authorized")
|
||||||
menu = False
|
menu = False
|
||||||
elif (request.application == 'admin' and not session.authorized) or \
|
elif (request.application == 'admin' and not session.authorized) or \
|
||||||
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
(request.application != 'admin' and not gluon.fileutils.check_credentials(request)):
|
||||||
@@ -80,7 +81,6 @@ if False and request.tickets_db:
|
|||||||
def get_databases(request):
|
def get_databases(request):
|
||||||
dbs = {}
|
dbs = {}
|
||||||
for (key, value) in global_env.items():
|
for (key, value) in global_env.items():
|
||||||
cond = False
|
|
||||||
try:
|
try:
|
||||||
cond = isinstance(value, GQLDB)
|
cond = isinstance(value, GQLDB)
|
||||||
except:
|
except:
|
||||||
@@ -420,7 +420,7 @@ def ccache():
|
|||||||
'oldest': time.time(),
|
'oldest': time.time(),
|
||||||
'keys': []
|
'keys': []
|
||||||
}
|
}
|
||||||
|
|
||||||
disk = copy.copy(ram)
|
disk = copy.copy(ram)
|
||||||
total = copy.copy(ram)
|
total = copy.copy(ram)
|
||||||
disk['keys'] = []
|
disk['keys'] = []
|
||||||
@@ -445,30 +445,31 @@ def ccache():
|
|||||||
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
gae_stats['oldest'] = GetInHMS(time.time() - gae_stats['oldest_item_age'])
|
||||||
total.update(gae_stats)
|
total.update(gae_stats)
|
||||||
else:
|
else:
|
||||||
|
# get ram stats directly from the cache object
|
||||||
|
ram_stats = cache.ram.stats[request.application]
|
||||||
|
ram['hits'] = ram_stats['hit_total'] - ram_stats['misses']
|
||||||
|
ram['misses'] = ram_stats['misses']
|
||||||
|
try:
|
||||||
|
ram['ratio'] = ram['hits'] * 100 / ram_stats['hit_total']
|
||||||
|
except (KeyError, ZeroDivisionError):
|
||||||
|
ram['ratio'] = 0
|
||||||
|
|
||||||
for key, value in cache.ram.storage.iteritems():
|
for key, value in cache.ram.storage.iteritems():
|
||||||
if isinstance(value, dict):
|
if hp:
|
||||||
ram['hits'] = value['hit_total'] - value['misses']
|
ram['bytes'] += hp.iso(value[1]).size
|
||||||
ram['misses'] = value['misses']
|
ram['objects'] += hp.iso(value[1]).count
|
||||||
try:
|
ram['entries'] += 1
|
||||||
ram['ratio'] = ram['hits'] * 100 / value['hit_total']
|
if value[0] < ram['oldest']:
|
||||||
except (KeyError, ZeroDivisionError):
|
ram['oldest'] = value[0]
|
||||||
ram['ratio'] = 0
|
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
else:
|
|
||||||
if hp:
|
|
||||||
ram['bytes'] += hp.iso(value[1]).size
|
|
||||||
ram['objects'] += hp.iso(value[1]).count
|
|
||||||
ram['entries'] += 1
|
|
||||||
if value[0] < ram['oldest']:
|
|
||||||
ram['oldest'] = value[0]
|
|
||||||
ram['keys'].append((key, GetInHMS(time.time() - value[0])))
|
|
||||||
|
|
||||||
for key in cache.disk.storage:
|
for key in cache.disk.storage:
|
||||||
value = cache.disk.storage[key]
|
value = cache.disk.storage[key]
|
||||||
if isinstance(value, dict):
|
if isinstance(value[1], dict):
|
||||||
disk['hits'] = value['hit_total'] - value['misses']
|
disk['hits'] = value[1]['hit_total'] - value[1]['misses']
|
||||||
disk['misses'] = value['misses']
|
disk['misses'] = value[1]['misses']
|
||||||
try:
|
try:
|
||||||
disk['ratio'] = disk['hits'] * 100 / value['hit_total']
|
disk['ratio'] = disk['hits'] * 100 / value[1]['hit_total']
|
||||||
except (KeyError, ZeroDivisionError):
|
except (KeyError, ZeroDivisionError):
|
||||||
disk['ratio'] = 0
|
disk['ratio'] = 0
|
||||||
else:
|
else:
|
||||||
@@ -480,12 +481,12 @@ def ccache():
|
|||||||
disk['oldest'] = value[0]
|
disk['oldest'] = value[0]
|
||||||
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
disk['keys'].append((key, GetInHMS(time.time() - value[0])))
|
||||||
|
|
||||||
total['entries'] = ram['entries'] + disk['entries']
|
ram_keys = ram.keys() # ['hits', 'objects', 'ratio', 'entries', 'keys', 'oldest', 'bytes', 'misses']
|
||||||
total['bytes'] = ram['bytes'] + disk['bytes']
|
ram_keys.remove('ratio')
|
||||||
total['objects'] = ram['objects'] + disk['objects']
|
ram_keys.remove('oldest')
|
||||||
total['hits'] = ram['hits'] + disk['hits']
|
for key in ram_keys:
|
||||||
total['misses'] = ram['misses'] + disk['misses']
|
total[key] = ram[key] + disk[key]
|
||||||
total['keys'] = ram['keys'] + disk['keys']
|
|
||||||
try:
|
try:
|
||||||
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
total['ratio'] = total['hits'] * 100 / (total['hits'] +
|
||||||
total['misses'])
|
total['misses'])
|
||||||
@@ -575,11 +576,9 @@ def bg_graph_model():
|
|||||||
meta_graphmodel = dict(group=request.application, color='#ECECEC')
|
meta_graphmodel = dict(group=request.application, color='#ECECEC')
|
||||||
|
|
||||||
group = meta_graphmodel['group'].replace(' ', '')
|
group = meta_graphmodel['group'].replace(' ', '')
|
||||||
if not subgraphs.has_key(group):
|
if group not in subgraphs:
|
||||||
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
|
subgraphs[group] = dict(meta=meta_graphmodel, tables=[])
|
||||||
subgraphs[group]['tables'].append(tablename)
|
subgraphs[group]['tables'].append(tablename)
|
||||||
else:
|
|
||||||
subgraphs[group]['tables'].append(tablename)
|
|
||||||
|
|
||||||
graph.add_node(tablename, name=tablename, shape='plaintext',
|
graph.add_node(tablename, name=tablename, shape='plaintext',
|
||||||
label=table_template(tablename))
|
label=table_template(tablename))
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# this file is released under public domain and you can use without limitations
|
# this file is released under public domain and you can use without limitations
|
||||||
|
|
||||||
#########################################################################
|
# -------------------------------------------------------------------------
|
||||||
## This is a sample controller
|
# This is a sample controller
|
||||||
## - index is the default action of any application
|
# - index is the default action of any application
|
||||||
## - user is required for authentication and authorization
|
# - user is required for authentication and authorization
|
||||||
## - download is for downloading files uploaded in the db (does streaming)
|
# - download is for downloading files uploaded in the db (does streaming)
|
||||||
#########################################################################
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
def index():
|
def index():
|
||||||
"""
|
"""
|
||||||
@@ -29,11 +30,12 @@ def user():
|
|||||||
http://..../[app]/default/user/profile
|
http://..../[app]/default/user/profile
|
||||||
http://..../[app]/default/user/retrieve_password
|
http://..../[app]/default/user/retrieve_password
|
||||||
http://..../[app]/default/user/change_password
|
http://..../[app]/default/user/change_password
|
||||||
http://..../[app]/default/user/manage_users (requires membership in
|
http://..../[app]/default/user/bulk_register
|
||||||
use @auth.requires_login()
|
use @auth.requires_login()
|
||||||
@auth.requires_membership('group name')
|
@auth.requires_membership('group name')
|
||||||
@auth.requires_permission('read','table name',record_id)
|
@auth.requires_permission('read','table name',record_id)
|
||||||
to decorate functions that need access control
|
to decorate functions that need access control
|
||||||
|
also notice there is http://..../[app]/appadmin/manage/auth to allow administrator to manage users
|
||||||
"""
|
"""
|
||||||
return dict(form=auth())
|
return dict(form=auth())
|
||||||
|
|
||||||
|
|||||||
@@ -1,480 +1,491 @@
|
|||||||
# coding: utf8
|
# -*- coding: utf-8 -*-
|
||||||
{
|
{
|
||||||
'!langcode!': 'cs-cz',
|
'!langcode!': 'cs-cz',
|
||||||
'!langname!': 'čeština',
|
'!langname!': 'čeština',
|
||||||
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
|
'"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN': 'Kolonka "Upravit" je nepovinný výraz, například "pole1=\'nováhodnota\'". Výsledky databázového JOINu nemůžete mazat ani upravovat.',
|
||||||
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
|
'"User Exception" debug mode. An error ticket could be issued!': '"User Exception" debug mode. An error ticket could be issued!',
|
||||||
'%%{Row} in Table': '%%{řádek} v tabulce',
|
'%%{Row} in Table': '%%{řádek} v tabulce',
|
||||||
'%%{Row} selected': 'označených %%{řádek}',
|
'%%{Row} selected': 'označených %%{řádek}',
|
||||||
'%s %%{row} deleted': '%s smazaných %%{záznam}',
|
'%s %%{row} deleted': '%s smazaných %%{záznam}',
|
||||||
'%s %%{row} updated': '%s upravených %%{záznam}',
|
'%s %%{row} updated': '%s upravených %%{záznam}',
|
||||||
'%s selected': '%s označených',
|
'%s selected': '%s označených',
|
||||||
'%Y-%m-%d': '%d.%m.%Y',
|
'%Y-%m-%d': '%d.%m.%Y',
|
||||||
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
|
'%Y-%m-%d %H:%M:%S': '%d.%m.%Y %H:%M:%S',
|
||||||
'(requires internet access)': '(vyžaduje připojení k internetu)',
|
'(requires internet access)': '(vyžaduje připojení k internetu)',
|
||||||
'(requires internet access, experimental)': '(requires internet access, experimental)',
|
'(requires internet access, experimental)': '(vyžaduje internetové připojení, experimentální)',
|
||||||
'(something like "it-it")': '(například "cs-cs")',
|
'(something like "it-it")': '(například "cs-cz")',
|
||||||
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
|
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '@markmin\x01(soubor **gluon/contrib/plural_rules/%s.py** nenalezen)',
|
||||||
'@markmin\x01Searching: **%s** %%{file}': 'Hledání: **%s** %%{soubor}',
|
'@markmin\x01An error occured, please [[reload %s]] the page': '@markmin\x01Došlo k chybě, prosím [[obnovte stránku %s]]',
|
||||||
'About': 'O programu',
|
'@markmin\x01Searching: **%s** %%{file}': '@markmin\x01Hledání: **%s** %%{soubor}',
|
||||||
'About application': 'O aplikaci',
|
'About': 'O programu',
|
||||||
'Access Control': 'Řízení přístupu',
|
'About application': 'O aplikaci',
|
||||||
'Add breakpoint': 'Přidat bod přerušení',
|
'Access Control': 'Řízení přístupu',
|
||||||
'Additional code for your application': 'Další kód pro Vaši aplikaci',
|
'Add breakpoint': 'Přidat bod přerušení',
|
||||||
'Admin design page': 'Admin design page',
|
'Additional code for your application': 'Další kód pro Vaši aplikaci',
|
||||||
'Admin language': 'jazyk rozhraní',
|
'admin': 'admin',
|
||||||
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
|
'Admin design page': 'Admin design page',
|
||||||
'Administrative Interface': 'Administrátorské rozhraní',
|
'Admin language': 'jazyk rozhraní',
|
||||||
'administrative interface': 'rozhraní pro správu',
|
'Administrative interface': 'pro administrátorské rozhraní klikněte sem',
|
||||||
'Administrator Password:': 'Administrátorské heslo:',
|
'Administrative Interface': 'Administrátorské rozhraní',
|
||||||
'Ajax Recipes': 'Recepty s ajaxem',
|
'administrative interface': 'rozhraní pro správu',
|
||||||
'An error occured, please %s the page': 'An error occured, please %s the page',
|
'Administrator Password:': 'Administrátorské heslo:',
|
||||||
'and rename it:': 'a přejmenovat na:',
|
'Ajax Recipes': 'Recepty s ajaxem',
|
||||||
'appadmin': 'appadmin',
|
'An error occured, please %s the page': 'Došlo k chybě, prosím %s stránku',
|
||||||
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
|
'and rename it:': 'a přejmenovat na:',
|
||||||
'Application': 'Application',
|
'appadmin': 'appadmin',
|
||||||
'application "%s" uninstalled': 'application "%s" odinstalována',
|
'appadmin is disabled because insecure channel': 'appadmin je zakázaná bez zabezpečeného spojení',
|
||||||
'application compiled': 'aplikace zkompilována',
|
'Application': 'Aplikace',
|
||||||
'Application name:': 'Název aplikace:',
|
'application "%s" uninstalled': 'application "%s" odinstalována',
|
||||||
'are not used': 'nepoužita',
|
'application compiled': 'aplikace zkompilována',
|
||||||
'are not used yet': 'ještě nepoužita',
|
'Application name:': 'Název aplikace:',
|
||||||
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
|
'are not used': 'nepoužita',
|
||||||
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
|
'are not used yet': 'ještě nepoužita',
|
||||||
'arguments': 'arguments',
|
'Are you sure you want to delete this object?': 'Opravdu chcete odstranit tento objekt?',
|
||||||
'at char %s': 'at char %s',
|
'Are you sure you want to uninstall application "%s"?': 'Opravdu chcete odinstalovat aplikaci "%s"?',
|
||||||
'at line %s': 'at line %s',
|
'arguments': 'argumenty',
|
||||||
'ATTENTION:': 'ATTENTION:',
|
'at char %s': 'na pozici znaku %s',
|
||||||
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
|
'at line %s': 'na řádku %s',
|
||||||
'Available Databases and Tables': 'Dostupné databáze a tabulky',
|
'ATTENTION:': 'POZOR:',
|
||||||
'back': 'zpět',
|
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.',
|
||||||
'Back to wizard': 'Back to wizard',
|
'Available Databases and Tables': 'Dostupné databáze a tabulky',
|
||||||
'Basics': 'Basics',
|
'back': 'zpět',
|
||||||
'Begin': 'Začít',
|
'Back to wizard': 'Zpátky do průvodce',
|
||||||
'breakpoint': 'bod přerušení',
|
'Basics': 'Základy',
|
||||||
'Breakpoints': 'Body přerušení',
|
'Begin': 'Začít',
|
||||||
'breakpoints': 'body přerušení',
|
'breakpoint': 'bod přerušení',
|
||||||
'Buy this book': 'Koupit web2py knihu',
|
'Breakpoints': 'Body přerušení',
|
||||||
'Cache': 'Cache',
|
'breakpoints': 'body přerušení',
|
||||||
'cache': 'cache',
|
'Buy this book': 'Koupit Web2py knihu',
|
||||||
'Cache Keys': 'Klíče cache',
|
"Buy web2py's book": 'Koupit Web2py knihu',
|
||||||
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
|
'Cache': 'Cache',
|
||||||
'can be a git repo': 'může to být git repo',
|
'cache': 'cache',
|
||||||
'Cancel': 'Storno',
|
'Cache Keys': 'Klíče cache',
|
||||||
'Cannot be empty': 'Nemůže být prázdné',
|
'cache, errors and sessions cleaned': 'cache, chyby a relace byly pročištěny',
|
||||||
'Change Admin Password': 'Změnit heslo pro správu',
|
'can be a git repo': 'může to být git repo',
|
||||||
'Change admin password': 'Změnit heslo pro správu aplikací',
|
'Cancel': 'Storno',
|
||||||
'Change password': 'Změna hesla',
|
'Cannot be empty': 'Nemůže být prázdné',
|
||||||
'check all': 'vše označit',
|
'Change Admin Password': 'Změnit heslo pro správu',
|
||||||
'Check for upgrades': 'Zkusit aktualizovat',
|
'Change admin password': 'Změnit heslo pro správu aplikací',
|
||||||
'Check to delete': 'Označit ke smazání',
|
'Change password': 'Změna hesla',
|
||||||
'Check to delete:': 'Označit ke smazání:',
|
'check all': 'vše označit',
|
||||||
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
|
'Check for upgrades': 'Zkusit aktualizovat',
|
||||||
'Clean': 'Pročistit',
|
'Check to delete': 'Označit ke smazání',
|
||||||
'Clear CACHE?': 'Vymazat CACHE?',
|
'Check to delete:': 'Označit ke smazání:',
|
||||||
'Clear DISK': 'Vymazat DISK',
|
'Checking for upgrades...': 'Zjišťuji, zda jsou k dispozici aktualizace...',
|
||||||
'Clear RAM': 'Vymazat RAM',
|
'Clean': 'Pročistit',
|
||||||
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
|
'Clear CACHE?': 'Vymazat CACHE?',
|
||||||
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
|
'Clear DISK': 'Vymazat DISK',
|
||||||
'Client IP': 'IP adresa klienta',
|
'Clear RAM': 'Vymazat RAM',
|
||||||
'code': 'code',
|
'Click row to expand traceback': 'Pro rozbalení stopy, klikněte na řádek',
|
||||||
'Code listing': 'Code listing',
|
'Click row to view a ticket': 'Pro zobrazení chyby (ticketu), klikněte na řádku...',
|
||||||
'collapse/expand all': 'vše sbalit/rozbalit',
|
'Client IP': 'IP adresa klienta',
|
||||||
'Community': 'Komunita',
|
'code': 'kód',
|
||||||
'Compile': 'Zkompilovat',
|
'Code listing': 'Výpis kódu',
|
||||||
'compiled application removed': 'zkompilovaná aplikace smazána',
|
'collapse/expand all': 'vše sbalit/rozbalit',
|
||||||
'Components and Plugins': 'Komponenty a zásuvné moduly',
|
'Community': 'Komunita',
|
||||||
'Condition': 'Podmínka',
|
'Compile': 'Zkompilovat',
|
||||||
'continue': 'continue',
|
'compiled application removed': 'zkompilovaná aplikace smazána',
|
||||||
'Controller': 'Kontrolér (Controller)',
|
'Components and Plugins': 'Komponenty a zásuvné moduly',
|
||||||
'Controllers': 'Kontroléry',
|
'Condition': 'Podmínka',
|
||||||
'controllers': 'kontroléry',
|
'Config.ini': 'Config.ini',
|
||||||
'Copyright': 'Copyright',
|
'continue': 'pokračovat',
|
||||||
'Count': 'Počet',
|
'Controller': 'Kontrolér (Controller)',
|
||||||
'Create': 'Vytvořit',
|
'Controllers': 'Kontroléry',
|
||||||
'create file with filename:': 'vytvořit soubor s názvem:',
|
'controllers': 'kontroléry',
|
||||||
'created by': 'vytvořil',
|
'Copyright': 'Copyright',
|
||||||
'Created By': 'Vytvořeno - kým',
|
'Count': 'Počet',
|
||||||
'Created On': 'Vytvořeno - kdy',
|
'Create': 'Vytvořit',
|
||||||
'crontab': 'crontab',
|
'create file with filename:': 'vytvořit soubor s názvem:',
|
||||||
'Current request': 'Aktuální požadavek',
|
'created by': 'vytvořil',
|
||||||
'Current response': 'Aktuální odpověď',
|
'Created By': 'Vytvořeno - kým',
|
||||||
'Current session': 'Aktuální relace',
|
'Created On': 'Vytvořeno - kdy',
|
||||||
'currently running': 'právě běží',
|
'crontab': 'crontab',
|
||||||
'currently saved or': 'uloženo nebo',
|
'Current request': 'Aktuální požadavek',
|
||||||
'customize me!': 'upravte mě!',
|
'Current response': 'Aktuální odpověď',
|
||||||
'data uploaded': 'data nahrána',
|
'Current session': 'Aktuální relace',
|
||||||
'Database': 'Rozhraní databáze',
|
'currently running': 'právě běží',
|
||||||
'Database %s select': 'databáze %s výběr',
|
'currently saved or': 'uloženo nebo',
|
||||||
'Database administration': 'Database administration',
|
'customize me!': 'upravte mě!',
|
||||||
'database administration': 'správa databáze',
|
'data uploaded': 'data nahrána',
|
||||||
'Date and Time': 'Datum a čas',
|
'Database': 'Rozhraní databáze',
|
||||||
'day': 'den',
|
'Database %s select': 'databáze %s výběr',
|
||||||
'db': 'db',
|
'Database administration': 'Administrace databáze',
|
||||||
'DB Model': 'Databázový model',
|
'database administration': 'správa databáze',
|
||||||
'Debug': 'Ladění',
|
'Date and Time': 'Datum a čas',
|
||||||
'defines tables': 'defines tables',
|
'day': 'den',
|
||||||
'Delete': 'Smazat',
|
'db': 'db',
|
||||||
'delete': 'smazat',
|
'DB Model': 'Databázový model',
|
||||||
'delete all checked': 'smazat vše označené',
|
'Debug': 'Ladění',
|
||||||
'delete plugin': 'delete plugin',
|
'defines tables': 'definuje tabulky',
|
||||||
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
|
'Delete': 'Smazat',
|
||||||
'Delete:': 'Smazat:',
|
'delete': 'smazat',
|
||||||
'deleted after first hit': 'smazat po prvním dosažení',
|
'delete all checked': 'smazat vše označené',
|
||||||
'Demo': 'Demo',
|
'delete plugin': 'zrušit plugin',
|
||||||
'Deploy': 'Nahrát',
|
'Delete this file (you will be asked to confirm deletion)': 'Smazat tento soubor (budete požádán o potvrzení mazání)',
|
||||||
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
|
'Delete:': 'Smazat:',
|
||||||
'Deploy to OpenShift': 'Nahrát na OpenShift',
|
'deleted after first hit': 'smazat po prvním dosažení',
|
||||||
'Deployment Recipes': 'Postupy pro deployment',
|
'Demo': 'Demo',
|
||||||
'Description': 'Popis',
|
'Deploy': 'Nahrát',
|
||||||
'design': 'návrh',
|
'Deploy on Google App Engine': 'Nahrát na Google App Engine',
|
||||||
'Detailed traceback description': 'Podrobný výpis prostředí',
|
'Deploy to OpenShift': 'Nahrát na OpenShift',
|
||||||
'details': 'podrobnosti',
|
'Deployment Recipes': 'Postupy pro deployment',
|
||||||
'direction: ltr': 'směr: ltr',
|
'Description': 'Popis',
|
||||||
'Disable': 'Zablokovat',
|
'design': 'návrh',
|
||||||
'DISK': 'DISK',
|
'Design': 'Design',
|
||||||
'Disk Cache Keys': 'Klíče diskové cache',
|
'Detailed traceback description': 'Podrobný výpis prostředí',
|
||||||
'Disk Cleared': 'Disk smazán',
|
'details': 'podrobnosti',
|
||||||
'docs': 'dokumentace',
|
'direction: ltr': 'směr: ltr',
|
||||||
'Documentation': 'Dokumentace',
|
'Disable': 'Zablokovat',
|
||||||
"Don't know what to do?": 'Nevíte kudy kam?',
|
'DISK': 'DISK',
|
||||||
'done!': 'hotovo!',
|
'Disk Cache Keys': 'Klíče diskové cache',
|
||||||
'Download': 'Stáhnout',
|
'Disk Cleared': 'Disk smazán',
|
||||||
'download layouts': 'stáhnout moduly rozvržení stránky',
|
'docs': 'dokumentace',
|
||||||
'download plugins': 'stáhnout zásuvné moduly',
|
'Documentation': 'Dokumentace',
|
||||||
'E-mail': 'E-mail',
|
"Don't know what to do?": 'Kde najdu další informace ?',
|
||||||
'Edit': 'Upravit',
|
'done!': 'hotovo!',
|
||||||
'edit all': 'edit all',
|
'Download': 'Stáhnout',
|
||||||
'Edit application': 'Správa aplikace',
|
'download layouts': 'stáhnout moduly rozvržení stránky',
|
||||||
'edit controller': 'edit controller',
|
'download plugins': 'stáhnout zásuvné moduly',
|
||||||
'Edit current record': 'Upravit aktuální záznam',
|
'E-mail': 'E-mail',
|
||||||
'Edit Profile': 'Upravit profil',
|
'Edit': 'Upravit',
|
||||||
'edit views:': 'upravit pohled:',
|
'edit all': 'editovat vše',
|
||||||
'Editing file "%s"': 'Úprava souboru "%s"',
|
'Edit application': 'Správa aplikace',
|
||||||
'Editing Language file': 'Úprava jazykového souboru',
|
'edit controller': 'editovat controller',
|
||||||
'Editing Plural Forms File': 'Editing Plural Forms File',
|
'Edit current record': 'Upravit aktuální záznam',
|
||||||
'Email and SMS': 'Email a SMS',
|
'Edit Profile': 'Upravit profil',
|
||||||
'Enable': 'Odblokovat',
|
'edit views:': 'upravit pohled:',
|
||||||
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
|
'Editing file "%s"': 'Úprava souboru "%s"',
|
||||||
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
|
'Editing Language file': 'Úprava jazykového souboru',
|
||||||
'Error': 'Chyba',
|
'Editing Plural Forms File': 'Editování souboru množných čísel',
|
||||||
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
|
'Email and SMS': 'Email a SMS',
|
||||||
'Error snapshot': 'Snapshot chyby',
|
'Enable': 'Odblokovat',
|
||||||
'Error ticket': 'Ticket chyby',
|
'enter a number between %(min)g and %(max)g': 'zadejte číslo mezi %(min)g a %(max)g',
|
||||||
'Errors': 'Chyby',
|
'Enter an integer between %(min)g and %(max)g': 'Enter an integer between %(min)g and %(max)g',
|
||||||
'Exception %(extype)s: %(exvalue)s': 'Exception %(extype)s: %(exvalue)s',
|
'enter an integer between %(min)g and %(max)g': 'zadejte celé číslo mezi %(min)g a %(max)g',
|
||||||
'Exception %s': 'Exception %s',
|
'Error': 'Chyba',
|
||||||
'Exception instance attributes': 'Prvky instance výjimky',
|
'Error logs for "%(app)s"': 'Seznam výskytu chyb pro aplikaci "%(app)s"',
|
||||||
'Expand Abbreviation': 'Expand Abbreviation',
|
'Error snapshot': 'Snapshot chyby',
|
||||||
'export as csv file': 'exportovat do .csv souboru',
|
'Error ticket': 'Ticket chyby',
|
||||||
'exposes': 'vystavuje',
|
'Errors': 'Chyby',
|
||||||
'exposes:': 'vystavuje funkce:',
|
'Exception %(extype)s: %(exvalue)s': 'Výjimka %(extype)s: %(exvalue)s',
|
||||||
'extends': 'rozšiřuje',
|
'Exception %s': 'Výjimka %s',
|
||||||
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
|
'Exception instance attributes': 'Prvky instance výjimky',
|
||||||
'FAQ': 'Často kladené dotazy',
|
'Expand Abbreviation': 'Expandovat zkratku',
|
||||||
'File': 'Soubor',
|
'export as csv file': 'exportovat do .csv souboru',
|
||||||
'file': 'soubor',
|
'exposes': 'vystavuje',
|
||||||
'file "%(filename)s" created': 'file "%(filename)s" created',
|
'exposes:': 'vystavuje funkce:',
|
||||||
'file saved on %(time)s': 'soubor uložen %(time)s',
|
'extends': 'rozšiřuje',
|
||||||
'file saved on %s': 'soubor uložen %s',
|
'failed to compile file because:': 'soubor se nepodařilo zkompilovat, protože:',
|
||||||
'Filename': 'Název souboru',
|
'FAQ': 'Často kladené dotazy',
|
||||||
'filter': 'filtr',
|
'File': 'Soubor',
|
||||||
'Find Next': 'Najít další',
|
'file': 'soubor',
|
||||||
'Find Previous': 'Najít předchozí',
|
'file "%(filename)s" created': 'soubor "%(filename)s" byl vytvořen',
|
||||||
'First name': 'Křestní jméno',
|
'file saved on %(time)s': 'soubor uložen %(time)s',
|
||||||
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
|
'file saved on %s': 'soubor uložen %s',
|
||||||
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
|
'Filename': 'Název souboru',
|
||||||
'Forms and Validators': 'Formuláře a validátory',
|
'filter': 'filtr',
|
||||||
'Frames': 'Frames',
|
'Find Next': 'Najít další',
|
||||||
'Free Applications': 'Aplikace zdarma',
|
'Find Previous': 'Najít předchozí',
|
||||||
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
|
'First name': 'Křestní jméno',
|
||||||
'Generate': 'Vytvořit',
|
'Forgot username?': 'Zapomněl jste svoje přihlašovací jméno?',
|
||||||
'Get from URL:': 'Stáhnout z internetu:',
|
'forgot username?': 'zapomněl jste svoje přihlašovací jméno?',
|
||||||
'Git Pull': 'Git Pull',
|
'Forms and Validators': 'Formuláře a validátory',
|
||||||
'Git Push': 'Git Push',
|
'Frames': 'Framy',
|
||||||
'Globals##debug': 'Globální proměnné',
|
'Free Applications': 'Aplikace zdarma',
|
||||||
'go!': 'OK!',
|
'Functions with no doctests will result in [passed] tests.': 'Functions with no doctests will result in [passed] tests.',
|
||||||
'Goto': 'Goto',
|
'Generate': 'Vytvořit',
|
||||||
'graph model': 'graph model',
|
'Get from URL:': 'Stáhnout z internetu:',
|
||||||
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
|
'Git Pull': 'Git Pull',
|
||||||
'Group ID': 'ID skupiny',
|
'Git Push': 'Git Push',
|
||||||
'Groups': 'Skupiny',
|
'Globals##debug': 'Globální proměnné',
|
||||||
'Hello World': 'Ahoj světe',
|
'go!': 'OK!',
|
||||||
'Help': 'Nápověda',
|
'Goto': 'Přejít na',
|
||||||
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
|
'graph model': 'grafický model',
|
||||||
'Hits': 'Kolikrát dosaženo',
|
'Group %(group_id)s created': 'Skupina %(group_id)s vytvořena',
|
||||||
'Home': 'Domovská stránka',
|
'Group ID': 'ID skupiny',
|
||||||
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
|
'Groups': 'Skupiny',
|
||||||
'How did you get here?': 'Jak jste se sem vlastně dostal?',
|
'Hello World': 'Ahoj všichni',
|
||||||
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
|
'Help': 'Nápověda',
|
||||||
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
'Helping web2py': 'Podpořte Web2py',
|
||||||
'import': 'import',
|
'Hide/Show Translated strings': 'Skrýt/Zobrazit přeložené texty',
|
||||||
'Import/Export': 'Import/Export',
|
'Hits': 'Kolikrát dosaženo',
|
||||||
'includes': 'zahrnuje',
|
'Home': 'Domovská stránka',
|
||||||
'Index': 'Index',
|
'honored only if the expression evaluates to true': 'brát v potaz jen když se tato podmínka vyhodnotí kladně',
|
||||||
'insert new': 'vložit nový záznam ',
|
'How did you get here?': 'Jak se Ti tato stránka vlastně zobrazila?',
|
||||||
'insert new %s': 'vložit nový záznam %s',
|
'If start the upgrade, be patient, it may take a while to download': 'If start the upgrade, be patient, it may take a while to download',
|
||||||
'inspect attributes': 'inspect attributes',
|
'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.': 'If the report above contains a ticket number it indicates a failure in executing the controller, before any attempt to execute the doctests. This is usually due to an indentation error or an error outside function code.\r\nA green title indicates that all tests (if defined) passed. In this case test results are not shown.',
|
||||||
'Install': 'Instalovat',
|
'import': 'import',
|
||||||
'Installed applications': 'Nainstalované aplikace',
|
'Import/Export': 'Import/Export',
|
||||||
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
|
'includes': 'zahrnuje',
|
||||||
'Interactive console': 'Interaktivní příkazová řádka',
|
'Index': 'Index',
|
||||||
'Internal State': 'Vnitřní stav',
|
'insert new': 'vložit nový záznam ',
|
||||||
'Introduction': 'Úvod',
|
'insert new %s': 'vložit nový záznam %s',
|
||||||
'Invalid email': 'Neplatný email',
|
'inspect attributes': 'prohlédnout atributy',
|
||||||
'Invalid password': 'Nesprávné heslo',
|
'Install': 'Instalovat',
|
||||||
'invalid password.': 'neplatné heslo',
|
'Installed applications': 'Nainstalované aplikace',
|
||||||
'Invalid Query': 'Neplatný dotaz',
|
'Interaction at %s line %s': 'Interakce v %s, na řádce %s',
|
||||||
'invalid request': 'Neplatný požadavek',
|
'Interactive console': 'Interaktivní příkazová řádka',
|
||||||
'Is Active': 'Je aktivní',
|
'Internal State': 'Vnitřní stav',
|
||||||
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
|
'Introduction': 'Úvod',
|
||||||
'Key': 'Klíč',
|
'Invalid email': 'Neplatný email',
|
||||||
'Key bindings': 'Vazby klíčů',
|
'Invalid password': 'Nesprávné heslo',
|
||||||
'Key bindings for ZenCoding Plugin': 'Key bindings for ZenCoding Plugin',
|
'invalid password.': 'neplatné heslo',
|
||||||
'languages': 'jazyky',
|
'Invalid Query': 'Neplatný dotaz',
|
||||||
'Languages': 'Jazyky',
|
'invalid request': 'Neplatný požadavek',
|
||||||
'Last name': 'Příjmení',
|
'Is Active': 'Je aktivní',
|
||||||
'Last saved on:': 'Naposledy uloženo:',
|
'It is %s %%{day} today.': 'Dnes je to %s %%{den}.',
|
||||||
'Layout': 'Rozvržení stránky (layout)',
|
'Key': 'Klíč',
|
||||||
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
|
'Key bindings': 'Vazby klíčů',
|
||||||
'Layouts': 'Rozvržení stránek',
|
'Key bindings for ZenCoding Plugin': 'Key bindings pro ZenCoding Plugin',
|
||||||
'License for': 'Licence pro',
|
'languages': 'jazyky',
|
||||||
'Line number': 'Číslo řádku',
|
'Languages': 'Jazyky',
|
||||||
'LineNo': 'Č.řádku',
|
'Last name': 'Příjmení',
|
||||||
'Live Chat': 'Online pokec',
|
'Last saved on:': 'Naposledy uloženo:',
|
||||||
'loading...': 'nahrávám...',
|
'Layout': 'Rozvržení stránky (layout)',
|
||||||
'locals': 'locals',
|
'Layout Plugins': 'Moduly rozvržení stránky (Layout Plugins)',
|
||||||
'Locals##debug': 'Lokální proměnné',
|
'Layouts': 'Rozvržení stránek',
|
||||||
'Logged in': 'Přihlášení proběhlo úspěšně',
|
'License for': 'Licence pro',
|
||||||
'Logged out': 'Odhlášení proběhlo úspěšně',
|
'Line number': 'Číslo řádku',
|
||||||
'Login': 'Přihlásit se',
|
'LineNo': 'Č.řádku',
|
||||||
'login': 'přihlásit se',
|
'Live Chat': 'Online chat',
|
||||||
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
|
'loading...': 'nahrávám...',
|
||||||
'logout': 'odhlásit se',
|
'locals': 'locals',
|
||||||
'Logout': 'Odhlásit se',
|
'Locals##debug': 'Lokální proměnné',
|
||||||
'Lost Password': 'Zapomněl jste heslo',
|
'Log In': 'Přihlásit se',
|
||||||
'Lost password?': 'Zapomněl jste heslo?',
|
'Logged in': 'Přihlášení proběhlo úspěšně',
|
||||||
'lost password?': 'zapomněl jste heslo?',
|
'Logged out': 'Odhlášení proběhlo úspěšně',
|
||||||
'Manage': 'Manage',
|
'Login': 'Přihlásit se',
|
||||||
'Manage Cache': 'Manage Cache',
|
'login': 'přihlásit se',
|
||||||
'Menu Model': 'Model rozbalovací nabídky',
|
'Login to the Administrative Interface': 'Přihlásit se do Správce aplikací',
|
||||||
'Models': 'Modely',
|
'logout': 'odhlásit se',
|
||||||
'models': 'modely',
|
'Logout': 'Odhlásit se',
|
||||||
'Modified By': 'Změněno - kým',
|
'Lost Password': 'Zapomněl jste heslo',
|
||||||
'Modified On': 'Změněno - kdy',
|
'Lost password?': 'Zapomněl jste heslo?',
|
||||||
'Modules': 'Moduly',
|
'lost password?': 'zapomněl jste heslo?',
|
||||||
'modules': 'moduly',
|
'Manage': 'Spravovat',
|
||||||
'My Sites': 'Správa aplikací',
|
'Manage Cache': 'Spravovat cache',
|
||||||
'Name': 'Jméno',
|
'Menu Model': 'Model rozbalovací nabídky',
|
||||||
'new application "%s" created': 'nová aplikace "%s" vytvořena',
|
'Models': 'Modely',
|
||||||
'New Application Wizard': 'Nový průvodce aplikací',
|
'models': 'modely',
|
||||||
'New application wizard': 'Nový průvodce aplikací',
|
'Modified By': 'Změněno - kým',
|
||||||
'New password': 'Nové heslo',
|
'Modified On': 'Změněno - kdy',
|
||||||
'New Record': 'Nový záznam',
|
'Modules': 'Moduly',
|
||||||
'new record inserted': 'nový záznam byl založen',
|
'modules': 'moduly',
|
||||||
'New simple application': 'Vytvořit primitivní aplikaci',
|
'My Sites': 'Správa aplikací',
|
||||||
'next': 'next',
|
'Name': 'Jméno',
|
||||||
'next 100 rows': 'dalších 100 řádků',
|
'new application "%s" created': 'nová aplikace "%s" vytvořena',
|
||||||
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
|
'New application wizard': 'Nový průvodce aplikací',
|
||||||
'No Interaction yet': 'Ještě žádná interakce nenastala',
|
'New Application Wizard': 'Nový průvodce aplikací',
|
||||||
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
|
'New password': 'Nové heslo',
|
||||||
'Object or table name': 'Objekt či tabulka',
|
'New Record': 'Nový záznam',
|
||||||
'Old password': 'Původní heslo',
|
'new record inserted': 'nový záznam byl založen',
|
||||||
'online designer': 'online návrhář',
|
'New simple application': 'Vytvořit novou aplikaci',
|
||||||
'Online examples': 'Příklady online',
|
'next': 'další',
|
||||||
'Open new app in new window': 'Open new app in new window',
|
'next 100 rows': 'dalších 100 řádků',
|
||||||
'or alternatively': 'or alternatively',
|
'No databases in this application': 'V této aplikaci nejsou žádné databáze',
|
||||||
'Or Get from URL:': 'Or Get from URL:',
|
'No Interaction yet': 'Ještě žádná interakce nenastala',
|
||||||
'or import from csv file': 'nebo importovat z .csv souboru',
|
'No ticket_storage.txt found under /private folder': 'Soubor ticket_storage.txt v adresáři /private nenalezen',
|
||||||
'Origin': 'Původ',
|
'Object or table name': 'Objekt či tabulka',
|
||||||
'Original/Translation': 'Originál/Překlad',
|
'Old password': 'Původní heslo',
|
||||||
'Other Plugins': 'Ostatní moduly',
|
'Online book': 'Online kniha',
|
||||||
'Other Recipes': 'Ostatní zásuvné moduly',
|
'online designer': 'online návrhář',
|
||||||
'Overview': 'Přehled',
|
'Online examples': 'Ukázka aplikace: web2py stránky',
|
||||||
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
|
'Open new app in new window': 'Otevřít novou aplikaci v novém okně',
|
||||||
'Pack all': 'Zabalit',
|
'or alternatively': 'nebo případně',
|
||||||
'Pack compiled': 'Zabalit zkompilované',
|
'Or Get from URL:': 'Nebo získat z URL adresy:',
|
||||||
'pack plugin': 'pack plugin',
|
'or import from csv file': 'nebo importovat z .csv souboru',
|
||||||
'password': 'heslo',
|
'Origin': 'Původ',
|
||||||
'Password': 'Heslo',
|
'Original/Translation': 'Originál/Překlad',
|
||||||
"Password fields don't match": 'Hesla se neshodují',
|
'Other Plugins': 'Ostatní moduly',
|
||||||
'Peeking at file': 'Peeking at file',
|
'Other Recipes': 'Ostatní zásuvné moduly',
|
||||||
'Please': 'Prosím',
|
'Overview': 'Přehled',
|
||||||
'Plugin "%s" in application': 'Plugin "%s" in application',
|
'Overwrite installed app': 'Přepsat instalovanou aplikaci',
|
||||||
'plugins': 'zásuvné moduly',
|
'Pack all': 'Zabalit',
|
||||||
'Plugins': 'Zásuvné moduly',
|
'Pack compiled': 'Zabalit zkompilované',
|
||||||
'Plural Form #%s': 'Plural Form #%s',
|
'pack plugin': 'pack (zabalit) plugin',
|
||||||
'Plural-Forms:': 'Množná čísla:',
|
'password': 'heslo',
|
||||||
'Powered by': 'Poháněno',
|
'Password': 'Heslo',
|
||||||
'Preface': 'Předmluva',
|
"Password fields don't match": 'Hesla se neshodují',
|
||||||
'previous 100 rows': 'předchozích 100 řádků',
|
'Peeking at file': 'Sledování souboru',
|
||||||
'Private files': 'Soukromé soubory',
|
'Please': 'Prosím',
|
||||||
'private files': 'soukromé soubory',
|
'Plugin "%s" in application': 'Plugin "%s" v aplikaci',
|
||||||
'profile': 'profil',
|
'plugins': 'zásuvné moduly',
|
||||||
'Project Progress': 'Vývoj projektu',
|
'Plugins': 'Zásuvné moduly',
|
||||||
'Python': 'Python',
|
'Plural Form #%s': 'Množné číslo #%s',
|
||||||
'Query:': 'Dotaz:',
|
'Plural-Forms:': 'Množná čísla:',
|
||||||
'Quick Examples': 'Krátké příklady',
|
'Powered by': 'Používá technologii',
|
||||||
'RAM': 'RAM',
|
'Preface': 'Předmluva',
|
||||||
'RAM Cache Keys': 'Klíče RAM Cache',
|
'previous 100 rows': 'předchozích 100 řádků',
|
||||||
'Ram Cleared': 'RAM smazána',
|
'Private files': 'Soukromé soubory',
|
||||||
'Readme': 'Nápověda',
|
'private files': 'soukromé soubory',
|
||||||
'Recipes': 'Postupy jak na to',
|
'profile': 'profil',
|
||||||
'Record': 'Záznam',
|
'Project Progress': 'Vývoj projektu',
|
||||||
'record does not exist': 'záznam neexistuje',
|
'Python': 'Python',
|
||||||
'Record ID': 'ID záznamu',
|
'Query:': 'Dotaz:',
|
||||||
'Record id': 'id záznamu',
|
'Quick Examples': 'Krátké příklady',
|
||||||
'refresh': 'obnovte',
|
'RAM': 'RAM',
|
||||||
'register': 'registrovat',
|
'RAM Cache Keys': 'Klíče RAM Cache',
|
||||||
'Register': 'Zaregistrovat se',
|
'Ram Cleared': 'RAM smazána',
|
||||||
'Registration identifier': 'Registrační identifikátor',
|
'Readme': 'Nápověda',
|
||||||
'Registration key': 'Registrační klíč',
|
'Recipes': 'Postupy jak na to',
|
||||||
'reload': 'reload',
|
'Record': 'Záznam',
|
||||||
'Reload routes': 'Znovu nahrát cesty',
|
'record does not exist': 'záznam neexistuje',
|
||||||
'Remember me (for 30 days)': 'Zapamatovat na 30 dní',
|
'Record ID': 'ID záznamu',
|
||||||
'Remove compiled': 'Odstranit zkompilované',
|
'Record id': 'id záznamu',
|
||||||
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
|
'refresh': 'obnovte',
|
||||||
'Replace': 'Zaměnit',
|
'register': 'registrovat',
|
||||||
'Replace All': 'Zaměnit vše',
|
'Register': 'Zaregistrovat se',
|
||||||
'request': 'request',
|
'Registration identifier': 'Registrační identifikátor',
|
||||||
'Reset Password key': 'Reset registračního klíče',
|
'Registration key': 'Registrační klíč',
|
||||||
'response': 'response',
|
'reload': 'reload',
|
||||||
'restart': 'restart',
|
'Reload routes': 'Znovu nahrát cesty',
|
||||||
'restore': 'obnovit',
|
'Remember me (for 30 days)': 'Zapamatovat na 30 dní',
|
||||||
'Retrieve username': 'Získat přihlašovací jméno',
|
'Remove compiled': 'Odstranit zkompilované',
|
||||||
'return': 'return',
|
'Removed Breakpoint on %s at line %s': 'Bod přerušení smazán - soubor %s na řádce %s',
|
||||||
'revert': 'vrátit se k původnímu',
|
'Replace': 'Zaměnit',
|
||||||
'Role': 'Role',
|
'Replace All': 'Zaměnit vše',
|
||||||
'Rows in Table': 'Záznamy v tabulce',
|
'request': 'request',
|
||||||
'Rows selected': 'Záznamů zobrazeno',
|
'Reset Password key': 'Reset registračního klíče',
|
||||||
'rules are not defined': 'pravidla nejsou definována',
|
'response': 'response',
|
||||||
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
|
'restart': 'restart',
|
||||||
'Running on %s': 'Běží na %s',
|
'restore': 'obnovit',
|
||||||
'Save': 'Uložit',
|
'Retrieve username': 'Získat přihlašovací jméno',
|
||||||
'Save file:': 'Save file:',
|
'return': 'return',
|
||||||
'Save via Ajax': 'Uložit pomocí Ajaxu',
|
'revert': 'vrátit se k původnímu',
|
||||||
'Saved file hash:': 'hash uloženého souboru:',
|
'Role': 'Role',
|
||||||
'Semantic': 'Modul semantic',
|
'Rows in Table': 'Záznamy v tabulce',
|
||||||
'Services': 'Služby',
|
'Rows selected': 'Záznamů zobrazeno',
|
||||||
'session': 'session',
|
'rules are not defined': 'pravidla nejsou definována',
|
||||||
'session expired': 'session expired',
|
"Run tests in this file (to run all files, you may also use the button labelled 'test')": "Spustí testy v tomto souboru (ke spuštění všech testů, použijte tlačítko 'test')",
|
||||||
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
|
'Running on %s': 'Běží na %s',
|
||||||
'shell': 'příkazová řádka',
|
'Save': 'Uložit',
|
||||||
'Singular Form': 'Singular Form',
|
'Save file:': 'Uložit soubor:',
|
||||||
'Site': 'Správa aplikací',
|
'Save via Ajax': 'Uložit pomocí Ajaxu',
|
||||||
'Size of cache:': 'Velikost cache:',
|
'Saved file hash:': 'hash uloženého souboru:',
|
||||||
'skip to generate': 'skip to generate',
|
'Semantic': 'Modul semantic',
|
||||||
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
|
'Services': 'Služby',
|
||||||
'Start a new app': 'Vytvořit novou aplikaci',
|
'session': 'session',
|
||||||
'Start searching': 'Začít hledání',
|
'session expired': 'vypršela session',
|
||||||
'Start wizard': 'Spustit průvodce',
|
'Set Breakpoint on %s at line %s: %s': 'Bod přerušení nastaven v souboru %s na řádce %s: %s',
|
||||||
'state': 'stav',
|
'shell': 'příkazová řádka',
|
||||||
'Static': 'Static',
|
'Sign Up': 'Registrovat se',
|
||||||
'static': 'statické soubory',
|
'Singular Form': 'Jednotné číslo',
|
||||||
'Static files': 'Statické soubory',
|
'Site': 'Správa aplikací',
|
||||||
'Statistics': 'Statistika',
|
'Size of cache:': 'Velikost cache:',
|
||||||
'Step': 'Step',
|
'skip to generate': 'přeskočit pro vytvoření',
|
||||||
'step': 'step',
|
'Sorry, could not find mercurial installed': 'Bohužel mercurial není nainstalován.',
|
||||||
'stop': 'stop',
|
'Start a new app': 'Vytvořit novou aplikaci',
|
||||||
'Stylesheet': 'CSS styly',
|
'Start searching': 'Začít hledání',
|
||||||
'submit': 'odeslat',
|
'Start wizard': 'Spustit průvodce',
|
||||||
'Submit': 'Odeslat',
|
'state': 'stav',
|
||||||
'successful': 'úspěšně',
|
'Static': 'Statické soubory',
|
||||||
'Support': 'Podpora',
|
'static': 'statické soubory',
|
||||||
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
|
'Static files': 'Statické soubory',
|
||||||
'Table': 'tabulka',
|
'Statistics': 'Statistika',
|
||||||
'Table name': 'Název tabulky',
|
'Step': 'Krok',
|
||||||
'Temporary': 'Dočasný',
|
'step': 'krok',
|
||||||
'test': 'test',
|
'stop': 'zastavit',
|
||||||
'Testing application': 'Testing application',
|
'Stylesheet': 'CSS styly',
|
||||||
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
|
'submit': 'odeslat',
|
||||||
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
|
'Submit': 'Odeslat',
|
||||||
'The Core': 'Jádro (The Core)',
|
'successful': 'úspěšně',
|
||||||
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
|
'Support': 'Podpora',
|
||||||
'The output of the file is a dictionary that was rendered by the view %s': 'Výstup ze souboru je slovník, který se zobrazil v pohledu %s.',
|
'Sure you want to delete this object?': 'Opravdu chcete smazat tento objekt?',
|
||||||
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
|
'Table': 'tabulka',
|
||||||
'The Views': 'Pohledy (The Views)',
|
'Table name': 'Název tabulky',
|
||||||
'There are no controllers': 'There are no controllers',
|
'Temporary': 'Dočasný',
|
||||||
'There are no modules': 'There are no modules',
|
'test': 'test',
|
||||||
'There are no plugins': 'Žádné moduly nejsou instalovány.',
|
'Testing application': 'Zkušební aplikace',
|
||||||
'There are no private files': 'Žádné soukromé soubory neexistují.',
|
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': '"Dotaz" je podmínka, například "db.tabulka1.pole1==\'hodnota\'". Podmínka "db.tabulka1.pole1==db.tabulka2.pole2" pak vytvoří SQL JOIN.',
|
||||||
'There are no static files': 'There are no static files',
|
'The application logic, each URL path is mapped in one exposed function in the controller': 'Logika aplikace: každá URL je mapována na funkci vystavovanou kontrolérem.',
|
||||||
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
|
'The Core': 'Jádro (The Core)',
|
||||||
'There are no views': 'There are no views',
|
'The data representation, define database tables and sets': 'Reprezentace dat: definovat tabulky databáze a záznamy',
|
||||||
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
|
'The output of the file is a dictionary that was rendered by the view %s': 'Funkce vrátila dictionary (slovník) hodnot, a ty se vypsaly pomocí šablony %s.',
|
||||||
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
|
'The presentations layer, views are also known as templates': 'Prezentační vrstva: pohledy či templaty (šablony)',
|
||||||
'This App': 'Tato aplikace',
|
'The Views': 'Pohledy (The Views)',
|
||||||
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
|
'There are no controllers': 'Nejsou vytvořeny žádné controllery',
|
||||||
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
|
'There are no modules': 'Nejsou přidány žádné moduly',
|
||||||
'This is the %(filename)s template': 'This is the %(filename)s template',
|
'There are no plugins': 'Žádné pluginy nejsou instalovány.',
|
||||||
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
|
'There are no private files': 'Žádné soukromé soubory neexistují.',
|
||||||
'Ticket': 'Ticket',
|
'There are no static files': 'Nejsou přidány žádné statické soubory',
|
||||||
'Ticket ID': 'Ticket ID',
|
'There are no translators, only default language is supported': 'There are no translators, only default language is supported',
|
||||||
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
|
'There are no views': 'Nejsou vytvořeny žádné šablony (views)',
|
||||||
'Timestamp': 'Časové razítko',
|
'These files are not served, they are only available from within your app': 'Tyto soubory jsou klientům nepřístupné. K dispozici jsou pouze v rámci aplikace.',
|
||||||
'to previous version.': 'k předchozí verzi.',
|
'These files are served without processing, your images go here': 'Tyto soubory jsou servírovány bez přídavné logiky, sem patří např. obrázky.',
|
||||||
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
|
'This App': 'Tato aplikace',
|
||||||
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
|
'This is a copy of the scaffolding application': 'Toto je kopie aplikace skelet.',
|
||||||
'to use the debugger!': ', abyste mohli ladící program používat!',
|
'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk': 'This is an experimental feature and it needs more testing. If you decide to upgrade you do it at your own risk',
|
||||||
'toggle breakpoint': 'vyp./zap. bod přerušení',
|
'This is the %(filename)s template': 'Toto je šablona %(filename)s',
|
||||||
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
|
'this page to see if a breakpoint was hit and debug interaction is required.': 'tuto stránku, abyste uviděli, zda se dosáhlo bodu přerušení.',
|
||||||
'too short': 'Příliš krátké',
|
'Ticket': 'Tiket',
|
||||||
'Traceback': 'Traceback',
|
'Ticket ID': 'ID tiketu',
|
||||||
'Translation strings for the application': 'Překlad textů pro aplikaci',
|
'Time in Cache (h:m:s)': 'Čas v Cache (h:m:s)',
|
||||||
'try something like': 'try something like',
|
'Timestamp': 'Časové razítko',
|
||||||
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
|
'to previous version.': 'k předchozí verzi.',
|
||||||
'try view': 'try view',
|
'To create a plugin, name a file/folder plugin_[name]': 'Zásuvný modul vytvoříte tak, že pojmenujete soubor/adresář plugin_[jméno modulu]',
|
||||||
'Twitter': 'Twitter',
|
'To emulate a breakpoint programatically, write:': 'K nastavení bodu přerušení v kódu programu, napište:',
|
||||||
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
|
'to use the debugger!': ', abyste mohli ladící program používat!',
|
||||||
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
|
'toggle breakpoint': 'vyp./zap. bod přerušení',
|
||||||
'Unable to check for upgrades': 'Unable to check for upgrades',
|
'Toggle Fullscreen': 'Na celou obrazovku a zpět',
|
||||||
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
|
'too short': 'Příliš krátké',
|
||||||
'uncheck all': 'vše odznačit',
|
'Traceback': 'Hierarchie volání',
|
||||||
'Uninstall': 'Odinstalovat',
|
'Translation strings for the application': 'Překlad textů pro aplikaci',
|
||||||
'update': 'aktualizovat',
|
'try something like': 'zkuste něco jako',
|
||||||
'update all languages': 'aktualizovat všechny jazyky',
|
'Try the mobile interface': 'Zkuste rozhraní pro mobilní zařízení',
|
||||||
'Update:': 'Upravit:',
|
'try view': 'vyzkoušet šablonu (view)',
|
||||||
'Upgrade': 'Upgrade',
|
'Twitter': 'Twitter',
|
||||||
'upgrade now': 'upgrade now',
|
'Type python statement in here and hit Return (Enter) to execute it.': 'Type python statement in here and hit Return (Enter) to execute it.',
|
||||||
'upgrade now to %s': 'upgrade now to %s',
|
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
|
||||||
'upload': 'nahrát',
|
'Unable to check for upgrades': 'Nelze zjistit informaci o aktualizacích',
|
||||||
'Upload': 'Upload',
|
'unable to parse csv file': 'csv soubor nedá sa zpracovat',
|
||||||
'Upload a package:': 'Nahrát balík:',
|
'uncheck all': 'vše odznačit',
|
||||||
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
|
'Uninstall': 'Odinstalovat',
|
||||||
'upload file:': 'nahrát soubor:',
|
'update': 'aktualizovat',
|
||||||
'upload plugin file:': 'nahrát soubor modulu:',
|
'update all languages': 'aktualizovat všechny jazyky',
|
||||||
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
|
'Update:': 'Upravit:',
|
||||||
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
|
'Upgrade': 'Upgrade',
|
||||||
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
|
'upgrade now': 'upgradovat nyní',
|
||||||
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
|
'upgrade now to %s': 'upgradovat nyní na %s',
|
||||||
'User %(id)s Profile updated': 'Uživatel %(id)s upravil profil',
|
'upload': 'nahrát',
|
||||||
'User %(id)s Registered': 'Uživatel %(id)s se zaregistroval',
|
'Upload': 'Upload (nahrát)',
|
||||||
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
|
'Upload a package:': 'Nahrát balík:',
|
||||||
'User ID': 'ID uživatele',
|
'Upload and install packed application': 'Nahrát a instalovat zabalenou aplikaci',
|
||||||
'Username': 'Přihlašovací jméno',
|
'upload file:': 'nahrát soubor:',
|
||||||
'variables': 'variables',
|
'upload plugin file:': 'nahrát soubor modulu:',
|
||||||
'Verify Password': 'Zopakujte heslo',
|
'Use (...)&(...) for AND, (...)|(...) for OR, and ~(...) for NOT to build more complex queries.': 'Použijte (...)&(...) pro AND, (...)|(...) pro OR a ~(...) pro NOT pro sestavení složitějších dotazů.',
|
||||||
'Version': 'Verze',
|
'User %(id)s Logged-in': 'Uživatel %(id)s přihlášen',
|
||||||
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
|
'User %(id)s Logged-out': 'Uživatel %(id)s odhlášen',
|
||||||
'Versioning': 'Verzování',
|
'User %(id)s Password changed': 'Uživatel %(id)s změnil heslo',
|
||||||
'Videos': 'Videa',
|
'User %(id)s Profile updated': 'Uživatel %(id)s upravil profil',
|
||||||
'View': 'Pohled (View)',
|
'User %(id)s Registered': 'Uživatel %(id)s se zaregistroval',
|
||||||
'Views': 'Pohledy',
|
'User %(id)s Username retrieved': 'Uživatel %(id)s si nachal zaslat přihlašovací jméno',
|
||||||
'views': 'pohledy',
|
'User ID': 'ID uživatele',
|
||||||
'Web Framework': 'Web Framework',
|
'Username': 'Přihlašovací jméno',
|
||||||
'web2py is up to date': 'Máte aktuální verzi web2py.',
|
'variables': 'proměnné',
|
||||||
'web2py online debugger': 'Ladící online web2py program',
|
'Verify Password': 'Zopakujte heslo',
|
||||||
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
|
'Version': 'Verze',
|
||||||
'web2py upgrade': 'web2py upgrade',
|
'Version %s.%s.%s (%s) %s': 'Verze %s.%s.%s (%s) %s',
|
||||||
'web2py upgraded; please restart it': 'web2py upgraded; please restart it',
|
'Versioning': 'Verzování',
|
||||||
'Welcome': 'Vítejte',
|
'Videos': 'Videa',
|
||||||
'Welcome to web2py': 'Vitejte ve web2py',
|
'View': 'Pohled (View)',
|
||||||
'Welcome to web2py!': 'Vítejte ve web2py!',
|
'Views': 'Pohledy',
|
||||||
'Which called the function %s located in the file %s': 'která zavolala funkci %s v souboru (kontroléru) %s.',
|
'views': 'pohledy',
|
||||||
'You are successfully running web2py': 'Úspěšně jste spustili web2py.',
|
'Web Framework': 'Webový framework',
|
||||||
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
|
'web2py is up to date': 'Máte aktuální verzi web2py.',
|
||||||
'You can modify this application and adapt it to your needs': 'Tuto aplikaci si můžete upravit a přizpůsobit ji svým potřebám.',
|
'web2py online debugger': 'Ladící online web2py program',
|
||||||
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
|
'web2py Recent Tweets': 'Štěbetání na Twitteru o web2py',
|
||||||
'You visited the url %s': 'Navštívili jste stránku %s,',
|
'web2py upgrade': 'aktualizace Web2py',
|
||||||
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
|
'web2py upgraded; please restart it': 'Web2py bylo aktualizováno; prosím restarujte jej',
|
||||||
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
'Welcome': 'Vítejte',
|
||||||
}
|
'Welcome to web2py': 'Vitejte ve Web2py aplikaci',
|
||||||
|
'Welcome to web2py!': 'Vítejte ve Web2py aplikaci.',
|
||||||
|
'Which called the function %s located in the file %s': 'Tím byla zavolána funkce %s ze souboru (kontroléru) %s.',
|
||||||
|
'Working...': 'Pracuji...',
|
||||||
|
'You are successfully running web2py': 'Spustil(a) jsi webový server a Web2py.',
|
||||||
|
'You can also set and remove breakpoint in the edit window, using the Toggle Breakpoint button': 'Nastavovat a mazat body přerušení je též možno v rámci editování zdrojového souboru přes tlačítko Vyp./Zap. bod přerušení',
|
||||||
|
'You can inspect variables using the console bellow': 'Níže pomocí příkazové řádky si můžete prohlédnout proměnné',
|
||||||
|
'You can modify this application and adapt it to your needs': 'V ADMIN rozhraní můžeš Vytvořit novou aplikaci jako kopii ukázkové Welcome aplikace. A začít upravovat: modely, kontroléry, šablony pro URL adresy, které požaduješ.',
|
||||||
|
'You need to set up and reach a': 'Je třeba nejprve nastavit a dojít až na',
|
||||||
|
'You visited the url %s': 'Zadal jsi URL adresu %s.',
|
||||||
|
'Your application will be blocked until you click an action button (next, step, continue, etc.)': 'Aplikace bude blokována než se klikne na jedno z tlačítek (další, krok, pokračovat, atd.)',
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,92 +1,132 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#########################################################################
|
# -------------------------------------------------------------------------
|
||||||
## This scaffolding model makes your app work on Google App Engine too
|
# This scaffolding model makes your app work on Google App Engine too
|
||||||
## File is released under public domain and you can use without limitations
|
# File is released under public domain and you can use without limitations
|
||||||
#########################################################################
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
## if SSL/HTTPS is properly configured and you want all HTTP requests to
|
if request.global_settings.web2py_version < "2.14.1":
|
||||||
## be redirected to HTTPS, uncomment the line below:
|
raise HTTP(500, "Requires web2py 2.13.3 or newer")
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# if SSL/HTTPS is properly configured and you want all HTTP requests to
|
||||||
|
# be redirected to HTTPS, uncomment the line below:
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
# request.requires_https()
|
# request.requires_https()
|
||||||
|
|
||||||
## app configuration made easy. Look inside private/appconfig.ini
|
# -------------------------------------------------------------------------
|
||||||
|
# app configuration made easy. Look inside private/appconfig.ini
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
from gluon.contrib.appconfig import AppConfig
|
from gluon.contrib.appconfig import AppConfig
|
||||||
## once in production, remove reload=True to gain full speed
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# once in production, remove reload=True to gain full speed
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
myconf = AppConfig(reload=True)
|
myconf = AppConfig(reload=True)
|
||||||
|
|
||||||
|
|
||||||
if not request.env.web2py_runtime_gae:
|
if not request.env.web2py_runtime_gae:
|
||||||
## if NOT running on Google App Engine use SQLite or other DB
|
# ---------------------------------------------------------------------
|
||||||
db = DAL(myconf.take('db.uri'), pool_size=myconf.take('db.pool_size', cast=int), check_reserved=['all'])
|
# if NOT running on Google App Engine use SQLite or other DB
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
db = DAL(myconf.get('db.uri'),
|
||||||
|
pool_size=myconf.get('db.pool_size'),
|
||||||
|
migrate_enabled=myconf.get('db.migrate'),
|
||||||
|
check_reserved=['all'])
|
||||||
else:
|
else:
|
||||||
## connect to Google BigTable (optional 'google:datastore://namespace')
|
# ---------------------------------------------------------------------
|
||||||
|
# connect to Google BigTable (optional 'google:datastore://namespace')
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
db = DAL('google:datastore+ndb')
|
db = DAL('google:datastore+ndb')
|
||||||
## store sessions and tickets there
|
# ---------------------------------------------------------------------
|
||||||
|
# store sessions and tickets there
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
session.connect(request, response, db=db)
|
session.connect(request, response, db=db)
|
||||||
## or store session in Memcache, Redis, etc.
|
# ---------------------------------------------------------------------
|
||||||
## from gluon.contrib.memdb import MEMDB
|
# or store session in Memcache, Redis, etc.
|
||||||
## from google.appengine.api.memcache import Client
|
# from gluon.contrib.memdb import MEMDB
|
||||||
## session.connect(request, response, db = MEMDB(Client()))
|
# from google.appengine.api.memcache import Client
|
||||||
|
# session.connect(request, response, db = MEMDB(Client()))
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
|
||||||
## by default give a view/generic.extension to all actions from localhost
|
# -------------------------------------------------------------------------
|
||||||
## none otherwise. a pattern can be 'controller/function.extension'
|
# by default give a view/generic.extension to all actions from localhost
|
||||||
|
# none otherwise. a pattern can be 'controller/function.extension'
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
response.generic_patterns = ['*'] if request.is_local else []
|
response.generic_patterns = ['*'] if request.is_local else []
|
||||||
## choose a style for forms
|
# -------------------------------------------------------------------------
|
||||||
response.formstyle = myconf.take('forms.formstyle') # or 'bootstrap3_stacked' or 'bootstrap2' or other
|
# choose a style for forms
|
||||||
response.form_label_separator = myconf.take('forms.separator')
|
# -------------------------------------------------------------------------
|
||||||
|
response.formstyle = myconf.get('forms.formstyle') # or 'bootstrap3_stacked' or 'bootstrap2' or other
|
||||||
|
response.form_label_separator = myconf.get('forms.separator') or ''
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
## (optional) optimize handling of static files
|
# (optional) optimize handling of static files
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
# response.optimize_css = 'concat,minify,inline'
|
# response.optimize_css = 'concat,minify,inline'
|
||||||
# response.optimize_js = 'concat,minify,inline'
|
# response.optimize_js = 'concat,minify,inline'
|
||||||
## (optional) static assets folder versioning
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# (optional) static assets folder versioning
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
# response.static_version = '0.0.0'
|
# response.static_version = '0.0.0'
|
||||||
#########################################################################
|
|
||||||
## Here is sample code if you need for
|
# -------------------------------------------------------------------------
|
||||||
## - email capabilities
|
# Here is sample code if you need for
|
||||||
## - authentication (registration, login, logout, ... )
|
# - email capabilities
|
||||||
## - authorization (role based authorization)
|
# - authentication (registration, login, logout, ... )
|
||||||
## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
|
# - authorization (role based authorization)
|
||||||
## - old style crud actions
|
# - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss)
|
||||||
## (more options discussed in gluon/tools.py)
|
# - old style crud actions
|
||||||
#########################################################################
|
# (more options discussed in gluon/tools.py)
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
from gluon.tools import Auth, Service, PluginManager
|
from gluon.tools import Auth, Service, PluginManager
|
||||||
|
|
||||||
auth = Auth(db)
|
# host names must be a list of allowed host names (glob syntax allowed)
|
||||||
|
auth = Auth(db, host_names=myconf.get('host.names'))
|
||||||
service = Service()
|
service = Service()
|
||||||
plugins = PluginManager()
|
plugins = PluginManager()
|
||||||
|
|
||||||
## create all tables needed by auth if not custom tables
|
# -------------------------------------------------------------------------
|
||||||
|
# create all tables needed by auth if not custom tables
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
auth.define_tables(username=False, signature=False)
|
auth.define_tables(username=False, signature=False)
|
||||||
|
|
||||||
## configure email
|
# -------------------------------------------------------------------------
|
||||||
|
# configure email
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
mail = auth.settings.mailer
|
mail = auth.settings.mailer
|
||||||
mail.settings.server = 'logging' if request.is_local else myconf.take('smtp.sender')
|
mail.settings.server = 'logging' if request.is_local else myconf.get('smtp.server')
|
||||||
mail.settings.sender = myconf.take('smtp.sender')
|
mail.settings.sender = myconf.get('smtp.sender')
|
||||||
mail.settings.login = myconf.take('smtp.login')
|
mail.settings.login = myconf.get('smtp.login')
|
||||||
|
mail.settings.tls = myconf.get('smtp.tls') or False
|
||||||
|
mail.settings.ssl = myconf.get('smtp.ssl') or False
|
||||||
|
|
||||||
## configure auth policy
|
# -------------------------------------------------------------------------
|
||||||
|
# configure auth policy
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
auth.settings.registration_requires_verification = False
|
auth.settings.registration_requires_verification = False
|
||||||
auth.settings.registration_requires_approval = False
|
auth.settings.registration_requires_approval = False
|
||||||
auth.settings.reset_password_requires_verification = True
|
auth.settings.reset_password_requires_verification = True
|
||||||
|
|
||||||
#########################################################################
|
# -------------------------------------------------------------------------
|
||||||
## Define your tables below (or better in another model file) for example
|
# Define your tables below (or better in another model file) for example
|
||||||
##
|
#
|
||||||
## >>> db.define_table('mytable',Field('myfield','string'))
|
# >>> db.define_table('mytable', Field('myfield', 'string'))
|
||||||
##
|
#
|
||||||
## Fields can be 'string','text','password','integer','double','boolean'
|
# Fields can be 'string','text','password','integer','double','boolean'
|
||||||
## 'date','time','datetime','blob','upload', 'reference TABLENAME'
|
# 'date','time','datetime','blob','upload', 'reference TABLENAME'
|
||||||
## There is an implicit 'id integer autoincrement' field
|
# There is an implicit 'id integer autoincrement' field
|
||||||
## Consult manual for more options, validators, etc.
|
# Consult manual for more options, validators, etc.
|
||||||
##
|
#
|
||||||
## More API examples for controllers:
|
# More API examples for controllers:
|
||||||
##
|
#
|
||||||
## >>> db.mytable.insert(myfield='value')
|
# >>> db.mytable.insert(myfield='value')
|
||||||
## >>> rows=db(db.mytable.myfield=='value').select(db.mytable.ALL)
|
# >>> rows = db(db.mytable.myfield == 'value').select(db.mytable.ALL)
|
||||||
## >>> for row in rows: print row.id, row.myfield
|
# >>> for row in rows: print row.id, row.myfield
|
||||||
#########################################################################
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
## after defining tables, uncomment below to enable auditing
|
# -------------------------------------------------------------------------
|
||||||
|
# after defining tables, uncomment below to enable auditing
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
# auth.enable_record_versioning(db)
|
# auth.enable_record_versioning(db)
|
||||||
|
|||||||
+125
-112
@@ -1,28 +1,32 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# this file is released under public domain and you can use without limitations
|
# this file is released under public domain and you can use without limitations
|
||||||
|
|
||||||
#########################################################################
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
## Customize your APP title, subtitle and menus here
|
# Customize your APP title, subtitle and menus here
|
||||||
#########################################################################
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
response.logo = A(B('web',SPAN(2),'py'),XML('™ '),
|
response.logo = A(B('web', SPAN(2), 'py'), XML('™ '),
|
||||||
_class="navbar-brand",_href="http://www.web2py.com/",
|
_class="navbar-brand", _href="http://www.web2py.com/",
|
||||||
_id="web2py-logo")
|
_id="web2py-logo")
|
||||||
response.title = request.application.replace('_',' ').title()
|
response.title = request.application.replace('_', ' ').title()
|
||||||
response.subtitle = ''
|
response.subtitle = ''
|
||||||
|
|
||||||
## read more at http://dev.w3.org/html5/markup/meta.name.html
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
response.meta.author = 'Your Name <you@example.com>'
|
# read more at http://dev.w3.org/html5/markup/meta.name.html
|
||||||
response.meta.description = 'a cool new app'
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
response.meta.keywords = 'web2py, python, framework'
|
response.meta.author = myconf.get('app.author')
|
||||||
response.meta.generator = 'Web2py Web Framework'
|
response.meta.description = myconf.get('app.description')
|
||||||
|
response.meta.keywords = myconf.get('app.keywords')
|
||||||
|
response.meta.generator = myconf.get('app.generator')
|
||||||
|
|
||||||
## your http://google.com/analytics id
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
|
# your http://google.com/analytics id
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
response.google_analytics_id = None
|
response.google_analytics_id = None
|
||||||
|
|
||||||
#########################################################################
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
## this is the main application menu add/remove items as required
|
# this is the main application menu add/remove items as required
|
||||||
#########################################################################
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
response.menu = [
|
response.menu = [
|
||||||
(T('Home'), False, URL('default', 'index'), [])
|
(T('Home'), False, URL('default', 'index'), [])
|
||||||
@@ -30,109 +34,118 @@ response.menu = [
|
|||||||
|
|
||||||
DEVELOPMENT_MENU = True
|
DEVELOPMENT_MENU = True
|
||||||
|
|
||||||
#########################################################################
|
|
||||||
## provide shortcuts for development. remove in production
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
#########################################################################
|
# provide shortcuts for development. remove in production
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
def _():
|
def _():
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
# shortcuts
|
# shortcuts
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
app = request.application
|
app = request.application
|
||||||
ctr = request.controller
|
ctr = request.controller
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
# useful links to internal and external resources
|
# useful links to internal and external resources
|
||||||
|
# ------------------------------------------------------------------------------------------------------------------
|
||||||
response.menu += [
|
response.menu += [
|
||||||
(T('My Sites'), False, URL('admin', 'default', 'site')),
|
(T('My Sites'), False, URL('admin', 'default', 'site')),
|
||||||
(T('This App'), False, '#', [
|
(T('This App'), False, '#', [
|
||||||
(T('Design'), False, URL('admin', 'default', 'design/%s' % app)),
|
(T('Design'), False, URL('admin', 'default', 'design/%s' % app)),
|
||||||
LI(_class="divider"),
|
LI(_class="divider"),
|
||||||
(T('Controller'), False,
|
(T('Controller'), False,
|
||||||
URL(
|
URL(
|
||||||
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
|
'admin', 'default', 'edit/%s/controllers/%s.py' % (app, ctr))),
|
||||||
(T('View'), False,
|
(T('View'), False,
|
||||||
URL(
|
URL(
|
||||||
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
|
'admin', 'default', 'edit/%s/views/%s' % (app, response.view))),
|
||||||
(T('DB Model'), False,
|
(T('DB Model'), False,
|
||||||
URL(
|
URL(
|
||||||
'admin', 'default', 'edit/%s/models/db.py' % app)),
|
'admin', 'default', 'edit/%s/models/db.py' % app)),
|
||||||
(T('Menu Model'), False,
|
(T('Menu Model'), False,
|
||||||
URL(
|
URL(
|
||||||
'admin', 'default', 'edit/%s/models/menu.py' % app)),
|
'admin', 'default', 'edit/%s/models/menu.py' % app)),
|
||||||
(T('Config.ini'), False,
|
(T('Config.ini'), False,
|
||||||
URL(
|
URL(
|
||||||
'admin', 'default', 'edit/%s/private/appconfig.ini' % app)),
|
'admin', 'default', 'edit/%s/private/appconfig.ini' % app)),
|
||||||
(T('Layout'), False,
|
(T('Layout'), False,
|
||||||
URL(
|
URL(
|
||||||
'admin', 'default', 'edit/%s/views/layout.html' % app)),
|
'admin', 'default', 'edit/%s/views/layout.html' % app)),
|
||||||
(T('Stylesheet'), False,
|
(T('Stylesheet'), False,
|
||||||
URL(
|
URL(
|
||||||
'admin', 'default', 'edit/%s/static/css/web2py-bootstrap3.css' % app)),
|
'admin', 'default', 'edit/%s/static/css/web2py-bootstrap3.css' % app)),
|
||||||
(T('Database'), False, URL(app, 'appadmin', 'index')),
|
(T('Database'), False, URL(app, 'appadmin', 'index')),
|
||||||
(T('Errors'), False, URL(
|
(T('Errors'), False, URL(
|
||||||
'admin', 'default', 'errors/' + app)),
|
'admin', 'default', 'errors/' + app)),
|
||||||
(T('About'), False, URL(
|
(T('About'), False, URL(
|
||||||
'admin', 'default', 'about/' + app)),
|
'admin', 'default', 'about/' + app)),
|
||||||
]),
|
]),
|
||||||
('web2py.com', False, '#', [
|
('web2py.com', False, '#', [
|
||||||
(T('Download'), False,
|
(T('Download'), False,
|
||||||
'http://www.web2py.com/examples/default/download'),
|
'http://www.web2py.com/examples/default/download'),
|
||||||
(T('Support'), False,
|
(T('Support'), False,
|
||||||
'http://www.web2py.com/examples/default/support'),
|
'http://www.web2py.com/examples/default/support'),
|
||||||
(T('Demo'), False, 'http://web2py.com/demo_admin'),
|
(T('Demo'), False, 'http://web2py.com/demo_admin'),
|
||||||
(T('Quick Examples'), False,
|
(T('Quick Examples'), False,
|
||||||
'http://web2py.com/examples/default/examples'),
|
'http://web2py.com/examples/default/examples'),
|
||||||
(T('FAQ'), False, 'http://web2py.com/AlterEgo'),
|
(T('FAQ'), False, 'http://web2py.com/AlterEgo'),
|
||||||
(T('Videos'), False,
|
(T('Videos'), False,
|
||||||
'http://www.web2py.com/examples/default/videos/'),
|
'http://www.web2py.com/examples/default/videos/'),
|
||||||
(T('Free Applications'),
|
(T('Free Applications'),
|
||||||
False, 'http://web2py.com/appliances'),
|
False, 'http://web2py.com/appliances'),
|
||||||
(T('Plugins'), False, 'http://web2py.com/plugins'),
|
(T('Plugins'), False, 'http://web2py.com/plugins'),
|
||||||
(T('Recipes'), False, 'http://web2pyslices.com/'),
|
(T('Recipes'), False, 'http://web2pyslices.com/'),
|
||||||
]),
|
]),
|
||||||
(T('Documentation'), False, '#', [
|
(T('Documentation'), False, '#', [
|
||||||
(T('Online book'), False, 'http://www.web2py.com/book'),
|
(T('Online book'), False, 'http://www.web2py.com/book'),
|
||||||
LI(_class="divider"),
|
LI(_class="divider"),
|
||||||
(T('Preface'), False,
|
(T('Preface'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/00'),
|
'http://www.web2py.com/book/default/chapter/00'),
|
||||||
(T('Introduction'), False,
|
(T('Introduction'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/01'),
|
'http://www.web2py.com/book/default/chapter/01'),
|
||||||
(T('Python'), False,
|
(T('Python'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/02'),
|
'http://www.web2py.com/book/default/chapter/02'),
|
||||||
(T('Overview'), False,
|
(T('Overview'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/03'),
|
'http://www.web2py.com/book/default/chapter/03'),
|
||||||
(T('The Core'), False,
|
(T('The Core'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/04'),
|
'http://www.web2py.com/book/default/chapter/04'),
|
||||||
(T('The Views'), False,
|
(T('The Views'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/05'),
|
'http://www.web2py.com/book/default/chapter/05'),
|
||||||
(T('Database'), False,
|
(T('Database'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/06'),
|
'http://www.web2py.com/book/default/chapter/06'),
|
||||||
(T('Forms and Validators'), False,
|
(T('Forms and Validators'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/07'),
|
'http://www.web2py.com/book/default/chapter/07'),
|
||||||
(T('Email and SMS'), False,
|
(T('Email and SMS'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/08'),
|
'http://www.web2py.com/book/default/chapter/08'),
|
||||||
(T('Access Control'), False,
|
(T('Access Control'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/09'),
|
'http://www.web2py.com/book/default/chapter/09'),
|
||||||
(T('Services'), False,
|
(T('Services'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/10'),
|
'http://www.web2py.com/book/default/chapter/10'),
|
||||||
(T('Ajax Recipes'), False,
|
(T('Ajax Recipes'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/11'),
|
'http://www.web2py.com/book/default/chapter/11'),
|
||||||
(T('Components and Plugins'), False,
|
(T('Components and Plugins'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/12'),
|
'http://www.web2py.com/book/default/chapter/12'),
|
||||||
(T('Deployment Recipes'), False,
|
(T('Deployment Recipes'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/13'),
|
'http://www.web2py.com/book/default/chapter/13'),
|
||||||
(T('Other Recipes'), False,
|
(T('Other Recipes'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/14'),
|
'http://www.web2py.com/book/default/chapter/14'),
|
||||||
(T('Helping web2py'), False,
|
(T('Helping web2py'), False,
|
||||||
'http://www.web2py.com/book/default/chapter/15'),
|
'http://www.web2py.com/book/default/chapter/15'),
|
||||||
(T("Buy web2py's book"), False,
|
(T("Buy web2py's book"), False,
|
||||||
'http://stores.lulu.com/web2py'),
|
'http://stores.lulu.com/web2py'),
|
||||||
]),
|
]),
|
||||||
(T('Community'), False, None, [
|
(T('Community'), False, None, [
|
||||||
(T('Groups'), False,
|
(T('Groups'), False,
|
||||||
'http://www.web2py.com/examples/default/usergroups'),
|
'http://www.web2py.com/examples/default/usergroups'),
|
||||||
(T('Twitter'), False, 'http://twitter.com/web2py'),
|
(T('Twitter'), False, 'http://twitter.com/web2py'),
|
||||||
(T('Live Chat'), False,
|
(T('Live Chat'), False,
|
||||||
'http://webchat.freenode.net/?channels=web2py'),
|
'http://webchat.freenode.net/?channels=web2py'),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
if DEVELOPMENT_MENU: _()
|
|
||||||
|
|
||||||
if "auth" in locals(): auth.wikimenu()
|
|
||||||
|
if DEVELOPMENT_MENU:
|
||||||
|
_()
|
||||||
|
|
||||||
|
if "auth" in locals():
|
||||||
|
auth.wikimenu()
|
||||||
|
|||||||
@@ -1,17 +1,28 @@
|
|||||||
; App configuration
|
; App configuration
|
||||||
|
[app]
|
||||||
|
name = Welcome
|
||||||
|
author = Your Name <you@example.com>
|
||||||
|
description = a cool new app
|
||||||
|
keywords = web2py, python, framework
|
||||||
|
generator = Web2py Web Framework
|
||||||
|
|
||||||
|
; Host configuration
|
||||||
|
[host]
|
||||||
|
names = localhost:*, 127.0.0.1:*, *:*, *
|
||||||
|
|
||||||
; db configuration
|
; db configuration
|
||||||
[db]
|
[db]
|
||||||
uri = sqlite://storage.sqlite
|
uri = sqlite://storage.sqlite
|
||||||
migrate = 1
|
migrate = true
|
||||||
pool_size = 1
|
pool_size = 10 ; ignored for sqlite
|
||||||
|
|
||||||
; smtp address and credentials
|
; smtp address and credentials
|
||||||
[smtp]
|
[smtp]
|
||||||
server = smtp.gmail.com:587
|
server = smtp.gmail.com:587
|
||||||
sender = you@gmail.com
|
sender = you@gmail.com
|
||||||
login = username:password
|
login = username:password
|
||||||
|
tls = true
|
||||||
|
ssl = true
|
||||||
|
|
||||||
; form styling
|
; form styling
|
||||||
[forms]
|
[forms]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
# This is an app-specific example router
|
# This is an app-specific example router
|
||||||
#
|
#
|
||||||
# This simple router is used for setting languages from app/languages directory
|
# This simple router is used for setting languages from app/languages directory
|
||||||
@@ -7,32 +8,34 @@
|
|||||||
# Language from default.py or 'en' (if the file is not found) is used as
|
# Language from default.py or 'en' (if the file is not found) is used as
|
||||||
# a default_language
|
# a default_language
|
||||||
#
|
#
|
||||||
# See <web2py-root-dir>/router.example.py for parameter's detail
|
# See <web2py-root-dir>/examples/routes.parametric.example.py for parameter's detail
|
||||||
#-------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
# To enable this route file you must do the steps:
|
# To enable this route file you must do the steps:
|
||||||
#
|
# 1. rename <web2py-root-dir>/examples/routes.parametric.example.py to routes.py
|
||||||
# 1. rename <web2py-root-dir>/router.example.py to routes.py
|
# 2. rename this APP/routes.example.py to APP/routes.py (where APP - is your application directory)
|
||||||
# 2. rename this APP/routes.example.py to APP/routes.py
|
# 3. restart web2py (or reload routes in web2py admin interface)
|
||||||
# (where APP - is your application directory)
|
|
||||||
# 3. restart web2py (or reload routes in web2py admin interfase)
|
|
||||||
#
|
#
|
||||||
# YOU CAN COPY THIS FILE TO ANY APPLICATION'S ROOT DIRECTORY WITHOUT CHANGES!
|
# YOU CAN COPY THIS FILE TO ANY APPLICATION'S ROOT DIRECTORY WITHOUT CHANGES!
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
from fileutils import abspath
|
from fileutils import abspath
|
||||||
from languages import read_possible_languages
|
from languages import read_possible_languages
|
||||||
|
|
||||||
possible_languages = read_possible_languages(abspath('applications', app))
|
possible_languages = read_possible_languages(abspath('applications', app))
|
||||||
#NOTE! app - is an application based router's parameter with name of an
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
# application. E.g.'welcome'
|
# NOTE! app - is an application based router's parameter with name of an application. E.g.'welcome'
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
routers = {
|
routers = {
|
||||||
app: dict(
|
app: dict(
|
||||||
default_language = possible_languages['default'][0],
|
default_language=possible_languages['default'][0],
|
||||||
languages = [lang for lang in possible_languages
|
languages=[lang for lang in possible_languages if lang != 'default']
|
||||||
if lang != 'default']
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#NOTE! To change language in your application using these rules add this line
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
#in one of your models files:
|
# NOTE! To change language in your application using these rules add this line in one of your models files:
|
||||||
|
# ----------------------------------------------------------------------------------------------------------------------
|
||||||
# if request.uri_language: T.force(request.uri_language)
|
# if request.uri_language: T.force(request.uri_language)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+11
-3
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
|||||||
div.flash {
|
div.w2p_flash {
|
||||||
background-image: none;
|
background-image: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
-o-border-radius: 4px;
|
-o-border-radius: 4px;
|
||||||
@@ -15,16 +15,18 @@ div.flash {
|
|||||||
margin: 0 0 20px;
|
margin: 0 0 20px;
|
||||||
padding: 15px 35px 15px 15px;
|
padding: 15px 35px 15px 15px;
|
||||||
}
|
}
|
||||||
div.flash.alert:hover {
|
div.w2p_flash.alert:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
.ie-lte8 div.flash {
|
.ie-lte8 div.w2p_flash {
|
||||||
filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0);
|
filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0);
|
||||||
}
|
}
|
||||||
.ie-lte8 div.flash:hover {
|
.ie-lte8 div.w2p_flash:hover {
|
||||||
filter: alpha(opacity=25);
|
filter: alpha(opacity=25);
|
||||||
}
|
}
|
||||||
|
.main-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
div.error {
|
div.error {
|
||||||
width: auto;
|
width: auto;
|
||||||
@@ -35,7 +37,7 @@ div.error {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
div.flash.alert {
|
div.w2p_flash.alert {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 70px;
|
top: 70px;
|
||||||
@@ -106,7 +108,7 @@ select.autocomplete {
|
|||||||
background: url(../images/background.jpg) no-repeat center center;
|
background: url(../images/background.jpg) no-repeat center center;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
padding-top: 50px;
|
padding-top: 60px;
|
||||||
margin-bottom: 60px;
|
margin-bottom: 60px;
|
||||||
}
|
}
|
||||||
header {
|
header {
|
||||||
@@ -134,7 +136,7 @@ header h1 {
|
|||||||
header .jumbotron {
|
header .jumbotron {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
.flash {
|
.w2p_flash {
|
||||||
opacity: 0.9!important;
|
opacity: 0.9!important;
|
||||||
right: 100px;
|
right: 100px;
|
||||||
}
|
}
|
||||||
@@ -231,7 +233,7 @@ div.error_wrapper {
|
|||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 3px 5px;
|
padding: 6px 12px;
|
||||||
}
|
}
|
||||||
.web2py_counter {
|
.web2py_counter {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
@@ -268,6 +270,7 @@ li.w2p_grid_breadcrumb_elem {
|
|||||||
.web2py_console select,
|
.web2py_console select,
|
||||||
.web2py_console a {
|
.web2py_console a {
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
|
padding: 6px 12px;
|
||||||
}
|
}
|
||||||
#wiki_page_body {
|
#wiki_page_body {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
@@ -283,6 +286,7 @@ li.w2p_grid_breadcrumb_elem {
|
|||||||
.web2py_console .form-control {
|
.web2py_console .form-control {
|
||||||
width: 20%;
|
width: 20%;
|
||||||
display: inline;
|
display: inline;
|
||||||
|
height: 32px;
|
||||||
}
|
}
|
||||||
.web2py_console #w2p_keywords {
|
.web2py_console #w2p_keywords {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
@@ -311,6 +315,3 @@ td.w2p_fc,
|
|||||||
input[type=checkbox], input[type=radio] {
|
input[type=checkbox], input[type=radio] {
|
||||||
margin: 4px 4px 0 0;
|
margin: 4px 4px 0 0;
|
||||||
}
|
}
|
||||||
.btn {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
@@ -33,7 +33,7 @@ audio {width:200px}
|
|||||||
[type="text"], [type="password"], select {
|
[type="text"], [type="password"], select {
|
||||||
margin-right: 5px; width: 300px;
|
margin-right: 5px; width: 300px;
|
||||||
}
|
}
|
||||||
.hidden {display:none;visibility:visible}
|
.w2p_hidden {display:none;visibility:visible}
|
||||||
.right {float:right; text-align:right}
|
.right {float:right; text-align:right}
|
||||||
.left {float:left; text-align:left}
|
.left {float:left; text-align:left}
|
||||||
.center {width:100%; text-align:center; vertical-align:middle}
|
.center {width:100%; text-align:center; vertical-align:middle}
|
||||||
@@ -88,7 +88,7 @@ div.w2p_export_menu a, div.w2p_wiki_tags a, div.w2p_cloud a {margin-left:5px; pa
|
|||||||
#web2py_user_form td {vertical-align:top}
|
#web2py_user_form td {vertical-align:top}
|
||||||
|
|
||||||
/*********** web2py specific ***********/
|
/*********** web2py specific ***********/
|
||||||
div.flash {
|
div.w2p_flash {
|
||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
display:none;
|
display:none;
|
||||||
position:fixed;
|
position:fixed;
|
||||||
@@ -117,11 +117,11 @@ div.flash {
|
|||||||
z-index:2000;
|
z-index:2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.flash #closeflash{color:inherit; float:right; margin-left:15px;}
|
div.w2p_flash #closeflash{color:inherit; float:right; margin-left:15px;}
|
||||||
.ie-lte7 div.flash #closeflash
|
.ie-lte7 div.flash #closeflash
|
||||||
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
|
{color:expression(this.parentNode.currentStyle['color']);float:none;position:absolute;right:4px;}
|
||||||
|
|
||||||
div.flash:hover { opacity:0.25; }
|
div.w2p_flash:hover { opacity:0.25; }
|
||||||
|
|
||||||
div.error_wrapper {display:block}
|
div.error_wrapper {display:block}
|
||||||
div.error {
|
div.error {
|
||||||
@@ -304,8 +304,8 @@ li.w2p_grid_breadcrumb_elem {
|
|||||||
/* fix some IE problems */
|
/* fix some IE problems */
|
||||||
|
|
||||||
.ie-lte7 .topbar .container {z-index:2}
|
.ie-lte7 .topbar .container {z-index:2}
|
||||||
.ie-lte8 div.flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
.ie-lte8 div.w2p_flash{ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#222222', endColorstr='#000000', GradientType=0 ); }
|
||||||
.ie-lte8 div.flash:hover {filter:alpha(opacity=25);}
|
.ie-lte8 div.w2p_flash:hover {filter:alpha(opacity=25);}
|
||||||
.ie9 #w2p_query_panel {padding-bottom:2px}
|
.ie9 #w2p_query_panel {padding-bottom:2px}
|
||||||
|
|
||||||
.web2py_console .form-control {width: 20%; display: inline;}
|
.web2py_console .form-control {width: 20%; display: inline;}
|
||||||
|
|||||||
+4
-4
File diff suppressed because one or more lines are too long
+5
-4
File diff suppressed because one or more lines are too long
@@ -6,9 +6,9 @@
|
|||||||
* this over and over... all will be bound to the document
|
* this over and over... all will be bound to the document
|
||||||
*/
|
*/
|
||||||
/*adds btn class to buttons*/
|
/*adds btn class to buttons*/
|
||||||
$('button', target).addClass('btn btn-default');
|
$('button:not([class^="btn"])', target).addClass('btn btn-default');
|
||||||
$("p.w2p-autocomplete-widget input").addClass('form-control');
|
$("p.w2p-autocomplete-widget input").addClass('form-control');
|
||||||
$('form input[type="submit"], form input[type="button"]', target).addClass('btn btn-default');
|
$('form input[type="submit"]:not([class^="btn"]), form input[type="button"]:not([class^="btn"])', target).addClass('btn btn-default');
|
||||||
/* javascript for PasswordWidget*/
|
/* javascript for PasswordWidget*/
|
||||||
$('input[type=password][data-w2p_entropy]', target).each(function() {
|
$('input[type=password][data-w2p_entropy]', target).each(function() {
|
||||||
web2py.validate_entropy($(this));
|
web2py.validate_entropy($(this));
|
||||||
@@ -18,9 +18,9 @@
|
|||||||
function pe(ul, e) {
|
function pe(ul, e) {
|
||||||
var new_line = ml(ul);
|
var new_line = ml(ul);
|
||||||
rel(ul);
|
rel(ul);
|
||||||
if ($(e.target).parent().is(':visible')) {
|
if ($(e.target).closest('li').is(':visible')) {
|
||||||
/* make sure we didn't delete the element before we insert after */
|
/* make sure we didn't delete the element before we insert after */
|
||||||
new_line.insertAfter($(e.target).parent());
|
new_line.insertAfter($(e.target).closest('li'));
|
||||||
} else {
|
} else {
|
||||||
/* the line we clicked on was deleted, just add to end of list */
|
/* the line we clicked on was deleted, just add to end of list */
|
||||||
new_line.appendTo(ul);
|
new_line.appendTo(ul);
|
||||||
@@ -30,9 +30,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function rl(ul, e) {
|
function rl(ul, e) {
|
||||||
if ($(ul).children().length > 1) {
|
if ($(ul).find('li').length > 1) {
|
||||||
/* only remove if we have more than 1 item so the list is never empty */
|
/* only remove if we have more than 1 item so the list is never empty */
|
||||||
$(e.target).parent().remove();
|
$(e.target).closest('li').remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,13 +46,13 @@
|
|||||||
function rel(ul) {
|
function rel(ul) {
|
||||||
/* keep only as many as needed*/
|
/* keep only as many as needed*/
|
||||||
$(ul).find("li").each(function() {
|
$(ul).find("li").each(function() {
|
||||||
var trimmed = $.trim($(this.firstChild).val());
|
var trimmed = $.trim($(this).find(":text").val());
|
||||||
if (trimmed == '') $(this).remove();
|
if (trimmed == '') $(this).remove();
|
||||||
else $(this.firstChild).val(trimmed);
|
else $(this).find(":text").val(trimmed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var ul = this;
|
var ul = this;
|
||||||
$(ul).find(":text").after('<a class="btn btn-default" href="#">+</a> <a class="btn btn-default" href="#">-</a>').keypress(function(e) {
|
$(ul).find(":text").addClass('form-control').wrap("<div class='input-group'></div>").after('<div class="input-group-addon"><i class="glyphicon glyphicon-plus"></i></div><div class="input-group-addon"><i class="glyphicon glyphicon-minus"></i></div>').keypress(function(e) {
|
||||||
return (e.which == 13) ? pe(ul, e) : true;
|
return (e.which == 13) ? pe(ul, e) : true;
|
||||||
}).next().click(function(e) {
|
}).next().click(function(e) {
|
||||||
pe(ul, e);
|
pe(ul, e);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -137,9 +137,9 @@
|
|||||||
<h4>{{=T("Overview")}}</h4>
|
<h4>{{=T("Overview")}}</h4>
|
||||||
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
|
<p>{{=T.M("Number of entries: **%s**", total['entries'])}}</p>
|
||||||
{{if total['entries'] > 0:}}
|
{{if total['entries'] > 0:}}
|
||||||
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses})",
|
<p>{{=T.M("Hit Ratio: **%(ratio)s%%** (**%(hits)s** %%{hit(hits)} and **%(misses)s** %%{miss(misses)})",
|
||||||
dict(ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
|
dict( ratio=total['ratio'], hits=total['hits'], misses=total['misses']))}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{=T("Size of cache:")}}
|
{{=T("Size of cache:")}}
|
||||||
{{if object_stats:}}
|
{{if object_stats:}}
|
||||||
@@ -155,8 +155,8 @@
|
|||||||
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("Cache contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
|
dict(hours=total['oldest'][0], min=total['oldest'][1], sec=total['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle();')}}
|
{{=BUTTON(T('Cache Keys'), _onclick='jQuery("#all_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="all_keys">
|
<div class="w2p_hidden" id="all_keys">
|
||||||
{{=total['keys']}}
|
{{=total['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -183,8 +183,8 @@
|
|||||||
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("RAM contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
|
dict(hours=ram['oldest'][0], min=ram['oldest'][1], sec=ram['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle();')}}
|
{{=BUTTON(T('RAM Cache Keys'), _onclick='jQuery("#ram_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="ram_keys">
|
<div class="w2p_hidden" id="ram_keys">
|
||||||
{{=ram['keys']}}
|
{{=ram['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -212,8 +212,8 @@
|
|||||||
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
{{=T.M("DISK contains items up to **%(hours)02d** %%{hour(hours)} **%(min)02d** %%{minute(min)} **%(sec)02d** %%{second(sec)} old.",
|
||||||
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
|
dict(hours=disk['oldest'][0], min=disk['oldest'][1], sec=disk['oldest'][2]))}}
|
||||||
</p>
|
</p>
|
||||||
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle();')}}
|
{{=BUTTON(T('Disk Cache Keys'), _onclick='jQuery("#disk_keys").toggle().toggleClass( "w2p_hidden" );')}}
|
||||||
<div class="hidden" id="disk_keys">
|
<div class="w2p_hidden" id="disk_keys">
|
||||||
{{=disk['keys']}}
|
{{=disk['keys']}}
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
@@ -249,8 +249,8 @@
|
|||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['png'])}}">png</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['svg'])}}">svg</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['pdf'])}}">pdf</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['ps'])}}">ps</a></li>
|
||||||
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
|
<li><a href="{{=URL('appadmin', 'bg_graph_model', args=['dot'])}}">dot</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
<meta name="google-site-verification" content="">
|
<meta name="google-site-verification" content="">
|
||||||
<!-- include stylesheets -->
|
<!-- include stylesheets -->
|
||||||
<link rel="stylesheet" href="{{=URL('static','css/bootstrap.min.css')}}"/>
|
<link rel="stylesheet" href="{{=URL('static','css/bootstrap.min.css')}}"/>
|
||||||
<link rel="stylesheet" href="{{=URL('static','css/bootstrap-theme.min.css')}}"/>
|
|
||||||
<link rel="stylesheet" href="{{=URL('static','css/web2py-bootstrap3.css')}}"/>
|
<link rel="stylesheet" href="{{=URL('static','css/web2py-bootstrap3.css')}}"/>
|
||||||
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
|
<link rel="shortcut icon" href="{{=URL('static','images/favicon.ico')}}" type="image/x-icon">
|
||||||
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
|
<link rel="apple-touch-icon" href="{{=URL('static','images/favicon.png')}}">
|
||||||
@@ -47,9 +46,9 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!--[if lt IE 8]><p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p><![endif]-->
|
<!--[if lt IE 8]><p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p><![endif]-->
|
||||||
<div class="flash alert alert-dismissable">{{=response.flash or ''}}</div>
|
<div class="w2p_flash alert alert-dismissable">{{=response.flash or ''}}</div>
|
||||||
<!-- Navbar ======================================= -->
|
<!-- Navbar ======================================= -->
|
||||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
@@ -75,7 +74,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
<!-- Main ========================================= -->
|
<!-- Main ========================================= -->
|
||||||
<!-- Begin page content -->
|
<!-- Begin page content -->
|
||||||
<div class="container-fluid">
|
<div class="container-fluid main-container">
|
||||||
{{if left_sidebar_enabled:}}
|
{{if left_sidebar_enabled:}}
|
||||||
<div class="col-md-3 left-sidebar">
|
<div class="col-md-3 left-sidebar">
|
||||||
{{block left_sidebar}}
|
{{block left_sidebar}}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
build: false
|
||||||
|
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- PYTHON: "C:/Python27"
|
||||||
|
COVERAGE_PROCESS_START: gluon/tests/coverage.ini
|
||||||
|
|
||||||
|
clone_depth: 50
|
||||||
|
|
||||||
|
init:
|
||||||
|
- "ECHO %PYTHON%"
|
||||||
|
- set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
|
||||||
|
|
||||||
|
install:
|
||||||
|
- ps: Start-FileDownload https://bootstrap.pypa.io/get-pip.py
|
||||||
|
- python get-pip.py
|
||||||
|
- pip install codecov
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- python web2py.py --run_system_tests --with_coverage
|
||||||
|
|
||||||
|
after_test:
|
||||||
|
- coverage combine
|
||||||
|
- codecov
|
||||||
@@ -120,7 +120,7 @@ args=()
|
|||||||
class=handlers.RotatingFileHandler
|
class=handlers.RotatingFileHandler
|
||||||
level=DEBUG
|
level=DEBUG
|
||||||
formatter=simpleFormatter
|
formatter=simpleFormatter
|
||||||
args=("logs/web2py.log", "a", 1000000, 5)
|
args=("web2py.log", "a", 1000000, 5)
|
||||||
|
|
||||||
[handler_osxSysLogHandler]
|
[handler_osxSysLogHandler]
|
||||||
class=handlers.SysLogHandler
|
class=handlers.SysLogHandler
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!-- app configuration for web2py on IIS -->
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="WSGI_HANDLER" value="gluon.main.wsgibase" />
|
||||||
|
<add key="WSGI_RESTART_FILE_REGEX" value=".*((routes\.py)|(\.config))$" />
|
||||||
|
</appSettings>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<clear />
|
||||||
|
<rule name="static" enabled="true" stopProcessing="true">
|
||||||
|
<match url="^(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$" />
|
||||||
|
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
|
||||||
|
<action type="Rewrite" url="applications/{R:1}/static/{R:2}" logRewrittenUrl="false" />
|
||||||
|
</rule>
|
||||||
|
<rule name="web2py_app" enabled="true" stopProcessing="true">
|
||||||
|
<match url="(.*)" ignoreCase="false" />
|
||||||
|
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
|
||||||
|
<action type="Rewrite" url="handler.web2py/{R:1}" appendQueryString="true" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
<outboundRules>
|
||||||
|
<rule name="static_version_cache_control" preCondition="static_version">
|
||||||
|
<match serverVariable="RESPONSE_Cache-Control" pattern=".*" />
|
||||||
|
<action type="Rewrite" value="max-age=315360000" />
|
||||||
|
<conditions>
|
||||||
|
</conditions>
|
||||||
|
</rule>
|
||||||
|
<rule name="static_version_Expires" preCondition="static_version">
|
||||||
|
<match serverVariable="RESPONSE_Expires" pattern=".*" />
|
||||||
|
<action type="Rewrite" value="Thu, 31 Dec 2037 23:59:59 GMT" />
|
||||||
|
</rule>
|
||||||
|
<preConditions>
|
||||||
|
<preCondition name="static_version">
|
||||||
|
<add input="{REQUEST_URI}" pattern="(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$" />
|
||||||
|
</preCondition>
|
||||||
|
</preConditions>
|
||||||
|
</outboundRules>
|
||||||
|
</rewrite>
|
||||||
|
<handlers>
|
||||||
|
<!-- replace SCRIPT_PROCESSOR with the configured handler for python -->
|
||||||
|
<add name="Python_via_FastCGI" path="handler.web2py" verb="*" modules="FastCgiModule" scriptProcessor="SCRIPT_PROCESSOR" resourceType="Unspecified" requireAccess="Script" />
|
||||||
|
</handlers>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
Vendored
+158
@@ -0,0 +1,158 @@
|
|||||||
|
from fabric.api import *
|
||||||
|
from fabric.operations import put, get
|
||||||
|
from fabric.contrib.files import exists
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
if os.path.exists('hosts'):
|
||||||
|
env.hosts = [h.strip() for h in open('hosts').readlines() if h.strip()]
|
||||||
|
|
||||||
|
env.hosts = env.hosts or raw_input('hostname (example.com):').split(',')
|
||||||
|
env.user = env.user or raw_input('username :')
|
||||||
|
|
||||||
|
INSTALL_SCRIPT = "setup-web2py-nginx-uwsgi-ubuntu.sh"
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
applications = '/home/www-data/web2py/applications'
|
||||||
|
|
||||||
|
def create_user(username):
|
||||||
|
"""fab -H root@host create_user:username"""
|
||||||
|
password = getpass.getpass(name+' password for %s> ' % username)
|
||||||
|
run('useradd -m %s' % username)
|
||||||
|
run('usermod --password %s %s' % (crypt.crypt(password, 'salt'), username))
|
||||||
|
run('mkdir -p ~%s/.ssh' % username)
|
||||||
|
run('cp /etc/sudoers /tmp/sudoers.new')
|
||||||
|
append('/tmp/sudoers.new', '%s ALL=NOPASSWD: ALL' % username, use_sudo=True)
|
||||||
|
run('visudo -c -f /tmp/sudoers.new')
|
||||||
|
run('EDITOR="cp /tmp/sudoers.new" visudo')
|
||||||
|
uncomment('~%s/.bashrc' % username, '#force_color_prompt=yes')
|
||||||
|
local('ssh-copy-id %s' % env.hosts[0])
|
||||||
|
|
||||||
|
def install_web2py():
|
||||||
|
"""fab -H username@host install_web2py"""
|
||||||
|
sudo('wget https://raw.githubusercontent.com/web2py/web2py/master/scripts/%s' % INSTALL_SCRIPT)
|
||||||
|
sudo('chmod +x %s' % INSTALL_SCRIPT)
|
||||||
|
sudo('./'+INSTALL_SCRIPT)
|
||||||
|
|
||||||
|
def start_webserver():
|
||||||
|
sudo('service nginx start')
|
||||||
|
sudo('start uwsgi-emperor')
|
||||||
|
sudo('start web2py-scheduler')
|
||||||
|
|
||||||
|
def stop_webserver():
|
||||||
|
sudo('stop uwsgi-emperor')
|
||||||
|
sudo('service nginx stop')
|
||||||
|
sudo('stop web2py-scheduler')
|
||||||
|
|
||||||
|
def restart_webserver():
|
||||||
|
stop_webserver()
|
||||||
|
start_webserver()
|
||||||
|
|
||||||
|
def notify(appname=None):
|
||||||
|
"""fab -H username@host notify:appname"""
|
||||||
|
appname = appname or os.path.split(os.getcwd())[-1]
|
||||||
|
appfolder = applications+'/'+appname
|
||||||
|
with cd(appfolder):
|
||||||
|
sudo('echo "response.flash = \'System Going Down For Maintenance\'" > models/flash_goingdown.py')
|
||||||
|
|
||||||
|
def down(appname=None):
|
||||||
|
"""fab -H username@host down:appname"""
|
||||||
|
appname = appname or os.path.split(os.getcwd())[-1]
|
||||||
|
appfolder = applications+'/'+appname
|
||||||
|
with cd(appfolder):
|
||||||
|
sudo('echo `date` > DISABLED')
|
||||||
|
sudo('rm -rf sessions/* || true')
|
||||||
|
|
||||||
|
def up(appname=None):
|
||||||
|
"""fab -H username@host up:appname"""
|
||||||
|
appname = appname or os.path.split(os.getcwd())[-1]
|
||||||
|
appfolder = applications+'/'+appname
|
||||||
|
with cd(appfolder):
|
||||||
|
if exists('modules/flash_goingdown.py'):
|
||||||
|
sudo('rm modules/flash_goingdown.py')
|
||||||
|
sudo('rm DISABLED')
|
||||||
|
|
||||||
|
def mkdir_or_backup(appname):
|
||||||
|
appfolder = applications+'/'+appname
|
||||||
|
if not exists(appfolder):
|
||||||
|
sudo('mkdir %s' % appfolder)
|
||||||
|
sudo('chown -R www-data:www-data %s' % appfolder)
|
||||||
|
backup = None
|
||||||
|
else:
|
||||||
|
dt = now.strftime('%y-%m-%d-%h-%m')
|
||||||
|
backup = '%s.%s.zip' % (appname, dt)
|
||||||
|
with cd(applications):
|
||||||
|
sudo('zip -r %s %s' % (backup, appname))
|
||||||
|
return backup
|
||||||
|
|
||||||
|
def git_deploy(appname, repo):
|
||||||
|
"""fab -H username@host git_deploy:appname,username/remoname"""
|
||||||
|
appfolder = applications+'/'+appname
|
||||||
|
backup = mkdir_or_backup(appname)
|
||||||
|
|
||||||
|
if exists(appfolder):
|
||||||
|
with cd(appfolder):
|
||||||
|
sudo('git pull origin master')
|
||||||
|
sudo('chown -R www-data:www-data *')
|
||||||
|
else:
|
||||||
|
with cd(applications):
|
||||||
|
sudo('git clone git@github.com/%s %s' % (repo, name))
|
||||||
|
sudo('chown -R www-data:www-data %s' % name)
|
||||||
|
|
||||||
|
def retrieve(appname=None):
|
||||||
|
"""fab -H username@host retrieve:appname"""
|
||||||
|
appname = appname or os.path.split(os.getcwd())[-1]
|
||||||
|
appfolder = applications+'/'+appname
|
||||||
|
filename = '%s.zip' % appname
|
||||||
|
with cd(appfolder):
|
||||||
|
sudo('zip -r /tmp/%s *' % filename)
|
||||||
|
get('/tmp/%s' % filename, filename)
|
||||||
|
sudo('rm /tmp/%s' % filename)
|
||||||
|
local('unzip %s' % filename)
|
||||||
|
local('rm %s' % filename)
|
||||||
|
|
||||||
|
def deploy(appname=None, all=False):
|
||||||
|
"""fab -H username@host deploy:appname,all"""
|
||||||
|
appname = appname or os.path.split(os.getcwd())[-1]
|
||||||
|
appfolder = applications+'/'+appname
|
||||||
|
zipfile = os.path.join(appfolder, '_update.zip')
|
||||||
|
if os.path.exists(zipfile):
|
||||||
|
os.unlink(zipfile)
|
||||||
|
|
||||||
|
backup = mkdir_or_backup(appname)
|
||||||
|
|
||||||
|
if all=='all' or not backup:
|
||||||
|
local('zip -r _update.zip * -x *~ -x .* -x \#* -x *.bak -x *.bak2')
|
||||||
|
else:
|
||||||
|
local('zip -r _update.zip */*.py views/*.html views/*/*.html static/*')
|
||||||
|
|
||||||
|
put('_update.zip','/tmp/_update.zip')
|
||||||
|
try:
|
||||||
|
with cd(appfolder):
|
||||||
|
sudo('unzip -o /tmp/_update.zip')
|
||||||
|
sudo('chown -R www-data:www-data *')
|
||||||
|
sudo('echo "%s" > DATE_DEPLOYMENT' % now)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
sudo('rm /tmp/_update.zip')
|
||||||
|
|
||||||
|
if backup:
|
||||||
|
print 'TO RESTORE: fab restore:%s' % backup
|
||||||
|
|
||||||
|
def restore(backup):
|
||||||
|
"""fab -H username@host restore:backupfilename"""
|
||||||
|
appname = backup.split('/')[-1].split('.')[0]
|
||||||
|
appfolder = applications + '/' + appname
|
||||||
|
with cd(appfolder):
|
||||||
|
sudo('rm -r *')
|
||||||
|
with cd(applications):
|
||||||
|
sudo('unzip %s' % backup)
|
||||||
|
sudo('chown -R www-data:www-data %s' % appname)
|
||||||
|
|
||||||
|
def cleanup(appname):
|
||||||
|
appname = appname or os.path.split(os.getcwd())[-1]
|
||||||
|
appfolder = applications + '/' + appname
|
||||||
|
with cd(appfolder):
|
||||||
|
sudo('rm -rf sessions/* || true')
|
||||||
|
sudo('rm -rf errors/* || true')
|
||||||
|
sudo('rm -rf cache/* || true')
|
||||||
+11
-9
@@ -59,6 +59,8 @@ def app_pack(app, request, raise_ex=False, filenames=None):
|
|||||||
w2p_pack(filename, apath(app, request), filenames=filenames)
|
w2p_pack(filename, apath(app, request), filenames=filenames)
|
||||||
return filename
|
return filename
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
import traceback
|
||||||
|
print traceback.format_exc()
|
||||||
if raise_ex:
|
if raise_ex:
|
||||||
raise
|
raise
|
||||||
return False
|
return False
|
||||||
@@ -114,22 +116,22 @@ def app_cleanup(app, request):
|
|||||||
for f in os.listdir(path):
|
for f in os.listdir(path):
|
||||||
try:
|
try:
|
||||||
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
|
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
|
||||||
except IOError:
|
except (OSError, IOError):
|
||||||
r = False
|
r = False
|
||||||
|
|
||||||
# Remove cache files
|
# Remove cache files
|
||||||
CacheOnDisk(folder=apath('%s/cache/' % app, request)).clear()
|
|
||||||
path = apath('%s/cache/' % app, request)
|
path = apath('%s/cache/' % app, request)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
CacheOnDisk(folder=path).clear()
|
||||||
for f in os.listdir(path):
|
for f in os.listdir(path):
|
||||||
try:
|
try:
|
||||||
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
|
if f[:1] != '.': recursive_unlink(os.path.join(path, f))
|
||||||
except IOError:
|
except (OSError, IOError):
|
||||||
r = False
|
r = False
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def app_compile(app, request):
|
def app_compile(app, request, skip_failed_views=False):
|
||||||
"""Compiles the application
|
"""Compiles the application
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -143,10 +145,10 @@ def app_compile(app, request):
|
|||||||
from compileapp import compile_application, remove_compiled_application
|
from compileapp import compile_application, remove_compiled_application
|
||||||
folder = apath(app, request)
|
folder = apath(app, request)
|
||||||
try:
|
try:
|
||||||
compile_application(folder)
|
failed_views = compile_application(folder, skip_failed_views)
|
||||||
return None
|
return failed_views
|
||||||
except (Exception, RestrictedError):
|
except (Exception, RestrictedError):
|
||||||
tb = traceback.format_exc(sys.exc_info)
|
tb = traceback.format_exc()
|
||||||
remove_compiled_application(folder)
|
remove_compiled_application(folder)
|
||||||
return tb
|
return tb
|
||||||
|
|
||||||
@@ -165,7 +167,7 @@ def app_create(app, request, force=False, key=None, info=False):
|
|||||||
os.mkdir(path)
|
os.mkdir(path)
|
||||||
except:
|
except:
|
||||||
if info:
|
if info:
|
||||||
return False, traceback.format_exc(sys.exc_info)
|
return False, traceback.format_exc()
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
elif not force:
|
elif not force:
|
||||||
@@ -195,7 +197,7 @@ def app_create(app, request, force=False, key=None, info=False):
|
|||||||
except:
|
except:
|
||||||
rmtree(path)
|
rmtree(path)
|
||||||
if info:
|
if info:
|
||||||
return False, traceback.format_exc(sys.exc_info)
|
return False, traceback.format_exc()
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
+59
-63
@@ -44,9 +44,9 @@ except ImportError:
|
|||||||
have_settings = False
|
have_settings = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
except:
|
except:
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import psutil
|
import psutil
|
||||||
@@ -54,11 +54,12 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
HAVE_PSUTIL = False
|
HAVE_PSUTIL = False
|
||||||
|
|
||||||
|
|
||||||
def remove_oldest_entries(storage, percentage=90):
|
def remove_oldest_entries(storage, percentage=90):
|
||||||
# compute current memory usage (%)
|
# compute current memory usage (%)
|
||||||
old_mem = psutil.virtual_memory().percent
|
old_mem = psutil.virtual_memory().percent
|
||||||
# if we have data in storage and utilization exceeds 90%
|
# if we have data in storage and utilization exceeds 90%
|
||||||
while storage and old_mem > percentage:
|
while storage and old_mem > percentage:
|
||||||
# removed oldest entry
|
# removed oldest entry
|
||||||
storage.popitem(last=False)
|
storage.popitem(last=False)
|
||||||
# garbage collect
|
# garbage collect
|
||||||
@@ -66,7 +67,8 @@ def remove_oldest_entries(storage, percentage=90):
|
|||||||
# comute used memory again
|
# comute used memory again
|
||||||
new_mem = psutil.virtual_memory().percent
|
new_mem = psutil.virtual_memory().percent
|
||||||
# if the used memory did not decrease stop
|
# if the used memory did not decrease stop
|
||||||
if new_mem >= old_mem: break
|
if new_mem >= old_mem:
|
||||||
|
break
|
||||||
# net new measurement for memory usage and loop
|
# net new measurement for memory usage and loop
|
||||||
old_mem = new_mem
|
old_mem = new_mem
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ __all__ = ['Cache', 'lazy_cache']
|
|||||||
|
|
||||||
DEFAULT_TIME_EXPIRE = 300
|
DEFAULT_TIME_EXPIRE = 300
|
||||||
|
|
||||||
|
|
||||||
class CacheAbstract(object):
|
class CacheAbstract(object):
|
||||||
"""
|
"""
|
||||||
Abstract class for cache implementations.
|
Abstract class for cache implementations.
|
||||||
@@ -99,7 +102,7 @@ class CacheAbstract(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
cache_stats_name = 'web2py_cache_statistics'
|
cache_stats_name = 'web2py_cache_statistics'
|
||||||
max_ram_utilization = 90 # percent
|
max_ram_utilization = None # percent
|
||||||
|
|
||||||
def __init__(self, request=None):
|
def __init__(self, request=None):
|
||||||
"""Initializes the object
|
"""Initializes the object
|
||||||
@@ -182,13 +185,14 @@ class CacheInRam(CacheAbstract):
|
|||||||
self.request = request
|
self.request = request
|
||||||
self.storage = OrderedDict() if HAVE_PSUTIL else {}
|
self.storage = OrderedDict() if HAVE_PSUTIL else {}
|
||||||
self.app = request.application if request else ''
|
self.app = request.application if request else ''
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if self.initialized:
|
if self.initialized:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.initialized = True
|
self.initialized = True
|
||||||
self.locker.acquire()
|
self.locker.acquire()
|
||||||
if not self.app in self.meta_storage:
|
if self.app not in self.meta_storage:
|
||||||
self.storage = self.meta_storage[self.app] = \
|
self.storage = self.meta_storage[self.app] = \
|
||||||
OrderedDict() if HAVE_PSUTIL else {}
|
OrderedDict() if HAVE_PSUTIL else {}
|
||||||
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
|
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
|
||||||
@@ -205,7 +209,7 @@ class CacheInRam(CacheAbstract):
|
|||||||
else:
|
else:
|
||||||
self._clear(storage, regex)
|
self._clear(storage, regex)
|
||||||
|
|
||||||
if not self.app in self.stats:
|
if self.app not in self.stats:
|
||||||
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
|
self.stats[self.app] = {'hit_total': 0, 'misses': 0}
|
||||||
|
|
||||||
self.locker.release()
|
self.locker.release()
|
||||||
@@ -251,8 +255,8 @@ class CacheInRam(CacheAbstract):
|
|||||||
self.locker.acquire()
|
self.locker.acquire()
|
||||||
self.storage[key] = (now, value)
|
self.storage[key] = (now, value)
|
||||||
self.stats[self.app]['misses'] += 1
|
self.stats[self.app]['misses'] += 1
|
||||||
if HAVE_PSUTIL and self.max_ram_utilization!=None and random.random()<0.10:
|
if HAVE_PSUTIL and self.max_ram_utilization is not None and random.random() < 0.10:
|
||||||
remove_oldest_entries(self.storage, percentage = self.max_ram_utilization)
|
remove_oldest_entries(self.storage, percentage=self.max_ram_utilization)
|
||||||
self.locker.release()
|
self.locker.release()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@@ -292,14 +296,15 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
self.folder = folder
|
self.folder = folder
|
||||||
self.key_filter_in = lambda key: key
|
self.key_filter_in = lambda key: key
|
||||||
self.key_filter_out = lambda key: key
|
self.key_filter_out = lambda key: key
|
||||||
self.file_lock_time_wait = file_lock_time_wait # How long we should wait before retrying to lock a file held by another process
|
self.file_lock_time_wait = file_lock_time_wait
|
||||||
|
# How long we should wait before retrying to lock a file held by another process
|
||||||
# We still need a mutex for each file as portalocker only blocks other processes
|
# We still need a mutex for each file as portalocker only blocks other processes
|
||||||
self.file_locks = defaultdict(thread.allocate_lock)
|
self.file_locks = defaultdict(thread.allocate_lock)
|
||||||
|
|
||||||
|
|
||||||
# Make sure we use valid filenames.
|
# Make sure we use valid filenames.
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
def key_filter_in_windows(key):
|
def key_filter_in_windows(key):
|
||||||
"""
|
"""
|
||||||
Windows doesn't allow \ / : * ? "< > | in filenames.
|
Windows doesn't allow \ / : * ? "< > | in filenames.
|
||||||
@@ -316,7 +321,6 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
self.key_filter_in = key_filter_in_windows
|
self.key_filter_in = key_filter_in_windows
|
||||||
self.key_filter_out = key_filter_out_windows
|
self.key_filter_out = key_filter_out_windows
|
||||||
|
|
||||||
|
|
||||||
def wait_portalock(self, val_file):
|
def wait_portalock(self, val_file):
|
||||||
"""
|
"""
|
||||||
Wait for the process file lock.
|
Wait for the process file lock.
|
||||||
@@ -328,15 +332,12 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
except:
|
except:
|
||||||
time.sleep(self.file_lock_time_wait)
|
time.sleep(self.file_lock_time_wait)
|
||||||
|
|
||||||
|
|
||||||
def acquire(self, key):
|
def acquire(self, key):
|
||||||
self.file_locks[key].acquire()
|
self.file_locks[key].acquire()
|
||||||
|
|
||||||
|
|
||||||
def release(self, key):
|
def release(self, key):
|
||||||
self.file_locks[key].release()
|
self.file_locks[key].release()
|
||||||
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
key = self.key_filter_in(key)
|
key = self.key_filter_in(key)
|
||||||
val_file = recfile.open(key, mode='wb', path=self.folder)
|
val_file = recfile.open(key, mode='wb', path=self.folder)
|
||||||
@@ -344,7 +345,6 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
pickle.dump(value, val_file, pickle.HIGHEST_PROTOCOL)
|
pickle.dump(value, val_file, pickle.HIGHEST_PROTOCOL)
|
||||||
val_file.close()
|
val_file.close()
|
||||||
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
key = self.key_filter_in(key)
|
key = self.key_filter_in(key)
|
||||||
try:
|
try:
|
||||||
@@ -353,16 +353,14 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
self.wait_portalock(val_file)
|
self.wait_portalock(val_file)
|
||||||
value = pickle.load(recfile.open(key, 'rb', path=self.folder))
|
value = pickle.load(val_file)
|
||||||
val_file.close()
|
val_file.close()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
key = self.key_filter_in(key)
|
key = self.key_filter_in(key)
|
||||||
return (key in self.file_locks) or recfile.exists(key, path=self.folder)
|
return (key in self.file_locks) or recfile.exists(key, path=self.folder)
|
||||||
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
key = self.key_filter_in(key)
|
key = self.key_filter_in(key)
|
||||||
try:
|
try:
|
||||||
@@ -370,15 +368,13 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
except IOError:
|
except IOError:
|
||||||
raise KeyError
|
raise KeyError
|
||||||
|
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for dirpath, dirnames, filenames in os.walk(self.folder):
|
for dirpath, dirnames, filenames in os.walk(self.folder):
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
yield self.key_filter_out(filename)
|
yield self.key_filter_out(filename)
|
||||||
|
|
||||||
|
|
||||||
def safe_apply(self, key, function, default_value=None):
|
def safe_apply(self, key, function, default_value=None):
|
||||||
"""
|
"""
|
||||||
Safely apply a function to the value of a key in storage and set
|
Safely apply a function to the value of a key in storage and set
|
||||||
the return value of the function to it.
|
the return value of the function to it.
|
||||||
|
|
||||||
@@ -403,25 +399,21 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
val_file.close()
|
val_file.close()
|
||||||
return new_value
|
return new_value
|
||||||
|
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return list(self.__iter__())
|
return list(self.__iter__())
|
||||||
|
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
try:
|
try:
|
||||||
return self[key]
|
return self[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, request=None, folder=None):
|
def __init__(self, request=None, folder=None):
|
||||||
self.initialized = False
|
self.initialized = False
|
||||||
self.request = request
|
self.request = request
|
||||||
self.folder = folder
|
self.folder = folder
|
||||||
self.storage = None
|
self.storage = None
|
||||||
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if self.initialized:
|
if self.initialized:
|
||||||
return
|
return
|
||||||
@@ -440,7 +432,6 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
|
|
||||||
self.storage = CacheOnDisk.PersistentStorage(folder)
|
self.storage = CacheOnDisk.PersistentStorage(folder)
|
||||||
|
|
||||||
|
|
||||||
def __call__(self, key, f,
|
def __call__(self, key, f,
|
||||||
time_expire=DEFAULT_TIME_EXPIRE):
|
time_expire=DEFAULT_TIME_EXPIRE):
|
||||||
self.initialize()
|
self.initialize()
|
||||||
@@ -473,16 +464,20 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
if item and ((dt is None) or (item[0] > now - dt)):
|
if item and ((dt is None) or (item[0] > now - dt)):
|
||||||
value = item[1]
|
value = item[1]
|
||||||
else:
|
else:
|
||||||
value = f()
|
try:
|
||||||
|
value = f()
|
||||||
|
except:
|
||||||
|
self.storage.release(CacheAbstract.cache_stats_name)
|
||||||
|
self.storage.release(key)
|
||||||
|
raise
|
||||||
self.storage[key] = (now, value)
|
self.storage[key] = (now, value)
|
||||||
self.storage.safe_apply(CacheAbstract.cache_stats_name, inc_misses,
|
self.storage.safe_apply(CacheAbstract.cache_stats_name, inc_misses,
|
||||||
default_value={'hit_total': 0, 'misses': 0})
|
default_value={'hit_total': 0, 'misses': 0})
|
||||||
|
|
||||||
self.storage.release(CacheAbstract.cache_stats_name)
|
self.storage.release(CacheAbstract.cache_stats_name)
|
||||||
self.storage.release(key)
|
self.storage.release(key)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def clear(self, regex=None):
|
def clear(self, regex=None):
|
||||||
self.initialize()
|
self.initialize()
|
||||||
storage = self.storage
|
storage = self.storage
|
||||||
@@ -499,7 +494,6 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
pass
|
pass
|
||||||
storage.release(key)
|
storage.release(key)
|
||||||
|
|
||||||
|
|
||||||
def increment(self, key, value=1):
|
def increment(self, key, value=1):
|
||||||
self.initialize()
|
self.initialize()
|
||||||
self.storage.acquire(key)
|
self.storage.acquire(key)
|
||||||
@@ -508,7 +502,6 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CacheAction(object):
|
class CacheAction(object):
|
||||||
def __init__(self, func, key, time_expire, cache, cache_model):
|
def __init__(self, func, key, time_expire, cache, cache_model):
|
||||||
self.__name__ = func.__name__
|
self.__name__ = func.__name__
|
||||||
@@ -567,9 +560,9 @@ class Cache(object):
|
|||||||
logger.warning('no cache.disk (AttributeError)')
|
logger.warning('no cache.disk (AttributeError)')
|
||||||
|
|
||||||
def action(self, time_expire=DEFAULT_TIME_EXPIRE, cache_model=None,
|
def action(self, time_expire=DEFAULT_TIME_EXPIRE, cache_model=None,
|
||||||
prefix=None, session=False, vars=True, lang=True,
|
prefix=None, session=False, vars=True, lang=True,
|
||||||
user_agent=False, public=True, valid_statuses=None,
|
user_agent=False, public=True, valid_statuses=None,
|
||||||
quick=None):
|
quick=None):
|
||||||
"""Better fit for caching an action
|
"""Better fit for caching an action
|
||||||
|
|
||||||
Warning:
|
Warning:
|
||||||
@@ -597,28 +590,34 @@ class Cache(object):
|
|||||||
"""
|
"""
|
||||||
from gluon import current
|
from gluon import current
|
||||||
from gluon.http import HTTP
|
from gluon.http import HTTP
|
||||||
|
|
||||||
def wrap(func):
|
def wrap(func):
|
||||||
def wrapped_f():
|
def wrapped_f():
|
||||||
if current.request.env.request_method != 'GET':
|
if current.request.env.request_method != 'GET':
|
||||||
return func()
|
return func()
|
||||||
|
|
||||||
|
if quick:
|
||||||
|
session_ = True if 'S' in quick else False
|
||||||
|
vars_ = True if 'V' in quick else False
|
||||||
|
lang_ = True if 'L' in quick else False
|
||||||
|
user_agent_ = True if 'U' in quick else False
|
||||||
|
public_ = True if 'P' in quick else False
|
||||||
|
else:
|
||||||
|
(session_, vars_, lang_, user_agent_, public_) = \
|
||||||
|
(session, vars, lang, user_agent, public)
|
||||||
|
|
||||||
if time_expire:
|
if time_expire:
|
||||||
cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict(time_expire=time_expire)
|
cache_control = 'max-age=%(time_expire)s, s-maxage=%(time_expire)s' % dict(time_expire=time_expire)
|
||||||
if quick:
|
|
||||||
session_ = True if 'S' in quick else False
|
|
||||||
vars_ = True if 'V' in quick else False
|
|
||||||
lang_ = True if 'L' in quick else False
|
|
||||||
user_agent_ = True if 'U' in quick else False
|
|
||||||
public_ = True if 'P' in quick else False
|
|
||||||
else:
|
|
||||||
session_, vars_, lang_, user_agent_, public_ = session, vars, lang, user_agent, public
|
|
||||||
if not session_ and public_:
|
if not session_ and public_:
|
||||||
cache_control += ', public'
|
cache_control += ', public'
|
||||||
expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)).strftime('%a, %d %b %Y %H:%M:%S GMT')
|
expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)
|
||||||
|
).strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||||
else:
|
else:
|
||||||
cache_control += ', private'
|
cache_control += ', private'
|
||||||
expires = 'Fri, 01 Jan 1990 00:00:00 GMT'
|
expires = 'Fri, 01 Jan 1990 00:00:00 GMT'
|
||||||
|
|
||||||
if cache_model:
|
if cache_model:
|
||||||
#figure out the correct cache key
|
# figure out the correct cache key
|
||||||
cache_key = [current.request.env.path_info, current.response.view]
|
cache_key = [current.request.env.path_info, current.response.view]
|
||||||
if session_:
|
if session_:
|
||||||
cache_key.append(current.response.session_id)
|
cache_key.append(current.response.session_id)
|
||||||
@@ -635,28 +634,28 @@ class Cache(object):
|
|||||||
if prefix:
|
if prefix:
|
||||||
cache_key = prefix + cache_key
|
cache_key = prefix + cache_key
|
||||||
try:
|
try:
|
||||||
#action returns something
|
# action returns something
|
||||||
rtn = cache_model(cache_key, lambda : func(), time_expire=time_expire)
|
rtn = cache_model(cache_key, lambda: func(), time_expire=time_expire)
|
||||||
http, status = None, current.response.status
|
http, status = None, current.response.status
|
||||||
except HTTP, e:
|
except HTTP, e:
|
||||||
#action raises HTTP (can still be valid)
|
# action raises HTTP (can still be valid)
|
||||||
rtn = cache_model(cache_key, lambda : e.body, time_expire=time_expire)
|
rtn = cache_model(cache_key, lambda: e.body, time_expire=time_expire)
|
||||||
http, status = HTTP(e.status, rtn, **e.headers), e.status
|
http, status = HTTP(e.status, rtn, **e.headers), e.status
|
||||||
else:
|
else:
|
||||||
#action raised a generic exception
|
# action raised a generic exception
|
||||||
http = None
|
http = None
|
||||||
else:
|
else:
|
||||||
#no server-cache side involved
|
# no server-cache side involved
|
||||||
try:
|
try:
|
||||||
#action returns something
|
# action returns something
|
||||||
rtn = func()
|
rtn = func()
|
||||||
http, status = None, current.response.status
|
http, status = None, current.response.status
|
||||||
except HTTP, e:
|
except HTTP, e:
|
||||||
#action raises HTTP (can still be valid)
|
# action raises HTTP (can still be valid)
|
||||||
status = e.status
|
status = e.status
|
||||||
http = HTTP(e.status, e.body, **e.headers)
|
http = HTTP(e.status, e.body, **e.headers)
|
||||||
else:
|
else:
|
||||||
#action raised a generic exception
|
# action raised a generic exception
|
||||||
http = None
|
http = None
|
||||||
send_headers = False
|
send_headers = False
|
||||||
if http and isinstance(valid_statuses, list):
|
if http and isinstance(valid_statuses, list):
|
||||||
@@ -666,15 +665,13 @@ class Cache(object):
|
|||||||
if str(status)[0] in '123':
|
if str(status)[0] in '123':
|
||||||
send_headers = True
|
send_headers = True
|
||||||
if send_headers:
|
if send_headers:
|
||||||
headers = {
|
headers = {'Pragma': None,
|
||||||
'Pragma' : None,
|
'Expires': expires,
|
||||||
'Expires' : expires,
|
'Cache-Control': cache_control}
|
||||||
'Cache-Control' : cache_control
|
|
||||||
}
|
|
||||||
current.response.headers.update(headers)
|
current.response.headers.update(headers)
|
||||||
if cache_model and not send_headers:
|
if cache_model and not send_headers:
|
||||||
#we cached already the value, but the status is not valid
|
# we cached already the value, but the status is not valid
|
||||||
#so we need to delete the cached value
|
# so we need to delete the cached value
|
||||||
cache_model(cache_key, None)
|
cache_model(cache_key, None)
|
||||||
if http:
|
if http:
|
||||||
if send_headers:
|
if send_headers:
|
||||||
@@ -731,8 +728,7 @@ class Cache(object):
|
|||||||
allow replacing cache.ram with cache.with_prefix(cache.ram,'prefix')
|
allow replacing cache.ram with cache.with_prefix(cache.ram,'prefix')
|
||||||
it will add prefix to all the cache keys used.
|
it will add prefix to all the cache keys used.
|
||||||
"""
|
"""
|
||||||
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix:\
|
return lambda key, f, time_expire=DEFAULT_TIME_EXPIRE, prefix=prefix: cache_model(prefix + key, f, time_expire)
|
||||||
cache_model(prefix + key, f, time_expire)
|
|
||||||
|
|
||||||
|
|
||||||
def lazy_cache(key=None, time_expire=None, cache_model='ram'):
|
def lazy_cache(key=None, time_expire=None, cache_model='ram'):
|
||||||
|
|||||||
+46
-42
@@ -261,7 +261,7 @@ class LoadFactory(object):
|
|||||||
import globals
|
import globals
|
||||||
target = target or 'c' + str(random.random())[2:]
|
target = target or 'c' + str(random.random())[2:]
|
||||||
attr['_id'] = target
|
attr['_id'] = target
|
||||||
request = self.environment['request']
|
request = current.request
|
||||||
if '.' in f:
|
if '.' in f:
|
||||||
f, extension = f.rsplit('.', 1)
|
f, extension = f.rsplit('.', 1)
|
||||||
if url or ajax:
|
if url or ajax:
|
||||||
@@ -464,22 +464,28 @@ def read_pyc(filename):
|
|||||||
return marshal.loads(data[8:])
|
return marshal.loads(data[8:])
|
||||||
|
|
||||||
|
|
||||||
def compile_views(folder):
|
def compile_views(folder, skip_failed_views=False):
|
||||||
"""
|
"""
|
||||||
Compiles all the views in the application specified by `folder`
|
Compiles all the views in the application specified by `folder`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
path = pjoin(folder, 'views')
|
path = pjoin(folder, 'views')
|
||||||
|
failed_views = []
|
||||||
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
|
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
|
||||||
try:
|
try:
|
||||||
data = parse_template(fname, path)
|
data = parse_template(fname, path)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
raise Exception("%s in %s" % (e, fname))
|
if skip_failed_views:
|
||||||
filename = 'views.%s.py' % fname.replace(os.path.sep, '.')
|
failed_views.append(fname)
|
||||||
filename = pjoin(folder, 'compiled', filename)
|
else:
|
||||||
write_file(filename, data)
|
raise Exception("%s in %s" % (e, fname))
|
||||||
save_pyc(filename)
|
else:
|
||||||
os.unlink(filename)
|
filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_')
|
||||||
|
filename = pjoin(folder, 'compiled', filename)
|
||||||
|
write_file(filename, data)
|
||||||
|
save_pyc(filename)
|
||||||
|
os.unlink(filename)
|
||||||
|
return failed_views if failed_views else None
|
||||||
|
|
||||||
|
|
||||||
def compile_models(folder):
|
def compile_models(folder):
|
||||||
@@ -532,10 +538,11 @@ def run_models_in(environment):
|
|||||||
It tries pre-compiled models first before compiling them.
|
It tries pre-compiled models first before compiling them.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
folder = environment['request'].folder
|
request = current.request
|
||||||
c = environment['request'].controller
|
folder = request.folder
|
||||||
|
c = request.controller
|
||||||
#f = environment['request'].function
|
#f = environment['request'].function
|
||||||
response = environment['response']
|
response = current.response
|
||||||
|
|
||||||
path = pjoin(folder, 'models')
|
path = pjoin(folder, 'models')
|
||||||
cpath = pjoin(folder, 'compiled')
|
cpath = pjoin(folder, 'compiled')
|
||||||
@@ -577,7 +584,7 @@ def run_controller_in(controller, function, environment):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# if compiled should run compiled!
|
# if compiled should run compiled!
|
||||||
folder = environment['request'].folder
|
folder = current.request.folder
|
||||||
path = pjoin(folder, 'compiled')
|
path = pjoin(folder, 'compiled')
|
||||||
badc = 'invalid controller (%s/%s)' % (controller, function)
|
badc = 'invalid controller (%s/%s)' % (controller, function)
|
||||||
badf = 'invalid function (%s/%s)' % (controller, function)
|
badf = 'invalid function (%s/%s)' % (controller, function)
|
||||||
@@ -631,7 +638,7 @@ def run_controller_in(controller, function, environment):
|
|||||||
layer = filename + ':' + function
|
layer = filename + ':' + function
|
||||||
code = getcfs(layer, filename, lambda: compile2(code, layer))
|
code = getcfs(layer, filename, lambda: compile2(code, layer))
|
||||||
restricted(code, environment, filename)
|
restricted(code, environment, filename)
|
||||||
response = environment['response']
|
response = current.response
|
||||||
vars = response._vars
|
vars = response._vars
|
||||||
if response.postprocessing:
|
if response.postprocessing:
|
||||||
vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars)
|
vars = reduce(lambda vars, p: p(vars), response.postprocessing, vars)
|
||||||
@@ -649,9 +656,9 @@ def run_view_in(environment):
|
|||||||
or `view/generic.extension`
|
or `view/generic.extension`
|
||||||
It tries the pre-compiled views_controller_function.pyc before compiling it.
|
It tries the pre-compiled views_controller_function.pyc before compiling it.
|
||||||
"""
|
"""
|
||||||
request = environment['request']
|
request = current.request
|
||||||
response = environment['response']
|
response = current.response
|
||||||
view = response.view
|
view = environment['response'].view
|
||||||
folder = request.folder
|
folder = request.folder
|
||||||
path = pjoin(folder, 'compiled')
|
path = pjoin(folder, 'compiled')
|
||||||
badv = 'invalid view (%s)' % view
|
badv = 'invalid view (%s)' % view
|
||||||
@@ -666,32 +673,28 @@ def run_view_in(environment):
|
|||||||
ccode = parse_template(view, pjoin(folder, 'views'),
|
ccode = parse_template(view, pjoin(folder, 'views'),
|
||||||
context=environment)
|
context=environment)
|
||||||
restricted(ccode, environment, 'file stream')
|
restricted(ccode, environment, 'file stream')
|
||||||
elif os.path.exists(path):
|
|
||||||
x = view.replace('/', '.')
|
|
||||||
files = ['views.%s.pyc' % x]
|
|
||||||
if allow_generic:
|
|
||||||
files.append('views.generic.%s.pyc' % request.extension)
|
|
||||||
# for backward compatibility
|
|
||||||
x = view.replace('/', '_')
|
|
||||||
files.append('views_%s.pyc' % x)
|
|
||||||
if allow_generic:
|
|
||||||
files.append('views_generic.%s.pyc' % request.extension)
|
|
||||||
if request.extension == 'html':
|
|
||||||
files.append('views_%s.pyc' % x[:-5])
|
|
||||||
if allow_generic:
|
|
||||||
files.append('views_generic.pyc')
|
|
||||||
# end backward compatibility code
|
|
||||||
for f in files:
|
|
||||||
filename = pjoin(path, f)
|
|
||||||
if os.path.exists(filename):
|
|
||||||
code = read_pyc(filename)
|
|
||||||
restricted(code, environment, layer=filename)
|
|
||||||
return
|
|
||||||
raise HTTP(404,
|
|
||||||
rewrite.THREAD_LOCAL.routes.error_message % badv,
|
|
||||||
web2py_error=badv)
|
|
||||||
else:
|
else:
|
||||||
filename = pjoin(folder, 'views', view)
|
filename = pjoin(folder, 'views', view)
|
||||||
|
if os.path.exists(path): # compiled views
|
||||||
|
x = view.replace('/', '_')
|
||||||
|
files = ['views_%s.pyc' % x]
|
||||||
|
is_compiled = os.path.exists(pjoin(path, files[0]))
|
||||||
|
# Don't use a generic view if the non-compiled view exists.
|
||||||
|
if is_compiled or (not is_compiled and not os.path.exists(filename)):
|
||||||
|
if allow_generic:
|
||||||
|
files.append('views_generic.%s.pyc' % request.extension)
|
||||||
|
# for backward compatibility
|
||||||
|
if request.extension == 'html':
|
||||||
|
files.append('views_%s.pyc' % x[:-5])
|
||||||
|
if allow_generic:
|
||||||
|
files.append('views_generic.pyc')
|
||||||
|
# end backward compatibility code
|
||||||
|
for f in files:
|
||||||
|
compiled = pjoin(path, f)
|
||||||
|
if os.path.exists(compiled):
|
||||||
|
code = read_pyc(compiled)
|
||||||
|
restricted(code, environment, layer=compiled)
|
||||||
|
return
|
||||||
if not os.path.exists(filename) and allow_generic:
|
if not os.path.exists(filename) and allow_generic:
|
||||||
view = 'generic.' + request.extension
|
view = 'generic.' + request.extension
|
||||||
filename = pjoin(folder, 'views', view)
|
filename = pjoin(folder, 'views', view)
|
||||||
@@ -725,7 +728,7 @@ def remove_compiled_application(folder):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def compile_application(folder):
|
def compile_application(folder, skip_failed_views=False):
|
||||||
"""
|
"""
|
||||||
Compiles all models, views, controller for the application in `folder`.
|
Compiles all models, views, controller for the application in `folder`.
|
||||||
"""
|
"""
|
||||||
@@ -733,7 +736,8 @@ def compile_application(folder):
|
|||||||
os.mkdir(pjoin(folder, 'compiled'))
|
os.mkdir(pjoin(folder, 'compiled'))
|
||||||
compile_models(folder)
|
compile_models(folder)
|
||||||
compile_controllers(folder)
|
compile_controllers(folder)
|
||||||
compile_views(folder)
|
failed_views = compile_views(folder, skip_failed_views)
|
||||||
|
return failed_views
|
||||||
|
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ from gluon.serializers import json_parser
|
|||||||
|
|
||||||
locker = thread.allocate_lock()
|
locker = thread.allocate_lock()
|
||||||
|
|
||||||
|
|
||||||
def AppConfig(*args, **vars):
|
def AppConfig(*args, **vars):
|
||||||
|
|
||||||
locker.acquire()
|
locker.acquire()
|
||||||
@@ -59,6 +58,27 @@ class AppConfigDict(dict):
|
|||||||
dict.__init__(self, *args, **kwargs)
|
dict.__init__(self, *args, **kwargs)
|
||||||
self.int_cache = {}
|
self.int_cache = {}
|
||||||
|
|
||||||
|
def get(self, path, default=None):
|
||||||
|
try:
|
||||||
|
value = self.take(path).strip()
|
||||||
|
if value.lower() in ('none','null',''):
|
||||||
|
return None
|
||||||
|
elif value.lower() == 'true':
|
||||||
|
return True
|
||||||
|
elif value.lower() == 'false':
|
||||||
|
return False
|
||||||
|
elif value.isdigit() or (value[0]=='-' and value[1:].isdigit()):
|
||||||
|
return int(value)
|
||||||
|
elif ',' in value:
|
||||||
|
return map(lambda x:x.strip(),value.split(','))
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
return float(value)
|
||||||
|
except:
|
||||||
|
return value
|
||||||
|
except:
|
||||||
|
return default
|
||||||
|
|
||||||
def take(self, path, cast=None):
|
def take(self, path, cast=None):
|
||||||
parts = path.split('.')
|
parts = path.split('.')
|
||||||
if path in self.int_cache:
|
if path in self.int_cache:
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ def video(url):
|
|||||||
|
|
||||||
|
|
||||||
def googledoc_viewer(url):
|
def googledoc_viewer(url):
|
||||||
return '<iframe src="http://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url)
|
return '<iframe src="https://docs.google.com/viewer?url=%s&embedded=true" style="max-width:100%%"></iframe>' % urllib.quote(url)
|
||||||
|
|
||||||
|
|
||||||
def web2py_component(url):
|
def web2py_component(url):
|
||||||
|
|||||||
Executable → Regular
+757
-737
File diff suppressed because it is too large
Load Diff
@@ -6,15 +6,17 @@
|
|||||||
#
|
#
|
||||||
# Given the model
|
# Given the model
|
||||||
#
|
#
|
||||||
# db.define_table("table_name", Field("picture", "upload"), Field("thumbnail", "upload"))
|
# db.define_table("table_name", Field("picture", "upload"),
|
||||||
|
# Field("thumbnail", "upload"))
|
||||||
#
|
#
|
||||||
# # to resize the picture on upload
|
# to resize the picture on upload
|
||||||
#
|
#
|
||||||
# from images import RESIZE
|
# from images import RESIZE
|
||||||
#
|
#
|
||||||
# db.table_name.picture.requires = RESIZE(200, 200)
|
# db.table_name.picture.requires = RESIZE(200, 200)
|
||||||
#
|
#
|
||||||
# # to store original image in picture and create a thumbnail in 'thumbnail' field
|
# to store original image in picture and create a thumbnail
|
||||||
|
# in 'thumbnail' field
|
||||||
#
|
#
|
||||||
# from images import THUMB
|
# from images import THUMB
|
||||||
# db.table_name.thumbnail.compute = lambda row: THUMB(row.picture, 200, 200)
|
# db.table_name.thumbnail.compute = lambda row: THUMB(row.picture, 200, 200)
|
||||||
@@ -24,8 +26,11 @@ from gluon import current
|
|||||||
|
|
||||||
|
|
||||||
class RESIZE(object):
|
class RESIZE(object):
|
||||||
def __init__(self, nx=160, ny=80, error_message=' image resize'):
|
|
||||||
(self.nx, self.ny, self.error_message) = (nx, ny, error_message)
|
def __init__(self, nx=160, ny=80, quality=100, padding = False,
|
||||||
|
error_message=' image resize'):
|
||||||
|
(self.nx, self.ny, self.quality, self.error_message, self.padding) = (
|
||||||
|
nx, ny, quality, error_message, padding)
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
if isinstance(value, str) and len(value) == 0:
|
if isinstance(value, str) and len(value) == 0:
|
||||||
@@ -36,7 +41,14 @@ class RESIZE(object):
|
|||||||
img = Image.open(value.file)
|
img = Image.open(value.file)
|
||||||
img.thumbnail((self.nx, self.ny), Image.ANTIALIAS)
|
img.thumbnail((self.nx, self.ny), Image.ANTIALIAS)
|
||||||
s = cStringIO.StringIO()
|
s = cStringIO.StringIO()
|
||||||
img.save(s, 'JPEG', quality=100)
|
if self.padding:
|
||||||
|
background = Image.new('RGBA', (self.nx, self.ny), (255, 255, 255, 0))
|
||||||
|
background.paste(
|
||||||
|
img,
|
||||||
|
((self.nx - img.size[0]) / 2, (self.ny - img.size[1]) / 2))
|
||||||
|
background.save(s, 'JPEG', quality=self.quality)
|
||||||
|
else:
|
||||||
|
img.save(s, 'JPEG', queality=self.quality)
|
||||||
s.seek(0)
|
s.seek(0)
|
||||||
value.file = s
|
value.file = s
|
||||||
except:
|
except:
|
||||||
@@ -51,7 +63,7 @@ def THUMB(image, nx=120, ny=120, gae=False, name='thumb'):
|
|||||||
request = current.request
|
request = current.request
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import os
|
import os
|
||||||
img = Image.open(os.path.join(request.folder,'uploads',image))
|
img = Image.open(os.path.join(request.folder, 'uploads', image))
|
||||||
img.thumbnail((nx, ny), Image.ANTIALIAS)
|
img.thumbnail((nx, ny), Image.ANTIALIAS)
|
||||||
root, ext = os.path.splitext(image)
|
root, ext = os.path.splitext(image)
|
||||||
thumb = '%s_%s%s' % (root, name, ext)
|
thumb = '%s_%s%s' % (root, name, ext)
|
||||||
|
|||||||
@@ -14,12 +14,20 @@ except Exception, e:
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def ldap_auth(server='ldap', port=None,
|
def ldap_auth(server='ldap',
|
||||||
|
port=None,
|
||||||
base_dn='ou=users,dc=domain,dc=com',
|
base_dn='ou=users,dc=domain,dc=com',
|
||||||
mode='uid', secure=False,
|
mode='uid',
|
||||||
cert_path=None, cert_file=None,
|
secure=False,
|
||||||
cacert_path=None, cacert_file=None, key_file=None,
|
self_signed_certificate=None, # See NOTE below
|
||||||
bind_dn=None, bind_pw=None, filterstr='objectClass=*',
|
cert_path=None,
|
||||||
|
cert_file=None,
|
||||||
|
cacert_path=None,
|
||||||
|
cacert_file=None,
|
||||||
|
key_file=None,
|
||||||
|
bind_dn=None,
|
||||||
|
bind_pw=None,
|
||||||
|
filterstr='objectClass=*',
|
||||||
username_attrib='uid',
|
username_attrib='uid',
|
||||||
custom_scope='subtree',
|
custom_scope='subtree',
|
||||||
allowed_groups=None,
|
allowed_groups=None,
|
||||||
@@ -28,11 +36,14 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
user_lastname_attrib='cn:2',
|
user_lastname_attrib='cn:2',
|
||||||
user_mail_attrib='mail',
|
user_mail_attrib='mail',
|
||||||
manage_groups=False,
|
manage_groups=False,
|
||||||
|
manage_groups_callback=[],
|
||||||
db=None,
|
db=None,
|
||||||
group_dn=None,
|
group_dn=None,
|
||||||
group_name_attrib='cn',
|
group_name_attrib='cn',
|
||||||
group_member_attrib='memberUid',
|
group_member_attrib='memberUid',
|
||||||
group_filterstr='objectClass=*',
|
group_filterstr='objectClass=*',
|
||||||
|
group_mapping={},
|
||||||
|
tls=False,
|
||||||
logging_level='error'):
|
logging_level='error'):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -80,6 +91,13 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
If ldap is using GnuTLS then you need cert_file="..." instead cert_path
|
If ldap is using GnuTLS then you need cert_file="..." instead cert_path
|
||||||
because cert_path isn't implemented in GnuTLS :(
|
because cert_path isn't implemented in GnuTLS :(
|
||||||
|
|
||||||
|
To enable TLS, set tls=True:
|
||||||
|
|
||||||
|
auth.settings.login_methods.append(ldap_auth(
|
||||||
|
server='my.ldap.server',
|
||||||
|
base_dn='ou=Users,dc=domain,dc=com',
|
||||||
|
tls=True))
|
||||||
|
|
||||||
If you need to bind to the directory with an admin account in order to
|
If you need to bind to the directory with an admin account in order to
|
||||||
search it then specify bind_dn & bind_pw to use for this.
|
search it then specify bind_dn & bind_pw to use for this.
|
||||||
- currently only implemented for Active Directory
|
- currently only implemented for Active Directory
|
||||||
@@ -151,6 +169,14 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
You can set the logging level with the "logging_level" parameter, default
|
You can set the logging level with the "logging_level" parameter, default
|
||||||
is "error" and can be set to error, warning, info, debug.
|
is "error" and can be set to error, warning, info, debug.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self_signed_certificate:
|
||||||
|
# NOTE : If you have a self-signed SSL Certificate pointing over "port=686" and "secure=True" alone
|
||||||
|
# will not work, you need also to set "self_signed_certificate=True".
|
||||||
|
# Ref1: https://onemoretech.wordpress.com/2015/06/25/connecting-to-ldap-over-self-signed-tls-with-python/
|
||||||
|
# Ref2: http://bneijt.nl/blog/post/connecting-to-ldaps-with-self-signed-cert-using-python/
|
||||||
|
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||||
|
|
||||||
logger = logging.getLogger('web2py.auth.ldap_auth')
|
logger = logging.getLogger('web2py.auth.ldap_auth')
|
||||||
if logging_level == 'error':
|
if logging_level == 'error':
|
||||||
logger.setLevel(logging.ERROR)
|
logger.setLevel(logging.ERROR)
|
||||||
@@ -183,13 +209,13 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
user_mail_attrib=user_mail_attrib,
|
user_mail_attrib=user_mail_attrib,
|
||||||
manage_groups=manage_groups,
|
manage_groups=manage_groups,
|
||||||
allowed_groups=allowed_groups,
|
allowed_groups=allowed_groups,
|
||||||
|
group_mapping=group_mapping,
|
||||||
db=db):
|
db=db):
|
||||||
if password == '': # http://tools.ietf.org/html/rfc4513#section-5.1.2
|
if password == '': # http://tools.ietf.org/html/rfc4513#section-5.1.2
|
||||||
logger.warning('blank password not allowed')
|
logger.warning('blank password not allowed')
|
||||||
return False
|
return False
|
||||||
logger.debug('mode: [%s] manage_user: [%s] custom_scope: [%s]'
|
logger.debug('mode: [%s] manage_user: [%s] custom_scope: [%s]'
|
||||||
' manage_groups: [%s]' % (str(mode), str(manage_user),
|
' manage_groups: [%s]' % (str(mode), str(manage_user), str(custom_scope), str(manage_groups)))
|
||||||
str(custom_scope), str(manage_groups)))
|
|
||||||
if manage_user:
|
if manage_user:
|
||||||
if user_firstname_attrib.count(':') > 0:
|
if user_firstname_attrib.count(':') > 0:
|
||||||
(user_firstname_attrib,
|
(user_firstname_attrib,
|
||||||
@@ -238,14 +264,11 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
# in the ldap_basedn
|
# in the ldap_basedn
|
||||||
requested_attrs = ['sAMAccountName']
|
requested_attrs = ['sAMAccountName']
|
||||||
if manage_user:
|
if manage_user:
|
||||||
requested_attrs.extend([user_firstname_attrib,
|
requested_attrs.extend([user_firstname_attrib, user_lastname_attrib, user_mail_attrib])
|
||||||
user_lastname_attrib,
|
|
||||||
user_mail_attrib])
|
|
||||||
result = con.search_ext_s(
|
result = con.search_ext_s(
|
||||||
ldap_basedn, ldap.SCOPE_SUBTREE,
|
ldap_basedn, ldap.SCOPE_SUBTREE,
|
||||||
"(&(sAMAccountName=%s)(%s))" % (
|
"(&(sAMAccountName=%s)(%s))" % (ldap.filter.escape_filter_chars(username_bare), filterstr),
|
||||||
ldap.filter.escape_filter_chars(username_bare),
|
|
||||||
filterstr),
|
|
||||||
requested_attrs)[0][1]
|
requested_attrs)[0][1]
|
||||||
if not isinstance(result, dict):
|
if not isinstance(result, dict):
|
||||||
# result should be a dict in the form
|
# result should be a dict in the form
|
||||||
@@ -278,25 +301,21 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
if manage_user:
|
if manage_user:
|
||||||
result = con.search_s(dn, ldap.SCOPE_BASE,
|
result = con.search_s(dn, ldap.SCOPE_BASE,
|
||||||
"(objectClass=*)",
|
"(objectClass=*)",
|
||||||
[user_firstname_attrib,
|
[user_firstname_attrib, user_lastname_attrib, user_mail_attrib])[0][1]
|
||||||
user_lastname_attrib,
|
|
||||||
user_mail_attrib])[0][1]
|
|
||||||
|
|
||||||
if ldap_mode == 'uid':
|
if ldap_mode == 'uid':
|
||||||
# OpenLDAP (UID)
|
# OpenLDAP (UID)
|
||||||
if ldap_binddn and ldap_bindpw:
|
if ldap_binddn and ldap_bindpw:
|
||||||
con.simple_bind_s(ldap_binddn, ldap_bindpw)
|
con.simple_bind_s(ldap_binddn, ldap_bindpw)
|
||||||
dn = "uid=" + username + "," + ldap_basedn
|
dn = "uid=" + username + "," + ldap_basedn
|
||||||
dn = con.search_s(ldap_basedn, ldap.SCOPE_SUBTREE, "(uid=%s)"%username, [''])[0][0]
|
dn = con.search_s(ldap_basedn, ldap.SCOPE_SUBTREE, "(uid=%s)" % username, [''])[0][0]
|
||||||
else:
|
else:
|
||||||
dn = "uid=" + username + "," + ldap_basedn
|
dn = "uid=" + username + "," + ldap_basedn
|
||||||
con.simple_bind_s(dn, password)
|
con.simple_bind_s(dn, password)
|
||||||
if manage_user:
|
if manage_user:
|
||||||
result = con.search_s(dn, ldap.SCOPE_BASE,
|
result = con.search_s(dn, ldap.SCOPE_BASE,
|
||||||
"(objectClass=*)",
|
"(objectClass=*)",
|
||||||
[user_firstname_attrib,
|
[user_firstname_attrib, user_lastname_attrib, user_mail_attrib])[0][1]
|
||||||
user_lastname_attrib,
|
|
||||||
user_mail_attrib])[0][1]
|
|
||||||
|
|
||||||
if ldap_mode == 'company':
|
if ldap_mode == 'company':
|
||||||
# no DNs or password needed to search directory
|
# no DNs or password needed to search directory
|
||||||
@@ -311,9 +330,7 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
# find the uid
|
# find the uid
|
||||||
attrs = ['uid']
|
attrs = ['uid']
|
||||||
if manage_user:
|
if manage_user:
|
||||||
attrs.extend([user_firstname_attrib,
|
attrs.extend([user_firstname_attrib, user_lastname_attrib, user_mail_attrib])
|
||||||
user_lastname_attrib,
|
|
||||||
user_mail_attrib])
|
|
||||||
# perform the actual search
|
# perform the actual search
|
||||||
company_search_result = con.search_s(ldap_basedn,
|
company_search_result = con.search_s(ldap_basedn,
|
||||||
ldap.SCOPE_SUBTREE,
|
ldap.SCOPE_SUBTREE,
|
||||||
@@ -329,13 +346,11 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
basedns = ldap_basedn
|
basedns = ldap_basedn
|
||||||
else:
|
else:
|
||||||
basedns = [ldap_basedn]
|
basedns = [ldap_basedn]
|
||||||
filter = '(&(uid=%s)(%s))' % (
|
filter = '(&(uid=%s)(%s))' % (ldap.filter.escape_filter_chars(username), filterstr)
|
||||||
ldap.filter.escape_filter_chars(username), filterstr)
|
|
||||||
found = False
|
found = False
|
||||||
for basedn in basedns:
|
for basedn in basedns:
|
||||||
try:
|
try:
|
||||||
result = con.search_s(basedn, ldap.SCOPE_SUBTREE,
|
result = con.search_s(basedn, ldap.SCOPE_SUBTREE, filter)
|
||||||
filter)
|
|
||||||
if result:
|
if result:
|
||||||
user_dn = result[0][0]
|
user_dn = result[0][0]
|
||||||
# Check the password
|
# Check the password
|
||||||
@@ -344,9 +359,10 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
break
|
break
|
||||||
except ldap.LDAPError, detail:
|
except ldap.LDAPError, detail:
|
||||||
(exc_type, exc_value) = sys.exc_info()[:2]
|
(exc_type, exc_value) = sys.exc_info()[:2]
|
||||||
logger.warning(
|
logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn,
|
||||||
"ldap_auth: searching %s for %s resulted in %s: %s\n" %
|
filter,
|
||||||
(basedn, filter, exc_type, exc_value)
|
exc_type,
|
||||||
|
exc_value)
|
||||||
)
|
)
|
||||||
if not found:
|
if not found:
|
||||||
logger.warning('User [%s] not found!' % username)
|
logger.warning('User [%s] not found!' % username)
|
||||||
@@ -359,10 +375,7 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
basedns = ldap_basedn
|
basedns = ldap_basedn
|
||||||
else:
|
else:
|
||||||
basedns = [ldap_basedn]
|
basedns = [ldap_basedn]
|
||||||
filter = '(&(%s=%s)(%s))' % (username_attrib,
|
filter = '(&(%s=%s)(%s))' % (username_attrib, ldap.filter.escape_filter_chars(username), filterstr)
|
||||||
ldap.filter.escape_filter_chars(
|
|
||||||
username),
|
|
||||||
filterstr)
|
|
||||||
if custom_scope == 'subtree':
|
if custom_scope == 'subtree':
|
||||||
ldap_scope = ldap.SCOPE_SUBTREE
|
ldap_scope = ldap.SCOPE_SUBTREE
|
||||||
elif custom_scope == 'base':
|
elif custom_scope == 'base':
|
||||||
@@ -381,9 +394,10 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
break
|
break
|
||||||
except ldap.LDAPError, detail:
|
except ldap.LDAPError, detail:
|
||||||
(exc_type, exc_value) = sys.exc_info()[:2]
|
(exc_type, exc_value) = sys.exc_info()[:2]
|
||||||
logger.warning(
|
logger.warning("ldap_auth: searching %s for %s resulted in %s: %s\n" % (basedn,
|
||||||
"ldap_auth: searching %s for %s resulted in %s: %s\n" %
|
filter,
|
||||||
(basedn, filter, exc_type, exc_value)
|
exc_type,
|
||||||
|
exc_value)
|
||||||
)
|
)
|
||||||
if not found:
|
if not found:
|
||||||
logger.warning('User [%s] not found!' % username)
|
logger.warning('User [%s] not found!' % username)
|
||||||
@@ -393,16 +407,14 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
logger.info('[%s] Manage user data' % str(username))
|
logger.info('[%s] Manage user data' % str(username))
|
||||||
try:
|
try:
|
||||||
if user_firstname_part is not None:
|
if user_firstname_part is not None:
|
||||||
store_user_firstname = result[user_firstname_attrib][
|
store_user_firstname = result[user_firstname_attrib][0].split(' ', 1)[user_firstname_part]
|
||||||
0].split(' ', 1)[user_firstname_part]
|
|
||||||
else:
|
else:
|
||||||
store_user_firstname = result[user_firstname_attrib][0]
|
store_user_firstname = result[user_firstname_attrib][0]
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
store_user_firstname = None
|
store_user_firstname = None
|
||||||
try:
|
try:
|
||||||
if user_lastname_part is not None:
|
if user_lastname_part is not None:
|
||||||
store_user_lastname = result[user_lastname_attrib][
|
store_user_lastname = result[user_lastname_attrib][0].split(' ', 1)[user_lastname_part]
|
||||||
0].split(' ', 1)[user_lastname_part]
|
|
||||||
else:
|
else:
|
||||||
store_user_lastname = result[user_lastname_attrib][0]
|
store_user_lastname = result[user_lastname_attrib][0]
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
@@ -411,36 +423,32 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
store_user_mail = result[user_mail_attrib][0]
|
store_user_mail = result[user_mail_attrib][0]
|
||||||
except KeyError, e:
|
except KeyError, e:
|
||||||
store_user_mail = None
|
store_user_mail = None
|
||||||
try:
|
update_or_insert_values = {'first_name': store_user_firstname,
|
||||||
#
|
'last_name': store_user_lastname,
|
||||||
|
'email': store_user_mail,
|
||||||
|
'username': username}
|
||||||
|
if '@' not in username:
|
||||||
# user as username
|
# user as username
|
||||||
# #################
|
# ################
|
||||||
|
fields = ['first_name', 'last_name', 'email']
|
||||||
user_in_db = db(db.auth_user.username == username)
|
user_in_db = db(db.auth_user.username == username)
|
||||||
if user_in_db.count() > 0:
|
elif '@' in username:
|
||||||
user_in_db.update(first_name=store_user_firstname,
|
|
||||||
last_name=store_user_lastname,
|
|
||||||
email=store_user_mail)
|
|
||||||
else:
|
|
||||||
db.auth_user.insert(first_name=store_user_firstname,
|
|
||||||
last_name=store_user_lastname,
|
|
||||||
email=store_user_mail,
|
|
||||||
username=username)
|
|
||||||
except:
|
|
||||||
#
|
|
||||||
# user as email
|
# user as email
|
||||||
# ##############
|
# #############
|
||||||
|
fields = ['first_name', 'last_name']
|
||||||
user_in_db = db(db.auth_user.email == username)
|
user_in_db = db(db.auth_user.email == username)
|
||||||
if user_in_db.count() > 0:
|
update_or_insert_values = dict(((f, update_or_insert_values[f]) for f in fields))
|
||||||
user_in_db.update(first_name=store_user_firstname,
|
|
||||||
last_name=store_user_lastname)
|
if user_in_db.count() > 0:
|
||||||
else:
|
actual_values = user_in_db.select(*[db.auth_user[f] for f in fields]).first().as_dict()
|
||||||
db.auth_user.insert(first_name=store_user_firstname,
|
if update_or_insert_values != actual_values: # We don't update record if values are the same
|
||||||
last_name=store_user_lastname,
|
user_in_db.update(**update_or_insert_values)
|
||||||
email=username)
|
else:
|
||||||
|
db.auth_user.insert(**update_or_insert_values)
|
||||||
con.unbind()
|
con.unbind()
|
||||||
|
|
||||||
if manage_groups:
|
if manage_groups:
|
||||||
if not do_manage_groups(username, password):
|
if not do_manage_groups(username, password, group_mapping):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
except ldap.INVALID_CREDENTIALS, e:
|
except ldap.INVALID_CREDENTIALS, e:
|
||||||
@@ -478,9 +486,7 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
# No match
|
# No match
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def do_manage_groups(username,
|
def do_manage_groups(username, password=None, group_mapping={}, db=db):
|
||||||
password=None,
|
|
||||||
db=db):
|
|
||||||
"""
|
"""
|
||||||
Manage user groups
|
Manage user groups
|
||||||
|
|
||||||
@@ -496,54 +502,65 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
ldap_groups_of_the_user = get_user_groups_from_ldap(
|
ldap_groups_of_the_user = get_user_groups_from_ldap(
|
||||||
username, password)
|
username, password)
|
||||||
|
|
||||||
|
if group_mapping != {}:
|
||||||
|
l = []
|
||||||
|
for group in ldap_groups_of_the_user:
|
||||||
|
if group in group_mapping:
|
||||||
|
l += group_mapping[group]
|
||||||
|
ldap_groups_of_the_user = l
|
||||||
|
logging.info("User groups after remapping: %s" % str(l))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get all group name where the user is in actually in local db
|
# Get all group name where the user is in actually in local db
|
||||||
# #############################################################
|
# #############################################################
|
||||||
try:
|
try:
|
||||||
db_user_id = db(db.auth_user.username == username).select(
|
db_user_id = db(db.auth_user.username == username).select(db.auth_user.id).first().id
|
||||||
db.auth_user.id).first().id
|
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
db_user_id = db(db.auth_user.email == username).select(
|
db_user_id = db(db.auth_user.email == username).select(db.auth_user.id).first().id
|
||||||
db.auth_user.id).first().id
|
|
||||||
except AttributeError, e:
|
except AttributeError, e:
|
||||||
#
|
#
|
||||||
# There is no user in local db
|
# There is no user in local db
|
||||||
# We create one
|
# We create one
|
||||||
# ##############################
|
# ##############################
|
||||||
try:
|
try:
|
||||||
db_user_id = db.auth_user.insert(username=username,
|
db_user_id = db.auth_user.insert(username=username, first_name=username)
|
||||||
first_name=username)
|
|
||||||
except AttributeError, e:
|
except AttributeError, e:
|
||||||
db_user_id = db.auth_user.insert(email=username,
|
db_user_id = db.auth_user.insert(email=username, first_name=username)
|
||||||
first_name=username)
|
|
||||||
if not db_user_id:
|
if not db_user_id:
|
||||||
logging.error(
|
logging.error(
|
||||||
'There is no username or email for %s!' % username)
|
'There is no username or email for %s!' % username)
|
||||||
raise
|
raise
|
||||||
db_group_search = db((db.auth_membership.user_id == db_user_id) &
|
# if old pydal version, assume this is a relational database which can do joins
|
||||||
(db.auth_user.id == db.auth_membership.user_id) &
|
db_can_join = db.can_join() if hasattr(db, 'can_join') else True
|
||||||
(db.auth_group.id == db.auth_membership.group_id))
|
if db_can_join:
|
||||||
|
db_group_search = \
|
||||||
|
db((db.auth_membership.user_id == db_user_id) &
|
||||||
|
(db.auth_user.id == db.auth_membership.user_id) &
|
||||||
|
(db.auth_group.id == db.auth_membership.group_id))
|
||||||
|
else:
|
||||||
|
# no joins on NoSQL databases, perform two queries
|
||||||
|
db_group_search = db(db.auth_membership.user_id == db_user_id)
|
||||||
|
group_ids = [x.group_id for x in db_group_search.select(db.auth_membership.group_id, distinct=True)]
|
||||||
|
db_group_search = db(db.auth_group.id.belongs(group_ids))
|
||||||
db_groups_of_the_user = list()
|
db_groups_of_the_user = list()
|
||||||
db_group_id = dict()
|
db_group_id = dict()
|
||||||
|
|
||||||
if db_group_search.count() > 0:
|
if db_group_search.count() > 0:
|
||||||
for group in db_group_search.select(db.auth_group.id,
|
for group in db_group_search.select(db.auth_group.id, db.auth_group.role, distinct=True):
|
||||||
db.auth_group.role,
|
|
||||||
distinct=True):
|
|
||||||
db_group_id[group.role] = group.id
|
db_group_id[group.role] = group.id
|
||||||
db_groups_of_the_user.append(group.role)
|
db_groups_of_the_user.append(group.role)
|
||||||
logging.debug('db groups of user %s: %s' %
|
logging.debug('db groups of user %s: %s' % (username, str(db_groups_of_the_user)))
|
||||||
(username, str(db_groups_of_the_user)))
|
|
||||||
|
|
||||||
|
auth_membership_changed = False
|
||||||
#
|
#
|
||||||
# Delete user membership from groups where user is not anymore
|
# Delete user membership from groups where user is not anymore
|
||||||
# #############################################################
|
# #############################################################
|
||||||
for group_to_del in db_groups_of_the_user:
|
for group_to_del in db_groups_of_the_user:
|
||||||
if ldap_groups_of_the_user.count(group_to_del) == 0:
|
if ldap_groups_of_the_user.count(group_to_del) == 0:
|
||||||
db((db.auth_membership.user_id == db_user_id) &
|
db((db.auth_membership.user_id == db_user_id) &
|
||||||
(db.auth_membership.group_id == \
|
(db.auth_membership.group_id == db_group_id[group_to_del])).delete()
|
||||||
db_group_id[group_to_del])).delete()
|
auth_membership_changed = True
|
||||||
|
|
||||||
#
|
#
|
||||||
# Create user membership in groups where user is not in already
|
# Create user membership in groups where user is not in already
|
||||||
@@ -551,16 +568,18 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
for group_to_add in ldap_groups_of_the_user:
|
for group_to_add in ldap_groups_of_the_user:
|
||||||
if db_groups_of_the_user.count(group_to_add) == 0:
|
if db_groups_of_the_user.count(group_to_add) == 0:
|
||||||
if db(db.auth_group.role == group_to_add).count() == 0:
|
if db(db.auth_group.role == group_to_add).count() == 0:
|
||||||
gid = db.auth_group.insert(role=group_to_add,
|
gid = db.auth_group.insert(role=group_to_add, description='Generated from LDAP')
|
||||||
description='Generated from LDAP')
|
|
||||||
else:
|
else:
|
||||||
gid = db(db.auth_group.role == group_to_add).select(
|
gid = db(db.auth_group.role == group_to_add).select(db.auth_group.id).first().id
|
||||||
db.auth_group.id).first().id
|
db.auth_membership.insert(user_id=db_user_id, group_id=gid)
|
||||||
db.auth_membership.insert(user_id=db_user_id,
|
auth_membership_changed = True
|
||||||
group_id=gid)
|
|
||||||
|
if auth_membership_changed:
|
||||||
|
for callback in manage_groups_callback:
|
||||||
|
callback()
|
||||||
|
|
||||||
except:
|
except:
|
||||||
logger.warning("[%s] Groups are not managed successfully!" %
|
logger.warning("[%s] Groups are not managed successfully!" % str(username))
|
||||||
str(username))
|
|
||||||
import traceback
|
import traceback
|
||||||
logger.debug(traceback.format_exc())
|
logger.debug(traceback.format_exc())
|
||||||
return False
|
return False
|
||||||
@@ -600,6 +619,8 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
ldap_port = 389
|
ldap_port = 389
|
||||||
con = ldap.initialize(
|
con = ldap.initialize(
|
||||||
"ldap://" + ldap_server + ":" + str(ldap_port))
|
"ldap://" + ldap_server + ":" + str(ldap_port))
|
||||||
|
if tls:
|
||||||
|
con.start_tls_s()
|
||||||
return con
|
return con
|
||||||
|
|
||||||
def get_user_groups_from_ldap(username,
|
def get_user_groups_from_ldap(username,
|
||||||
@@ -649,10 +670,12 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
con.simple_bind_s(username, password)
|
con.simple_bind_s(username, password)
|
||||||
logger.debug('Ldap username connect...')
|
logger.debug('Ldap username connect...')
|
||||||
# We have to use the full string
|
# We have to use the full string
|
||||||
username = con.search_ext_s(base_dn, ldap.SCOPE_SUBTREE,
|
username = \
|
||||||
"(&(sAMAccountName=%s)(%s))" %
|
con.search_ext_s(base_dn,
|
||||||
(ldap.filter.escape_filter_chars(username_bare),
|
ldap.SCOPE_SUBTREE,
|
||||||
filterstr), ["cn"])[0][0]
|
"(&(sAMAccountName=%s)(%s))" % (ldap.filter.escape_filter_chars(username_bare),
|
||||||
|
filterstr),
|
||||||
|
["cn"])[0][0]
|
||||||
else:
|
else:
|
||||||
if ldap_binddn:
|
if ldap_binddn:
|
||||||
# need to search directory with an bind_dn account 1st
|
# need to search directory with an bind_dn account 1st
|
||||||
@@ -665,18 +688,14 @@ def ldap_auth(server='ldap', port=None,
|
|||||||
if username is None:
|
if username is None:
|
||||||
return list()
|
return list()
|
||||||
# search for groups where user is in
|
# search for groups where user is in
|
||||||
filter = '(&(%s=%s)(%s))' % (ldap.filter.escape_filter_chars(
|
filter = '(&(%s=%s)(%s))' % (ldap.filter.escape_filter_chars(group_member_attrib),
|
||||||
group_member_attrib
|
|
||||||
),
|
|
||||||
ldap.filter.escape_filter_chars(username),
|
ldap.filter.escape_filter_chars(username),
|
||||||
group_filterstr)
|
group_filterstr)
|
||||||
group_search_result = con.search_s(group_dn,
|
group_search_result = con.search_s(group_dn, ldap.SCOPE_SUBTREE, filter, [group_name_attrib])
|
||||||
ldap.SCOPE_SUBTREE,
|
|
||||||
filter, [group_name_attrib])
|
|
||||||
ldap_groups_of_the_user = list()
|
ldap_groups_of_the_user = list()
|
||||||
for group_row in group_search_result:
|
for group_row in group_search_result:
|
||||||
group = group_row[1]
|
group = group_row[1]
|
||||||
if type(group) == dict and group.has_key(group_name_attrib):
|
if type(group) == dict and group_name_attrib in group:
|
||||||
ldap_groups_of_the_user.extend(group[group_name_attrib])
|
ldap_groups_of_the_user.extend(group[group_name_attrib])
|
||||||
|
|
||||||
con.unbind()
|
con.unbind()
|
||||||
|
|||||||
@@ -139,24 +139,36 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
Return the access token generated by the authenticating server.
|
Return the access token generated by the authenticating server.
|
||||||
|
|
||||||
If token is already in the session that one will be used.
|
If token is already in the session that one will be used.
|
||||||
|
If token has expired refresh_token is used to get another token.
|
||||||
Otherwise the token is fetched from the auth server.
|
Otherwise the token is fetched from the auth server.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
refresh_token = None
|
||||||
if current.session.token and 'expires' in current.session.token:
|
if current.session.token and 'expires' in current.session.token:
|
||||||
expires = current.session.token['expires']
|
expires = current.session.token['expires']
|
||||||
# reuse token until expiration
|
# reuse token until expiration
|
||||||
if expires == 0 or expires > time.time():
|
if expires == 0 or expires > time.time():
|
||||||
return current.session.token['access_token']
|
return current.session.token['access_token']
|
||||||
|
if 'refresh_token' in current.session.token:
|
||||||
|
refresh_token = current.session.token['refresh_token']
|
||||||
|
|
||||||
code = current.request.vars.code
|
code = current.request.vars.code
|
||||||
|
|
||||||
if code:
|
if code or refresh_token:
|
||||||
data = dict(client_id=self.client_id,
|
data = dict(
|
||||||
client_secret=self.client_secret,
|
client_id=self.client_id,
|
||||||
redirect_uri=current.session.redirect_uri,
|
client_secret=self.client_secret,
|
||||||
code=code,
|
)
|
||||||
grant_type='authorization_code'
|
if code:
|
||||||
)
|
data.update(
|
||||||
|
redirect_uri=current.session.redirect_uri,
|
||||||
|
code=code,
|
||||||
|
grant_type='authorization_code'
|
||||||
|
)
|
||||||
|
elif refresh_token:
|
||||||
|
data.update(
|
||||||
|
refresh_token=refresh_token,
|
||||||
|
grant_type='refresh_token'
|
||||||
|
)
|
||||||
|
|
||||||
open_url = None
|
open_url = None
|
||||||
opener = self.__build_url_opener(self.token_url)
|
opener = self.__build_url_opener(self.token_url)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class OneallAccount(object):
|
|||||||
reg_id=profile.get('identity_token','')
|
reg_id=profile.get('identity_token','')
|
||||||
username=profile.get('preferredUsername',email)
|
username=profile.get('preferredUsername',email)
|
||||||
first_name=name.get('givenName', dname.split(' ')[0])
|
first_name=name.get('givenName', dname.split(' ')[0])
|
||||||
last_name=profile.get('familyName',dname.split(' ')[1])
|
last_name=profile.get('familyName', dname.split(' ')[1] if(dname.count(' ') > 0) else None)
|
||||||
return dict(registration_id=reg_id,username=username,email=email,
|
return dict(registration_id=reg_id,username=username,email=email,
|
||||||
first_name=first_name,last_name=last_name)
|
first_name=first_name,last_name=last_name)
|
||||||
self.mappings.default = defaultmapping
|
self.mappings.default = defaultmapping
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Include in your model (eg db.py)::
|
|||||||
|
|
||||||
auth.define_tables(username=True)
|
auth.define_tables(username=True)
|
||||||
from gluon.contrib.login_methods.saml2_auth import Saml2Auth
|
from gluon.contrib.login_methods.saml2_auth import Saml2Auth
|
||||||
|
import os
|
||||||
auth.settings.login_form=Saml2Auth(
|
auth.settings.login_form=Saml2Auth(
|
||||||
config_file = os.path.join(request.folder,'private','sp_conf'),
|
config_file = os.path.join(request.folder,'private','sp_conf'),
|
||||||
maps=dict(
|
maps=dict(
|
||||||
@@ -20,10 +21,59 @@ Include in your model (eg db.py)::
|
|||||||
email=lambda v: v['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn'][0],
|
email=lambda v: v['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn'][0],
|
||||||
user_id=lambda v: v['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn'][0]))
|
user_id=lambda v: v['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn'][0]))
|
||||||
|
|
||||||
you must have private/sp_conf.py, the pysaml2 sp configuration file
|
you must have private/sp_conf.py, the pysaml2 sp configuration file. For example:
|
||||||
|
|
||||||
|
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
|
||||||
|
import os.path
|
||||||
|
import requests
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
BASEDIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
# Web2py SP url and application name
|
||||||
|
HOST = 'http://127.0.0.1:8000'
|
||||||
|
APP = 'sp'
|
||||||
|
|
||||||
|
# To load the IDP metadata...
|
||||||
|
IDP_METADATA = 'http://127.0.0.1:8088/metadata'
|
||||||
|
|
||||||
|
def full_path(local_file):
|
||||||
|
return os.path.join(BASEDIR, local_file)
|
||||||
|
|
||||||
|
CONFIG = {
|
||||||
|
# your entity id, usually your subdomain plus the url to the metadata view.
|
||||||
|
'entityid': '%s/%s/default/metadata' % (HOST, APP),
|
||||||
|
'service': {
|
||||||
|
'sp' : {
|
||||||
|
'name': 'MYSP',
|
||||||
|
'endpoints': {
|
||||||
|
'assertion_consumer_service': [
|
||||||
|
('%s/%s/default/user/login' % (HOST, APP), BINDING_HTTP_REDIRECT),
|
||||||
|
('%s/%s/default/user/login' % (HOST, APP), BINDING_HTTP_POST),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# Your private and public key.
|
||||||
|
'key_file': full_path('pki/mykey.pem'),
|
||||||
|
'cert_file': full_path('pki/mycert.pem'),
|
||||||
|
|
||||||
|
# where the remote metadata is stored
|
||||||
|
'metadata': {
|
||||||
|
"remote": [{
|
||||||
|
"url": IDP_METADATA,
|
||||||
|
"cert":full_path('pki/mycert.pem')
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from saml2 import BINDING_HTTP_REDIRECT
|
from saml2 import BINDING_HTTP_REDIRECT, BINDING_HTTP_POST
|
||||||
from saml2.client import Saml2Client
|
from saml2.client import Saml2Client
|
||||||
from gluon.utils import web2py_uuid
|
from gluon.utils import web2py_uuid
|
||||||
from gluon import current, redirect, URL
|
from gluon import current, redirect, URL
|
||||||
@@ -59,10 +109,13 @@ def saml2_handler(session, request, config_filename = None):
|
|||||||
client = Saml2Client(config_file = config_filename)
|
client = Saml2Client(config_file = config_filename)
|
||||||
idps = client.metadata.with_descriptor("idpsso")
|
idps = client.metadata.with_descriptor("idpsso")
|
||||||
entityid = idps.keys()[0]
|
entityid = idps.keys()[0]
|
||||||
bindings = [BINDING_HTTP_REDIRECT]
|
bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]
|
||||||
binding, destination = client.pick_binding(
|
binding, destination = client.pick_binding(
|
||||||
"single_sign_on_service", bindings, "idpsso", entity_id=entityid)
|
"single_sign_on_service", bindings, "idpsso", entity_id=entityid)
|
||||||
binding = BINDING_HTTP_REDIRECT
|
if request.env.request_method == 'GET':
|
||||||
|
binding = BINDING_HTTP_REDIRECT
|
||||||
|
elif request.env.request_method == 'POST':
|
||||||
|
binding = BINDING_HTTP_POST
|
||||||
if not request.vars.SAMLResponse:
|
if not request.vars.SAMLResponse:
|
||||||
req_id, req = client.create_authn_request(destination, binding=binding)
|
req_id, req = client.create_authn_request(destination, binding=binding)
|
||||||
relay_state = web2py_uuid().replace('-','')
|
relay_state = web2py_uuid().replace('-','')
|
||||||
|
|||||||
@@ -53,8 +53,9 @@ see <https://github.com/trentm/python-markdown2/wiki/Extras> for details):
|
|||||||
* header-ids: Adds "id" attributes to headers. The id value is a slug of
|
* header-ids: Adds "id" attributes to headers. The id value is a slug of
|
||||||
the header text.
|
the header text.
|
||||||
* html-classes: Takes a dict mapping html tag names (lowercase) to a
|
* html-classes: Takes a dict mapping html tag names (lowercase) to a
|
||||||
string to use for a "class" tag attribute. Currently only supports
|
string to use for a "class" tag attribute. Currently only supports "img",
|
||||||
"pre" and "code" tags. Add an issue if you require this for other tags.
|
"table", "pre" and "code" tags. Add an issue if you require this for other
|
||||||
|
tags.
|
||||||
* markdown-in-html: Allow the use of `markdown="1"` in a block HTML tag to
|
* markdown-in-html: Allow the use of `markdown="1"` in a block HTML tag to
|
||||||
have markdown processing be done on its contents. Similar to
|
have markdown processing be done on its contents. Similar to
|
||||||
<http://michelf.com/projects/php-markdown/extra/#markdown-attr> but with
|
<http://michelf.com/projects/php-markdown/extra/#markdown-attr> but with
|
||||||
@@ -70,9 +71,14 @@ see <https://github.com/trentm/python-markdown2/wiki/Extras> for details):
|
|||||||
* smarty-pants: Replaces ' and " with curly quotation marks or curly
|
* smarty-pants: Replaces ' and " with curly quotation marks or curly
|
||||||
apostrophes. Replaces --, ---, ..., and . . . with en dashes, em dashes,
|
apostrophes. Replaces --, ---, ..., and . . . with en dashes, em dashes,
|
||||||
and ellipses.
|
and ellipses.
|
||||||
|
* spoiler: A special kind of blockquote commonly hidden behind a
|
||||||
|
click on SO. Syntax per <http://meta.stackexchange.com/a/72878>.
|
||||||
* toc: The returned HTML string gets a new "toc_html" attribute which is
|
* toc: The returned HTML string gets a new "toc_html" attribute which is
|
||||||
a Table of Contents for the document. (experimental)
|
a Table of Contents for the document. (experimental)
|
||||||
* xml: Passes one-liner processing instructions and namespaced XML tags.
|
* xml: Passes one-liner processing instructions and namespaced XML tags.
|
||||||
|
* tables: Tables using the same format as GFM
|
||||||
|
<https://help.github.com/articles/github-flavored-markdown#tables> and
|
||||||
|
PHP-Markdown Extra <https://michelf.ca/projects/php-markdown/extra/#table>.
|
||||||
* wiki-tables: Google Code Wiki-style tables. See
|
* wiki-tables: Google Code Wiki-style tables. See
|
||||||
<http://code.google.com/p/support/wiki/WikiSyntax#Tables>.
|
<http://code.google.com/p/support/wiki/WikiSyntax#Tables>.
|
||||||
"""
|
"""
|
||||||
@@ -82,13 +88,11 @@ see <https://github.com/trentm/python-markdown2/wiki/Extras> for details):
|
|||||||
# not yet sure if there implications with this. Compare 'pydoc sre'
|
# not yet sure if there implications with this. Compare 'pydoc sre'
|
||||||
# and 'perldoc perlre'.
|
# and 'perldoc perlre'.
|
||||||
|
|
||||||
__version_info__ = (2, 2, 4)
|
__version_info__ = (2, 3, 1)
|
||||||
__version__ = '.'.join(map(str, __version_info__))
|
__version__ = '.'.join(map(str, __version_info__))
|
||||||
__author__ = "Trent Mick"
|
__author__ = "Trent Mick"
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
from pprint import pprint
|
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
try:
|
try:
|
||||||
@@ -102,13 +106,7 @@ import codecs
|
|||||||
|
|
||||||
#---- Python version compat
|
#---- Python version compat
|
||||||
|
|
||||||
try:
|
|
||||||
from urllib.parse import quote # python3
|
|
||||||
except ImportError:
|
|
||||||
from urllib import quote # python2
|
|
||||||
|
|
||||||
if sys.version_info[:2] < (2,4):
|
if sys.version_info[:2] < (2,4):
|
||||||
from sets import Set as set
|
|
||||||
def reversed(sequence):
|
def reversed(sequence):
|
||||||
for i in sequence[::-1]:
|
for i in sequence[::-1]:
|
||||||
yield i
|
yield i
|
||||||
@@ -804,6 +802,8 @@ class Markdown(object):
|
|||||||
text = self._prepare_pyshell_blocks(text)
|
text = self._prepare_pyshell_blocks(text)
|
||||||
if "wiki-tables" in self.extras:
|
if "wiki-tables" in self.extras:
|
||||||
text = self._do_wiki_tables(text)
|
text = self._do_wiki_tables(text)
|
||||||
|
if "tables" in self.extras:
|
||||||
|
text = self._do_tables(text)
|
||||||
|
|
||||||
text = self._do_code_blocks(text)
|
text = self._do_code_blocks(text)
|
||||||
|
|
||||||
@@ -844,6 +844,79 @@ class Markdown(object):
|
|||||||
|
|
||||||
return _pyshell_block_re.sub(self._pyshell_block_sub, text)
|
return _pyshell_block_re.sub(self._pyshell_block_sub, text)
|
||||||
|
|
||||||
|
def _table_sub(self, match):
|
||||||
|
trim_space_re = '^[ \t\n]+|[ \t\n]+$'
|
||||||
|
trim_bar_re = '^\||\|$'
|
||||||
|
|
||||||
|
head, underline, body = match.groups()
|
||||||
|
|
||||||
|
# Determine aligns for columns.
|
||||||
|
cols = [cell.strip() for cell in re.sub(trim_bar_re, "", re.sub(trim_space_re, "", underline)).split('|')]
|
||||||
|
align_from_col_idx = {}
|
||||||
|
for col_idx, col in enumerate(cols):
|
||||||
|
if col[0] == ':' and col[-1] == ':':
|
||||||
|
align_from_col_idx[col_idx] = ' align="center"'
|
||||||
|
elif col[0] == ':':
|
||||||
|
align_from_col_idx[col_idx] = ' align="left"'
|
||||||
|
elif col[-1] == ':':
|
||||||
|
align_from_col_idx[col_idx] = ' align="right"'
|
||||||
|
|
||||||
|
# thead
|
||||||
|
hlines = ['<table%s>' % self._html_class_str_from_tag('table'), '<thead>', '<tr>']
|
||||||
|
cols = [cell.strip() for cell in re.sub(trim_bar_re, "", re.sub(trim_space_re, "", head)).split('|')]
|
||||||
|
for col_idx, col in enumerate(cols):
|
||||||
|
hlines.append(' <th%s>%s</th>' % (
|
||||||
|
align_from_col_idx.get(col_idx, ''),
|
||||||
|
self._run_span_gamut(col)
|
||||||
|
))
|
||||||
|
hlines.append('</tr>')
|
||||||
|
hlines.append('</thead>')
|
||||||
|
|
||||||
|
# tbody
|
||||||
|
hlines.append('<tbody>')
|
||||||
|
for line in body.strip('\n').split('\n'):
|
||||||
|
hlines.append('<tr>')
|
||||||
|
cols = [cell.strip() for cell in re.sub(trim_bar_re, "", re.sub(trim_space_re, "", line)).split('|')]
|
||||||
|
for col_idx, col in enumerate(cols):
|
||||||
|
hlines.append(' <td%s>%s</td>' % (
|
||||||
|
align_from_col_idx.get(col_idx, ''),
|
||||||
|
self._run_span_gamut(col)
|
||||||
|
))
|
||||||
|
hlines.append('</tr>')
|
||||||
|
hlines.append('</tbody>')
|
||||||
|
hlines.append('</table>')
|
||||||
|
|
||||||
|
return '\n'.join(hlines) + '\n'
|
||||||
|
|
||||||
|
def _do_tables(self, text):
|
||||||
|
"""Copying PHP-Markdown and GFM table syntax. Some regex borrowed from
|
||||||
|
https://github.com/michelf/php-markdown/blob/lib/Michelf/Markdown.php#L2538
|
||||||
|
"""
|
||||||
|
less_than_tab = self.tab_width - 1
|
||||||
|
table_re = re.compile(r'''
|
||||||
|
(?:(?<=\n\n)|\A\n?) # leading blank line
|
||||||
|
|
||||||
|
^[ ]{0,%d} # allowed whitespace
|
||||||
|
(.*[|].*) \n # $1: header row (at least one pipe)
|
||||||
|
|
||||||
|
^[ ]{0,%d} # allowed whitespace
|
||||||
|
( # $2: underline row
|
||||||
|
# underline row with leading bar
|
||||||
|
(?: \|\ *:?-+:?\ * )+ \|? \n
|
||||||
|
|
|
||||||
|
# or, underline row without leading bar
|
||||||
|
(?: \ *:?-+:?\ *\| )+ (?: \ *:?-+:?\ * )? \n
|
||||||
|
)
|
||||||
|
|
||||||
|
( # $3: data rows
|
||||||
|
(?:
|
||||||
|
^[ ]{0,%d}(?!\ ) # ensure line begins with 0 to less_than_tab spaces
|
||||||
|
.*\|.* \n
|
||||||
|
)+
|
||||||
|
)
|
||||||
|
''' % (less_than_tab, less_than_tab, less_than_tab), re.M | re.X)
|
||||||
|
return table_re.sub(self._table_sub, text)
|
||||||
|
|
||||||
def _wiki_table_sub(self, match):
|
def _wiki_table_sub(self, match):
|
||||||
ttext = match.group(0).strip()
|
ttext = match.group(0).strip()
|
||||||
#print 'wiki table: %r' % match.group(0)
|
#print 'wiki table: %r' % match.group(0)
|
||||||
@@ -853,7 +926,7 @@ class Markdown(object):
|
|||||||
row = [c.strip() for c in re.split(r'(?<!\\)\|\|', line)]
|
row = [c.strip() for c in re.split(r'(?<!\\)\|\|', line)]
|
||||||
rows.append(row)
|
rows.append(row)
|
||||||
#pprint(rows)
|
#pprint(rows)
|
||||||
hlines = ['<table>', '<tbody>']
|
hlines = ['<table%s>' % self._html_class_str_from_tag('table'), '<tbody>']
|
||||||
for row in rows:
|
for row in rows:
|
||||||
hrow = ['<tr>']
|
hrow = ['<tr>']
|
||||||
for cell in row:
|
for cell in row:
|
||||||
@@ -899,6 +972,9 @@ class Markdown(object):
|
|||||||
|
|
||||||
text = self._encode_amps_and_angles(text)
|
text = self._encode_amps_and_angles(text)
|
||||||
|
|
||||||
|
if "strike" in self.extras:
|
||||||
|
text = self._do_strike(text)
|
||||||
|
|
||||||
text = self._do_italics_and_bold(text)
|
text = self._do_italics_and_bold(text)
|
||||||
|
|
||||||
if "smarty-pants" in self.extras:
|
if "smarty-pants" in self.extras:
|
||||||
@@ -1206,7 +1282,6 @@ class Markdown(object):
|
|||||||
.replace('_', self._escape_table['_'])
|
.replace('_', self._escape_table['_'])
|
||||||
title = self.titles.get(link_id)
|
title = self.titles.get(link_id)
|
||||||
if title:
|
if title:
|
||||||
before = title
|
|
||||||
title = _xml_escape_attr(title) \
|
title = _xml_escape_attr(title) \
|
||||||
.replace('*', self._escape_table['*']) \
|
.replace('*', self._escape_table['*']) \
|
||||||
.replace('_', self._escape_table['_'])
|
.replace('_', self._escape_table['_'])
|
||||||
@@ -1418,7 +1493,6 @@ class Markdown(object):
|
|||||||
def _list_item_sub(self, match):
|
def _list_item_sub(self, match):
|
||||||
item = match.group(4)
|
item = match.group(4)
|
||||||
leading_line = match.group(1)
|
leading_line = match.group(1)
|
||||||
leading_space = match.group(2)
|
|
||||||
if leading_line or "\n\n" in item or self._last_li_endswith_two_eols:
|
if leading_line or "\n\n" in item or self._last_li_endswith_two_eols:
|
||||||
item = self._run_block_gamut(self._outdent(item))
|
item = self._run_block_gamut(self._outdent(item))
|
||||||
else:
|
else:
|
||||||
@@ -1654,6 +1728,11 @@ class Markdown(object):
|
|||||||
self._escape_table[text] = hashed
|
self._escape_table[text] = hashed
|
||||||
return hashed
|
return hashed
|
||||||
|
|
||||||
|
_strike_re = re.compile(r"~~(?=\S)(.+?)(?<=\S)~~", re.S)
|
||||||
|
def _do_strike(self, text):
|
||||||
|
text = self._strike_re.sub(r"<strike>\1</strike>", text)
|
||||||
|
return text
|
||||||
|
|
||||||
_strong_re = re.compile(r"(\*\*|__)(?=\S)(.+?[*_]*)(?<=\S)\1", re.S)
|
_strong_re = re.compile(r"(\*\*|__)(?=\S)(.+?[*_]*)(?<=\S)\1", re.S)
|
||||||
_em_re = re.compile(r"(\*|_)(?=\S)(.+?)(?<=\S)\1", re.S)
|
_em_re = re.compile(r"(\*|_)(?=\S)(.+?)(?<=\S)\1", re.S)
|
||||||
_code_friendly_strong_re = re.compile(r"\*\*(?=\S)(.+?[*_]*)(?<=\S)\*\*", re.S)
|
_code_friendly_strong_re = re.compile(r"\*\*(?=\S)(.+?[*_]*)(?<=\S)\*\*", re.S)
|
||||||
@@ -1714,38 +1793,53 @@ class Markdown(object):
|
|||||||
text = text.replace(". . .", "…")
|
text = text.replace(". . .", "…")
|
||||||
return text
|
return text
|
||||||
|
|
||||||
_block_quote_re = re.compile(r'''
|
_block_quote_base = r'''
|
||||||
( # Wrap whole match in \1
|
( # Wrap whole match in \1
|
||||||
(
|
(
|
||||||
^[ \t]*>[ \t]? # '>' at the start of a line
|
^[ \t]*>%s[ \t]? # '>' at the start of a line
|
||||||
.+\n # rest of the first line
|
.+\n # rest of the first line
|
||||||
(.+\n)* # subsequent consecutive lines
|
(.+\n)* # subsequent consecutive lines
|
||||||
\n* # blanks
|
\n* # blanks
|
||||||
)+
|
)+
|
||||||
)
|
)
|
||||||
''', re.M | re.X)
|
'''
|
||||||
|
_block_quote_re = re.compile(_block_quote_base % '', re.M | re.X)
|
||||||
|
_block_quote_re_spoiler = re.compile(_block_quote_base % '[ \t]*?!?', re.M | re.X)
|
||||||
_bq_one_level_re = re.compile('^[ \t]*>[ \t]?', re.M);
|
_bq_one_level_re = re.compile('^[ \t]*>[ \t]?', re.M);
|
||||||
|
_bq_one_level_re_spoiler = re.compile('^[ \t]*>[ \t]*?![ \t]?', re.M);
|
||||||
|
_bq_all_lines_spoilers = re.compile(r'\A(?:^[ \t]*>[ \t]*?!.*[\n\r]*)+\Z', re.M)
|
||||||
_html_pre_block_re = re.compile(r'(\s*<pre>.+?</pre>)', re.S)
|
_html_pre_block_re = re.compile(r'(\s*<pre>.+?</pre>)', re.S)
|
||||||
def _dedent_two_spaces_sub(self, match):
|
def _dedent_two_spaces_sub(self, match):
|
||||||
return re.sub(r'(?m)^ ', '', match.group(1))
|
return re.sub(r'(?m)^ ', '', match.group(1))
|
||||||
|
|
||||||
def _block_quote_sub(self, match):
|
def _block_quote_sub(self, match):
|
||||||
bq = match.group(1)
|
bq = match.group(1)
|
||||||
bq = self._bq_one_level_re.sub('', bq) # trim one level of quoting
|
is_spoiler = 'spoiler' in self.extras and self._bq_all_lines_spoilers.match(bq)
|
||||||
bq = self._ws_only_line_re.sub('', bq) # trim whitespace-only lines
|
# trim one level of quoting
|
||||||
|
if is_spoiler:
|
||||||
|
bq = self._bq_one_level_re_spoiler.sub('', bq)
|
||||||
|
else:
|
||||||
|
bq = self._bq_one_level_re.sub('', bq)
|
||||||
|
# trim whitespace-only lines
|
||||||
|
bq = self._ws_only_line_re.sub('', bq)
|
||||||
bq = self._run_block_gamut(bq) # recurse
|
bq = self._run_block_gamut(bq) # recurse
|
||||||
|
|
||||||
bq = re.sub('(?m)^', ' ', bq)
|
bq = re.sub('(?m)^', ' ', bq)
|
||||||
# These leading spaces screw with <pre> content, so we need to fix that:
|
# These leading spaces screw with <pre> content, so we need to fix that:
|
||||||
bq = self._html_pre_block_re.sub(self._dedent_two_spaces_sub, bq)
|
bq = self._html_pre_block_re.sub(self._dedent_two_spaces_sub, bq)
|
||||||
|
|
||||||
return "<blockquote>\n%s\n</blockquote>\n\n" % bq
|
if is_spoiler:
|
||||||
|
return '<blockquote class="spoiler">\n%s\n</blockquote>\n\n' % bq
|
||||||
|
else:
|
||||||
|
return '<blockquote>\n%s\n</blockquote>\n\n' % bq
|
||||||
|
|
||||||
def _do_block_quotes(self, text):
|
def _do_block_quotes(self, text):
|
||||||
if '>' not in text:
|
if '>' not in text:
|
||||||
return text
|
return text
|
||||||
return self._block_quote_re.sub(self._block_quote_sub, text)
|
if 'spoiler' in self.extras:
|
||||||
|
return self._block_quote_re_spoiler.sub(self._block_quote_sub, text)
|
||||||
|
else:
|
||||||
|
return self._block_quote_re.sub(self._block_quote_sub, text)
|
||||||
|
|
||||||
def _form_paragraphs(self, text):
|
def _form_paragraphs(self, text):
|
||||||
# Strip leading and trailing lines:
|
# Strip leading and trailing lines:
|
||||||
@@ -2053,7 +2147,6 @@ def _dedentlines(lines, tabsize=8, skip_first_line=False):
|
|||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("dedent: dedent(..., tabsize=%d, skip_first_line=%r)"\
|
print("dedent: dedent(..., tabsize=%d, skip_first_line=%r)"\
|
||||||
% (tabsize, skip_first_line))
|
% (tabsize, skip_first_line))
|
||||||
indents = []
|
|
||||||
margin = None
|
margin = None
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
if i == 0 and skip_first_line: continue
|
if i == 0 and skip_first_line: continue
|
||||||
@@ -2362,4 +2455,4 @@ def main(argv=None):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit( main(sys.argv) )
|
sys.exit( main(sys.argv) )
|
||||||
@@ -7,10 +7,11 @@ import re
|
|||||||
import urllib
|
import urllib
|
||||||
from cgi import escape
|
from cgi import escape
|
||||||
from string import maketrans
|
from string import maketrans
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from ast import parse as ast_parse
|
from ast import parse as ast_parse
|
||||||
import ast
|
import ast
|
||||||
except ImportError: # python 2.5
|
except ImportError: # python 2.5
|
||||||
from compiler import parse
|
from compiler import parse
|
||||||
import compiler.ast as ast
|
import compiler.ast as ast
|
||||||
|
|
||||||
@@ -530,41 +531,47 @@ As shown in Ref.!`!`mdipierro`!`!:cite
|
|||||||
``<ul/>``, ``<ol/>``, ``<code/>``, ``<table/>``, ``<blockquote/>``, ``<h1/>``, ..., ``<h6/>`` do not have ``<p>...</p>`` around them.
|
``<ul/>``, ``<ol/>``, ``<code/>``, ``<table/>``, ``<blockquote/>``, ``<h1/>``, ..., ``<h6/>`` do not have ``<p>...</p>`` around them.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
html_colors=['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
|
html_colors = ['aqua', 'black', 'blue', 'fuchsia', 'gray', 'green',
|
||||||
'lime', 'maroon', 'navy', 'olive', 'purple', 'red',
|
'lime', 'maroon', 'navy', 'olive', 'purple', 'red',
|
||||||
'silver', 'teal', 'white', 'yellow']
|
'silver', 'teal', 'white', 'yellow']
|
||||||
|
|
||||||
META = '\x06'
|
META = '\x06'
|
||||||
LINK = '\x07'
|
LINK = '\x07'
|
||||||
DISABLED_META = '\x08'
|
DISABLED_META = '\x08'
|
||||||
LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
|
LATEX = '<img src="http://chart.apis.google.com/chart?cht=tx&chl=%s" />'
|
||||||
regex_URL=re.compile(r'@/(?P<a>\w*)/(?P<c>\w*)/(?P<f>\w*(\.\w+)?)(/(?P<args>[\w\.\-/]+))?')
|
regex_URL = re.compile(r'@/(?P<a>\w*)/(?P<c>\w*)/(?P<f>\w*(\.\w+)?)(/(?P<args>[\w\.\-/]+))?')
|
||||||
regex_env2=re.compile(r'@\{(?P<a>[\w\-\.]+?)(\:(?P<b>.*?))?\}')
|
regex_env2 = re.compile(r'@\{(?P<a>[\w\-\.]+?)(\:(?P<b>.*?))?\}')
|
||||||
regex_expand_meta = re.compile('('+META+'|'+DISABLED_META+'|````)')
|
regex_expand_meta = re.compile('(' + META + '|' + DISABLED_META + '|````)')
|
||||||
regex_dd=re.compile(r'\$\$(?P<latex>.*?)\$\$')
|
regex_dd = re.compile(r'\$\$(?P<latex>.*?)\$\$')
|
||||||
regex_code = re.compile('('+META+'|'+DISABLED_META+r'|````)|(``(?P<t>.+?)``(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[^\]]*)\])?)?)',re.S)
|
regex_code = re.compile(
|
||||||
regex_strong=re.compile(r'\*\*(?P<t>[^\s*]+( +[^\s*]+)*)\*\*')
|
'(' + META + '|' + DISABLED_META + r'|````)|(``(?P<t>.+?)``(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[^\]]*)\])?)?)',
|
||||||
regex_del=re.compile(r'~~(?P<t>[^\s*]+( +[^\s*]+)*)~~')
|
re.S)
|
||||||
regex_em=re.compile(r"''(?P<t>([^\s']| |'(?!'))+)''")
|
regex_strong = re.compile(r'\*\*(?P<t>[^\s*]+( +[^\s*]+)*)\*\*')
|
||||||
regex_num=re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$")
|
regex_del = re.compile(r'~~(?P<t>[^\s*]+( +[^\s*]+)*)~~')
|
||||||
regex_list=re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s*)?(.*)$')
|
regex_em = re.compile(r"''(?P<t>([^\s']| |'(?!'))+)''")
|
||||||
regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
|
regex_num = re.compile(r"^\s*[+-]?((\d+(\.\d*)?)|\.\d+)([eE][+-]?[0-9]+)?\s*$")
|
||||||
regex_tq=re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
|
regex_list = re.compile('^(?:(?:(#{1,6})|(?:(\.+|\++|\-+)(\.)?))\s*)?(.*)$')
|
||||||
|
regex_bq_headline = re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$')
|
||||||
|
regex_tq = re.compile('^(-{3}-*)(?::(?P<c>[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P<p>[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$')
|
||||||
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
regex_proto = re.compile(r'(?<!["\w>/=])(?P<p>\w+):(?P<k>\w+://[\w\d\-+=?%&/:.]+)', re.M)
|
||||||
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.,;#]+\w|[\w\-.]+@[\w\-.]+)',re.M)
|
regex_auto = re.compile(r'(?<!["\w>/=])(?P<k>\w+://[\w\d\-+_=?%&/:.,;#]+\w|[\w\-.]+@[\w\-.]+)', re.M)
|
||||||
regex_link=re.compile(r'('+LINK+r')|\[\[(?P<s>.+?)\]\]',re.S)
|
regex_link = re.compile(r'(' + LINK + r')|\[\[(?P<s>.+?)\]\]', re.S)
|
||||||
regex_link_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$',re.S)
|
regex_link_level2 = re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?(?:\s+(?P<p>popup))?\s*$', re.S)
|
||||||
regex_media_level2=re.compile(r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio|blockleft|blockright)(?:\s+(?P<w>\d+px))?\s*$',re.S)
|
regex_media_level2 = re.compile(
|
||||||
|
r'^(?P<t>\S.*?)?(?:\s+\[(?P<a>.+?)\])?(?:\s+(?P<k>\S+))?\s+(?P<p>img|IMG|left|right|center|video|audio|blockleft|blockright)(?:\s+(?P<w>\d+px))?\s*$',
|
||||||
|
re.S)
|
||||||
|
|
||||||
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#\n])")
|
regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#\n])")
|
||||||
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#\n])")
|
regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#\n])")
|
||||||
ttab_in = maketrans("'`:*~\\[]{}@$+-.#\n", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05')
|
ttab_in = maketrans("'`:*~\\[]{}@$+-.#\n", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05')
|
||||||
ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05',"'`:*~\\[]{}@$+-.#\n")
|
ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05', "'`:*~\\[]{}@$+-.#\n")
|
||||||
regex_quote = re.compile('(?P<name>\w+?)\s*\=\s*')
|
regex_quote = re.compile('(?P<name>\w+?)\s*\=\s*')
|
||||||
|
|
||||||
|
|
||||||
def make_dict(b):
|
def make_dict(b):
|
||||||
return '{%s}' % regex_quote.sub("'\g<name>':",b)
|
return '{%s}' % regex_quote.sub("'\g<name>':", b)
|
||||||
|
|
||||||
|
|
||||||
def safe_eval(node_or_string, env):
|
def safe_eval(node_or_string, env):
|
||||||
"""
|
"""
|
||||||
Safely evaluate an expression node or a string containing a Python
|
Safely evaluate an expression node or a string containing a Python
|
||||||
@@ -578,6 +585,7 @@ def safe_eval(node_or_string, env):
|
|||||||
node_or_string = ast_parse(node_or_string, mode='eval')
|
node_or_string = ast_parse(node_or_string, mode='eval')
|
||||||
if isinstance(node_or_string, ast.Expression):
|
if isinstance(node_or_string, ast.Expression):
|
||||||
node_or_string = node_or_string.body
|
node_or_string = node_or_string.body
|
||||||
|
|
||||||
def _convert(node):
|
def _convert(node):
|
||||||
if isinstance(node, ast.Str):
|
if isinstance(node, ast.Str):
|
||||||
return node.s
|
return node.s
|
||||||
@@ -594,11 +602,11 @@ def safe_eval(node_or_string, env):
|
|||||||
if node.id in _safe_names:
|
if node.id in _safe_names:
|
||||||
return _safe_names[node.id]
|
return _safe_names[node.id]
|
||||||
elif isinstance(node, ast.BinOp) and \
|
elif isinstance(node, ast.BinOp) and \
|
||||||
isinstance(node.op, (Add, Sub)) and \
|
isinstance(node.op, (Add, Sub)) and \
|
||||||
isinstance(node.right, Num) and \
|
isinstance(node.right, Num) and \
|
||||||
isinstance(node.right.n, complex) and \
|
isinstance(node.right.n, complex) and \
|
||||||
isinstance(node.left, Num) and \
|
isinstance(node.left, Num) and \
|
||||||
isinstance(node.left.n, (int, long, float)):
|
isinstance(node.left.n, (int, long, float)):
|
||||||
left = node.left.n
|
left = node.left.n
|
||||||
right = node.right.n
|
right = node.right.n
|
||||||
if isinstance(node.op, Add):
|
if isinstance(node.op, Add):
|
||||||
@@ -606,57 +614,66 @@ def safe_eval(node_or_string, env):
|
|||||||
else:
|
else:
|
||||||
return left - right
|
return left - right
|
||||||
raise ValueError('malformed string')
|
raise ValueError('malformed string')
|
||||||
|
|
||||||
return _convert(node_or_string)
|
return _convert(node_or_string)
|
||||||
|
|
||||||
|
|
||||||
def markmin_escape(text):
|
def markmin_escape(text):
|
||||||
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
|
""" insert \\ before markmin control characters: '`:*~[]{}@$ """
|
||||||
return regex_markmin_escape.sub(
|
return regex_markmin_escape.sub(
|
||||||
lambda m: '\\'+m.group(0).replace('\\','\\\\'), text)
|
lambda m: '\\' + m.group(0).replace('\\', '\\\\'), text)
|
||||||
|
|
||||||
def replace_autolinks(text,autolinks):
|
|
||||||
|
def replace_autolinks(text, autolinks):
|
||||||
return regex_auto.sub(lambda m: autolinks(m.group('k')), text)
|
return regex_auto.sub(lambda m: autolinks(m.group('k')), text)
|
||||||
|
|
||||||
def replace_at_urls(text,url):
|
|
||||||
# this is experimental @{function/args}
|
|
||||||
def u1(match,url=url):
|
|
||||||
a,c,f,args = match.group('a','c','f','args')
|
|
||||||
return url(a=a or None,c=c or None,f = f or None,
|
|
||||||
args=(args or '').split('/'), scheme=True, host=True)
|
|
||||||
return regex_URL.sub(u1,text)
|
|
||||||
|
|
||||||
def replace_components(text,env):
|
def replace_at_urls(text, url):
|
||||||
|
# this is experimental @{function/args}
|
||||||
|
def u1(match, url=url):
|
||||||
|
a, c, f, args = match.group('a', 'c', 'f', 'args')
|
||||||
|
return url(a=a or None, c=c or None, f=f or None,
|
||||||
|
args=(args or '').split('/'), scheme=True, host=True)
|
||||||
|
|
||||||
|
return regex_URL.sub(u1, text)
|
||||||
|
|
||||||
|
|
||||||
|
def replace_components(text, env):
|
||||||
# not perfect but acceptable
|
# not perfect but acceptable
|
||||||
def u2(match, env=env):
|
def u2(match, env=env):
|
||||||
f = env.get(match.group('a'), match.group(0))
|
f = env.get(match.group('a'), match.group(0))
|
||||||
if callable(f):
|
if callable(f):
|
||||||
b = match.group('b')
|
b = match.group('b')
|
||||||
try:
|
try:
|
||||||
b = safe_eval(make_dict(b),env)
|
b = safe_eval(make_dict(b), env)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
f = f(**b) if isinstance(b,dict) else f(b)
|
f = f(**b) if isinstance(b, dict) else f(b)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
f = 'ERROR: %s' % e
|
f = 'ERROR: %s' % e
|
||||||
return str(f)
|
return str(f)
|
||||||
|
|
||||||
text = regex_env2.sub(u2, text)
|
text = regex_env2.sub(u2, text)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def autolinks_simple(url):
|
def autolinks_simple(url):
|
||||||
"""
|
"""
|
||||||
it automatically converts the url to link,
|
it automatically converts the url to link,
|
||||||
image, video or audio tag
|
image, video or audio tag
|
||||||
"""
|
"""
|
||||||
u_url=url.lower()
|
u_url = url.lower()
|
||||||
if '@' in url and not '://' in url:
|
if '@' in url and '://' not in url:
|
||||||
return '<a href="mailto:%s">%s</a>' % (url, url)
|
return '<a href="mailto:%s">%s</a>' % (url, url)
|
||||||
elif u_url.endswith(('.jpg','.jpeg','.gif','.png')):
|
elif u_url.endswith(('.jpg', '.jpeg', '.gif', '.png')):
|
||||||
return '<img src="%s" controls />' % url
|
return '<img src="%s" controls />' % url
|
||||||
elif u_url.endswith(('.mp4','.mpeg','.mov','.ogv')):
|
elif u_url.endswith(('.mp4', '.mpeg', '.mov', '.ogv')):
|
||||||
return '<video src="%s" controls></video>' % url
|
return '<video src="%s" controls></video>' % url
|
||||||
elif u_url.endswith(('.mp3','.wav','.ogg')):
|
elif u_url.endswith(('.mp3', '.wav', '.ogg')):
|
||||||
return '<audio src="%s" controls></audio>' % url
|
return '<audio src="%s" controls></audio>' % url
|
||||||
return '<a href="%s">%s</a>' % (url,url)
|
return '<a href="%s">%s</a>' % (url, url)
|
||||||
|
|
||||||
|
|
||||||
def protolinks_simple(proto, url):
|
def protolinks_simple(proto, url):
|
||||||
"""
|
"""
|
||||||
@@ -667,16 +684,18 @@ def protolinks_simple(proto, url):
|
|||||||
proto="iframe"
|
proto="iframe"
|
||||||
url="http://www.example.com/path"
|
url="http://www.example.com/path"
|
||||||
"""
|
"""
|
||||||
if proto in ('iframe','embed'): #== 'iframe':
|
if proto in ('iframe', 'embed'): # == 'iframe':
|
||||||
return '<iframe src="%s" frameborder="0" allowfullscreen></iframe>'%url
|
return '<iframe src="%s" frameborder="0" allowfullscreen></iframe>' % url
|
||||||
#elif proto == 'embed': # NOTE: embed is a synonym to iframe now
|
# elif proto == 'embed': # NOTE: embed is a synonym to iframe now
|
||||||
# return '<a href="%s" class="%sembed">%s></a>'%(url,class_prefix,url)
|
# return '<a href="%s" class="%sembed">%s></a>'%(url,class_prefix,url)
|
||||||
elif proto == 'qr':
|
elif proto == 'qr':
|
||||||
return '<img style="width:100px" src="http://chart.apis.google.com/chart?cht=qr&chs=100x100&chl=%s&choe=UTF-8&chld=H" alt="QR Code" title="QR Code" />'%url
|
return '<img style="width:100px" src="http://chart.apis.google.com/chart?cht=qr&chs=100x100&chl=%s&choe=UTF-8&chld=H" alt="QR Code" title="QR Code" />' % url
|
||||||
return proto+':'+url
|
return proto + ':' + url
|
||||||
|
|
||||||
|
|
||||||
def email_simple(email):
|
def email_simple(email):
|
||||||
return '<a href="mailto:%s">%s</a>' % (email, email)
|
return '<a href="mailto:%s">%s</a>' % (email, email)
|
||||||
|
|
||||||
|
|
||||||
def render(text,
|
def render(text,
|
||||||
extra={},
|
extra={},
|
||||||
@@ -925,17 +944,19 @@ def render(text,
|
|||||||
>>> render("anchor with name 'NEWLINE': [[NEWLINE [newline] ]]")
|
>>> render("anchor with name 'NEWLINE': [[NEWLINE [newline] ]]")
|
||||||
'<p>anchor with name \\'NEWLINE\\': <span class="anchor" id="markmin_NEWLINE">newline</span></p>'
|
'<p>anchor with name \\'NEWLINE\\': <span class="anchor" id="markmin_NEWLINE">newline</span></p>'
|
||||||
"""
|
"""
|
||||||
if autolinks=="default": autolinks = autolinks_simple
|
if autolinks == "default":
|
||||||
if protolinks=="default": protolinks = protolinks_simple
|
autolinks = autolinks_simple
|
||||||
pp='\n' if pretty_print else ''
|
if protolinks == "default":
|
||||||
if isinstance(text,unicode):
|
protolinks = protolinks_simple
|
||||||
|
pp = '\n' if pretty_print else ''
|
||||||
|
if isinstance(text, unicode):
|
||||||
text = text.encode('utf8')
|
text = text.encode('utf8')
|
||||||
text = str(text or '')
|
text = str(text or '')
|
||||||
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
|
text = regex_backslash.sub(lambda m: m.group(1).translate(ttab_in), text)
|
||||||
text = text.replace('\x05','').replace('\r\n', '\n') # concatenate strings separeted by \\n
|
text = text.replace('\x05', '').replace('\r\n', '\n') # concatenate strings separeted by \\n
|
||||||
|
|
||||||
if URL is not None:
|
if URL is not None:
|
||||||
text = replace_at_urls(text,URL)
|
text = replace_at_urls(text, URL)
|
||||||
|
|
||||||
if latex == 'google':
|
if latex == 'google':
|
||||||
text = regex_dd.sub('``\g<latex>``:latex ', text)
|
text = regex_dd.sub('``\g<latex>``:latex ', text)
|
||||||
@@ -945,9 +966,10 @@ def render(text,
|
|||||||
# store them into segments they will be treated as code
|
# store them into segments they will be treated as code
|
||||||
#############################################################
|
#############################################################
|
||||||
segments = []
|
segments = []
|
||||||
|
|
||||||
def mark_code(m):
|
def mark_code(m):
|
||||||
g = m.group(0)
|
g = m.group(0)
|
||||||
if g in (META, DISABLED_META ):
|
if g in (META, DISABLED_META):
|
||||||
segments.append((None, None, None, g))
|
segments.append((None, None, None, g))
|
||||||
return m.group()
|
return m.group()
|
||||||
elif g == '````':
|
elif g == '````':
|
||||||
@@ -956,10 +978,12 @@ def render(text,
|
|||||||
else:
|
else:
|
||||||
c = m.group('c') or ''
|
c = m.group('c') or ''
|
||||||
p = m.group('p') or ''
|
p = m.group('p') or ''
|
||||||
if 'code' in allowed and not c in allowed['code']: c = ''
|
if 'code' in allowed and c not in allowed['code']:
|
||||||
code = m.group('t').replace('!`!','`')
|
c = ''
|
||||||
|
code = m.group('t').replace('!`!', '`')
|
||||||
segments.append((code, c, p, m.group(0)))
|
segments.append((code, c, p, m.group(0)))
|
||||||
return META
|
return META
|
||||||
|
|
||||||
text = regex_code.sub(mark_code, text)
|
text = regex_code.sub(mark_code, text)
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
@@ -967,56 +991,58 @@ def render(text,
|
|||||||
# store them into links they will be treated as link
|
# store them into links they will be treated as link
|
||||||
#############################################################
|
#############################################################
|
||||||
links = []
|
links = []
|
||||||
|
|
||||||
def mark_link(m):
|
def mark_link(m):
|
||||||
links.append( None if m.group() == LINK
|
links.append(None if m.group() == LINK
|
||||||
else m.group('s') )
|
else m.group('s'))
|
||||||
return LINK
|
return LINK
|
||||||
|
|
||||||
text = regex_link.sub(mark_link, text)
|
text = regex_link.sub(mark_link, text)
|
||||||
text = escape(text)
|
text = escape(text)
|
||||||
|
|
||||||
if protolinks:
|
if protolinks:
|
||||||
text = regex_proto.sub(lambda m: protolinks(*m.group('p','k')), text)
|
text = regex_proto.sub(lambda m: protolinks(*m.group('p', 'k')), text)
|
||||||
|
|
||||||
if autolinks:
|
if autolinks:
|
||||||
text = replace_autolinks(text,autolinks)
|
text = replace_autolinks(text, autolinks)
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# normalize spaces
|
# normalize spaces
|
||||||
#############################################################
|
#############################################################
|
||||||
strings=text.split('\n')
|
strings = text.split('\n')
|
||||||
|
|
||||||
def parse_title(t, s): #out, lev, etags, tag, s):
|
def parse_title(t, s): # out, lev, etags, tag, s):
|
||||||
hlevel=str(len(t))
|
hlevel = str(len(t))
|
||||||
out.extend(etags[::-1])
|
out.extend(etags[::-1])
|
||||||
out.append("<h%s>%s"%(hlevel,s))
|
out.append("<h%s>%s" % (hlevel, s))
|
||||||
etags[:]=["</h%s>%s"%(hlevel,pp)]
|
etags[:] = ["</h%s>%s" % (hlevel, pp)]
|
||||||
lev=0
|
lev = 0
|
||||||
ltags[:]=[]
|
ltags[:] = []
|
||||||
tlev[:]=[]
|
tlev[:] = []
|
||||||
return (lev, 'h')
|
return (lev, 'h')
|
||||||
|
|
||||||
def parse_list(t, p, s, tag, lev, mtag, lineno):
|
def parse_list(t, p, s, tag, lev, mtag, lineno):
|
||||||
lent=len(t)
|
lent = len(t)
|
||||||
if lent<lev: # current item level < previous item level
|
if lent < lev: # current item level < previous item level
|
||||||
while ltags[-1]>lent:
|
while ltags[-1] > lent:
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
lev=lent
|
lev = lent
|
||||||
tlev[lev:]=[]
|
tlev[lev:] = []
|
||||||
|
|
||||||
if lent>lev: # current item level > previous item level
|
if lent > lev: # current item level > previous item level
|
||||||
if lev==0: # previous line is not a list (paragraph or title)
|
if lev == 0: # previous line is not a list (paragraph or title)
|
||||||
out.extend(etags[::-1])
|
out.extend(etags[::-1])
|
||||||
ltags[:]=[]
|
ltags[:] = []
|
||||||
tlev[:]=[]
|
tlev[:] = []
|
||||||
etags[:]=[]
|
etags[:] = []
|
||||||
if pend and mtag == '.': # paragraph in a list:
|
if pend and mtag == '.': # paragraph in a list:
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
for i in xrange(lent-lev):
|
for i in xrange(lent - lev):
|
||||||
out.append('<'+tag+'>'+pp)
|
out.append('<' + tag + '>' + pp)
|
||||||
etags.append('</'+tag+'>'+pp)
|
etags.append('</' + tag + '>' + pp)
|
||||||
lev+=1
|
lev += 1
|
||||||
ltags.append(lev)
|
ltags.append(lev)
|
||||||
tlev.append(tag)
|
tlev.append(tag)
|
||||||
elif lent == lev:
|
elif lent == lev:
|
||||||
@@ -1025,22 +1051,22 @@ def render(text,
|
|||||||
for i in xrange(ltags.count(lent)):
|
for i in xrange(ltags.count(lent)):
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
tlev[-1]=tag
|
tlev[-1] = tag
|
||||||
out.append('<'+tag+'>'+pp)
|
out.append('<' + tag + '>' + pp)
|
||||||
etags.append('</'+tag+'>'+pp)
|
etags.append('</' + tag + '>' + pp)
|
||||||
ltags.append(lev)
|
ltags.append(lev)
|
||||||
else:
|
else:
|
||||||
if ltags.count(lev)>1:
|
if ltags.count(lev) > 1:
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
mtag='l'
|
mtag = 'l'
|
||||||
out.append('<li>')
|
out.append('<li>')
|
||||||
etags.append('</li>'+pp)
|
etags.append('</li>' + pp)
|
||||||
ltags.append(lev)
|
ltags.append(lev)
|
||||||
if s[:1] == '-':
|
if s[:1] == '-':
|
||||||
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
||||||
if p and mtag=='l':
|
if p and mtag == 'l':
|
||||||
(lev,mtag,lineno)=parse_point(t, s, lev, '', lineno)
|
(lev, mtag, lineno) = parse_point(t, s, lev, '', lineno)
|
||||||
else:
|
else:
|
||||||
out.append(s)
|
out.append(s)
|
||||||
|
|
||||||
@@ -1048,28 +1074,28 @@ def render(text,
|
|||||||
|
|
||||||
def parse_point(t, s, lev, mtag, lineno):
|
def parse_point(t, s, lev, mtag, lineno):
|
||||||
""" paragraphs in lists """
|
""" paragraphs in lists """
|
||||||
lent=len(t)
|
lent = len(t)
|
||||||
if lent>lev:
|
if lent > lev:
|
||||||
return parse_list(t, '.', s, 'ul', lev, mtag, lineno)
|
return parse_list(t, '.', s, 'ul', lev, mtag, lineno)
|
||||||
elif lent<lev:
|
elif lent < lev:
|
||||||
while ltags[-1]>lent:
|
while ltags[-1] > lent:
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
lev=lent
|
lev = lent
|
||||||
tlev[lev:]=[]
|
tlev[lev:] = []
|
||||||
mtag=''
|
mtag = ''
|
||||||
elif lent==lev:
|
elif lent == lev:
|
||||||
if pend and mtag == '.':
|
if pend and mtag == '.':
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
if br and mtag in ('l','.'):
|
if br and mtag in ('l', '.'):
|
||||||
out.append(br)
|
out.append(br)
|
||||||
if s == META:
|
if s == META:
|
||||||
mtag = ''
|
mtag = ''
|
||||||
else:
|
else:
|
||||||
mtag = '.'
|
mtag = '.'
|
||||||
if s[:1] == '-':
|
if s[:1] == '-':
|
||||||
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
||||||
if mtag == '.':
|
if mtag == '.':
|
||||||
out.append(pbeg)
|
out.append(pbeg)
|
||||||
if pend:
|
if pend:
|
||||||
@@ -1083,19 +1109,19 @@ def render(text,
|
|||||||
# - is empty -> this is an <hr /> tag
|
# - is empty -> this is an <hr /> tag
|
||||||
# - consists '|' -> table
|
# - consists '|' -> table
|
||||||
# - consists other characters -> blockquote
|
# - consists other characters -> blockquote
|
||||||
if (lineno+1 >= strings_len or
|
if (lineno + 1 >= strings_len or
|
||||||
not(s.count('-') == len(s) and len(s)>3)):
|
not (s.count('-') == len(s) and len(s) > 3)):
|
||||||
return (s, mtag, lineno)
|
return (s, mtag, lineno)
|
||||||
|
|
||||||
lineno+=1
|
lineno += 1
|
||||||
s = strings[lineno].strip()
|
s = strings[lineno].strip()
|
||||||
if s:
|
if s:
|
||||||
if '|' in s:
|
if '|' in s:
|
||||||
# table
|
# table
|
||||||
tout=[]
|
tout = []
|
||||||
thead=[]
|
thead = []
|
||||||
tbody=[]
|
tbody = []
|
||||||
rownum=0
|
rownum = 0
|
||||||
t_id = ''
|
t_id = ''
|
||||||
t_cls = ''
|
t_cls = ''
|
||||||
|
|
||||||
@@ -1104,14 +1130,14 @@ def render(text,
|
|||||||
s = strings[lineno].strip()
|
s = strings[lineno].strip()
|
||||||
if s[:1] == '=':
|
if s[:1] == '=':
|
||||||
# header or footer
|
# header or footer
|
||||||
if s.count('=')==len(s) and len(s)>3:
|
if s.count('=') == len(s) and len(s) > 3:
|
||||||
if not thead: # if thead list is empty:
|
if not thead: # if thead list is empty:
|
||||||
thead = tout
|
thead = tout
|
||||||
else:
|
else:
|
||||||
tbody.extend(tout)
|
tbody.extend(tout)
|
||||||
tout = []
|
tout = []
|
||||||
rownum=0
|
rownum = 0
|
||||||
lineno+=1
|
lineno += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
m = regex_tq.match(s)
|
m = regex_tq.match(s)
|
||||||
@@ -1121,36 +1147,36 @@ def render(text,
|
|||||||
break
|
break
|
||||||
|
|
||||||
if rownum % 2:
|
if rownum % 2:
|
||||||
tr = '<tr class="even">'
|
tr = '<tr class="even">'
|
||||||
else:
|
else:
|
||||||
tr = '<tr class="first">' if rownum == 0 else '<tr>'
|
tr = '<tr class="first">' if rownum == 0 else '<tr>'
|
||||||
tout.append(tr + ''.join(['<td%s>%s</td>' % (
|
tout.append(tr + ''.join(['<td%s>%s</td>' % (
|
||||||
' class="num"'
|
' class="num"'
|
||||||
if regex_num.match(f) else '',
|
if regex_num.match(f) else '',
|
||||||
f.strip()
|
f.strip()
|
||||||
) for f in s.split('|')])+'</tr>'+pp)
|
) for f in s.split('|')]) + '</tr>' + pp)
|
||||||
rownum+=1
|
rownum += 1
|
||||||
lineno+=1
|
lineno += 1
|
||||||
|
|
||||||
t_cls = ' class="%s%s"'%(class_prefix, t_cls) \
|
t_cls = ' class="%s%s"' % (class_prefix, t_cls) \
|
||||||
if t_cls and t_cls != 'id' else ''
|
if t_cls and t_cls != 'id' else ''
|
||||||
t_id = ' id="%s%s"'%(id_prefix, t_id) if t_id else ''
|
t_id = ' id="%s%s"' % (id_prefix, t_id) if t_id else ''
|
||||||
s = ''
|
s = ''
|
||||||
if thead:
|
if thead:
|
||||||
s += '<thead>'+pp+''.join([l for l in thead])+'</thead>'+pp
|
s += '<thead>' + pp + ''.join([l for l in thead]) + '</thead>' + pp
|
||||||
if not tbody: # tbody strings are in tout list
|
if not tbody: # tbody strings are in tout list
|
||||||
tbody = tout
|
tbody = tout
|
||||||
tout = []
|
tout = []
|
||||||
if tbody: # if tbody list is not empty:
|
if tbody: # if tbody list is not empty:
|
||||||
s += '<tbody>'+pp+''.join([l for l in tbody])+'</tbody>'+pp
|
s += '<tbody>' + pp + ''.join([l for l in tbody]) + '</tbody>' + pp
|
||||||
if tout: # tfoot is not empty:
|
if tout: # tfoot is not empty:
|
||||||
s += '<tfoot>'+pp+''.join([l for l in tout])+'</tfoot>'+pp
|
s += '<tfoot>' + pp + ''.join([l for l in tout]) + '</tfoot>' + pp
|
||||||
s = '<table%s%s>%s%s</table>%s' % (t_cls, t_id, pp, s, pp)
|
s = '<table%s%s>%s%s</table>%s' % (t_cls, t_id, pp, s, pp)
|
||||||
mtag='t'
|
mtag = 't'
|
||||||
else:
|
else:
|
||||||
# parse blockquote:
|
# parse blockquote:
|
||||||
bq_begin=lineno
|
bq_begin = lineno
|
||||||
t_mode = False # embedded table
|
t_mode = False # embedded table
|
||||||
t_cls = ''
|
t_cls = ''
|
||||||
t_id = ''
|
t_id = ''
|
||||||
|
|
||||||
@@ -1160,57 +1186,57 @@ def render(text,
|
|||||||
if not t_mode:
|
if not t_mode:
|
||||||
m = regex_tq.match(s)
|
m = regex_tq.match(s)
|
||||||
if m:
|
if m:
|
||||||
if (lineno+1 == strings_len or
|
if (lineno + 1 == strings_len or
|
||||||
'|' not in strings[lineno+1]):
|
'|' not in strings[lineno + 1]):
|
||||||
t_cls = m.group('c') or ''
|
t_cls = m.group('c') or ''
|
||||||
t_id = m.group('p') or ''
|
t_id = m.group('p') or ''
|
||||||
break
|
break
|
||||||
|
|
||||||
if regex_bq_headline.match(s):
|
if regex_bq_headline.match(s):
|
||||||
if (lineno+1 < strings_len and
|
if (lineno + 1 < strings_len and
|
||||||
strings[lineno+1].strip()):
|
strings[lineno + 1].strip()):
|
||||||
t_mode = True
|
t_mode = True
|
||||||
lineno+=1
|
lineno += 1
|
||||||
continue
|
continue
|
||||||
elif regex_tq.match(s):
|
elif regex_tq.match(s):
|
||||||
t_mode=False
|
t_mode = False
|
||||||
lineno+=1
|
lineno += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
lineno+=1
|
lineno += 1
|
||||||
|
|
||||||
t_cls = ' class="%s%s"'%(class_prefix,t_cls) \
|
t_cls = ' class="%s%s"' % (class_prefix, t_cls) \
|
||||||
if t_cls and t_cls != 'id' else ''
|
if t_cls and t_cls != 'id' else ''
|
||||||
t_id = ' id="%s%s"'%(id_prefix,t_id) \
|
t_id = ' id="%s%s"' % (id_prefix, t_id) \
|
||||||
if t_id else ''
|
if t_id else ''
|
||||||
|
|
||||||
s = '<blockquote%s%s>%s</blockquote>%s' \
|
s = '<blockquote%s%s>%s</blockquote>%s' \
|
||||||
% (t_cls,
|
% (t_cls,
|
||||||
t_id,
|
t_id,
|
||||||
'\n'.join(strings[bq_begin:lineno]),pp)
|
'\n'.join(strings[bq_begin:lineno]), pp)
|
||||||
mtag='q'
|
mtag = 'q'
|
||||||
else:
|
else:
|
||||||
s = '<hr />'
|
s = '<hr />'
|
||||||
lineno-=1
|
lineno -= 1
|
||||||
mtag='q'
|
mtag = 'q'
|
||||||
return (s, 'q', lineno)
|
return (s, 'q', lineno)
|
||||||
|
|
||||||
if sep == 'p':
|
if sep == 'p':
|
||||||
pbeg = "<p>"
|
pbeg = "<p>"
|
||||||
pend = "</p>"+pp
|
pend = "</p>" + pp
|
||||||
br = ''
|
br = ''
|
||||||
else:
|
else:
|
||||||
pbeg = pend = ''
|
pbeg = pend = ''
|
||||||
br = "<br />"+pp if sep=='br' else ''
|
br = "<br />" + pp if sep == 'br' else ''
|
||||||
|
|
||||||
lev = 0 # nesting level of lists
|
lev = 0 # nesting level of lists
|
||||||
c0 = '' # first character of current line
|
c0 = '' # first character of current line
|
||||||
out = [] # list of processed lines
|
out = [] # list of processed lines
|
||||||
etags = [] # trailing tags
|
etags = [] # trailing tags
|
||||||
ltags = [] # level# correspondent to trailing tag
|
ltags = [] # level# correspondent to trailing tag
|
||||||
tlev = [] # list of tags for each level ('ul' or 'ol')
|
tlev = [] # list of tags for each level ('ul' or 'ol')
|
||||||
mtag = '' # marked tag (~last tag) ('l','.','h','p','t'). Used to set <br/>
|
mtag = '' # marked tag (~last tag) ('l','.','h','p','t'). Used to set <br/>
|
||||||
# and to avoid <p></p> around tables and blockquotes
|
# and to avoid <p></p> around tables and blockquotes
|
||||||
lineno = 0
|
lineno = 0
|
||||||
strings_len = len(strings)
|
strings_len = len(strings)
|
||||||
while lineno < strings_len:
|
while lineno < strings_len:
|
||||||
@@ -1222,65 +1248,67 @@ def render(text,
|
|||||||
#### ++++ ---- .... ------- field | field | field <-body
|
#### ++++ ---- .... ------- field | field | field <-body
|
||||||
##### +++++ ----- ..... ---------------------:class[id]
|
##### +++++ ----- ..... ---------------------:class[id]
|
||||||
"""
|
"""
|
||||||
pc0=c0 # first character of previous line
|
pc0 = c0 # first character of previous line
|
||||||
c0=s[:1]
|
c0 = s[:1]
|
||||||
if c0: # for non empty strings
|
if c0: # for non empty strings
|
||||||
if c0 in "#+-.": # first character is one of: # + - .
|
if c0 in "#+-.": # first character is one of: # + - .
|
||||||
(t1,t2,p,ss) = regex_list.findall(s)[0]
|
(t1, t2, p, ss) = regex_list.findall(s)[0]
|
||||||
# t1 - tag ("###")
|
# t1 - tag ("###")
|
||||||
# t2 - tag ("+++", "---", "...")
|
# t2 - tag ("+++", "---", "...")
|
||||||
# p - paragraph point ('.')->for "++." or "--."
|
# p - paragraph point ('.')->for "++." or "--."
|
||||||
# ss - other part of string
|
# ss - other part of string
|
||||||
if t1 or t2:
|
if t1 or t2:
|
||||||
# headers and lists:
|
# headers and lists:
|
||||||
if c0 == '#': # headers
|
if c0 == '#': # headers
|
||||||
(lev, mtag) = parse_title(t1, ss)
|
(lev, mtag) = parse_title(t1, ss)
|
||||||
lineno+=1
|
lineno += 1
|
||||||
continue
|
continue
|
||||||
elif c0 == '+': # ordered list
|
elif c0 == '+': # ordered list
|
||||||
(lev, mtag, lineno)= parse_list(t2, p, ss, 'ol', lev, mtag, lineno)
|
(lev, mtag, lineno) = parse_list(t2, p, ss, 'ol', lev, mtag, lineno)
|
||||||
lineno+=1
|
lineno += 1
|
||||||
continue
|
continue
|
||||||
elif c0 == '-': # unordered list, table or blockquote
|
elif c0 == '-': # unordered list, table or blockquote
|
||||||
if p or ss:
|
if p or ss:
|
||||||
(lev, mtag, lineno) = parse_list(t2, p, ss, 'ul', lev, mtag, lineno)
|
(lev, mtag, lineno) = parse_list(t2, p, ss, 'ul', lev, mtag, lineno)
|
||||||
lineno+=1
|
lineno += 1
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
(s, mtag, lineno) = parse_table_or_blockquote(s, mtag, lineno)
|
||||||
elif lev>0: # and c0 == '.' # paragraph in lists
|
elif lev > 0: # and c0 == '.' # paragraph in lists
|
||||||
(lev, mtag, lineno) = parse_point(t2, ss, lev, mtag, lineno)
|
(lev, mtag, lineno) = parse_point(t2, ss, lev, mtag, lineno)
|
||||||
lineno+=1
|
lineno += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if lev == 0 and (mtag == 'q' or s == META):
|
if lev == 0 and (mtag == 'q' or s == META):
|
||||||
# new paragraph
|
# new paragraph
|
||||||
pc0=''
|
pc0 = ''
|
||||||
|
|
||||||
if pc0 == '' or (mtag != 'p' and s0 not in (' ','\t')):
|
if pc0 == '' or (mtag != 'p' and s0 not in (' ', '\t')):
|
||||||
# paragraph
|
# paragraph
|
||||||
out.extend(etags[::-1])
|
out.extend(etags[::-1])
|
||||||
etags=[]
|
etags = []
|
||||||
ltags=[]
|
ltags = []
|
||||||
tlev=[]
|
tlev = []
|
||||||
lev=0
|
lev = 0
|
||||||
if br and mtag == 'p': out.append(br)
|
if br and mtag == 'p':
|
||||||
|
out.append(br)
|
||||||
if mtag != 'q' and s != META:
|
if mtag != 'q' and s != META:
|
||||||
if pend: etags=[pend]
|
if pend:
|
||||||
out.append(pbeg)
|
etags = [pend]
|
||||||
mtag = 'p'
|
out.append(pbeg)
|
||||||
|
mtag = 'p'
|
||||||
else:
|
else:
|
||||||
mtag = ''
|
mtag = ''
|
||||||
out.append(s)
|
out.append(s)
|
||||||
else:
|
else:
|
||||||
if lev>0 and mtag=='.' and s == META:
|
if lev > 0 and mtag == '.' and s == META:
|
||||||
out.append(etags.pop())
|
out.append(etags.pop())
|
||||||
ltags.pop()
|
ltags.pop()
|
||||||
out.append(s)
|
out.append(s)
|
||||||
mtag = ''
|
mtag = ''
|
||||||
else:
|
else:
|
||||||
out.append(' '+s)
|
out.append(' ' + s)
|
||||||
lineno+=1
|
lineno += 1
|
||||||
out.extend(etags[::-1])
|
out.extend(etags[::-1])
|
||||||
text = ''.join(out)
|
text = ''.join(out)
|
||||||
|
|
||||||
@@ -1295,7 +1323,7 @@ def render(text,
|
|||||||
# deal with images, videos, audios and links
|
# deal with images, videos, audios and links
|
||||||
#############################################################
|
#############################################################
|
||||||
def sub_media(m):
|
def sub_media(m):
|
||||||
t,a,k,p,w = m.group('t','a','k','p','w')
|
t, a, k, p, w = m.group('t', 'a', 'k', 'p', 'w')
|
||||||
if not k:
|
if not k:
|
||||||
return m.group(0)
|
return m.group(0)
|
||||||
k = escape(k)
|
k = escape(k)
|
||||||
@@ -1305,40 +1333,40 @@ def render(text,
|
|||||||
p_begin = p_end = ''
|
p_begin = p_end = ''
|
||||||
if p == 'center':
|
if p == 'center':
|
||||||
p_begin = '<p style="text-align:center">'
|
p_begin = '<p style="text-align:center">'
|
||||||
p_end = '</p>'+pp
|
p_end = '</p>' + pp
|
||||||
elif p == 'blockleft':
|
elif p == 'blockleft':
|
||||||
p_begin = '<p style="text-align:left">'
|
p_begin = '<p style="text-align:left">'
|
||||||
p_end = '</p>'+pp
|
p_end = '</p>' + pp
|
||||||
elif p == 'blockright':
|
elif p == 'blockright':
|
||||||
p_begin = '<p style="text-align:right">'
|
p_begin = '<p style="text-align:right">'
|
||||||
p_end = '</p>'+pp
|
p_end = '</p>' + pp
|
||||||
elif p in ('left','right'):
|
elif p in ('left', 'right'):
|
||||||
style = ('float:%s' % p)+(';%s' % style if style else '')
|
style = ('float:%s' % p) + (';%s' % style if style else '')
|
||||||
if t and regex_auto.match(t):
|
if t and regex_auto.match(t):
|
||||||
p_begin = p_begin + '<a href="%s">' % t
|
p_begin = p_begin + '<a href="%s">' % t
|
||||||
p_end = '</a>' + p_end
|
p_end = '</a>' + p_end
|
||||||
t = ''
|
t = ''
|
||||||
if style:
|
if style:
|
||||||
style = ' style="%s"' % style
|
style = ' style="%s"' % style
|
||||||
if p in ('video','audio'):
|
if p in ('video', 'audio'):
|
||||||
t = render(t, {}, {}, 'br', URL, environment, latex,
|
t = render(t, {}, {}, 'br', URL, environment, latex,
|
||||||
autolinks, protolinks, class_prefix, id_prefix, pretty_print)
|
autolinks, protolinks, class_prefix, id_prefix, pretty_print)
|
||||||
return '<%(p)s controls="controls"%(title)s%(style)s><source src="%(k)s" />%(t)s</%(p)s>' \
|
return '<%(p)s controls="controls"%(title)s%(style)s><source src="%(k)s" />%(t)s</%(p)s>' \
|
||||||
% dict(p=p, title=title, style=style, k=k, t=t)
|
% dict(p=p, title=title, style=style, k=k, t=t)
|
||||||
alt = ' alt="%s"'%escape(t).replace(META, DISABLED_META) if t else ''
|
alt = ' alt="%s"' % escape(t).replace(META, DISABLED_META) if t else ''
|
||||||
return '%(begin)s<img src="%(k)s"%(alt)s%(title)s%(style)s />%(end)s' \
|
return '%(begin)s<img src="%(k)s"%(alt)s%(title)s%(style)s />%(end)s' \
|
||||||
% dict(begin=p_begin, k=k, alt=alt, title=title, style=style, end=p_end)
|
% dict(begin=p_begin, k=k, alt=alt, title=title, style=style, end=p_end)
|
||||||
|
|
||||||
def sub_link(m):
|
def sub_link(m):
|
||||||
t,a,k,p = m.group('t','a','k','p')
|
t, a, k, p = m.group('t', 'a', 'k', 'p')
|
||||||
if not k and not t:
|
if not k and not t:
|
||||||
return m.group(0)
|
return m.group(0)
|
||||||
t = t or ''
|
t = t or ''
|
||||||
a = escape(a) if a else ''
|
a = escape(a) if a else ''
|
||||||
if k:
|
if k:
|
||||||
if '#' in k and not ':' in k.split('#')[0]:
|
if '#' in k and ':' not in k.split('#')[0]:
|
||||||
# wikipage, not external url
|
# wikipage, not external url
|
||||||
k=k.replace('#','#'+id_prefix)
|
k = k.replace('#', '#' + id_prefix)
|
||||||
k = escape(k)
|
k = escape(k)
|
||||||
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
|
title = ' title="%s"' % a.replace(META, DISABLED_META) if a else ''
|
||||||
target = ' target="_blank"' if p == 'popup' else ''
|
target = ' target="_blank"' if p == 'popup' else ''
|
||||||
@@ -1347,18 +1375,18 @@ def render(text,
|
|||||||
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
|
return '<a href="%(k)s"%(title)s%(target)s>%(t)s</a>' \
|
||||||
% dict(k=k, title=title, target=target, t=t)
|
% dict(k=k, title=title, target=target, t=t)
|
||||||
if t == 'NEWLINE' and not a:
|
if t == 'NEWLINE' and not a:
|
||||||
return '<br />'+pp
|
return '<br />' + pp
|
||||||
return '<span class="anchor" id="%s">%s</span>' % (
|
return '<span class="anchor" id="%s">%s</span>' % (
|
||||||
escape(id_prefix+t),
|
escape(id_prefix + t),
|
||||||
render(a, {},{},'br', URL,
|
render(a, {}, {}, 'br', URL,
|
||||||
environment, latex, autolinks,
|
environment, latex, autolinks,
|
||||||
protolinks, class_prefix,
|
protolinks, class_prefix,
|
||||||
id_prefix, pretty_print))
|
id_prefix, pretty_print))
|
||||||
|
|
||||||
parts = text.split(LINK)
|
parts = text.split(LINK)
|
||||||
text = parts[0]
|
text = parts[0]
|
||||||
for i,s in enumerate(links):
|
for i, s in enumerate(links):
|
||||||
if s == None:
|
if s is None:
|
||||||
html = LINK
|
html = LINK
|
||||||
else:
|
else:
|
||||||
html = regex_media_level2.sub(sub_media, s)
|
html = regex_media_level2.sub(sub_media, s)
|
||||||
@@ -1366,51 +1394,53 @@ def render(text,
|
|||||||
html = regex_link_level2.sub(sub_link, html)
|
html = regex_link_level2.sub(sub_link, html)
|
||||||
if html == s:
|
if html == s:
|
||||||
# return unprocessed string as a signal of an error
|
# return unprocessed string as a signal of an error
|
||||||
html = '[[%s]]'%s
|
html = '[[%s]]' % s
|
||||||
text += html + parts[i+1]
|
text += html + parts[i + 1]
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# process all code text
|
# process all code text
|
||||||
#############################################################
|
#############################################################
|
||||||
def expand_meta(m):
|
def expand_meta(m):
|
||||||
code,b,p,s = segments.pop(0)
|
code, b, p, s = segments.pop(0)
|
||||||
if code==None or m.group() == DISABLED_META:
|
if code is None or m.group() == DISABLED_META:
|
||||||
return escape(s)
|
return escape(s)
|
||||||
if b in extra:
|
if b in extra:
|
||||||
if code[:1]=='\n': code=code[1:]
|
if code[:1] == '\n':
|
||||||
if code[-1:]=='\n': code=code[:-1]
|
code = code[1:]
|
||||||
|
if code[-1:] == '\n':
|
||||||
|
code = code[:-1]
|
||||||
if p:
|
if p:
|
||||||
return str(extra[b](code,p))
|
return str(extra[b](code, p))
|
||||||
else:
|
else:
|
||||||
return str(extra[b](code))
|
return str(extra[b](code))
|
||||||
elif b=='cite':
|
elif b == 'cite':
|
||||||
return '['+','.join('<a href="#%s" class="%s">%s</a>' \
|
return '[' + ','.join('<a href="#%s" class="%s">%s</a>' %
|
||||||
% (id_prefix+d,b,d) \
|
(id_prefix + d, b, d) for d in escape(code).split(',')) + ']'
|
||||||
for d in escape(code).split(','))+']'
|
elif b == 'latex':
|
||||||
elif b=='latex':
|
|
||||||
return LATEX % urllib.quote(code)
|
return LATEX % urllib.quote(code)
|
||||||
elif b in html_colors:
|
elif b in html_colors:
|
||||||
return '<span style="color: %s">%s</span>' \
|
return '<span style="color: %s">%s</span>' \
|
||||||
% (b, render(code, {}, {}, 'br', URL, environment, latex,
|
% (b, render(code, {}, {}, 'br', URL, environment, latex,
|
||||||
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
|
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
|
||||||
elif b in ('c', 'color') and p:
|
elif b in ('c', 'color') and p:
|
||||||
c=p.split(':')
|
c = p.split(':')
|
||||||
fg='color: %s;' % c[0] if c[0] else ''
|
fg = 'color: %s;' % c[0] if c[0] else ''
|
||||||
bg='background-color: %s;' % c[1] if len(c)>1 and c[1] else ''
|
bg = 'background-color: %s;' % c[1] if len(c) > 1 and c[1] else ''
|
||||||
return '<span style="%s%s">%s</span>' \
|
return '<span style="%s%s">%s</span>' \
|
||||||
% (fg, bg, render(code, {}, {}, 'br', URL, environment, latex,
|
% (fg, bg, render(code, {}, {}, 'br', URL, environment, latex,
|
||||||
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
|
autolinks, protolinks, class_prefix, id_prefix, pretty_print))
|
||||||
cls = ' class="%s%s"'%(class_prefix,b) if b and b != 'id' else ''
|
cls = ' class="%s%s"' % (class_prefix, b) if b and b != 'id' else ''
|
||||||
id = ' id="%s%s"'%(id_prefix,escape(p)) if p else ''
|
id = ' id="%s%s"' % (id_prefix, escape(p)) if p else ''
|
||||||
beg=(code[:1]=='\n')
|
beg = (code[:1] == '\n')
|
||||||
end=[None,-1][code[-1:]=='\n']
|
end = [None, -1][code[-1:] == '\n']
|
||||||
if beg and end:
|
if beg and end:
|
||||||
return '<pre><code%s%s>%s</code></pre>%s' % (cls, id, escape(code[1:-1]), pp)
|
return '<pre><code%s%s>%s</code></pre>%s' % (cls, id, escape(code[1:-1]), pp)
|
||||||
return '<code%s%s>%s</code>' % (cls, id, escape(code[beg:end]))
|
return '<code%s%s>%s</code>' % (cls, id, escape(code[beg:end]))
|
||||||
|
|
||||||
text = regex_expand_meta.sub(expand_meta, text)
|
text = regex_expand_meta.sub(expand_meta, text)
|
||||||
|
|
||||||
if environment:
|
if environment:
|
||||||
text = replace_components(text,environment)
|
text = replace_components(text, environment)
|
||||||
|
|
||||||
return text.translate(ttab_out)
|
return text.translate(ttab_out)
|
||||||
|
|
||||||
@@ -1423,16 +1453,18 @@ def markmin2html(text, extra={}, allowed={}, sep='p',
|
|||||||
class_prefix=class_prefix, id_prefix=id_prefix,
|
class_prefix=class_prefix, id_prefix=id_prefix,
|
||||||
pretty_print=pretty_print)
|
pretty_print=pretty_print)
|
||||||
|
|
||||||
|
|
||||||
def run_doctests():
|
def run_doctests():
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
import doctest
|
import doctest
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
html=dedent("""
|
html = dedent("""
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
<head>
|
<head>
|
||||||
@@ -1446,7 +1478,7 @@ if __name__ == '__main__':
|
|||||||
</html>""")[1:]
|
</html>""")[1:]
|
||||||
|
|
||||||
if sys.argv[1:2] == ['-h']:
|
if sys.argv[1:2] == ['-h']:
|
||||||
style=dedent("""
|
style = dedent("""
|
||||||
<style>
|
<style>
|
||||||
blockquote { background-color: #FFFAAE; padding: 7px; }
|
blockquote { background-color: #FFFAAE; padding: 7px; }
|
||||||
table { border-collapse: collapse; }
|
table { border-collapse: collapse; }
|
||||||
@@ -1467,22 +1499,23 @@ if __name__ == '__main__':
|
|||||||
body=markmin2html(__doc__, pretty_print=True))
|
body=markmin2html(__doc__, pretty_print=True))
|
||||||
elif sys.argv[1:2] == ['-t']:
|
elif sys.argv[1:2] == ['-t']:
|
||||||
from timeit import Timer
|
from timeit import Timer
|
||||||
loops=1000
|
|
||||||
ts = Timer("markmin2html(__doc__)","from markmin2html import markmin2html")
|
loops = 1000
|
||||||
|
ts = Timer("markmin2html(__doc__)", "from markmin2html import markmin2html")
|
||||||
print 'timeit "markmin2html(__doc__)":'
|
print 'timeit "markmin2html(__doc__)":'
|
||||||
t = min([ts.timeit(loops) for i in range(3)])
|
t = min([ts.timeit(loops) for i in range(3)])
|
||||||
print "%s loops, best of 3: %.3f ms per loop" % (loops, t/1000*loops)
|
print "%s loops, best of 3: %.3f ms per loop" % (loops, t / 1000 * loops)
|
||||||
elif len(sys.argv) > 1:
|
elif len(sys.argv) > 1:
|
||||||
fargv = open(sys.argv[1],'r')
|
fargv = open(sys.argv[1], 'r')
|
||||||
try:
|
try:
|
||||||
markmin_text=fargv.read()
|
markmin_text = fargv.read()
|
||||||
|
|
||||||
# embed css file from second parameter into html file
|
# embed css file from second parameter into html file
|
||||||
if len(sys.argv) > 2:
|
if len(sys.argv) > 2:
|
||||||
if sys.argv[2].startswith('@'):
|
if sys.argv[2].startswith('@'):
|
||||||
markmin_style = '<link rel="stylesheet" href="'+sys.argv[2][1:]+'"/>'
|
markmin_style = '<link rel="stylesheet" href="' + sys.argv[2][1:] + '"/>'
|
||||||
else:
|
else:
|
||||||
fargv2 = open(sys.argv[2],'r')
|
fargv2 = open(sys.argv[2], 'r')
|
||||||
try:
|
try:
|
||||||
markmin_style = "<style>\n" + fargv2.read() + "</style>"
|
markmin_style = "<style>\n" + fargv2.read() + "</style>"
|
||||||
finally:
|
finally:
|
||||||
@@ -1496,10 +1529,9 @@ if __name__ == '__main__':
|
|||||||
fargv.close()
|
fargv.close()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print "Usage: "+sys.argv[0]+" -h | -t | file.markmin [file.css|@path_to/css]"
|
print "Usage: " + sys.argv[0] + " -h | -t | file.markmin [file.css|@path_to/css]"
|
||||||
print "where: -h - print __doc__"
|
print "where: -h - print __doc__"
|
||||||
print " -t - timeit __doc__ (for testing purpuse only)"
|
print " -t - timeit __doc__ (for testing purpuse only)"
|
||||||
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)"
|
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)"
|
||||||
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)"
|
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)"
|
||||||
run_doctests()
|
run_doctests()
|
||||||
|
|
||||||
|
|||||||
@@ -7,53 +7,57 @@ import sys
|
|||||||
import doctest
|
import doctest
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
__all__ = ['render','markmin2latex']
|
__all__ = ['render', 'markmin2latex']
|
||||||
|
|
||||||
META = 'META'
|
META = 'META'
|
||||||
regex_newlines = re.compile('(\n\r)|(\r\n)')
|
regex_newlines = re.compile('(\n\r)|(\r\n)')
|
||||||
regex_dd=re.compile('\$\$(?P<latex>.*?)\$\$')
|
regex_dd = re.compile('\$\$(?P<latex>.*?)\$\$')
|
||||||
regex_code = re.compile('('+META+')|(``(?P<t>.*?)``(:(?P<c>\w+))?)',re.S)
|
regex_code = re.compile('(' + META + ')|(``(?P<t>.*?)``(:(?P<c>\w+))?)', re.S)
|
||||||
regex_title = re.compile('^#{1} (?P<t>[^\n]+)',re.M)
|
regex_title = re.compile('^#{1} (?P<t>[^\n]+)', re.M)
|
||||||
regex_maps = [
|
regex_maps = [
|
||||||
(re.compile('[ \t\r]+\n'),'\n'),
|
(re.compile('[ \t\r]+\n'), '\n'),
|
||||||
(re.compile('\*\*(?P<t>[^\s\*]+( +[^\s\*]+)*)\*\*'),'{\\\\bf \g<t>}'),
|
(re.compile('\*\*(?P<t>[^\s\*]+( +[^\s\*]+)*)\*\*'), '{\\\\bf \g<t>}'),
|
||||||
(re.compile("''(?P<t>[^\s']+( +[^\s']+)*)''"),'{\\it \g<t>}'),
|
(re.compile("''(?P<t>[^\s']+( +[^\s']+)*)''"), '{\\it \g<t>}'),
|
||||||
(re.compile('^#{5,6}\s*(?P<t>[^\n]+)',re.M),'\n\n{\\\\bf \g<t>}\n'),
|
(re.compile('^#{5,6}\s*(?P<t>[^\n]+)', re.M), '\n\n{\\\\bf \g<t>}\n'),
|
||||||
(re.compile('^#{4}\s*(?P<t>[^\n]+)',re.M),'\n\n\\\\goodbreak\\subsubsection{\g<t>}\n'),
|
(re.compile('^#{4}\s*(?P<t>[^\n]+)', re.M), '\n\n\\\\goodbreak\\subsubsection{\g<t>}\n'),
|
||||||
(re.compile('^#{3}\s*(?P<t>[^\n]+)',re.M),'\n\n\\\\goodbreak\\subsection{\g<t>}\n'),
|
(re.compile('^#{3}\s*(?P<t>[^\n]+)', re.M), '\n\n\\\\goodbreak\\subsection{\g<t>}\n'),
|
||||||
(re.compile('^#{2}\s*(?P<t>[^\n]+)',re.M),'\n\n\\\\goodbreak\\section{\g<t>}\n'),
|
(re.compile('^#{2}\s*(?P<t>[^\n]+)', re.M), '\n\n\\\\goodbreak\\section{\g<t>}\n'),
|
||||||
(re.compile('^#{1}\s*(?P<t>[^\n]+)',re.M),''),
|
(re.compile('^#{1}\s*(?P<t>[^\n]+)', re.M), ''),
|
||||||
(re.compile('^\- +(?P<t>.*)',re.M),'\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
|
(re.compile('^\- +(?P<t>.*)', re.M), '\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
|
||||||
(re.compile('^\+ +(?P<t>.*)',re.M),'\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
|
(re.compile('^\+ +(?P<t>.*)', re.M), '\\\\begin{itemize}\n\\item \g<t>\n\\end{itemize}'),
|
||||||
(re.compile('\\\\end\{itemize\}\s+\\\\begin\{itemize\}'),'\n'),
|
(re.compile('\\\\end\{itemize\}\s+\\\\begin\{itemize\}'), '\n'),
|
||||||
(re.compile('\n\s+\n'),'\n\n')]
|
(re.compile('\n\s+\n'), '\n\n')]
|
||||||
regex_table = re.compile('^\-{4,}\n(?P<t>.*?)\n\-{4,}(:(?P<c>\w+))?\n',re.M|re.S)
|
regex_table = re.compile('^\-{4,}\n(?P<t>.*?)\n\-{4,}(:(?P<c>\w+))?\n', re.M | re.S)
|
||||||
|
|
||||||
regex_anchor = re.compile('\[\[(?P<t>\S+)\]\]')
|
regex_anchor = re.compile('\[\[(?P<t>\S+)\]\]')
|
||||||
regex_bibitem = re.compile('\-\s*\[\[(?P<t>\S+)\]\]')
|
regex_bibitem = re.compile('\-\s*\[\[(?P<t>\S+)\]\]')
|
||||||
regex_image_width = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right|center) +(?P<w>\d+px)\]\]')
|
regex_image_width = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right|center) +(?P<w>\d+px)\]\]')
|
||||||
regex_image = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right|center)\]\]')
|
regex_image = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +(?P<p>left|right|center)\]\]')
|
||||||
#regex_video = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +video\]\]')
|
# regex_video = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +video\]\]')
|
||||||
#regex_audio = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +audio\]\]')
|
# regex_audio = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+) +audio\]\]')
|
||||||
regex_link = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+)\]\]')
|
regex_link = re.compile('\[\[(?P<t>[^\]]*?) +(?P<k>\S+)\]\]')
|
||||||
regex_auto = re.compile('(?<!["\w])(?P<k>\w+://[\w\.\-\?&%\:]+)',re.M)
|
regex_auto = re.compile('(?<!["\w])(?P<k>\w+://[\w\.\-\?&%\:]+)', re.M)
|
||||||
regex_commas = re.compile('[ ]+(?P<t>[,;\.])')
|
regex_commas = re.compile('[ ]+(?P<t>[,;\.])')
|
||||||
regex_noindent = re.compile('\n\n(?P<t>[a-z])')
|
regex_noindent = re.compile('\n\n(?P<t>[a-z])')
|
||||||
#regex_quote_left = re.compile('"(?=\w)')
|
|
||||||
#regex_quote_right = re.compile('(?=\w\.)"')
|
|
||||||
|
|
||||||
def latex_escape(text,pound=True):
|
|
||||||
text=text.replace('\\','{\\textbackslash}')
|
# regex_quote_left = re.compile('"(?=\w)')
|
||||||
for c in '^_&$%{}': text=text.replace(c,'\\'+c)
|
# regex_quote_right = re.compile('(?=\w\.)"')
|
||||||
text=text.replace('\\{\\textbackslash\\}','{\\textbackslash}')
|
|
||||||
if pound: text=text.replace('#','\\#')
|
def latex_escape(text, pound=True):
|
||||||
|
text = text.replace('\\', '{\\textbackslash}')
|
||||||
|
for c in '^_&$%{}':
|
||||||
|
text = text.replace(c, '\\' + c)
|
||||||
|
text = text.replace('\\{\\textbackslash\\}', '{\\textbackslash}')
|
||||||
|
if pound: text = text.replace('#', '\\#')
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def render(text,
|
def render(text,
|
||||||
extra={},
|
extra={},
|
||||||
allowed={},
|
allowed={},
|
||||||
sep='p',
|
sep='p',
|
||||||
image_mapper=lambda x:x,
|
image_mapper=lambda x: x,
|
||||||
chapters=False):
|
chapters=False):
|
||||||
#############################################################
|
#############################################################
|
||||||
# replace all blocks marked with ``...``:class with META
|
# replace all blocks marked with ``...``:class with META
|
||||||
@@ -61,62 +65,68 @@ def render(text,
|
|||||||
#############################################################
|
#############################################################
|
||||||
text = str(text or '')
|
text = str(text or '')
|
||||||
segments, i = [], 0
|
segments, i = [], 0
|
||||||
text = regex_dd.sub('``\g<latex>``:latex ',text)
|
text = regex_dd.sub('``\g<latex>``:latex ', text)
|
||||||
text = regex_newlines.sub('\n',text)
|
text = regex_newlines.sub('\n', text)
|
||||||
while True:
|
while True:
|
||||||
item = regex_code.search(text,i)
|
item = regex_code.search(text, i)
|
||||||
if not item: break
|
if not item:
|
||||||
if item.group()==META:
|
break
|
||||||
segments.append((None,None))
|
if item.group() == META:
|
||||||
text = text[:item.start()]+META+text[item.end():]
|
segments.append((None, None))
|
||||||
|
text = text[:item.start()] + META + text[item.end():]
|
||||||
else:
|
else:
|
||||||
c = item.group('c') or ''
|
c = item.group('c') or ''
|
||||||
if 'code' in allowed and not c in allowed['code']: c = ''
|
if 'code' in allowed and c not in allowed['code']:
|
||||||
code = item.group('t').replace('!`!','`')
|
c = ''
|
||||||
segments.append((code,c))
|
code = item.group('t').replace('!`!', '`')
|
||||||
text = text[:item.start()]+META+text[item.end():]
|
segments.append((code, c))
|
||||||
i=item.start()+3
|
text = text[:item.start()] + META + text[item.end():]
|
||||||
|
i = item.start() + 3
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# do h1,h2,h3,h4,h5,h6,b,i,ol,ul and normalize spaces
|
# do h1,h2,h3,h4,h5,h6,b,i,ol,ul and normalize spaces
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
title = regex_title.search(text)
|
title = regex_title.search(text)
|
||||||
if not title: title='Title'
|
if not title:
|
||||||
else: title=title.group('t')
|
title = 'Title'
|
||||||
|
else:
|
||||||
|
title = title.group('t')
|
||||||
|
|
||||||
text = latex_escape(text,pound=False)
|
text = latex_escape(text, pound=False)
|
||||||
|
|
||||||
texts = text.split('## References',1)
|
texts = text.split('## References', 1)
|
||||||
text = regex_anchor.sub('\\label{\g<t>}', texts[0])
|
text = regex_anchor.sub('\\label{\g<t>}', texts[0])
|
||||||
if len(texts)==2:
|
if len(texts) == 2:
|
||||||
text += '\n\\begin{thebibliography}{999}\n'
|
text += '\n\\begin{thebibliography}{999}\n'
|
||||||
text += regex_bibitem.sub('\n\\\\bibitem{\g<t>}', texts[1])
|
text += regex_bibitem.sub('\n\\\\bibitem{\g<t>}', texts[1])
|
||||||
text += '\n\\end{thebibliography}\n'
|
text += '\n\\end{thebibliography}\n'
|
||||||
|
|
||||||
text = '\n'.join(t.strip() for t in text.split('\n'))
|
text = '\n'.join(t.strip() for t in text.split('\n'))
|
||||||
for regex, sub in regex_maps:
|
for regex, sub in regex_maps:
|
||||||
text = regex.sub(sub,text)
|
text = regex.sub(sub, text)
|
||||||
text=text.replace('#','\\#')
|
text = text.replace('#', '\\#')
|
||||||
text=text.replace('`',"'")
|
text = text.replace('`', "'")
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# process tables and blockquotes
|
# process tables and blockquotes
|
||||||
#############################################################
|
#############################################################
|
||||||
while True:
|
while True:
|
||||||
item = regex_table.search(text)
|
item = regex_table.search(text)
|
||||||
if not item: break
|
if not item:
|
||||||
|
break
|
||||||
c = item.group('c') or ''
|
c = item.group('c') or ''
|
||||||
if 'table' in allowed and not c in allowed['table']: c = ''
|
if 'table' in allowed and c not in allowed['table']:
|
||||||
|
c = ''
|
||||||
content = item.group('t')
|
content = item.group('t')
|
||||||
if ' | ' in content:
|
if ' | ' in content:
|
||||||
rows = content.replace('\n','\\\\\n').replace(' | ',' & ')
|
rows = content.replace('\n', '\\\\\n').replace(' | ', ' & ')
|
||||||
row0,row2 = rows.split('\\\\\n',1)
|
row0, row2 = rows.split('\\\\\n', 1)
|
||||||
cols=row0.count(' & ')+1
|
cols = row0.count(' & ') + 1
|
||||||
cal='{'+''.join('l' for j in range(cols))+'}'
|
cal = '{' + ''.join('l' for j in range(cols)) + '}'
|
||||||
tabular = '\\begin{center}\n{\\begin{tabular}'+cal+'\\hline\n' + row0+'\\\\ \\hline\n'+row2 + ' \\\\ \\hline\n\\end{tabular}}\n\\end{center}'
|
tabular = '\\begin{center}\n{\\begin{tabular}' + cal + '\\hline\n' + row0 + '\\\\ \\hline\n' + row2 + ' \\\\ \\hline\n\\end{tabular}}\n\\end{center}'
|
||||||
if row2.count('\n')>20: tabular='\\newpage\n'+tabular
|
if row2.count('\n') > 20:
|
||||||
|
tabular = '\\newpage\n' + tabular
|
||||||
text = text[:item.start()] + tabular + text[item.end():]
|
text = text[:item.start()] + tabular + text[item.end():]
|
||||||
else:
|
else:
|
||||||
text = text[:item.start()] + '\\begin{quote}' + content + '\\end{quote}' + text[item.end():]
|
text = text[:item.start()] + '\\begin{quote}' + content + '\\end{quote}' + text[item.end():]
|
||||||
@@ -126,29 +136,32 @@ def render(text,
|
|||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
def sub(x):
|
def sub(x):
|
||||||
f=image_mapper(x.group('k'))
|
f = image_mapper(x.group('k'))
|
||||||
if not f: return None
|
if not f:
|
||||||
return '\n\\begin{center}\\includegraphics[width=8cm]{%s}\\end{center}\n' % (f)
|
return None
|
||||||
text = regex_image_width.sub(sub,text)
|
return '\n\\begin{center}\\includegraphics[width=8cm]{%s}\\end{center}\n' % f
|
||||||
text = regex_image.sub(sub,text)
|
|
||||||
|
text = regex_image_width.sub(sub, text)
|
||||||
|
text = regex_image.sub(sub, text)
|
||||||
|
|
||||||
text = regex_link.sub('{\\\\footnotesize\\href{\g<k>}{\g<t>}}', text)
|
text = regex_link.sub('{\\\\footnotesize\\href{\g<k>}{\g<t>}}', text)
|
||||||
text = regex_commas.sub('\g<t>',text)
|
text = regex_commas.sub('\g<t>', text)
|
||||||
text = regex_noindent.sub('\n\\\\noindent \g<t>',text)
|
text = regex_noindent.sub('\n\\\\noindent \g<t>', text)
|
||||||
|
|
||||||
### fix paths in images
|
# ## fix paths in images
|
||||||
regex=re.compile('\\\\_\w*\.(eps|png|jpg|gif)')
|
regex = re.compile('\\\\_\w*\.(eps|png|jpg|gif)')
|
||||||
while True:
|
while True:
|
||||||
match=regex.search(text)
|
match = regex.search(text)
|
||||||
if not match: break
|
if not match:
|
||||||
text=text[:match.start()]+text[match.start()+1:]
|
break
|
||||||
#text = regex_quote_left.sub('``',text)
|
text = text[:match.start()] + text[match.start() + 1:]
|
||||||
#text = regex_quote_right.sub("''",text)
|
# text = regex_quote_left.sub('``',text)
|
||||||
|
# text = regex_quote_right.sub("''",text)
|
||||||
|
|
||||||
if chapters:
|
if chapters:
|
||||||
text=text.replace(r'\section*{',r'\chapter*{')
|
text = text.replace(r'\section*{', r'\chapter*{')
|
||||||
text=text.replace(r'\section{',r'\chapter{')
|
text = text.replace(r'\section{', r'\chapter{')
|
||||||
text=text.replace(r'subsection{',r'section{')
|
text = text.replace(r'subsection{', r'section{')
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# process all code text
|
# process all code text
|
||||||
@@ -156,57 +169,64 @@ def render(text,
|
|||||||
parts = text.split(META)
|
parts = text.split(META)
|
||||||
text = parts[0]
|
text = parts[0]
|
||||||
authors = []
|
authors = []
|
||||||
for i,(code,b) in enumerate(segments):
|
for i, (code, b) in enumerate(segments):
|
||||||
if code==None:
|
if code is None:
|
||||||
html = META
|
html = META
|
||||||
else:
|
else:
|
||||||
if b=='hidden':
|
if b == 'hidden':
|
||||||
html=''
|
html = ''
|
||||||
elif b=='author':
|
elif b == 'author':
|
||||||
author = latex_escape(code.strip())
|
author = latex_escape(code.strip())
|
||||||
authors.append(author)
|
authors.append(author)
|
||||||
html=''
|
html = ''
|
||||||
elif b=='inxx':
|
elif b == 'inxx':
|
||||||
html='\inxx{%s}' % latex_escape(code)
|
html = '\inxx{%s}' % latex_escape(code)
|
||||||
elif b=='cite':
|
elif b == 'cite':
|
||||||
html='~\cite{%s}' % latex_escape(code.strip())
|
html = '~\cite{%s}' % latex_escape(code.strip())
|
||||||
elif b=='ref':
|
elif b == 'ref':
|
||||||
html='~\ref{%s}' % latex_escape(code.strip())
|
html = '~\ref{%s}' % latex_escape(code.strip())
|
||||||
elif b=='latex':
|
elif b == 'latex':
|
||||||
if '\n' in code:
|
if '\n' in code:
|
||||||
html='\n\\begin{equation}\n%s\n\\end{equation}\n' % code.strip()
|
html = '\n\\begin{equation}\n%s\n\\end{equation}\n' % code.strip()
|
||||||
else:
|
else:
|
||||||
html='$%s$' % code.strip()
|
html = '$%s$' % code.strip()
|
||||||
elif b=='latex_eqnarray':
|
elif b == 'latex_eqnarray':
|
||||||
code=code.strip()
|
code = code.strip()
|
||||||
code='\\\\'.join(x.replace('=','&=&',1) for x in code.split('\\\\'))
|
code = '\\\\'.join(x.replace('=', '&=&', 1) for x in code.split('\\\\'))
|
||||||
html='\n\\begin{eqnarray}\n%s\n\\end{eqnarray}\n' % code
|
html = '\n\\begin{eqnarray}\n%s\n\\end{eqnarray}\n' % code
|
||||||
elif b.startswith('latex_'):
|
elif b.startswith('latex_'):
|
||||||
key=b[6:]
|
key = b[6:]
|
||||||
html='\\begin{%s}%s\\end{%s}' % (key,code,key)
|
html = '\\begin{%s}%s\\end{%s}' % (key, code, key)
|
||||||
elif b in extra:
|
elif b in extra:
|
||||||
if code[:1]=='\n': code=code[1:]
|
if code[:1] == '\n':
|
||||||
if code[-1:]=='\n': code=code[:-1]
|
code = code[1:]
|
||||||
|
if code[-1:] == '\n':
|
||||||
|
code = code[:-1]
|
||||||
html = extra[b](code)
|
html = extra[b](code)
|
||||||
elif code[:1]=='\n' or code[:-1]=='\n':
|
elif code[:1] == '\n' or code[:-1] == '\n':
|
||||||
if code[:1]=='\n': code=code[1:]
|
if code[:1] == '\n':
|
||||||
if code[-1:]=='\n': code=code[:-1]
|
code = code[1:]
|
||||||
|
if code[-1:] == '\n':
|
||||||
|
code = code[:-1]
|
||||||
if code.startswith('<') or code.startswith('{{') or code.startswith('http'):
|
if code.startswith('<') or code.startswith('{{') or code.startswith('http'):
|
||||||
html = '\\begin{lstlisting}[keywords={}]\n%s\n\\end{lstlisting}' % code
|
html = '\\begin{lstlisting}[keywords={}]\n%s\n\\end{lstlisting}' % code
|
||||||
else:
|
else:
|
||||||
html = '\\begin{lstlisting}\n%s\n\\end{lstlisting}' % code
|
html = '\\begin{lstlisting}\n%s\n\\end{lstlisting}' % code
|
||||||
else:
|
else:
|
||||||
if code[:1]=='\n': code=code[1:]
|
if code[:1] == '\n':
|
||||||
if code[-1:]=='\n': code=code[:-1]
|
code = code[1:]
|
||||||
|
if code[-1:] == '\n':
|
||||||
|
code = code[:-1]
|
||||||
html = '{\\ft %s}' % latex_escape(code)
|
html = '{\\ft %s}' % latex_escape(code)
|
||||||
try:
|
try:
|
||||||
text = text+html+parts[i+1]
|
text = text + html + parts[i + 1]
|
||||||
except:
|
except:
|
||||||
text = text + '... WIKI PROCESSING ERROR ...'
|
text = text + '... WIKI PROCESSING ERROR ...'
|
||||||
break
|
break
|
||||||
text = text.replace(' ~\\cite','~\\cite')
|
text = text.replace(' ~\\cite', '~\\cite')
|
||||||
return text, title, authors
|
return text, title, authors
|
||||||
|
|
||||||
|
|
||||||
WRAPPER = """
|
WRAPPER = """
|
||||||
\\documentclass[12pt]{article}
|
\\documentclass[12pt]{article}
|
||||||
\\usepackage{hyperref}
|
\\usepackage{hyperref}
|
||||||
@@ -239,12 +259,14 @@ WRAPPER = """
|
|||||||
\\end{document}
|
\\end{document}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def markmin2latex(data, image_mapper=lambda x:x, extra={},
|
|
||||||
|
def markmin2latex(data, image_mapper=lambda x: x, extra={},
|
||||||
wrapper=WRAPPER):
|
wrapper=WRAPPER):
|
||||||
body, title, authors = render(data, extra=extra, image_mapper=image_mapper)
|
body, title, authors = render(data, extra=extra, image_mapper=image_mapper)
|
||||||
author = '\n\\and\n'.join(a.replace('\n','\\\\\n\\footnotesize ') for a in authors)
|
author = '\n\\and\n'.join(a.replace('\n', '\\\\\n\\footnotesize ') for a in authors)
|
||||||
return wrapper % dict(title=title, author=author, body=body)
|
return wrapper % dict(title=title, author=author, body=body)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
parser.add_option("-i", "--info", dest="info",
|
parser.add_option("-i", "--info", dest="info",
|
||||||
@@ -252,40 +274,39 @@ if __name__ == '__main__':
|
|||||||
parser.add_option("-t", "--test", dest="test", action="store_true",
|
parser.add_option("-t", "--test", dest="test", action="store_true",
|
||||||
default=False)
|
default=False)
|
||||||
parser.add_option("-n", "--no_wrapper", dest="no_wrapper",
|
parser.add_option("-n", "--no_wrapper", dest="no_wrapper",
|
||||||
action="store_true",default=False)
|
action="store_true", default=False)
|
||||||
parser.add_option("-c", "--chapters", dest="chapters",action="store_true",
|
parser.add_option("-c", "--chapters", dest="chapters", action="store_true",
|
||||||
default=False,help="switch section for chapter")
|
default=False, help="switch section for chapter")
|
||||||
parser.add_option("-w", "--wrapper", dest="wrapper", default=False,
|
parser.add_option("-w", "--wrapper", dest="wrapper", default=False,
|
||||||
help="latex file containing header and footer")
|
help="latex file containing header and footer")
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
if options.info:
|
if options.info:
|
||||||
import markmin2html
|
import markmin2html
|
||||||
|
|
||||||
markmin2latex(markmin2html.__doc__)
|
markmin2latex(markmin2html.__doc__)
|
||||||
elif options.test:
|
elif options.test:
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
else:
|
else:
|
||||||
if options.wrapper:
|
if options.wrapper:
|
||||||
fwrapper = open(options.wrapper,'rb')
|
fwrapper = open(options.wrapper, 'rb')
|
||||||
try:
|
try:
|
||||||
wrapper = fwrapper.read()
|
wrapper = fwrapper.read()
|
||||||
finally:
|
finally:
|
||||||
fwrapper.close()
|
fwrapper.close()
|
||||||
elif options.no_wrapper:
|
elif options.no_wrapper:
|
||||||
wrapper = '%(body)s'
|
wrapper = '%(body)s'
|
||||||
else:
|
else:
|
||||||
wrapper = WRAPPER
|
wrapper = WRAPPER
|
||||||
for f in args:
|
for f in args:
|
||||||
fargs = open(f,'r')
|
fargs = open(f, 'r')
|
||||||
content_data = []
|
content_data = []
|
||||||
try:
|
try:
|
||||||
content_data.append(fargs.read())
|
content_data.append(fargs.read())
|
||||||
finally:
|
finally:
|
||||||
fargs.close()
|
fargs.close()
|
||||||
content = '\n'.join(content_data)
|
content = '\n'.join(content_data)
|
||||||
output= markmin2latex(content,
|
output = markmin2latex(content,
|
||||||
wrapper=wrapper,
|
wrapper=wrapper,
|
||||||
chapters=options.chapters)
|
chapters=options.chapters)
|
||||||
print output
|
print output
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user