mirror of
https://github.com/getgrav/grav.git
synced 2025-12-05 15:29:57 +01:00
Compare commits
1166 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4e0c06ea8 | ||
|
|
0c807b6108 | ||
|
|
3a47d6a580 | ||
|
|
52947b3a2c | ||
|
|
eacfc798f4 | ||
|
|
5c0e5f3c01 | ||
|
|
985141b842 | ||
|
|
1aac2ab95d | ||
|
|
aa7d5ddf59 | ||
|
|
e87505378d | ||
|
|
53f097c2b3 | ||
|
|
6ea7fe9dba | ||
|
|
0206f1b0c7 | ||
|
|
ef9f2c77dd | ||
|
|
822292f541 | ||
|
|
ec08cd9374 | ||
|
|
8fb4063cf2 | ||
|
|
8a2b444c48 | ||
|
|
9c6f243902 | ||
|
|
d5bd99b363 | ||
|
|
5554c07cbf | ||
|
|
acd95aac6f | ||
|
|
8ad5f2624d | ||
|
|
8adc0e1c17 | ||
|
|
fab66cf3a5 | ||
|
|
5df48e7a68 | ||
|
|
079a8c5728 | ||
|
|
d9196426a1 | ||
|
|
2f686f5b74 | ||
|
|
c4b5df20a9 | ||
|
|
06608a6d3c | ||
|
|
fd63911faf | ||
|
|
66a1e55867 | ||
|
|
af2eb2e75d | ||
|
|
9b4f32cafd | ||
|
|
9179fbd1a2 | ||
|
|
24ea7f1f55 | ||
|
|
9b95053110 | ||
|
|
71ffb9c72f | ||
|
|
f29f698f61 | ||
|
|
f1f8579a0b | ||
|
|
4ca8fab750 | ||
|
|
b80ed731b0 | ||
|
|
23a9a73600 | ||
|
|
dc8c0b6522 | ||
|
|
e695b1942c | ||
|
|
3f543e7e84 | ||
|
|
7f6f9e82e3 | ||
|
|
51529eb0ce | ||
|
|
05b24a4b75 | ||
|
|
ca5819489f | ||
|
|
1d2acf8096 | ||
|
|
98278e965b | ||
|
|
7bc990688c | ||
|
|
b86aa6d473 | ||
|
|
dba7347c1e | ||
|
|
fa52e18e3f | ||
|
|
b605753a6d | ||
|
|
0af4fb351c | ||
|
|
90edf95077 | ||
|
|
ab3843442a | ||
|
|
023b9dd708 | ||
|
|
0ac882314e | ||
|
|
0fe9264582 | ||
|
|
b1e16b2206 | ||
|
|
a67c1780c1 | ||
|
|
1170f2f58d | ||
|
|
199c0a08ea | ||
|
|
84ad152536 | ||
|
|
5b0f905ae3 | ||
|
|
a2bba8f09d | ||
|
|
2007975428 | ||
|
|
e484997515 | ||
|
|
af5c52c52f | ||
|
|
f3d0e10378 | ||
|
|
b33ab43ff9 | ||
|
|
c580399db6 | ||
|
|
00d8717d7c | ||
|
|
6e2f4607a6 | ||
|
|
3a7abeb18b | ||
|
|
84a5984c65 | ||
|
|
1465c26b1f | ||
|
|
b399d8e3b9 | ||
|
|
b5c04bdc9b | ||
|
|
b4725800c3 | ||
|
|
2b1a102efa | ||
|
|
500c548af4 | ||
|
|
fc7017f822 | ||
|
|
5b254f4cf8 | ||
|
|
43783f3ce6 | ||
|
|
ae39aabee1 | ||
|
|
df7a94148b | ||
|
|
63890661fe | ||
|
|
793ac1a1bb | ||
|
|
77db54c50d | ||
|
|
b259927348 | ||
|
|
e8972a6aa5 | ||
|
|
8d8420c0d6 | ||
|
|
7a6707f597 | ||
|
|
b0ec66cce8 | ||
|
|
edfd7db88b | ||
|
|
fb3e68e16e | ||
|
|
080ab9e289 | ||
|
|
f67e441b83 | ||
|
|
9c07d69c45 | ||
|
|
13207f13ad | ||
|
|
34f83ebde2 | ||
|
|
14ed805656 | ||
|
|
385233c508 | ||
|
|
8a3b987cd5 | ||
|
|
bdd17fc56a | ||
|
|
29b3c081ee | ||
|
|
b1d80b6c5f | ||
|
|
e00560f81a | ||
|
|
20f17130a2 | ||
|
|
583156d2f3 | ||
|
|
88f36f4987 | ||
|
|
965c8cfbe9 | ||
|
|
b8f00243e6 | ||
|
|
1d97f98515 | ||
|
|
9764cf3f65 | ||
|
|
1f5df81496 | ||
|
|
5f76a0255c | ||
|
|
17f3ca6eba | ||
|
|
b29d79738b | ||
|
|
020cdd7324 | ||
|
|
1e39f3b22d | ||
|
|
37035a488d | ||
|
|
745b418cd7 | ||
|
|
2a02c8bc4f | ||
|
|
a15e063b92 | ||
|
|
2051fed5b7 | ||
|
|
268714863e | ||
|
|
60c6532307 | ||
|
|
50c6e81c09 | ||
|
|
2a0a9a225c | ||
|
|
aee92b58c7 | ||
|
|
16db950009 | ||
|
|
bde33e7188 | ||
|
|
267efbe164 | ||
|
|
f9e137c994 | ||
|
|
e7f9751403 | ||
|
|
9adf81294d | ||
|
|
3033818589 | ||
|
|
06d663680c | ||
|
|
1bbdca5032 | ||
|
|
c1654a988e | ||
|
|
18a540c867 | ||
|
|
99fc8df322 | ||
|
|
2d21cb8b1e | ||
|
|
d8008654b9 | ||
|
|
146295fb1e | ||
|
|
09ed480628 | ||
|
|
5dd1554e5d | ||
|
|
748f329c8e | ||
|
|
7228b25393 | ||
|
|
63e083ea37 | ||
|
|
b1630feb5d | ||
|
|
1185a91c90 | ||
|
|
dce6d7894b | ||
|
|
375ee0d1fa | ||
|
|
ce0574f897 | ||
|
|
c515111446 | ||
|
|
7d6393628e | ||
|
|
24fde7261a | ||
|
|
3d922abf1a | ||
|
|
7f1d3a94fe | ||
|
|
3d774b7585 | ||
|
|
b0083548b6 | ||
|
|
905dae3b16 | ||
|
|
d79979371b | ||
|
|
c4bff94f7d | ||
|
|
7c4fd3858c | ||
|
|
3b9af8883d | ||
|
|
29b34d7de0 | ||
|
|
90fcf448c7 | ||
|
|
5193551d04 | ||
|
|
d2660e0755 | ||
|
|
2d8ac27fdd | ||
|
|
dd2ddfeb40 | ||
|
|
ac3396e6c4 | ||
|
|
49a5b38589 | ||
|
|
6e2f792bb9 | ||
|
|
da098fd46a | ||
|
|
3e081b340f | ||
|
|
698015a03d | ||
|
|
000a10f936 | ||
|
|
c764e31c8a | ||
|
|
c18021d52a | ||
|
|
3d0cc67415 | ||
|
|
3f94a6fda9 | ||
|
|
7f0eefbde5 | ||
|
|
280377985f | ||
|
|
d5b3f070a5 | ||
|
|
3505ef046d | ||
|
|
a6bc565356 | ||
|
|
a1ee3cf4e4 | ||
|
|
e96445abe3 | ||
|
|
c22fae0d3d | ||
|
|
d888dcd085 | ||
|
|
184cb9ea3a | ||
|
|
3cf6e8762c | ||
|
|
f0cdd7c03e | ||
|
|
5e40201888 | ||
|
|
f2c2debb28 | ||
|
|
997c772b7c | ||
|
|
bc4a09f80d | ||
|
|
0e3e7497ac | ||
|
|
72313ac9ec | ||
|
|
dc80228f0b | ||
|
|
a83642a7e3 | ||
|
|
00d8403095 | ||
|
|
e1ec8e9742 | ||
|
|
0725af5367 | ||
|
|
65e543af02 | ||
|
|
b49e8315eb | ||
|
|
c5a89112b4 | ||
|
|
94ec474ffa | ||
|
|
da4593fdc1 | ||
|
|
b8413cefaf | ||
|
|
d3097e4fd0 | ||
|
|
51753f0716 | ||
|
|
b7ada873b8 | ||
|
|
ed8b08a9e4 | ||
|
|
e1fdb6803d | ||
|
|
5cb9f2f42f | ||
|
|
fcf48ed2e5 | ||
|
|
050512536a | ||
|
|
99207fca13 | ||
|
|
55890b4fd8 | ||
|
|
6fdfaccc92 | ||
|
|
76e01e7aea | ||
|
|
87378562ea | ||
|
|
77d80f12f3 | ||
|
|
e400207a65 | ||
|
|
4b68036a1b | ||
|
|
a95b716aa7 | ||
|
|
dc8efded34 | ||
|
|
e016b17276 | ||
|
|
b99876f0b4 | ||
|
|
66abc842b7 | ||
|
|
9f36158c67 | ||
|
|
18c1ca3919 | ||
|
|
0c729e5b0a | ||
|
|
55f3b78ab1 | ||
|
|
a73b796ca7 | ||
|
|
bb0bca7ef1 | ||
|
|
b3144ee921 | ||
|
|
a86ce7cb28 | ||
|
|
ccf2a780b6 | ||
|
|
b0c1dbe4b7 | ||
|
|
ec73eef695 | ||
|
|
467d68344e | ||
|
|
8899b3ebb8 | ||
|
|
5478cfaf9f | ||
|
|
4b6a85f30a | ||
|
|
e62ff07726 | ||
|
|
a045107cc7 | ||
|
|
c97edb60a5 | ||
|
|
695793b752 | ||
|
|
c953ffb471 | ||
|
|
3d7fa06129 | ||
|
|
49d4fbcf3d | ||
|
|
fc18a40c35 | ||
|
|
1e81d5e38c | ||
|
|
daf8b53c0d | ||
|
|
8de55a745d | ||
|
|
6bf669815d | ||
|
|
8ba49e163d | ||
|
|
26918d90ab | ||
|
|
929b0806dc | ||
|
|
3e32e61db1 | ||
|
|
038693bffb | ||
|
|
9445aa43e6 | ||
|
|
bb16dbab78 | ||
|
|
658212e7be | ||
|
|
e91554770c | ||
|
|
8f9671ad32 | ||
|
|
7f134e39f4 | ||
|
|
c87e3f419d | ||
|
|
07b2767ac9 | ||
|
|
0ca24a9786 | ||
|
|
c84c1366e7 | ||
|
|
ebf9bb5c18 | ||
|
|
70b67a0805 | ||
|
|
545b97716f | ||
|
|
7e540e0623 | ||
|
|
f7140522f6 | ||
|
|
bd2f7088e9 | ||
|
|
5260c181a1 | ||
|
|
a9538adf2b | ||
|
|
8bba0fd332 | ||
|
|
abf6d6638e | ||
|
|
36e52146f5 | ||
|
|
24eaa24839 | ||
|
|
fafd72fcd8 | ||
|
|
df9b219a16 | ||
|
|
5c9c378889 | ||
|
|
47e1eab6c1 | ||
|
|
d88f56316d | ||
|
|
8b414c388d | ||
|
|
acb828eacf | ||
|
|
293dfad87e | ||
|
|
e4e1927126 | ||
|
|
edf6f86cb5 | ||
|
|
d086664a61 | ||
|
|
b0c171f453 | ||
|
|
feed15f75b | ||
|
|
95fd54d909 | ||
|
|
79f6380aae | ||
|
|
8478d690a0 | ||
|
|
5db8197db2 | ||
|
|
8407e5b295 | ||
|
|
3e3b4548e9 | ||
|
|
868a61dd34 | ||
|
|
a7a5625a8b | ||
|
|
a614c8c7cc | ||
|
|
f65633043a | ||
|
|
de61d88d29 | ||
|
|
dc57bef5f3 | ||
|
|
9d86c0a9db | ||
|
|
2721bb511a | ||
|
|
1e07cb9b5b | ||
|
|
39a4a1e9bf | ||
|
|
7a56a361a0 | ||
|
|
d54359d441 | ||
|
|
98d0538868 | ||
|
|
f03921690c | ||
|
|
46869de29c | ||
|
|
b7b29b3f84 | ||
|
|
b9e1d9af6e | ||
|
|
edf313a7a2 | ||
|
|
4f22d1c918 | ||
|
|
67fefb53ad | ||
|
|
0ff5dc0016 | ||
|
|
ae17a77789 | ||
|
|
5f11ae7482 | ||
|
|
4d33eb2173 | ||
|
|
fe7873ddbe | ||
|
|
f95a4f5cc6 | ||
|
|
f973b61b5e | ||
|
|
f1d4192ae7 | ||
|
|
fb500d3e1c | ||
|
|
98b8f1f9e5 | ||
|
|
9324847bac | ||
|
|
14347ebf88 | ||
|
|
3e0188e40b | ||
|
|
7c6471fe2a | ||
|
|
647ec528d3 | ||
|
|
667ad5c580 | ||
|
|
b82f17f367 | ||
|
|
2e4866f5fa | ||
|
|
3f28dc59ea | ||
|
|
77deea8ad4 | ||
|
|
077ba28706 | ||
|
|
db2caf4b04 | ||
|
|
464a65b574 | ||
|
|
e27f638fe3 | ||
|
|
00ae0988ab | ||
|
|
ce4350bc63 | ||
|
|
aa60d9f53d | ||
|
|
7cb7891fa7 | ||
|
|
3848a266d0 | ||
|
|
29b8c1d124 | ||
|
|
813ab70895 | ||
|
|
efcaf00e88 | ||
|
|
5476ef4fa8 | ||
|
|
5857882417 | ||
|
|
fe4d178fb4 | ||
|
|
247e45bfea | ||
|
|
b7784a23ff | ||
|
|
fa4893804e | ||
|
|
373130d8ac | ||
|
|
8e781976eb | ||
|
|
266b56f947 | ||
|
|
2b8adfee05 | ||
|
|
d4c4f8593e | ||
|
|
1f8aa032c4 | ||
|
|
7194f7b674 | ||
|
|
24db4cfc49 | ||
|
|
7781389dea | ||
|
|
30f09994d6 | ||
|
|
babd50fb6c | ||
|
|
5da88d2751 | ||
|
|
1f23f20163 | ||
|
|
dadce54a6a | ||
|
|
0d3d396229 | ||
|
|
6c39e432d2 | ||
|
|
2a6437a2f1 | ||
|
|
52fcf7c39d | ||
|
|
f47d3faea9 | ||
|
|
d1e7ec2e22 | ||
|
|
1efab799b5 | ||
|
|
7ad9996cc3 | ||
|
|
00ec536761 | ||
|
|
3f2d9b42c8 | ||
|
|
ce76eeb512 | ||
|
|
1bc4a6f208 | ||
|
|
8595b7972b | ||
|
|
22054e232f | ||
|
|
5876b6693a | ||
|
|
9ef501fe0c | ||
|
|
08790aa9a8 | ||
|
|
79f244f012 | ||
|
|
143653e2ce | ||
|
|
ef83d874c3 | ||
|
|
eb999c3dc9 | ||
|
|
9a455901dd | ||
|
|
c207fe563e | ||
|
|
ce8e985e56 | ||
|
|
0f4c65f689 | ||
|
|
f332cee568 | ||
|
|
0fa53d5f5d | ||
|
|
e5933811fd | ||
|
|
9ae506ad07 | ||
|
|
12101f6014 | ||
|
|
93af0e7992 | ||
|
|
abfa90755e | ||
|
|
f302c8a5d4 | ||
|
|
b7da95bc36 | ||
|
|
14b014be20 | ||
|
|
9669fe90d7 | ||
|
|
e0d51beb84 | ||
|
|
198046a5d3 | ||
|
|
16dd2fea4c | ||
|
|
b8a38c2fb6 | ||
|
|
9a2906e9db | ||
|
|
578140256b | ||
|
|
c614d27f3e | ||
|
|
538dff16a6 | ||
|
|
fd1118d493 | ||
|
|
6bb00c73de | ||
|
|
cca7eb6c6d | ||
|
|
a35aad61ee | ||
|
|
f30a586b5c | ||
|
|
03fadd86f0 | ||
|
|
2d133f3d57 | ||
|
|
fa60b93ff9 | ||
|
|
65729d9d86 | ||
|
|
15d3d8c709 | ||
|
|
8b49eca549 | ||
|
|
2cd2cb0480 | ||
|
|
5c1112f552 | ||
|
|
f84363fbf1 | ||
|
|
3afce91504 | ||
|
|
57b18edb55 | ||
|
|
2c278c1fde | ||
|
|
1ae743e60c | ||
|
|
3f701f8c55 | ||
|
|
cff36d7cde | ||
|
|
4153dbb8e5 | ||
|
|
d2ee4310e6 | ||
|
|
575282dbe8 | ||
|
|
2f3c5b59a5 | ||
|
|
fb91c361bc | ||
|
|
dce8c78882 | ||
|
|
129b5d58d7 | ||
|
|
9a454a9c89 | ||
|
|
63bb99d2f1 | ||
|
|
60644c38dd | ||
|
|
8ff21e6718 | ||
|
|
34a079aae4 | ||
|
|
a73972f11a | ||
|
|
f18dbbaf4c | ||
|
|
633f0a7c6d | ||
|
|
3ffd6ed833 | ||
|
|
da74bd7428 | ||
|
|
51615f4ada | ||
|
|
9c0525f292 | ||
|
|
952ed806ac | ||
|
|
86ca9cf01c | ||
|
|
d4bac5a6da | ||
|
|
cfdead2bbf | ||
|
|
357ebbb6be | ||
|
|
3908ada113 | ||
|
|
93ae7fbaee | ||
|
|
dbe4bb87d0 | ||
|
|
565152dee0 | ||
|
|
29fb88fbdc | ||
|
|
70831690a5 | ||
|
|
d90da464b3 | ||
|
|
d81b08eda7 | ||
|
|
37f6bef152 | ||
|
|
8ed6ebb0fe | ||
|
|
83ceb1b1f7 | ||
|
|
4cef330f0b | ||
|
|
8573c3736a | ||
|
|
bee065d603 | ||
|
|
0f1f336c3a | ||
|
|
66d5eab041 | ||
|
|
075c5f90cc | ||
|
|
28b88f1566 | ||
|
|
70e347cfce | ||
|
|
42987d96e3 | ||
|
|
2c85f1cc2b | ||
|
|
35c67d6e8f | ||
|
|
c91d06e4c6 | ||
|
|
b991bf5301 | ||
|
|
d2ecdf2016 | ||
|
|
c27497dd16 | ||
|
|
da58ff3d7a | ||
|
|
e366cdfb05 | ||
|
|
e92e9296c7 | ||
|
|
67d17080e6 | ||
|
|
345ed1178c | ||
|
|
e54c614f9f | ||
|
|
f8c02d065e | ||
|
|
07fe7f4f89 | ||
|
|
546bb9bb13 | ||
|
|
5208304ef6 | ||
|
|
9ce5cc8f77 | ||
|
|
bef9e3c5ce | ||
|
|
572bb429ce | ||
|
|
955e985f4d | ||
|
|
fab8667dd4 | ||
|
|
03a8baf51c | ||
|
|
1f2f259554 | ||
|
|
989f5f5b61 | ||
|
|
063b31e7e6 | ||
|
|
9abbb85b4a | ||
|
|
2ecebd14b0 | ||
|
|
2f38277993 | ||
|
|
faf690b833 | ||
|
|
506517901d | ||
|
|
2a1f5500bd | ||
|
|
38fad35119 | ||
|
|
502eab85bf | ||
|
|
567169c4cb | ||
|
|
cdc3f45257 | ||
|
|
f7ff0f8ad5 | ||
|
|
f9ac87db3a | ||
|
|
b712174136 | ||
|
|
81ca34ea1d | ||
|
|
27a2f462a0 | ||
|
|
986664a766 | ||
|
|
3a4bea928a | ||
|
|
0ad8c43c7b | ||
|
|
87ddd619de | ||
|
|
5827fe4a22 | ||
|
|
bd06842375 | ||
|
|
71c8dcb595 | ||
|
|
1b76486bff | ||
|
|
7b1d5efe0d | ||
|
|
9d7a46fe94 | ||
|
|
e494c87e28 | ||
|
|
6215f148b5 | ||
|
|
7f35c69b12 | ||
|
|
0688909fb7 | ||
|
|
a5e2f76cb8 | ||
|
|
119e52fa15 | ||
|
|
083ef6d474 | ||
|
|
d7bbbb2d76 | ||
|
|
2fa9f79962 | ||
|
|
8fdac33219 | ||
|
|
d3e4adb3c4 | ||
|
|
469ab56b64 | ||
|
|
89c694443d | ||
|
|
6fd95154bb | ||
|
|
4de2665192 | ||
|
|
23d38083f6 | ||
|
|
0ae486737f | ||
|
|
cd3aa54a12 | ||
|
|
ec55020f77 | ||
|
|
d4461f075b | ||
|
|
f67bb675a1 | ||
|
|
a084f804f2 | ||
|
|
a898f97d21 | ||
|
|
9c3b062cff | ||
|
|
dd00f34cb8 | ||
|
|
b9e24712a8 | ||
|
|
1ebbef257e | ||
|
|
e7aca138d3 | ||
|
|
f0ed155814 | ||
|
|
838ddabd3c | ||
|
|
5f3c20b71b | ||
|
|
76bff5a1a9 | ||
|
|
e7270f17fd | ||
|
|
aa709c4089 | ||
|
|
807032b0f0 | ||
|
|
b2597d1058 | ||
|
|
56bb8c0304 | ||
|
|
c4a51c2c9f | ||
|
|
c3cdf0238a | ||
|
|
f28fc339df | ||
|
|
45be24192e | ||
|
|
bb2929dfe9 | ||
|
|
5b2cf24840 | ||
|
|
19688ffcb5 | ||
|
|
0baab3ae9f | ||
|
|
9364c07c81 | ||
|
|
b46ab8aa5b | ||
|
|
9d70a93619 | ||
|
|
688ec17cba | ||
|
|
8bdef0dc57 | ||
|
|
826fa8e225 | ||
|
|
c41e58b1d7 | ||
|
|
198c181ed7 | ||
|
|
665974a21e | ||
|
|
be4af2403b | ||
|
|
19a4480b96 | ||
|
|
f58df3c48f | ||
|
|
a19e20e347 | ||
|
|
cb074afd85 | ||
|
|
03613481a3 | ||
|
|
7e3226e596 | ||
|
|
c7c81e5380 | ||
|
|
b3c1584630 | ||
|
|
889a1a147c | ||
|
|
795268a98b | ||
|
|
70a36602e8 | ||
|
|
46736becc7 | ||
|
|
af160168f1 | ||
|
|
6e21a3f56a | ||
|
|
86f29ebe57 | ||
|
|
cf867d29a0 | ||
|
|
93a3d800ef | ||
|
|
056ad33f50 | ||
|
|
e750e1b183 | ||
|
|
257949505c | ||
|
|
b688660ff3 | ||
|
|
ddc98f99da | ||
|
|
8e41b51cb7 | ||
|
|
0675ce718c | ||
|
|
25ac6a0600 | ||
|
|
e8ca646070 | ||
|
|
ce8fd4d3ef | ||
|
|
26d1973110 | ||
|
|
c4cd355f5b | ||
|
|
4a59b8ae43 | ||
|
|
c3f2ddf3e4 | ||
|
|
8cbb86045e | ||
|
|
e54b202de3 | ||
|
|
6466241cbb | ||
|
|
dbccdbd51f | ||
|
|
3141336c9b | ||
|
|
07bf588aa4 | ||
|
|
ce84648689 | ||
|
|
cdef7d62c8 | ||
|
|
440c27d27b | ||
|
|
e82b90b117 | ||
|
|
1ecf147764 | ||
|
|
58b9ecf030 | ||
|
|
0e28dc835e | ||
|
|
8800f48312 | ||
|
|
6315004a24 | ||
|
|
ee63192512 | ||
|
|
1c9dec6ea4 | ||
|
|
6fd85c8dbd | ||
|
|
80e4ed1746 | ||
|
|
06b5a93fe9 | ||
|
|
7ca2e9b5f0 | ||
|
|
274ff3d8c0 | ||
|
|
42e6d587d8 | ||
|
|
c13daf7780 | ||
|
|
e47b3e73d3 | ||
|
|
38a7b0d7ab | ||
|
|
e13c5c214a | ||
|
|
a975786b7b | ||
|
|
0bccaf5458 | ||
|
|
9b760da29b | ||
|
|
5a7ad45a7e | ||
|
|
3cf5c6e4ab | ||
|
|
659517001b | ||
|
|
4c94776ace | ||
|
|
76c4da7945 | ||
|
|
aacd9732f2 | ||
|
|
16b2cccea4 | ||
|
|
8922f6a486 | ||
|
|
d28656ce4b | ||
|
|
8c4f6d68e8 | ||
|
|
972987c515 | ||
|
|
09fc5b768e | ||
|
|
77caad9944 | ||
|
|
5c367ac598 | ||
|
|
867445cbd8 | ||
|
|
65df265e30 | ||
|
|
11869ad4ec | ||
|
|
62b8486431 | ||
|
|
11fc34cfed | ||
|
|
b5717c2cbb | ||
|
|
0c085a5aab | ||
|
|
5cee23cbfa | ||
|
|
1e168b3100 | ||
|
|
018f7a6dec | ||
|
|
a62e88f22b | ||
|
|
dc5ba9eff4 | ||
|
|
4bebdfe0c7 | ||
|
|
f8fd065192 | ||
|
|
9d38d0818b | ||
|
|
a1ad9b7f4d | ||
|
|
29cb55e91c | ||
|
|
0687d2ff78 | ||
|
|
cd04572b78 | ||
|
|
6bb47124a9 | ||
|
|
1a21186ba1 | ||
|
|
82d1193090 | ||
|
|
ea76ac024a | ||
|
|
ff52d61322 | ||
|
|
83e970731e | ||
|
|
c6ea5eb5e9 | ||
|
|
aa7a4111e6 | ||
|
|
2b01f832bd | ||
|
|
1401102396 | ||
|
|
8963d024a6 | ||
|
|
bb5e7b508f | ||
|
|
bfc9efea92 | ||
|
|
75feea3e75 | ||
|
|
e142f5ee61 | ||
|
|
9746c2db5d | ||
|
|
311598e3a6 | ||
|
|
109d19f02e | ||
|
|
bc5ea13821 | ||
|
|
e9cc34f481 | ||
|
|
9f254b6c84 | ||
|
|
4f442d1edc | ||
|
|
a1a10ab23d | ||
|
|
21beefd387 | ||
|
|
a7e03c9d5c | ||
|
|
49781f9717 | ||
|
|
ca12c69741 | ||
|
|
333814eab0 | ||
|
|
c18311eeb2 | ||
|
|
3caa0d1ef5 | ||
|
|
dc56f85881 | ||
|
|
532e035724 | ||
|
|
c3431e1ead | ||
|
|
3016e77897 | ||
|
|
cf69ba0d66 | ||
|
|
4e82891779 | ||
|
|
7fa3e7bf28 | ||
|
|
656c23a891 | ||
|
|
00f758dd98 | ||
|
|
8962d2b1e4 | ||
|
|
eefb761e98 | ||
|
|
9363da137f | ||
|
|
c4daae2f95 | ||
|
|
b201b21e46 | ||
|
|
c959fd9c48 | ||
|
|
0845b5e28a | ||
|
|
b9f9570033 | ||
|
|
baa0e73703 | ||
|
|
e97aaccfee | ||
|
|
f58cfd8571 | ||
|
|
1a43d31c50 | ||
|
|
d244442e70 | ||
|
|
a009c56271 | ||
|
|
f30af37faf | ||
|
|
bb4eea7999 | ||
|
|
e26b80d873 | ||
|
|
b23aa1bc4c | ||
|
|
e22655b440 | ||
|
|
8e57839271 | ||
|
|
16f779c8f5 | ||
|
|
bd08d787f2 | ||
|
|
df99fe0073 | ||
|
|
7a2fceaee9 | ||
|
|
bb69656bd7 | ||
|
|
5be0618b4d | ||
|
|
ad00252a4e | ||
|
|
84eee30d1f | ||
|
|
8975c2936c | ||
|
|
b64bfc9ab0 | ||
|
|
cc9f5ed096 | ||
|
|
2161daa398 | ||
|
|
f1a41394ab | ||
|
|
6d5bb6f887 | ||
|
|
9bcf9a7dcd | ||
|
|
6d69f03111 | ||
|
|
0b709ddb1a | ||
|
|
6ba780ba3b | ||
|
|
f0f24142b2 | ||
|
|
a716da14f7 | ||
|
|
d8a80479c2 | ||
|
|
8d4a55a3a4 | ||
|
|
0c0aa94ded | ||
|
|
0fd4991dd4 | ||
|
|
5f32ea64eb | ||
|
|
dc6705c74a | ||
|
|
4479f251a6 | ||
|
|
ac076fb892 | ||
|
|
503b38c17f | ||
|
|
7b6680cde2 | ||
|
|
7029edfd58 | ||
|
|
3b3ac68f47 | ||
|
|
5e28d04aa6 | ||
|
|
102140b917 | ||
|
|
17d7e19e84 | ||
|
|
d7b810e87e | ||
|
|
3cf44b4c62 | ||
|
|
96a9962895 | ||
|
|
b2cd4db395 | ||
|
|
015ef2c6ce | ||
|
|
0ba1af244d | ||
|
|
547a049140 | ||
|
|
05e0013990 | ||
|
|
b9d6f75923 | ||
|
|
07f4cb0892 | ||
|
|
e48be33c6c | ||
|
|
b3ba54894e | ||
|
|
14753d499d | ||
|
|
bb348fff94 | ||
|
|
c097907098 | ||
|
|
3719bac746 | ||
|
|
85add10bef | ||
|
|
8a7a9d4a45 | ||
|
|
875885f647 | ||
|
|
3af85ed14f | ||
|
|
34f6020e7f | ||
|
|
2a6b96937c | ||
|
|
8861918827 | ||
|
|
6212aef8b1 | ||
|
|
f13c4e916a | ||
|
|
60e183a8c0 | ||
|
|
939449c1b0 | ||
|
|
5970e5bf5c | ||
|
|
aee5a38313 | ||
|
|
19b2de7040 | ||
|
|
20d7ed5421 | ||
|
|
0dd53aea02 | ||
|
|
801d5d361a | ||
|
|
dc7362c70b | ||
|
|
fc3c0e7fa5 | ||
|
|
e172f5c82d | ||
|
|
3a7426ed04 | ||
|
|
3ab1feb7b1 | ||
|
|
1c90ee6db3 | ||
|
|
046136bc37 | ||
|
|
1d0234550e | ||
|
|
cca3a039ad | ||
|
|
e73d101c97 | ||
|
|
389e53207e | ||
|
|
5bdce4fb28 | ||
|
|
b06e3b3281 | ||
|
|
a4d39ce424 | ||
|
|
79f5aaa032 | ||
|
|
740ea2e86d | ||
|
|
364f95ec45 | ||
|
|
6668a7b8ab | ||
|
|
571f27d518 | ||
|
|
0fa70b5b35 | ||
|
|
be8d424404 | ||
|
|
08e239fcf4 | ||
|
|
947cb79558 | ||
|
|
1f1df9afc7 | ||
|
|
ef40bb25fd | ||
|
|
e2db025aa0 | ||
|
|
63369247ab | ||
|
|
8c695df9da | ||
|
|
1c9d41ad58 | ||
|
|
e7721d21a2 | ||
|
|
547f72919f | ||
|
|
2b6740dc7b | ||
|
|
1a91cf7033 | ||
|
|
1e9418b87b | ||
|
|
bedf1555af | ||
|
|
5d070f4d9e | ||
|
|
7eff48bd4f | ||
|
|
dfccfb3cf3 | ||
|
|
aeebc13d83 | ||
|
|
0a42ace4ba | ||
|
|
7b4f0a29ac | ||
|
|
b529456745 | ||
|
|
f1a929624f | ||
|
|
65285ad11e | ||
|
|
eb421bc95e | ||
|
|
917a5c3082 | ||
|
|
ea491fbde5 | ||
|
|
a98d01ba65 | ||
|
|
7e2fa8295a | ||
|
|
adf758a569 | ||
|
|
49941105dc | ||
|
|
c07afab981 | ||
|
|
c2b07fec1f | ||
|
|
7f8baf326e | ||
|
|
9601061f25 | ||
|
|
b1317e56ec | ||
|
|
353832c386 | ||
|
|
8bf04d4593 | ||
|
|
c9f0500c6f | ||
|
|
0dc465bb41 | ||
|
|
34e50aab21 | ||
|
|
5a2411a0e6 | ||
|
|
178f66c940 | ||
|
|
6d3a7a3989 | ||
|
|
2400eaf04e | ||
|
|
752a3ca5bd | ||
|
|
6dbb6eb432 | ||
|
|
e580bb9998 | ||
|
|
d309491f06 | ||
|
|
0e35048143 | ||
|
|
c919ed36b4 | ||
|
|
6d2a7c53dc | ||
|
|
a8582fc131 | ||
|
|
76b7bd855d | ||
|
|
5656bb3caf | ||
|
|
57bd4d8f22 | ||
|
|
e71cd5a7ad | ||
|
|
4132388dda | ||
|
|
1edabe3b00 | ||
|
|
019fdd65e9 | ||
|
|
fa432cd32f | ||
|
|
4935679659 | ||
|
|
835c64c173 | ||
|
|
4d6ecbe618 | ||
|
|
63456aad85 | ||
|
|
bec2ee91b5 | ||
|
|
027c9cdd04 | ||
|
|
8ecea3a8c1 | ||
|
|
69e6d57346 | ||
|
|
8127d9cf31 | ||
|
|
bc1a9b31fa | ||
|
|
ff5658e803 | ||
|
|
3d986cdd91 | ||
|
|
32810efcd9 | ||
|
|
76b463792e | ||
|
|
b4a0a31539 | ||
|
|
acbc7efdc8 | ||
|
|
8475e0803a | ||
|
|
f779fc57df | ||
|
|
7afef9073c | ||
|
|
370b5db34e | ||
|
|
6adabb5f71 | ||
|
|
df9a0eeab2 | ||
|
|
e6d58b780e | ||
|
|
e4b65d5d7f | ||
|
|
bf61a123cc | ||
|
|
71f0757015 | ||
|
|
f1e57e0e9c | ||
|
|
1147516dcc | ||
|
|
3f1661965b | ||
|
|
adb0b3ab18 | ||
|
|
8afad07146 | ||
|
|
81bce07a6e | ||
|
|
e883b57ac6 | ||
|
|
921685ff88 | ||
|
|
ae2f95b1ae | ||
|
|
4f77ef26b5 | ||
|
|
d8df9ffb53 | ||
|
|
3c51c0acd4 | ||
|
|
c085540143 | ||
|
|
d239dd56d5 | ||
|
|
8f9eb3b48b | ||
|
|
1f906e6a50 | ||
|
|
e0a4efe181 | ||
|
|
78e9c8fa1a | ||
|
|
9382dc9c10 | ||
|
|
aa85f20aa9 | ||
|
|
4ae01d48ae | ||
|
|
fe3082c6c9 | ||
|
|
ab6c257ba6 | ||
|
|
628ae561d5 | ||
|
|
56b5a65b24 | ||
|
|
73654a99f9 | ||
|
|
ea8add59b1 | ||
|
|
5078ae62c0 | ||
|
|
e026ba32f4 | ||
|
|
e9ebe3b533 | ||
|
|
cea130700d | ||
|
|
0ae7ebac68 | ||
|
|
326f1bc890 | ||
|
|
cabec818e2 | ||
|
|
ff04b33efd | ||
|
|
4f1a71b145 | ||
|
|
f7f8aa108a | ||
|
|
718d443d52 | ||
|
|
57c5885216 | ||
|
|
14767a3e11 | ||
|
|
fb31caefef | ||
|
|
7ceb0dd065 | ||
|
|
b2a78d587c | ||
|
|
16c3a3690b | ||
|
|
7f8e8f67a5 | ||
|
|
9792c9a84e | ||
|
|
13e9e6f5e1 | ||
|
|
e62133233c | ||
|
|
3ec855e28f | ||
|
|
4b56a05f57 | ||
|
|
845da953e1 | ||
|
|
565a76c317 | ||
|
|
e01a116173 | ||
|
|
4e07c294c5 | ||
|
|
58bb5a6993 | ||
|
|
2c51dd5fe1 | ||
|
|
ce8513d3ff | ||
|
|
08c4fd02d2 | ||
|
|
2e680cd35a | ||
|
|
f12ef84a98 | ||
|
|
0563b2b6e5 | ||
|
|
c68c39df27 | ||
|
|
41c00d7fbe | ||
|
|
750dfb60dc | ||
|
|
4305bbabd5 | ||
|
|
ecc12be531 | ||
|
|
b65280f3c9 | ||
|
|
e077b3d04c | ||
|
|
91a963f580 | ||
|
|
8404ba7a09 | ||
|
|
86b907c86c | ||
|
|
ca899072d4 | ||
|
|
bbfc63e943 | ||
|
|
9bce9ce026 | ||
|
|
3a25f028df | ||
|
|
491c6d6a1f | ||
|
|
64bb6ea2ad | ||
|
|
084e59dc90 | ||
|
|
f7ea2e95e4 | ||
|
|
7acdf231a4 | ||
|
|
5d38e0fa14 | ||
|
|
e364616730 | ||
|
|
5ccefee288 | ||
|
|
93f4ad6e5a | ||
|
|
c481acbb71 | ||
|
|
bbdb0189f1 | ||
|
|
e1d655a3ac | ||
|
|
d849f8a03e | ||
|
|
67c3d64275 | ||
|
|
1546783371 | ||
|
|
21cc9f86f3 | ||
|
|
2936d26f8d | ||
|
|
ae453dbc71 | ||
|
|
d25699397f | ||
|
|
d461fac089 | ||
|
|
4bda629a6a | ||
|
|
8a2817a305 | ||
|
|
8887f8862d | ||
|
|
4883a408c7 | ||
|
|
7b75171f79 | ||
|
|
dc42288fa0 | ||
|
|
f576f914ae | ||
|
|
88faa5040c | ||
|
|
1e5365ba51 | ||
|
|
eb93dacba0 | ||
|
|
1e79cbc945 | ||
|
|
d350bd31cb | ||
|
|
89b9b4e9b7 | ||
|
|
9549e5aa4c | ||
|
|
1517d0e40b | ||
|
|
f13593aac7 | ||
|
|
b8023b2444 | ||
|
|
bb49098a05 | ||
|
|
c368fbcda9 | ||
|
|
1c1bf86e9a | ||
|
|
5f1b190ba9 | ||
|
|
0860f53d68 | ||
|
|
1ffd1cb6e7 | ||
|
|
030d230312 | ||
|
|
974f9d52a4 | ||
|
|
1a238ea1b1 | ||
|
|
a049441048 | ||
|
|
20e771f121 | ||
|
|
cff4e225e6 | ||
|
|
2c69f539ae | ||
|
|
548081471c | ||
|
|
3688cfa397 | ||
|
|
20b2856dee | ||
|
|
7e94e46459 | ||
|
|
f3b4efb661 | ||
|
|
7947ba2442 | ||
|
|
ef63e993d2 | ||
|
|
29ae5b7aae | ||
|
|
6baf7e0b35 | ||
|
|
2e7ece17d7 | ||
|
|
2a56f21d13 | ||
|
|
d253c3c6c5 | ||
|
|
289a838ba1 | ||
|
|
f6f3e96106 | ||
|
|
7d22305678 | ||
|
|
7571d1d562 | ||
|
|
b4c06f537d | ||
|
|
830c723bae | ||
|
|
b83ab07374 | ||
|
|
8200cb9336 | ||
|
|
b1a38306af | ||
|
|
6ec0f4782f | ||
|
|
d25f9bcf1b | ||
|
|
cd3fd5a7b7 | ||
|
|
1ab1378259 | ||
|
|
21f87ade2d | ||
|
|
8f54e5739f | ||
|
|
21a6594573 | ||
|
|
01ce80fb1a | ||
|
|
174672c411 | ||
|
|
4785103081 | ||
|
|
7030422b11 | ||
|
|
2a06dc9bea | ||
|
|
66927043de | ||
|
|
7d16bafd52 | ||
|
|
ee340e2d6f | ||
|
|
66d9fd1a5e | ||
|
|
7c28de6ae5 | ||
|
|
c95f602ea2 | ||
|
|
6361280d99 | ||
|
|
b3a9d7cd41 | ||
|
|
071989c554 | ||
|
|
f956d7113f | ||
|
|
f0472fdd76 | ||
|
|
01899676a4 | ||
|
|
b13d572ca8 | ||
|
|
a588e08405 | ||
|
|
6c93483220 | ||
|
|
733c13102b | ||
|
|
688d6fe17a | ||
|
|
25ff1f230f | ||
|
|
094b58130a | ||
|
|
a18ec00962 | ||
|
|
d9188e76ed | ||
|
|
a04a79af3e | ||
|
|
0c84392d0f | ||
|
|
be12f350cb | ||
|
|
01c7eadc92 | ||
|
|
4b3abc282a | ||
|
|
81358e9984 | ||
|
|
8179d8eac1 | ||
|
|
c22a2579a9 | ||
|
|
0a26772e35 | ||
|
|
364fc7afa8 | ||
|
|
82bd54eb0b | ||
|
|
d92d9bafc6 | ||
|
|
9c541ee20b | ||
|
|
105dc34b2a | ||
|
|
0d8b46a157 | ||
|
|
6142a12f48 | ||
|
|
1bda3eb1e3 | ||
|
|
96b2b327b2 | ||
|
|
e014b12626 | ||
|
|
d473f72edd | ||
|
|
7139425812 | ||
|
|
f5722d7baa | ||
|
|
467eb00f0f | ||
|
|
0ce3646977 | ||
|
|
53dd6c0860 | ||
|
|
e4a130c919 | ||
|
|
0d9ddb92d5 | ||
|
|
68a561d4fb | ||
|
|
5e651dd0e5 | ||
|
|
1bb2965916 | ||
|
|
4ea650fc6d | ||
|
|
501b38c4ba | ||
|
|
ede958bd61 | ||
|
|
f3d099e655 | ||
|
|
db5c3ea400 | ||
|
|
504f57930a | ||
|
|
02b1b2cf9d | ||
|
|
99dbb3225b | ||
|
|
08a8d69be2 | ||
|
|
a029f89ad2 | ||
|
|
ed02fed866 | ||
|
|
06de6c8e17 | ||
|
|
9ddfcd2154 | ||
|
|
217e5e5a2c | ||
|
|
272bf357d4 | ||
|
|
9a5d14aa13 | ||
|
|
2b70b2ad4f | ||
|
|
9323385b25 | ||
|
|
ff95a116c2 | ||
|
|
f30a3c137e | ||
|
|
a5d31e7187 | ||
|
|
73c42313fa | ||
|
|
21772c5481 | ||
|
|
5b08a8605e | ||
|
|
0cc35b56e5 | ||
|
|
1423375312 | ||
|
|
640ba16f8b | ||
|
|
345d61f04f | ||
|
|
6f06e0c424 | ||
|
|
8dfb9d08c4 |
@@ -2,15 +2,15 @@ git:
|
||||
problems:
|
||||
url: https://github.com/getgrav/grav-plugin-problems
|
||||
path: user/plugins/problems
|
||||
branch: develop
|
||||
branch: master
|
||||
error:
|
||||
url: https://github.com/getgrav/grav-plugin-error
|
||||
path: user/plugins/error
|
||||
branch: develop
|
||||
branch: master
|
||||
antimatter:
|
||||
url: https://github.com/getgrav/grav-theme-antimatter
|
||||
path: user/themes/antimatter
|
||||
branch: develop
|
||||
branch: master
|
||||
links:
|
||||
problems:
|
||||
src: grav-plugin-problems
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
# Composer
|
||||
composer.lock
|
||||
.composer
|
||||
vendor/
|
||||
|
||||
@@ -7,6 +6,8 @@ vendor/
|
||||
.sass-cache
|
||||
|
||||
# Grav Specific
|
||||
backup/*
|
||||
!backup/.*
|
||||
cache/*
|
||||
!cache/.*
|
||||
assets/*
|
||||
@@ -15,12 +16,15 @@ logs/*
|
||||
!logs/.*
|
||||
images/*
|
||||
!images/.*
|
||||
user/accounts/*
|
||||
!user/accounts/.*
|
||||
user/data/*
|
||||
!user/data/.*
|
||||
user/plugins/*
|
||||
!user/plugins/.*
|
||||
user/themes/*
|
||||
!user/themes/.*
|
||||
user/localhost/config/security.yaml
|
||||
|
||||
# OS Generated
|
||||
.DS_Store*
|
||||
|
||||
19
.htaccess
19
.htaccess
@@ -44,13 +44,22 @@ RewriteRule .* index.php [L]
|
||||
|
||||
## Begin - Security
|
||||
# Block all direct access for these folders
|
||||
RewriteRule ^(cache|bin|logs)/(.*) error [L]
|
||||
# Block access to specific file types for these folders
|
||||
RewriteRule ^(system|user|vendor)/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$ error [L]
|
||||
RewriteRule ^(.git|cache|bin|logs|backup)/(.*) error [F]
|
||||
# Block access to specific file types for these system folders
|
||||
RewriteRule ^(system|vendor)/(.*)\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
|
||||
# Block access to specific file types for these user folders
|
||||
RewriteRule ^(user)/(.*)\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
|
||||
# Block all direct access to .md files:
|
||||
RewriteRule \.md$ error [F]
|
||||
# Block all direct access to files and folders beginning with a dot
|
||||
RewriteRule (^\.|/\.) - [F]
|
||||
# Block access to specific files in the root folder
|
||||
RewriteRule ^(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
|
||||
## End - Security
|
||||
|
||||
</IfModule>
|
||||
|
||||
# Begin - Prevent Browsing
|
||||
# Begin - Prevent Browsing and Set Default Resources
|
||||
Options -Indexes
|
||||
# End - Prevent Browsing
|
||||
DirectoryIndex index.php index.html index.htm
|
||||
# End - Prevent Browsing and Set Default Resources
|
||||
|
||||
82
.travis.yml
Normal file
82
.travis.yml
Normal file
@@ -0,0 +1,82 @@
|
||||
language: php
|
||||
php: 5.6
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- build_test
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: always
|
||||
hipchat:
|
||||
# hipchat_api@grav
|
||||
rooms:
|
||||
- secure: "bqO0wM1B7bJnQw2fuhquSXEqI9gw6WmFytIh9sEWXzbYTzTUP5t0PcKOd3FT2BNMRaDxPJLVl+vG/oqmqDUBkEmOGcG504IQjeNzZqnMz0tXQMIcCc22Las9tFfc4Jf6RVi/qGomFtHGE9Wgii+TAN4zqZaufbNjwd8SyjO0+W8="
|
||||
template:
|
||||
- '%{repository}#%{build_number} (%{branch}): Grav Core and Skeletons packages have been uploaded. (<a href="%{build_url}">Details</a>)'
|
||||
format: html
|
||||
env:
|
||||
global:
|
||||
# Colors!
|
||||
- TEXTRESET=$(tput sgr0) # reset the foreground colour
|
||||
- RED=$(tput setaf 1)
|
||||
- GREEN=$(tput setaf 2)
|
||||
- YELLOW=$(tput setaf 3)
|
||||
- BLUE=$(tput setaf 4)
|
||||
- BOLD=$(tput bold)
|
||||
# User
|
||||
- GH_USER="getgrav"
|
||||
# Paths
|
||||
- RT_DEVTOOLS=$HOME/devtools
|
||||
- GOPATH="$HOME/go"
|
||||
- PATH="$GOPATH/bin:$PATH"
|
||||
# GH_TOKEN [API Key]
|
||||
- secure: "jS+c+g2v33vypG4VtqiSDW2qQ4dGJZlrUKBRCztoy1yrOrYRPvc5Vzi/AS3fDmZ4yizukEwmUNNzyZQcgFvLPpmCCml46Dovp8R9OXhbNe8OnULmaSn2Zkr71oblMYu6ZP+RpYvNq0BIdSB3u2TiFriHMiTIkX9UwZNaUCOX1ig="
|
||||
# BB_TOKEN value => "user:pass@"
|
||||
- secure: "einUtSEkUWy2IrqLXyVjwUU+mwaaoiOXRRVdLBpA3Zye6bZx8cm5h/5AplkPWhM/NmCJoW/MwNZHHkFhlr3mDRov5iOxVmTTYfnXB+I5lxYTSgduOLLErS7mU8hfADpVDU8bHNU44fNGD3UEiG1PD4qQBX4DMlqIFmR20mjs81k="
|
||||
# GH_API_USER [for curl]
|
||||
- secure: "Xbk/V9aIys0NxccJGR3Zrm2GRxDnA0RuazBs1puIboTYDhbi0Z7JTL+mOx3xp5Kfoniad/xAuijQESTM9MMrKqq/qCzhAMaC1+vcL4pCHZH4NSG6DBxB9BPkKVFq+1llu5FTEf8bkxHzwGR0l1ARW6TVRcgTHr5B58bCEIwEOrI="
|
||||
# Latest Release version
|
||||
- TRAVIS_TAG=$(curl --fail --user ${GH_API_USER} -s https://api.github.com/repos/getgrav/grav/releases/latest | grep tag_name | head -n 1 | cut -d '"' -f 4)
|
||||
|
||||
before_install:
|
||||
- composer self-update
|
||||
- go get github.com/aktau/github-release
|
||||
- git clone --quiet --depth=50 --branch=master https://${BB_TOKEN}bitbucket.org/rockettheme/grav-devtools.git $RT_DEVTOOLS &>/dev/null;
|
||||
- if [ ! -z "$TRAVIS_TAG" ]; then
|
||||
cd "${RT_DEVTOOLS}";
|
||||
./build-grav.sh skeletons.txt;
|
||||
fi
|
||||
script:
|
||||
- if [ ! -z "$TRAVIS_TAG" ]; then
|
||||
FILES="$RT_DEVTOOLS/grav-dist/*.zip";
|
||||
for file in ${FILES[@]}; do
|
||||
NAME=${file##*/};
|
||||
if [[ "$NAME" == *"-rc"* ]]; then
|
||||
REPO="$(echo ${NAME} | rev | cut -f 3- -d "-" | rev)";
|
||||
else
|
||||
REPO="$(echo ${NAME} | rev | cut -f 2- -d "-" | rev)";
|
||||
fi;
|
||||
if [[ $REPO == 'grav' || $REPO == 'grav-admin' || $REPO == 'grav-update' ]]; then
|
||||
REPO="grav";
|
||||
fi;
|
||||
API="$(curl --fail --user "${GH_API_USER}" -s https://api.github.com/repos/${GH_USER}/${REPO}/releases/latest)";
|
||||
ASSETS="$(echo "${API}" | node gh-assets.js)";
|
||||
TAG="$(echo "${API}" | grep tag_name | head -n 1 | cut -d '"' -f 4)";
|
||||
if [ $REPO == "grav" ]; then
|
||||
TAG="$TRAVIS_TAG";
|
||||
fi;
|
||||
if [ ! -z "$ASSETS" ]; then
|
||||
for asset in ${ASSETS[@]}; do
|
||||
asset_id=$(echo ${asset} | cut -d ':' -f 1);
|
||||
asset_name=$(echo ${asset} | cut -d ':' -f 2);
|
||||
if [ "${NAME}" == "${asset_name}" ]; then
|
||||
echo -e "\nAsset ${BOLD}${BLUE}${NAME}${TEXTRESET} already exists in ${YELLOW}${REPO}${TEXTRESET}@${BOLD}${YELLOW}${TAG}${TEXTRESET}... deleting id ${BOLD}${RED}${asset_id}${TEXTRESET}...";
|
||||
curl -X DELETE --fail --user "${GH_API_USER}" "https://api.github.com/repos/${GH_USER}/${REPO}/releases/assets/${asset_id}";
|
||||
fi;
|
||||
done;
|
||||
fi;
|
||||
echo "Uploading package ${BOLD}${BLUE}${NAME}${TEXTRESET} to ${YELLOW}${REPO}${TEXTRESET}@${YELLOW}${TAG}${TEXTRESET}";
|
||||
github-release upload --security-token $GH_TOKEN --user ${GH_USER} --repo $REPO --tag "$TAG" --name "$NAME" --file "$file";
|
||||
done;
|
||||
fi
|
||||
609
CHANGELOG.md
609
CHANGELOG.md
@@ -1,3 +1,604 @@
|
||||
# v1.0.0
|
||||
## 12/11/2015
|
||||
|
||||
1. [](#new)
|
||||
* Add new link attributes via markdown media
|
||||
* Added setters to set state of CSS/JS pipelining
|
||||
* Added `user/accounts` to `.gitignore`
|
||||
* Added configurable permissions option for Image cache
|
||||
1. [](#improved)
|
||||
* Hungarian translation updated
|
||||
* Refactored Theme initialization for improved flexibility
|
||||
* Wrapped security section of account blueprints in an 'super user' authorize check
|
||||
* Minor performance optimizations
|
||||
* Updated core page blueprints with markdown preview option
|
||||
* Added useful cache info output to Debugbar
|
||||
* Added `iconv` polyfill library used by Symfony 2.8
|
||||
* Force lowercase of username in a few places for case sensitive filesystems
|
||||
1. [](#bugfix)
|
||||
* Fix for GPM problems "Call to a member function set() on null"
|
||||
* Fix for individual asset pipeline values not functioning
|
||||
* Fix `Page::copy()` and `Page::move()` to support multiple moves at once
|
||||
* Fixed page moving of a page with no content
|
||||
* Fix for wrong ordering when moving many pages
|
||||
* Escape root path in page medium files to work with special characters
|
||||
* Add missing parent constructor to Themes class
|
||||
* Fix missing file error in `bin/grav sandbox` command
|
||||
* Fixed changelog differ when upgrading Grav
|
||||
* Fixed a logic error in `Validation->validate()`
|
||||
* Make `$container` available in `setup.php` to fix multi-site
|
||||
|
||||
# v1.0.0-rc.6
|
||||
## 12/01/2015
|
||||
|
||||
1. [](#new)
|
||||
* Refactor Config classes for improved performance!
|
||||
* Refactor Data classes to use `NestedArrayAccess` instead of `DataMutatorTrait`
|
||||
* Added support for `classes` and `id` on medium objects to set CSS values
|
||||
* Data objects: Allow function call chaining
|
||||
* Data objects: Lazy load blueprints only if needed
|
||||
* Automatically create unique security salt for each configuration
|
||||
* Added Hungarian translation
|
||||
* Added support for User groups
|
||||
1. [](#improved)
|
||||
* Improved robots.txt to disallow crawling of non-user folders
|
||||
* Nonces only generated once per action and process
|
||||
* Added IP into Nonce string calculation
|
||||
* Nonces now use random string with random salt to improve performance
|
||||
* Improved list form handling #475
|
||||
* Vendor library updates
|
||||
1. [](#bugfix)
|
||||
* Fixed help output for `bin/plugin`
|
||||
* Fix for nested logic for lists and form parsing #273
|
||||
* Fix for array form fields and last entry not getting deleted
|
||||
* Should not be able to set parent to self #308
|
||||
|
||||
# v1.0.0-rc.5
|
||||
## 11/20/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added **nonce** functionality for all admin forms for improved security
|
||||
* Implemented the ability for Plugins to provide their own CLI commands through `bin/plugin`
|
||||
* Added Croatian translation
|
||||
* Added missing `umask_fix` property to `system.yaml`
|
||||
* Added current theme's config to global config. E.g. `config.theme.dropdown_enabled`
|
||||
* Added `append_url_extension` option to system config & page headers
|
||||
* Users have a new `state` property to allow disabling/banning
|
||||
* Added new `Page.relativePagePath()` helper method
|
||||
* Added new `|pad` Twig filter for strings (uses `str_pad()`)
|
||||
* Added `lighttpd.conf` for Lightly web server
|
||||
1. [](#improved)
|
||||
* Clear previously applied operations when doing a reset on image media
|
||||
* Password no longer required when editing user
|
||||
* Improved support for trailing `/` URLs
|
||||
* Improved `.nginx.conf` configuration file
|
||||
* Improved `.htaccess` security
|
||||
* Updated vendor libs
|
||||
* Updated `composer.phar`
|
||||
* Use streams instead of paths for `clearCache()`
|
||||
* Use PCRE_UTF8 so unicode strings can be regexed in Truncator
|
||||
* Handle case when login plugin is disabled
|
||||
* Improved `quality` functionality in media handling
|
||||
* Added some missing translation strings
|
||||
* Deprecated `bin/grav newuser` in favor of `bin/plugin login new-user`
|
||||
* Moved fallback types to use any valid media type
|
||||
* Renamed `system.pages.fallback_types` to `system.media.allowed_fallback_types`
|
||||
* Removed version number in default `generator` meta tag
|
||||
* Disable time limit in case of slow downloads
|
||||
* Removed default hash in `system.yaml`
|
||||
1. [](#bugfix)
|
||||
* Fix for media using absolute URLs causing broken links
|
||||
* Fix theme auto-loading #432
|
||||
* Don't create empty `<style>` or `<script>` scripts if no data
|
||||
* Code cleanups
|
||||
* Fix undefined variable in Config class
|
||||
* Fix exception message when label is not set
|
||||
* Check in `Plugins::get()` to ensure plugins exists
|
||||
* Fixed GZip compression making output buffering work correctly with all servers and browsers
|
||||
* Fixed date representation in system config
|
||||
|
||||
# v1.0.0-rc.4
|
||||
## 10/29/2015
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed a fatal error if you have a collection with missing or invalid `@page: /route`
|
||||
|
||||
# v1.0.0-rc.3
|
||||
## 10/29/2015
|
||||
|
||||
1. [](#new)
|
||||
* New Page collection options! `@self.parent, @self.siblings, @self.descendants` + more
|
||||
* White list of file types for fallback route functionality (images by default)
|
||||
1. [](#improved)
|
||||
* Assets switched from defines to streams
|
||||
1. [](#bugfix)
|
||||
* README.md typos fixed
|
||||
* Fixed issue with routes that have lang string in them (`/en/english`)
|
||||
* Trim strings before validation so whitespace is not satisfy 'required'
|
||||
|
||||
# v1.0.0-rc.2
|
||||
## 10/27/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added support for CSS Asset groups
|
||||
* Added a `wrapped_site` system option for themes/plugins to use
|
||||
* Pass `Page` object as event to `onTwigPageVariables()` event hook
|
||||
* New `Data.items()` method to get all items
|
||||
1. [](#improved)
|
||||
* Missing pipelined remote asset will now fail quietly
|
||||
* More reliably handle inline JS and CSS to remove only surrounding HTML tags
|
||||
* `Medium.meta` returns new Data object so null checks are possible
|
||||
* Improved Medium metadata merging to allow for automatic title/alt/class attributes
|
||||
* Moved Grav object to global variable rather than template variable (useful for macros)
|
||||
* German language improvements
|
||||
* Updated bundled composer
|
||||
1. [](#bugfix)
|
||||
* Accept variety of `true` values in `User.authorize()` method
|
||||
* Fix for `Validation` throwing an error if no label set
|
||||
|
||||
# v1.0.0-rc.1
|
||||
## 10/23/2015
|
||||
|
||||
1. [](#new)
|
||||
* Use native PECL YAML parser if installed for 4X speed boost in parsing YAML files
|
||||
* Support for inherited theme class
|
||||
* Added new default language prepend system configuration option
|
||||
* New `|evaluate` Twig filter to evaluate a string as twig
|
||||
* New system option to ignore all **hidden** files and folders
|
||||
* New system option for default redirect code
|
||||
* Added ability to append specific `[30x]` codes to redirect URLs
|
||||
* Added `url_taxonomy_filters` for page collections
|
||||
* Added `@root` page and `recurse` flag for page collections
|
||||
* Support for **multiple** page collection types as an array
|
||||
* Added Dutch language file
|
||||
* Added Russian language file
|
||||
* Added `remove` method to User object
|
||||
1. [](#improved)
|
||||
* Moved hardcoded mimetypes to `media.yaml` to be treated as Page media files
|
||||
* Set `errors: display: false` by default in `system.yaml`
|
||||
* Strip out extra slashes in the URI
|
||||
* Validate hostname to ensure it is valid
|
||||
* Ignore more SCM folders in Backups
|
||||
* Removed `home_redirect` settings from `system.yaml`
|
||||
* Added Page `media` as root twig object for consistency
|
||||
* Updated to latest vendor libraries
|
||||
* Optimizations to Asset pipeline logic for minor speed increase
|
||||
* Block direct access to a variety of files in `.htaccess` for increased security
|
||||
* Debugbar vendor library update
|
||||
* Always fallback to english if other translations are not available
|
||||
1. [](#bugfix)
|
||||
* Fix for redirecting external URL with multi-language
|
||||
* Fix for Asset pipeline not respecting asset groups
|
||||
* Fix language files with child/parent theme relationships
|
||||
* Fixed a regression issue resulting in incorrect default language
|
||||
* Ensure error handler is initialized before URI is processed
|
||||
* Use default language in Twig if active language is not set
|
||||
* Fixed issue with `safeEmailFilter()` Twig filter not separating with `;` properly
|
||||
* Fixed empty YAML file causing error with native PECL YAML parser
|
||||
* Fixed `SVG` mimetype
|
||||
* Fixed incorrect `Cache-control: max-age` value format
|
||||
|
||||
# v0.9.45
|
||||
## 10/08/2015
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed a regression issue resulting in incorrect default language
|
||||
|
||||
# v0.9.44
|
||||
## 10/07/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added Redis back as a supported cache mechanism
|
||||
* Allow Twig `nicetime` translations
|
||||
* Added `-y` option for 'Yes to all' in `bin/gpm update`
|
||||
* Added CSS `media` attribute to the Assets manager
|
||||
* New German language support
|
||||
* New Czech language support
|
||||
* New French language support
|
||||
* Added `modulus` twig filter
|
||||
1. [](#improved)
|
||||
* URL decode in medium actions to allow complex syntax
|
||||
* Take into account `HTTP_HOST` before `SERVER_NAME` (helpful with Nginx)
|
||||
* More friendly cache naming to ease manual management of cache systems
|
||||
* Added default Apache resource for `DirectoryIndex`
|
||||
1. [](#bugfix)
|
||||
* Fix GPM failure when offline
|
||||
* Fix `open_basedir` error in `bin/gpm install`
|
||||
* Fix an HHVM error in Truncator
|
||||
* Fix for XSS vulnerability with params
|
||||
* Fix chaining for responsive size derivatives
|
||||
* Fix for saving pages when removing the page title and all other header elements
|
||||
* Fix when saving array fields
|
||||
* Fix for ports being included in `HTTP_HOST`
|
||||
* Fix for Truncator to handle PHP tags gracefully
|
||||
* Fix for locate style lang codes in `getNativeName()`
|
||||
* Urldecode image basenames in markdown
|
||||
|
||||
# v0.9.43
|
||||
## 09/16/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added new `AudioMedium` for HTML5 audio
|
||||
* Added ability for Assets to be added and displayed in separate *groups*
|
||||
* New support for responsive image derivative sizes
|
||||
1. [](#improved)
|
||||
* GPM theme install now uses a `copy` method so new files are not lost (e.g. `/css/custom.css`)
|
||||
* Code analysis improvements and cleanup
|
||||
* Removed Twig panel from debugger (no longer supported in Twig 1.20)
|
||||
* Updated composer packages
|
||||
* Prepend active language to `convertUrl()` when used in markdown links
|
||||
* Added some pre/post flight options for installer via blueprints
|
||||
* Hyphenize the site name in the backup filename
|
||||
1. [](#bugfix)
|
||||
* Fix broken routable logic
|
||||
* Check for `phpinfo()` method in case it is restricted by hosting provider
|
||||
* Fixes for windows when running GPM
|
||||
* Fix for ampersand (`&`) causing error in `truncateHtml()` via `Page.summary()`
|
||||
|
||||
# v0.9.42
|
||||
## 09/11/2015
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fixed `User.authorise()` to be backwards compabile
|
||||
|
||||
# v0.9.41
|
||||
## 09/11/2015
|
||||
|
||||
1. [](#new)
|
||||
* New and improved multibyte-safe TruncateHTML function and filter
|
||||
* Added support for custom page date format
|
||||
* Added a `string` Twig filter to render as json_encoded string
|
||||
* Added `authorize` Twig filter
|
||||
* Added support for theme inheritance in the admin
|
||||
* Support for multiple content collections on a page
|
||||
* Added configurable files/folders ignores for pages
|
||||
* Added the ability to set the default PHP locale and override via multi-lang configuration
|
||||
* Added ability to save as YAML via admin
|
||||
* Added check for `mbstring` support
|
||||
* Added new `redirect` header for pages
|
||||
1. [](#improved)
|
||||
* Changed dependencies from `develop` to `master`
|
||||
* Updated logging to log everything from `debug` level on (was `warning`)
|
||||
* Added missing `accounts/` folder
|
||||
* Default to performing a 301 redirect for URIs with trailing slashes
|
||||
* Improved Twig error messages
|
||||
* Allow validating of forms from anywhere such as plugins
|
||||
* Added logic so modular pages are by default non-routable
|
||||
* Hide password input in `bin/grav newuser` command
|
||||
1. [](#bugfix)
|
||||
* Fixed `Pages.all()` not returning modular pages
|
||||
* Fix for modular template types not getting found
|
||||
* Fix for `markdown_extra:` overriding `markdown:extra:` setting
|
||||
* Fix for multi-site routing
|
||||
* Fix for multi-lang page name error
|
||||
* Fixed a redirect loop in `URI` class
|
||||
* Fixed a potential error when `unsupported_inline_types` is empty
|
||||
* Correctly generate 2x retina image
|
||||
* Typo fixes in page publish/unpublish blueprint
|
||||
|
||||
# v0.9.40
|
||||
## 08/31/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added some new Twig filters: `defined`, `rtrim`, `ltrim`
|
||||
* Admin support for customizable page file name + template override
|
||||
1. [](#improved)
|
||||
* Better message for incompatible/unsupported Twig template
|
||||
* Improved User blueprints with better help
|
||||
* Switched to composer **install** rather than **update** by default
|
||||
* Admin autofocus on page title
|
||||
* `.htaccess` hardening (`.htaccess` & `htaccess.txt`)
|
||||
* Cache safety checks for missing folders
|
||||
1. [](#bugfix)
|
||||
* Fixed issue with unescaped `o` character in date formats
|
||||
|
||||
# v0.9.39
|
||||
## 08/25/2015
|
||||
|
||||
1. [](#bugfix)
|
||||
* `Page.active()` not triggering on **homepage**
|
||||
* Fix for invalid session name in Opera browser
|
||||
|
||||
# v0.9.38
|
||||
## 08/24/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added `language` to **user** blueprint
|
||||
* Added translations to blueprints
|
||||
* New extending logic for blueprints
|
||||
* Blueprints are now loaded with Streams to allow for better overrides
|
||||
* Added new Symfony `dump()` method
|
||||
1. [](#improved)
|
||||
* Catch YAML header parse exception so site doesn't die
|
||||
* Better `Page.parent()` logic
|
||||
* Improved GPM display layout
|
||||
* Tweaked default page layout
|
||||
* Unset route and slug for improved reliability of route changes
|
||||
* Added requirements to README.md
|
||||
* Updated various libraries
|
||||
* Allow use of custom page date field for dateRange collections
|
||||
1. [](#bugfix)
|
||||
* Slug fixes with GPM
|
||||
* Unset plaintext password on save
|
||||
* Fix for trailing `/` not matching active children
|
||||
|
||||
# v0.9.37
|
||||
## 08/12/2015
|
||||
|
||||
3. [](#bugfix)
|
||||
* Fixed issue when saving `header.process` in page forms via the **admin plugin**
|
||||
* Fixed error due to use of `set_time_limit` that might be disabled on some hosts
|
||||
|
||||
# v0.9.36
|
||||
## 08/11/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added a new `newuser` CLI command to create user accounts
|
||||
* Added `default` blueprint for all templates
|
||||
* Support `user` and `system` language translation merging
|
||||
1. [](#improved)
|
||||
* Added isSymlink method in GPM to determine if Grav is symbolically linked or not
|
||||
* Refactored page recursing
|
||||
* Updated blueprints to use new toggles
|
||||
* Updated blueprints to use current date for date format fields
|
||||
* Updated composer.phar
|
||||
* Use sessions for admin even when disabled for site
|
||||
* Use `GRAV_ROOT` in session identifier
|
||||
|
||||
# v0.9.35
|
||||
## 08/06/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added `body_classes` field
|
||||
* Added `visiblity` toggle and help tooltips on new page form
|
||||
* Added new `Page.unsetRoute()` method to allow admin to regenerate the route
|
||||
2. [](#improved)
|
||||
* User save no longer stores username each time
|
||||
* Page list form field now shows all pages except root
|
||||
* Removed required option from page title
|
||||
* Added configuration settings for running Nginx in sub directory
|
||||
3. [](#bugfix)
|
||||
* Fixed deep translation merging
|
||||
* Fixed broken **metadata** merging with site defaults
|
||||
* Fixed broken **summary** field
|
||||
* Fixed broken robots field
|
||||
* Fixed GPM issue when using cURL, throwing an `Undefined offset: 1` exception
|
||||
* Removed duplicate hidden page `type` field
|
||||
|
||||
# v0.9.34
|
||||
## 08/04/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added new `cache_all` system setting + media `cache()` method
|
||||
* Added base languages configuration
|
||||
* Added property language to page to help plugins identify page language
|
||||
* New `Utils::arrayFilterRecursive()` method
|
||||
2. [](#improved)
|
||||
* Improved Session handling to support site and admin independently
|
||||
* Allow Twig variables to be modified in other events
|
||||
* Blueprint updates in preparation for Admin plugin
|
||||
* Changed `Inflector` from static to object and added multi-language support
|
||||
* Support for admin override of a page's blueprints
|
||||
3. [](#bugfix)
|
||||
* Removed unused `use` in `VideoMedium` that was causing error
|
||||
* Array fix in `User.authorise()` method
|
||||
* Fix for typo in `translations_fallback`
|
||||
* Fixed moving page to the root
|
||||
|
||||
# v0.9.33
|
||||
## 07/21/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added new `onImageMediumSaved()` event (useful for post-image processing)
|
||||
* Added `Vary: Accept-Encoding` option
|
||||
2. [](#improved)
|
||||
* Multilang-safe delimeter position
|
||||
* Refactored Twig classes and added optional umask setting
|
||||
* Removed `pageinit()` timing
|
||||
* `Page->routable()` now takes `published()` state into account
|
||||
* Improved how page extension is set
|
||||
* Support `Language->translate()` method taking string and array
|
||||
3. [](#bugfix)
|
||||
* Fixed `backup` command to include empty folders
|
||||
|
||||
# v0.9.32
|
||||
## 07/14/2015
|
||||
|
||||
1. [](#new)
|
||||
* Detect users preferred language via `http_accept_language` setting
|
||||
* Added new `translateArray()` language method
|
||||
2. [](#improved)
|
||||
* Support `en` translations by default for plugins & themes
|
||||
* Improved default generator tag
|
||||
* Minor language tweaks and fixes
|
||||
3. [](#bugfix)
|
||||
* Fix for session active language and homepage redirects
|
||||
* Ignore root-level page rather than throwing error
|
||||
|
||||
# v0.9.31
|
||||
## 07/09/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added xml, json, css and js to valid media file types
|
||||
2. [](#improved)
|
||||
* Better handling of unsupported media type downloads
|
||||
* Improved `bin/grav backup` command to mimic admin plugin location/name
|
||||
3. [](#bugfix)
|
||||
* Critical fix for broken language translations
|
||||
* Fix for Twig markdown filter error
|
||||
* Safety check for download extension
|
||||
|
||||
# v0.9.30
|
||||
## 07/08/2015
|
||||
|
||||
1. [](#new)
|
||||
* BIG NEWS! Extensive Multi-Language support is all new in 0.9.30!
|
||||
* Translation support via Twig filter/function and PHP method
|
||||
* Page specific default route
|
||||
* Page specific route aliases
|
||||
* Canonical URL route support
|
||||
* Added built-in session support
|
||||
* New `Page.rawRoute()` to get a consistent folder-based route to a page
|
||||
* Added option to always redirect to default page on alias URL
|
||||
* Added language safe redirect function for use in core and plugins
|
||||
2. [](#improved)
|
||||
* Improved `Page.active()` and `Page.activeChild()` methods to support route aliases
|
||||
* Various spelling corrections in `.php` comments, `.md` and `.yaml` files
|
||||
* `Utils::startsWith()` and `Utils::endsWith()` now support needle arrays
|
||||
* Added a new timer around `pageInitialized` event
|
||||
* Updated jQuery library to v2.1.4
|
||||
3. [](#bugfix)
|
||||
* In-page CSS and JS files are now handled properly
|
||||
* Fix for `enable_media_timestamp` not working properly
|
||||
|
||||
# v0.9.29
|
||||
## 06/22/2015
|
||||
|
||||
1. [](#new)
|
||||
* New and improved Regex-powered redirect and route alias logic
|
||||
* Added new `onBuildPagesInitialized` event for memory critical or time-consuming plugins
|
||||
* Added a `setSummary()` method for pages
|
||||
2. [](#improved)
|
||||
* Improved `MergeConfig()` logic for more control
|
||||
* Travis skeleton build trigger implemented
|
||||
* Set composer.json versions to stable versions where possible
|
||||
* Disabled `last_modified` and `etag` page headers by default (causing too much page caching)
|
||||
3. [](#bugfix)
|
||||
* Preload classes during `bin/gpm selfupgrade` to avoid issues with updated classes
|
||||
* Fix for directory relative _down_ links
|
||||
|
||||
# v0.9.28
|
||||
## 06/16/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added method to set raw markdown on a page
|
||||
* Added ability to enabled system and page level `etag` and `last_modified` headers
|
||||
2. [](#improved)
|
||||
* Improved image path processing
|
||||
* Improved query string handling
|
||||
* Optimization to image handling supporting URL encoded filenames
|
||||
* Use global `composer` when available rather than Grv provided one
|
||||
* Use `PHP_BINARY` contant rather than `php` executable
|
||||
* Updated Doctrine Cache library
|
||||
* Updated Symfony libraries
|
||||
* Moved `convertUrl()` method to Uri object
|
||||
3. [](#bugfix)
|
||||
* Fix incorrect slug causing problems with CLI `uninstall`
|
||||
* Fix Twig runtime error with assets pipeline in sufolder installations
|
||||
* Fix for `+` in image filenames
|
||||
* Fix for dot files causing issues with page processing
|
||||
* Fix for Uri path detection on Windows platform
|
||||
* Fix for alternative media resolutions
|
||||
* Fix for modularTypes key properties
|
||||
|
||||
# v0.9.27
|
||||
## 05/09/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added new composer CLI command
|
||||
* Added page-level summary header overrides
|
||||
* Added `size` back for Media objects
|
||||
* Refactored Backup command in preparation for admin plugin
|
||||
* Added a new `parseLinks` method to Plugins class
|
||||
* Added `starts_with` and `ends_with` Twig filters
|
||||
2. [](#improved)
|
||||
* Optimized install of vendor libraries for speed improvement
|
||||
* Improved configuration handling in preparation for admin plugin
|
||||
* Cache optimization: Don't cache Twig templates when you pass dynamic params
|
||||
* Moved `Utils::rcopy` to `Folder::rcopy`
|
||||
* Improved `Folder::doDelete`
|
||||
* Added check for required Curl in GPM
|
||||
* Updated included composer.phar to latest version
|
||||
* Various blueprint fixes for admin plugin
|
||||
* Various PSR and code cleanup tasks
|
||||
3. [](#bugfix)
|
||||
* Fix issue with Gzip not working with `onShutDown()` event
|
||||
* Fix for URLs with trailing slashes
|
||||
* Handle condition where certain errors resulted in blank page
|
||||
* Fix for issue with theme name equal to base_url and asset pipeline
|
||||
* Fix to properly normalize font rewrite path
|
||||
* Fix for absolute URLs below the current page
|
||||
* Fix for `..` page references
|
||||
|
||||
# v0.9.26
|
||||
## 04/24/2015
|
||||
|
||||
3. [](#bugfix)
|
||||
* Fixed issue with homepage routes failing with 'dirname' error
|
||||
|
||||
# v0.9.25
|
||||
## 04/24/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added support for E-Tag, Last-Modified, Cache-Control and Page-based expires headers
|
||||
2. [](#improved)
|
||||
* Refactored media image handling to make it more flexible and support absolute paths
|
||||
* Refactored page modification check process to make it faster
|
||||
* User account improvements in preparation for admin plugin
|
||||
* Protect against timing attacks
|
||||
* Reset default system expires time to 0 seconds (can override if you need to)
|
||||
3. [](#bugfix)
|
||||
* Fix issues with spaces in webroot when using `bin/grav install`
|
||||
* Fix for spaces in relative directory
|
||||
* Bug fix in collection filtering
|
||||
|
||||
# v0.9.24
|
||||
## 04/15/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added support for chunked downloads of Assets
|
||||
* Added new `onBeforeDownload()` event
|
||||
* Added new `download()` and `getMimeType()` methods to Utils class
|
||||
* Added configuration option for supported page types
|
||||
* Added assets and media timestamp options (off by default)
|
||||
* Added page expires configuration option
|
||||
2. [](#bugfix)
|
||||
* Fixed issue with Nginx/Gzip and `ob_flush()` throwing error
|
||||
* Fixed assets actions on 'direct media' URLs
|
||||
* Fix for 'direct assets` with any parameters
|
||||
|
||||
# v0.9.23
|
||||
## 04/09/2015
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fix for broken GPM `selfupgrade` (Grav 0.9.21 and 0.9.22 will need to manually upgrade to this version)
|
||||
|
||||
# v0.9.22
|
||||
## 04/08/2015
|
||||
|
||||
1. [](#bugfix)
|
||||
* Fix to normalize GRAV_ROOT path for Windows
|
||||
* Fix to normalize Media image paths for Windows
|
||||
* Fix for GPM `selfupgrade` when you are on latest version
|
||||
|
||||
# v0.9.21
|
||||
## 04/07/2015
|
||||
|
||||
1. [](#new)
|
||||
* Major Media functionality enhancements: SVG, Animated GIF, Video support!
|
||||
* Added ability to configure default image quality in system configuration
|
||||
* Added `sizes` attributes for custom retina image breakpoints
|
||||
2. [](#improved)
|
||||
* Don't scale @1x retina images
|
||||
* Add filter to Iterator class
|
||||
* Updated various composer packages
|
||||
* Various PSR fixes
|
||||
|
||||
# v0.9.20
|
||||
## 03/24/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added `addAsyncJs()` and `addDeferJs()` to Assets manager
|
||||
* Added support for extranal URL redirects
|
||||
2. [](#improved)
|
||||
* Fix unpredictable asset ordering when set from plugin/system
|
||||
* Updated `nginx.conf` to ensure system assets are accessible
|
||||
* Ensure images are served as static files in Nginx
|
||||
* Updated vendor libraries to latest versions
|
||||
* Updated included composer.phar to latest version
|
||||
3. [](#bugfix)
|
||||
* Fixed issue with markdown links to `#` breaking HTML
|
||||
|
||||
# v0.9.19
|
||||
## 02/28/2015
|
||||
|
||||
@@ -61,7 +662,7 @@
|
||||
* Improved the markdown Lightbox functionality to better mimic Twig version
|
||||
* Fullsize Lightbox can now have filters applied
|
||||
* Added a new `mergeConfig()` method to Plugin class to merge system + page header configuration
|
||||
* Added a new `disable()` method to Plugin class to programatically disable a plugin
|
||||
* Added a new `disable()` method to Plugin class to programmatically disable a plugin
|
||||
* Updated Parsedown and Parsedown Extra to address bugs
|
||||
* Various PSR fixes
|
||||
3. [](#bugfix)
|
||||
@@ -114,7 +715,7 @@
|
||||
* Added `publish_date` in page headers to automatically publish page
|
||||
* Added `unpublish_date` in page headers to automatically unpublish page
|
||||
* Added `dateRange()` capability for collections
|
||||
* Added ability to dynamically control Cache lifetime programatically
|
||||
* Added ability to dynamically control Cache lifetime programmatically
|
||||
* Added ability to sort by anything in the page header. E.g. `sort: header.taxonomy.year`
|
||||
* Added various helper methods to collections: `copy, nonVisible, modular, nonModular, published, nonPublished, nonRoutable`
|
||||
2. [](#improved)
|
||||
@@ -289,7 +890,7 @@
|
||||
* Broke cache types out into multiple directories in the cache folder
|
||||
* Removed vendor libs from github repository
|
||||
* Various PSR cleanup of code
|
||||
* Various Blueprint updates to support upcoming Admin plugin
|
||||
* Various Blueprint updates to support upcoming admin plugin
|
||||
* Added ability to filter page children for normal/modular/all
|
||||
* Added `sort_by_key` twig filter
|
||||
* Added `visible()` and `routable()` filters to page collections
|
||||
@@ -362,7 +963,7 @@
|
||||
* Addition of Dependency Injection Container
|
||||
* Refactored plugins to use Symfony Event Dispatcher
|
||||
* New Asset Manager to provide unified management of JavaScript and CSS
|
||||
* Asset Pipelining to provide unification, minify, and optimazation of JavaScript and CSS
|
||||
* Asset Pipelining to provide unification, minify, and optimization of JavaScript and CSS
|
||||
* Grav Media support directly in Markdown syntax
|
||||
* Additional Grav Generator meta tag in default themes
|
||||
* Added support for PHP Stream Wrapper for resource location
|
||||
|
||||
21
README.md
21
README.md
@@ -2,20 +2,25 @@
|
||||
|
||||
[](https://insight.sensiolabs.com/projects/cfd20465-d0f8-4a0a-8444-467f5b5f16ad) [](https://gitter.im/getgrav/grav?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Grav is a **Fast**, **Simple**, and **Flexible**, file-based Web-platform. There is **Zero** installation required. Just extract the ZIP archive, and you are already up and running. It follows similar principals to other flat-file CMS platforms, but has a different design philosophy than most. Grav comes with a powerful **Package Management System** to allow for simple installation and upgrading of plugins and themes, as well as simple updating of Grav itself.
|
||||
Grav is a **Fast**, **Simple**, and **Flexible**, file-based Web-platform. There is **Zero** installation required. Just extract the ZIP archive, and you are already up and running. It follows similar principles to other flat-file CMS platforms, but has a different design philosophy than most. Grav comes with a powerful **Package Management System** to allow for simple installation and upgrading of plugins and themes, as well as simple updating of Grav itself.
|
||||
|
||||
The underlying architecture of Grav has been designed to use well-established and _best-in-class_ technologies, where applicable, to ensure that Grav is simple to use and easy to extend. Some of these key technologies include:
|
||||
The underlying architecture of Grav is designed to use well-established and _best-in-class_ technologies to ensure that Grav is simple to use and easy to extend. Some of these key technologies include:
|
||||
|
||||
* [Twig Templating](http://twig.sensiolabs.org/): for powerful control of the user interface
|
||||
* [Markdown](http://en.wikipedia.org/wiki/Markdown): for easy content creation
|
||||
* [YAML](http://yaml.org): for simple configuration
|
||||
* [Parsedown](http://parsedown.org/): for fast Markdown and Mardown Extra support
|
||||
* [Parsedown](http://parsedown.org/): for fast Markdown and Markdown Extra support
|
||||
* [Doctrine Cache](http://docs.doctrine-project.org/en/2.0.x/reference/caching.html): layer for performance
|
||||
* [Pimple Dependency Injection Container](http://pimple.sensiolabs.org/): for extensibility and maintainability
|
||||
* [Symfony Event Dispacher](http://symfony.com/doc/current/components/event_dispatcher/introduction.html): for plugin event handling
|
||||
* [Symfony Event Dispatcher](http://symfony.com/doc/current/components/event_dispatcher/introduction.html): for plugin event handling
|
||||
* [Symfony Console](http://symfony.com/doc/current/components/console/introduction.html): for CLI interface
|
||||
* [Gregwar Image Library](https://github.com/Gregwar/Image): for dynamic image manipulation
|
||||
|
||||
# Requirements
|
||||
|
||||
- PHP 5.4 or higher. Check the [required modules list](http://learn.getgrav.org/basics/requirements#php-requirements)
|
||||
- Check the [Apache](http://learn.getgrav.org/basics/requirements#apache-requirements) or [IIS](http://learn.getgrav.org/basics/requirements#iis-requirements) requirements
|
||||
|
||||
# QuickStart
|
||||
|
||||
You have two options to get Grav:
|
||||
@@ -42,13 +47,13 @@ Check out the [install procedures](http://learn.getgrav.org/basics/installation)
|
||||
|
||||
# Adding Functionality
|
||||
|
||||
You can download manually from the [Downloads page on http://getgrav.org](http://getgrav.org/downloads), but the preferred solution is to use the [Grav Package Manager](http://learn.getgrav.org/advanced/grav-gpm) or `GPM`:
|
||||
You can download [plugins](http://getgrav.org/downloads/plugins) or [themes](http://getgrav.org/downloads/themes) manually from the appropriate tab on the [Downloads page on http://getgrav.org](http://getgrav.org/downloads), but the preferred solution is to use the [Grav Package Manager](http://learn.getgrav.org/advanced/grav-gpm) or `GPM`:
|
||||
|
||||
```
|
||||
$ bin/gpm index
|
||||
```
|
||||
|
||||
This will display all the available plugins and then you can install one ore more with:
|
||||
This will display all the available plugins and then you can install one or more with:
|
||||
|
||||
```
|
||||
$ bin/gpm install <plugin/theme>
|
||||
@@ -71,7 +76,7 @@ $ bin/gpm update
|
||||
|
||||
# Contributing
|
||||
We appreciate any contribution to Grav, whether it is related to bugs, grammar, or simply a suggestion or improvement.
|
||||
However, we ask that any contribution follow our simple guidelines in order to be properly received.
|
||||
However, we ask that any contributions follow our simple guidelines in order to be properly received.
|
||||
|
||||
All our projects follow the [GitFlow branching model][gitflow-model], from development to release. If you are not familiar with it, there are several guides and tutorials to make you understand what it is about.
|
||||
|
||||
@@ -98,7 +103,7 @@ What you mainly want to know is that:
|
||||
|
||||
# License
|
||||
|
||||
See [LICENSE](LICENSE)
|
||||
See [LICENSE](LICENSE.txt)
|
||||
|
||||
|
||||
[gitflow-model]: http://nvie.com/posts/a-successful-git-branching-model/
|
||||
|
||||
0
backup/.gitkeep
Normal file
0
backup/.gitkeep
Normal file
Binary file not shown.
15
bin/gpm
15
bin/gpm
@@ -6,10 +6,17 @@ if (version_compare($ver = PHP_VERSION, $req = '5.4.0', '<')) {
|
||||
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
|
||||
}
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor')){
|
||||
require_once __DIR__ . '/../system/src/Grav/Common/Composer.php';
|
||||
}
|
||||
|
||||
use Grav\Common\Composer;
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor')){
|
||||
// Before we can even start, we need to run composer first
|
||||
$composer = Composer::getComposerExecutor();
|
||||
echo "Preparing to install vendor dependencies...\n\n";
|
||||
echo system('php bin/composer.phar --working-dir="'.__DIR__.'/../" --no-interaction install');
|
||||
echo system($composer.' --working-dir="'.__DIR__.'/../" --no-interaction --no-dev --prefer-dist -o install');
|
||||
echo "\n\n";
|
||||
}
|
||||
|
||||
@@ -26,11 +33,13 @@ if (!file_exists(ROOT_DIR . 'index.php')) {
|
||||
exit('FATAL: Must be run from ROOT directory of Grav!');
|
||||
}
|
||||
|
||||
if (!function_exists('curl_version')) {
|
||||
exit('FATAL: GPM requires PHP Curl module to be installed');
|
||||
}
|
||||
|
||||
$grav = Grav::instance(array('loader' => $autoload));
|
||||
$grav['config']->init();
|
||||
$grav['streams'];
|
||||
$grav['plugins']->init();
|
||||
$grav['themes']->init();
|
||||
|
||||
$app = new Application('Grav Package Manager', GRAV_VERSION);
|
||||
$app->addCommands(array(
|
||||
|
||||
11
bin/grav
11
bin/grav
@@ -6,10 +6,17 @@ if (version_compare($ver = PHP_VERSION, $req = '5.4.0', '<')) {
|
||||
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
|
||||
}
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor')){
|
||||
require_once __DIR__ . '/../system/src/Grav/Common/Composer.php';
|
||||
}
|
||||
|
||||
use Grav\Common\Composer;
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor')){
|
||||
// Before we can even start, we need to run composer first
|
||||
$composer = Composer::getComposerExecutor();
|
||||
echo "Preparing to install vendor dependencies...\n\n";
|
||||
echo system('php bin/composer.phar --working-dir="'.__DIR__.'/../" --no-interaction install');
|
||||
echo system($composer.' --working-dir="'.__DIR__.'/../" --no-interaction --no-dev --prefer-dist -o install');
|
||||
echo "\n\n";
|
||||
}
|
||||
|
||||
@@ -28,10 +35,12 @@ if (!file_exists(ROOT_DIR . 'index.php')) {
|
||||
$app = new Application('Grav CLI Application', '0.1.0');
|
||||
$app->addCommands(array(
|
||||
new Grav\Console\Cli\InstallCommand(),
|
||||
new Grav\Console\Cli\ComposerCommand(),
|
||||
new Grav\Console\Cli\SandboxCommand(),
|
||||
new Grav\Console\Cli\CleanCommand(),
|
||||
new Grav\Console\Cli\ClearCacheCommand(),
|
||||
new Grav\Console\Cli\BackupCommand(),
|
||||
new Grav\Console\Cli\NewProjectCommand(),
|
||||
new Grav\Console\Cli\NewUserCommand(),
|
||||
));
|
||||
$app->run();
|
||||
|
||||
116
bin/plugin
Executable file
116
bin/plugin
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
define('GRAV_CLI', true);
|
||||
|
||||
if (version_compare($ver = PHP_VERSION, $req = '5.4.0', '<')) {
|
||||
exit(sprintf("You are running PHP %s, but Grav needs at least PHP %s to run.\n", $ver, $req));
|
||||
}
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor')) {
|
||||
require_once __DIR__ . '/../system/src/Grav/Common/Composer.php';
|
||||
}
|
||||
|
||||
use Grav\Common\Composer;
|
||||
|
||||
if (!file_exists(__DIR__ . '/../vendor')) {
|
||||
// Before we can even start, we need to run composer first
|
||||
$composer = Composer::getComposerExecutor();
|
||||
echo "Preparing to install vendor dependencies...\n\n";
|
||||
echo system($composer . ' --working-dir="' . __DIR__ . '/../" --no-interaction --no-dev --prefer-dist -o install');
|
||||
echo "\n\n";
|
||||
}
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
|
||||
$autoload = require_once(__DIR__ . '/../vendor/autoload.php');
|
||||
|
||||
if (!ini_get('date.timezone')) {
|
||||
date_default_timezone_set('UTC');
|
||||
}
|
||||
|
||||
if (!file_exists(ROOT_DIR . 'index.php')) {
|
||||
exit('FATAL: Must be run from ROOT directory of Grav!');
|
||||
}
|
||||
|
||||
$grav = Grav::instance(array('loader' => $autoload));
|
||||
$grav['config']->init();
|
||||
$grav['streams'];
|
||||
$grav['plugins']->init();
|
||||
$grav['themes']->init();
|
||||
|
||||
$app = new Application('Grav Plugins Commands', GRAV_VERSION);
|
||||
$pattern = '([A-Z]\w+Command\.php)';
|
||||
|
||||
// get arguments and strip the application name
|
||||
if (null === $argv) {
|
||||
$argv = $_SERVER['argv'];
|
||||
}
|
||||
|
||||
$bin = array_shift($argv);
|
||||
$name = array_shift($argv);
|
||||
$argv = array_merge([$bin], $argv);
|
||||
|
||||
$input = new ArgvInput($argv);
|
||||
|
||||
$plugin = $grav['plugins']->get($name);
|
||||
|
||||
$output = new ConsoleOutput();
|
||||
$output->getFormatter()->setStyle('red', new OutputFormatterStyle('red', null, array('bold')));
|
||||
$output->getFormatter()->setStyle('white', new OutputFormatterStyle('white', null, array('bold')));
|
||||
|
||||
if (!$name) {
|
||||
$output->writeln('');
|
||||
$output->writeln("<red>Usage:</red>");
|
||||
$output->writeln(" {$bin} [slug] [command] [arguments]");
|
||||
$output->writeln('');
|
||||
$output->writeln("<red>Example:</red>");
|
||||
$output->writeln(" {$bin} error log -l 1 --trace");
|
||||
$list = Folder::all('plugins://', ['compare' => 'Pathname', 'pattern' => '/\/cli\/' . $pattern . '$/usm']);
|
||||
|
||||
if (count($list)) {
|
||||
$available = [];
|
||||
$output->writeln('');
|
||||
$output->writeln('<red>Plugins with CLI available:</red>');
|
||||
foreach ($list as $index => $entry) {
|
||||
$split = explode('/', $entry);
|
||||
$entry = array_shift($split);
|
||||
$index = str_pad($index++ + 1, 2, '0', STR_PAD_LEFT);
|
||||
|
||||
if (in_array($entry, $available)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$available[] = $entry;
|
||||
$output->writeln(' ' . $index . ". <red>" . str_pad($entry, 15) . "</red> <white>${bin} ${entry} list</white>");
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($plugin === null) {
|
||||
$output->writeln("<red>Grav Plugin <white>'{$name}'</white> is not installed</red>");
|
||||
exit;
|
||||
}
|
||||
|
||||
$path = 'plugins://' . $name . '/cli';
|
||||
|
||||
try {
|
||||
$commands = Folder::all($path, ['compare' => 'Filename', 'pattern' => '/' . $pattern . '$/usm']);
|
||||
} catch (\RuntimeException $e) {
|
||||
$output->writeln("<red>No Console Commands for <white>'{$name}'</white> where found in <white>'{$path}'</white></red>");
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach ($commands as $command) {
|
||||
require_once "plugins://{$name}/cli/{$command}";
|
||||
$command = 'Grav\Plugin\Console\\' . preg_replace('/.php$/', '', $command);
|
||||
$app->add(new $command());
|
||||
}
|
||||
|
||||
$app->run($input);
|
||||
@@ -7,29 +7,24 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"twig/twig": "~1.16",
|
||||
"twig/twig": "~1.23",
|
||||
"erusev/parsedown-extra": "~0.7",
|
||||
"symfony/yaml": "~2.6",
|
||||
"symfony/console": "~2.6",
|
||||
"symfony/event-dispatcher": "~2.6",
|
||||
"doctrine/cache": "~1.3",
|
||||
"maximebf/debugbar": "dev-master",
|
||||
"filp/whoops": "1.2.*@dev",
|
||||
"monolog/monolog": "~1.1",
|
||||
"gregwar/image": "~2.0",
|
||||
"symfony/yaml": "~2.8",
|
||||
"symfony/console": "~2.8",
|
||||
"symfony/event-dispatcher": "~2.8",
|
||||
"symfony/var-dumper": "~2.8",
|
||||
"symfony/polyfill-iconv": "~1.0",
|
||||
"doctrine/cache": "~1.5",
|
||||
"filp/whoops": "1.1.10",
|
||||
"monolog/monolog": "~1.0",
|
||||
"gregwar/image": "~2.0",
|
||||
"ircmaxell/password-compat": "1.0.*",
|
||||
"mrclay/minify": "dev-master",
|
||||
"donatj/phpuseragentparser": "dev-master",
|
||||
"mrclay/minify": "~2.2",
|
||||
"donatj/phpuseragentparser": "~0.3",
|
||||
"pimple/pimple": "~3.0",
|
||||
"rockettheme/toolbox": "dev-develop"
|
||||
"rockettheme/toolbox": "~1.2",
|
||||
"maximebf/debugbar": "~1.10"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"no-api": true,
|
||||
"url": "https://github.com/rockettheme/toolbox"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Grav\\": "system/src/Grav"
|
||||
|
||||
1137
composer.lock
generated
Normal file
1137
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
htaccess.txt
19
htaccess.txt
@@ -44,13 +44,22 @@ RewriteRule .* index.php [L]
|
||||
|
||||
## Begin - Security
|
||||
# Block all direct access for these folders
|
||||
RewriteRule ^(cache|bin|logs)/(.*) error [L]
|
||||
# Block access to specific file types for these folders
|
||||
RewriteRule ^(system|user|vendor)/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$ error [L]
|
||||
RewriteRule ^(.git|cache|bin|logs|backup)/(.*) error [F]
|
||||
# Block access to specific file types for these system folders
|
||||
RewriteRule ^(system|vendor)/(.*)\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
|
||||
# Block access to specific file types for these user folders
|
||||
RewriteRule ^(user)/(.*)\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ error [F]
|
||||
# Block all direct access to .md files:
|
||||
RewriteRule \.md$ error [F]
|
||||
# Block all direct access to files and folders beginning with a dot
|
||||
RewriteRule (^\.|/\.) - [F]
|
||||
# Block access to specific files in the root folder
|
||||
RewriteRule ^(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess)$ error [F]
|
||||
## End - Security
|
||||
|
||||
</IfModule>
|
||||
|
||||
# Begin - Prevent Browsing
|
||||
# Begin - Prevent Browsing and Set Default Resources
|
||||
Options -Indexes
|
||||
# End - Prevent Browsing
|
||||
DirectoryIndex index.php index.html index.htm
|
||||
# End - Prevent Browsing and Set Default Resources
|
||||
|
||||
@@ -19,6 +19,12 @@ $loader = require_once $autoload;
|
||||
// Set timezone to default, falls back to system if php.ini not set
|
||||
date_default_timezone_set(@date_default_timezone_get());
|
||||
|
||||
// Set internal encoding if mbstring loaded
|
||||
if (!extension_loaded('mbstring')) {
|
||||
throw new \RuntimeException("'mbstring' extension is not loaded. This is required for Grav to run correctly");
|
||||
}
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
// Get the Grav instance
|
||||
$grav = Grav::instance(
|
||||
array(
|
||||
|
||||
48
lighttpd.conf
Normal file
48
lighttpd.conf
Normal file
@@ -0,0 +1,48 @@
|
||||
############# DO NOT FORGET TO CHANGE "grav_path" BY YOUR ACTUAL GRAV INSTALLATION FOLDER #############
|
||||
############# IF GRAV IS AT THE ROOT OF YOUR WEBSITE, ie http://yoursite.tld POINTS TO #############
|
||||
############# GRAV DIRECTLY, THEN JUST REMOVE ANY "/grav_path/" MENTION BELOW. OTHERWISE #############
|
||||
############# WE ASSUME YOU RUN AN INSTALLATION SUCH AS http://yoursite.tld/grav_path/ #############
|
||||
#######################################################################################################
|
||||
### GRAV RULES FOR LIGHTTPD ###
|
||||
### By Mr3ase ###
|
||||
### Last Rev. 2015/11/20 ###
|
||||
|
||||
#PREVENTING EXPLOITS
|
||||
$HTTP["querystring"] =~ "base64_encode[^(]*\([^)]*\)" {
|
||||
url.redirect = (".*" => "/grav_path/index.php" )
|
||||
}
|
||||
$HTTP["querystring"] =~ "(<|%3C)([^s]*s)+cript.*(>|%3E)" {
|
||||
url.redirect = (".*" => "/grav_path/index.php" )
|
||||
}
|
||||
$HTTP["querystring"] =~ "GLOBALS(=|\[|\%[0-9A-Z])" {
|
||||
url.redirect = (".*" => "/grav_path/index.php" )
|
||||
}
|
||||
$HTTP["querystring"] =~ "_REQUEST(=|\[|\%[0-9A-Z])" {
|
||||
url.redirect = (".*" => "/grav_path/index.php" )
|
||||
}
|
||||
|
||||
#REROUTING TO THE INDEX PAGE
|
||||
url.rewrite-if-not-file = (
|
||||
"^/grav_path/(.*)$" => "/grav_path/index.php"
|
||||
)
|
||||
|
||||
#IMPROVING SECURITY
|
||||
$HTTP["url"] =~ "^/grav_path/(LICENSE.txt|composer.json|composer.lock|nginx.conf|web.config)$" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
$HTTP["url"] =~ "^/grav_path/(.git|cache|bin|logs|backup)/(.*)" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
$HTTP["url"] =~ "^/grav_path/(system|user|vendor)/(.*)\.(txt|md|html|yaml|php|twig|sh|bat)$" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
$HTTP["url"] =~ "^/grav_path/(\.(.*))|(\.(.*)/)" {
|
||||
url.access-deny = ("")
|
||||
}
|
||||
url.access-deny = (".md","~",".inc")
|
||||
|
||||
#PREVENT BROWSING AND SET INDEXES
|
||||
$HTTP["url"] =~ "^/grav_path($|/)" {
|
||||
dir-listing.activate = "disable"
|
||||
index-file.names = ( "index.php", "index.html" , "index.htm" )
|
||||
}
|
||||
103
nginx.conf
103
nginx.conf
@@ -1,65 +1,44 @@
|
||||
worker_processes 1;
|
||||
server {
|
||||
#listen 80;
|
||||
index index.html index.php;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
## Begin - Server Info
|
||||
root /home/user/www/html;
|
||||
server_name localhost;
|
||||
## End - Server Info
|
||||
|
||||
## Begin - Index
|
||||
# for subfolders, simply adjust:
|
||||
# `location /subfolder {`
|
||||
# and the rewrite to use `/subfolder/index.php`
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
if (!-e $request_filename){ rewrite ^(.*)$ /index.php last; }
|
||||
}
|
||||
## End - Index
|
||||
|
||||
## Begin - PHP
|
||||
location ~ \.php$ {
|
||||
# Choose either a socket or TCP/IP address
|
||||
fastcgi_pass unix:/var/run/php5-fpm.sock;
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
|
||||
}
|
||||
## End - PHP
|
||||
|
||||
## Begin - Security
|
||||
# deny all direct access for these folders
|
||||
location ~* /(.git|cache|bin|logs|backups)/.*$ { return 403; }
|
||||
# deny running scripts inside core system folders
|
||||
location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
|
||||
# deny running scripts inside user folder
|
||||
location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
|
||||
# deny access to specific files in the root folder
|
||||
location ~ /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
|
||||
## End - Security
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root html;
|
||||
}
|
||||
|
||||
location / {
|
||||
root html;
|
||||
index index.php;
|
||||
if (!-e $request_filename){ rewrite ^(.*)$ /index.php last; }
|
||||
}
|
||||
|
||||
location /user {
|
||||
rewrite ^/user/accounts/(.*)$ /error redirect;
|
||||
rewrite ^/user/config/(.*)$ /error redirect;
|
||||
rewrite ^/user/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
|
||||
}
|
||||
|
||||
location /cache {
|
||||
rewrite ^/cache/(.*) /error redirect;
|
||||
}
|
||||
|
||||
location /bin {
|
||||
rewrite ^/bin/(.*)$ /error redirect;
|
||||
}
|
||||
|
||||
location /system {
|
||||
rewrite ^/system/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
|
||||
}
|
||||
|
||||
location /vendor {
|
||||
rewrite ^/vendor/(.*)\.(txt|md|html|php|yaml|json|twig|sh|bat)$ /error redirect;
|
||||
}
|
||||
|
||||
# Remember to change 127.0.0.1:9000 to the Ip/port
|
||||
# you configured php-cgi.exe to run from
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
11
robots.txt
11
robots.txt
@@ -1,2 +1,11 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
Disallow: /backup/
|
||||
Disallow: /bin/
|
||||
Disallow: /cache/
|
||||
Disallow: /grav/
|
||||
Disallow: /logs/
|
||||
Disallow: /system/
|
||||
Disallow: /vendor/
|
||||
Disallow: /user/
|
||||
Allow: /user/pages/
|
||||
Allow: /user/themes/
|
||||
|
||||
4
system/assets/jquery/jquery-2.1.3.min.js
vendored
4
system/assets/jquery/jquery-2.1.3.min.js
vendored
File diff suppressed because one or more lines are too long
4
system/assets/jquery/jquery-2.1.4.min.js
vendored
Normal file
4
system/assets/jquery/jquery-2.1.4.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
title: Media
|
||||
title: PLUGIN_ADMIN.MEDIA
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
@@ -1,70 +1,116 @@
|
||||
title: Site
|
||||
title: PLUGIN_ADMIN.SITE
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: Defaults
|
||||
title: PLUGIN_ADMIN.DEFAULTS
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
title:
|
||||
type: text
|
||||
label: Site Title
|
||||
label: PLUGIN_ADMIN.SITE_TITLE
|
||||
size: large
|
||||
placeholder: "Site wide title"
|
||||
help: Default title for your site
|
||||
placeholder: PLUGIN_ADMIN.SITE_TITLE_PLACEHOLDER
|
||||
help: PLUGIN_ADMIN.SITE_TITLE_HELP
|
||||
|
||||
author.name:
|
||||
type: text
|
||||
size: large
|
||||
label: Default Author
|
||||
label: PLUGIN_ADMIN.DEFAULT_AUTHOR
|
||||
help: PLUGIN_ADMIN.DEFAULT_AUTHOR_HELP
|
||||
|
||||
author.email:
|
||||
type: text
|
||||
size: large
|
||||
label: Default Email
|
||||
label: PLUGIN_ADMIN.DEFAULT_EMAIL
|
||||
help: PLUGIN_ADMIN.DEFAULT_EMAIL_HELP
|
||||
validate:
|
||||
type: email
|
||||
|
||||
taxonomies:
|
||||
type: text
|
||||
type: selectize
|
||||
size: large
|
||||
label: Taxonomy Types
|
||||
label: PLUGIN_ADMIN.TAXONOMY_TYPES
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.TAXONOMY_TYPES_HELP
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
metadata:
|
||||
type: array
|
||||
label: Metadata
|
||||
placeholder_key: Name
|
||||
placeholder_value: Content
|
||||
|
||||
blog:
|
||||
summary:
|
||||
type: section
|
||||
title: Blog
|
||||
title: PLUGIN_ADMIN.PAGE_SUMMARY
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
blog.route:
|
||||
type: text
|
||||
size: large
|
||||
label: Blog URL
|
||||
summary.enabled:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ENABLED
|
||||
highlight: 1
|
||||
help: PLUGIN_ADMIN.ENABLED_HELP
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
summary.size:
|
||||
type: text
|
||||
size: x-small
|
||||
label: Summary Size
|
||||
label: PLUGIN_ADMIN.SUMMARY_SIZE
|
||||
help: PLUGIN_ADMIN.SUMMARY_SIZE_HELP
|
||||
validate:
|
||||
type: int
|
||||
min: 0
|
||||
max: 65536
|
||||
type: int
|
||||
min: 0
|
||||
max: 65536
|
||||
|
||||
summary.format:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FORMAT
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.FORMAT_HELP
|
||||
highlight: short
|
||||
options:
|
||||
'short': PLUGIN_ADMIN.SHORT
|
||||
'long': PLUGIN_ADMIN.LONG
|
||||
|
||||
summary.delimiter:
|
||||
type: text
|
||||
size: x-small
|
||||
label: PLUGIN_ADMIN.DELIMITER
|
||||
help: PLUGIN_ADMIN.DELIMITER_HELP
|
||||
|
||||
metadata:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.METADATA
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
metadata:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.METADATA
|
||||
help: PLUGIN_ADMIN.METADATA_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.METADATA_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.METADATA_VALUE
|
||||
|
||||
routes:
|
||||
type: section
|
||||
title: Routes
|
||||
title: PLUGIN_ADMIN.REDIRECTS_AND_ROUTES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
redirects:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.CUSTOM_REDIRECTS
|
||||
help: PLUGIN_ADMIN.CUSTOM_REDIRECTS_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.CUSTOM_REDIRECTS_PLACEHOLDER_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.CUSTOM_REDIRECTS_PLACEHOLDER_VALUE
|
||||
|
||||
routes:
|
||||
type: array
|
||||
label: Custom
|
||||
placeholder_key: /your/alias
|
||||
placeholder_value: /your/route
|
||||
label: PLUGIN_ADMIN.CUSTOM_ROUTES
|
||||
help: PLUGIN_ADMIN.CUSTOM_ROUTES_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.CUSTOM_ROUTES_PLACEHOLDER_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.CUSTOM_ROUTES_PLACEHOLDER_VALUE
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
title: File Streams
|
||||
title: PLUGIN_ADMIN.FILE_STREAMS
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
title: System
|
||||
title: PLUGIN_ADMIN.SYSTEM
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
@@ -6,7 +6,7 @@ form:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: Content
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
@@ -14,135 +14,403 @@ form:
|
||||
type: pages
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Home Page
|
||||
label: PLUGIN_ADMIN.HOME_PAGE
|
||||
show_all: false
|
||||
show_modular: false
|
||||
show_root: false
|
||||
help: "The page that Grav will use as the default landing page"
|
||||
help: PLUGIN_ADMIN.HOME_PAGE_HELP
|
||||
|
||||
pages.theme:
|
||||
type: themeselect
|
||||
classes: fancy
|
||||
selectize: true
|
||||
size: medium
|
||||
label: Default Theme
|
||||
help: "Set the theme (defaults to 'default')"
|
||||
|
||||
pages.markdown_extra:
|
||||
type: toggle
|
||||
label: Markdown Extra
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
label: PLUGIN_ADMIN.DEFAULT_THEME
|
||||
help: PLUGIN_ADMIN.DEFAULT_THEME_HELP
|
||||
|
||||
pages.process:
|
||||
type: checkboxes
|
||||
label: Process
|
||||
label: PLUGIN_ADMIN.PROCESS
|
||||
help: PLUGIN_ADMIN.PROCESS_HELP
|
||||
default: [markdown: true, twig: true]
|
||||
options:
|
||||
markdown: Markdown
|
||||
twig: Twig
|
||||
use: keys
|
||||
|
||||
pages.dateformat.short:
|
||||
timezone:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.TIMEZONE
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Short Date Format
|
||||
help: "Set the short date format"
|
||||
default: 'jS M Y'
|
||||
help: PLUGIN_ADMIN.TIMEZONE_HELP
|
||||
'@data-options': '\Grav\Common\Utils::timezones'
|
||||
default: ''
|
||||
options:
|
||||
'F jS \\a\\t g:ia': "January 1st at 11:59pm"
|
||||
'l jS of F g:i A': "Monday 1st of January at 11:59 PM"
|
||||
'D, m M Y G:i:s': "Mon, 01 Jan 2014 23:59:00"
|
||||
'd-m-y G:i': "01-01-14 23:59"
|
||||
'jS M Y': "10th Feb 2014"
|
||||
'': 'Default (Server Timezone)'
|
||||
|
||||
pages.dateformat.default:
|
||||
type: select
|
||||
size: medium
|
||||
selectize:
|
||||
create: true
|
||||
label: PLUGIN_ADMIN.DEFAULT_DATE_FORMAT
|
||||
help: PLUGIN_ADMIN.DEFAULT_DATE_FORMAT_HELP
|
||||
placeholder: PLUGIN_ADMIN.DEFAULT_DATE_FORMAT_PLACEHOLDER
|
||||
'@data-options': '\Grav\Common\Utils::dateFormats'
|
||||
options:
|
||||
"": Auto Guess or Enter Custom
|
||||
validate:
|
||||
type: string
|
||||
|
||||
pages.dateformat.short:
|
||||
type: dateformat
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.SHORT_DATE_FORMAT
|
||||
help: PLUGIN_ADMIN.SHORT_DATE_FORMAT_HELP
|
||||
default: "jS M Y"
|
||||
options:
|
||||
"F jS \\a\\t g:ia": Date1
|
||||
"l jS \\of F g:i A": Date2
|
||||
"D, d M Y G:i:s": Date3
|
||||
"d-m-y G:i": Date4
|
||||
"jS M Y": Date5
|
||||
|
||||
pages.dateformat.long:
|
||||
type: select
|
||||
type: dateformat
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Long Date Format
|
||||
help: "Set the long date format"
|
||||
label: PLUGIN_ADMIN.LONG_DATE_FORMAT
|
||||
help: PLUGIN_ADMIN.LONG_DATE_FORMAT_HELP
|
||||
options:
|
||||
'F jS \a\t g:ia': "January 1st at 11:59pm"
|
||||
'l jS of F g:i A': "Monday 1st of January at 11:59 PM"
|
||||
'D, m M Y G:i:s': "Mon, 01 Jan 2014 23:59:00"
|
||||
'd-m-y G:i': "01-01-14 23:59"
|
||||
'jS M Y': "10th Feb 2014"
|
||||
"F jS \\a\\t g:ia": Date1
|
||||
"l jS \\of F g:i A": Date2
|
||||
"D, d M Y G:i:s": Date3
|
||||
"d-m-y G:i": Date4
|
||||
"jS M Y": Date5
|
||||
|
||||
pages.order.by:
|
||||
type: select
|
||||
size: medium
|
||||
size: long
|
||||
classes: fancy
|
||||
label: Default Ordering
|
||||
label: PLUGIN_ADMIN.DEFAULT_ORDERING
|
||||
help: PLUGIN_ADMIN.DEFAULT_ORDERING_HELP
|
||||
options:
|
||||
default: Default - based on folder name
|
||||
folder: Folder - based on prefix-less folder name
|
||||
title: Title - based on title field in header
|
||||
date: Date - based on date field in header
|
||||
default: PLUGIN_ADMIN.DEFAULT_ORDERING_DEFAULT
|
||||
folder: PLUGIN_ADMIN.DEFAULT_ORDERING_FOLDER
|
||||
title: PLUGIN_ADMIN.DEFAULT_ORDERING_TITLE
|
||||
date: PLUGIN_ADMIN.DEFAULT_ORDERING_DATE
|
||||
|
||||
pages.order.dir:
|
||||
type: toggle
|
||||
label: Default Order Direction
|
||||
label: PLUGIN_ADMIN.DEFAULT_ORDER_DIRECTION
|
||||
highlight: asc
|
||||
default: desc
|
||||
help: PLUGIN_ADMIN.DEFAULT_ORDER_DIRECTION_HELP
|
||||
options:
|
||||
asc: Ascending
|
||||
desc: Descending
|
||||
asc: PLUGIN_ADMIN.ASCENDING
|
||||
desc: PLUGIN_ADMIN.DESCENDING
|
||||
|
||||
pages.list.count:
|
||||
type: text
|
||||
size: x-small
|
||||
label: Default Item Count
|
||||
help: "Default max pages count"
|
||||
label: PLUGIN_ADMIN.DEFAULT_PAGE_COUNT
|
||||
help: PLUGIN_ADMIN.DEFAULT_PAGE_COUNT_HELP
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
|
||||
|
||||
|
||||
events:
|
||||
type: section
|
||||
title: Events
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.events.page:
|
||||
pages.publish_dates:
|
||||
type: toggle
|
||||
label: Page events
|
||||
label: PLUGIN_ADMIN.DATE_BASED_PUBLISHING
|
||||
help: PLUGIN_ADMIN.DATE_BASED_PUBLISHING_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.events.twig:
|
||||
pages.events:
|
||||
type: checkboxes
|
||||
label: PLUGIN_ADMIN.EVENTS
|
||||
help: PLUGIN_ADMIN.EVENTS_HELP
|
||||
default: [page: true, twig: true]
|
||||
options:
|
||||
page: Page Events
|
||||
twig: Twig Events
|
||||
use: keys
|
||||
|
||||
pages.append_url_extension:
|
||||
type: text
|
||||
placeholder: "e.g. .html"
|
||||
label: PLUGIN_ADMIN.APPEND_URL_EXT
|
||||
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
|
||||
|
||||
pages.redirect_default_route:
|
||||
type: toggle
|
||||
label: Twig events
|
||||
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE
|
||||
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.redirect_default_code:
|
||||
type: select
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE
|
||||
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE_HELP
|
||||
options:
|
||||
301: 301 - Permanent
|
||||
303: 303 - Other
|
||||
307: 307 - Temporary
|
||||
|
||||
pages.redirect_trailing_slash:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH
|
||||
help: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.ignore_hidden:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.IGNORE_HIDDEN
|
||||
help: PLUGIN_ADMIN.IGNORE_HIDDEN_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.ignore_files:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.IGNORE_FILES
|
||||
help: PLUGIN_ADMIN.IGNORE_FILES_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
pages.ignore_folders:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.IGNORE_FOLDERS
|
||||
help: PLUGIN_ADMIN.IGNORE_FOLDERS_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
pages.url_taxonomy_filters:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ALLOW_URL_TAXONOMY_FILTERS
|
||||
help: PLUGIN_ADMIN.ALLOW_URL_TAXONOMY_FILTERS_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.LANGUAGES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
|
||||
languages.supported:
|
||||
type: selectize
|
||||
size: large
|
||||
placeholder: "e.g. en, fr"
|
||||
label: PLUGIN_ADMIN.SUPPORTED
|
||||
help: PLUGIN_ADMIN.SUPPORTED_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
languages.include_default_lang:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.INCLUDE_DEFAULT_LANG
|
||||
help: PLUGIN_ADMIN.INCLUDE_DEFAULT_LANG_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
languages.translations:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TRANSLATIONS_ENABLED
|
||||
help: PLUGIN_ADMIN.TRANSLATIONS_ENABLED_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.translations_fallback:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TRANSLATIONS_FALLBACK
|
||||
help: PLUGIN_ADMIN.TRANSLATIONS_FALLBACK_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.session_store_active:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ACTIVE_LANGUAGE_IN_SESSION
|
||||
help: PLUGIN_ADMIN.ACTIVE_LANGUAGE_IN_SESSION_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.http_accept_language:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.HTTP_ACCEPT_LANGUAGE
|
||||
help: PLUGIN_ADMIN.HTTP_ACCEPT_LANGUAGE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.override_locale:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.OVERRIDE_LOCALE
|
||||
help: PLUGIN_ADMIN.OVERRIDE_LOCALE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
http_headers:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.HTTP_HEADERS
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.expires:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.EXPIRES
|
||||
help: PLUGIN_ADMIN.EXPIRES_HELP
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
pages.last_modified:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.LAST_MODIFIED
|
||||
help: PLUGIN_ADMIN.LAST_MODIFIED_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.etag:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ETAG
|
||||
help: PLUGIN_ADMIN.ETAG_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.vary_accept_encoding:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.VARY_ACCEPT_ENCODING
|
||||
help: PLUGIN_ADMIN.VARY_ACCEPT_ENCODING_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
markdown:
|
||||
type: section
|
||||
title: Markdown
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.markdown.extra:
|
||||
type: toggle
|
||||
label: Markdown extra
|
||||
help: PLUGIN_ADMIN.MARKDOWN_EXTRA_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.auto_line_breaks:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.AUTO_LINE_BREAKS
|
||||
help: PLUGIN_ADMIN.AUTO_LINE_BREAKS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.auto_url_links:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.AUTO_URL_LINKS
|
||||
help: PLUGIN_ADMIN.AUTO_URL_LINKS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.escape_markup:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ESCAPE_MARKUP
|
||||
help: PLUGIN_ADMIN.ESCAPE_MARKUP_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
caching:
|
||||
type: section
|
||||
title: Caching
|
||||
title: PLUGIN_ADMIN.CACHING
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
cache.enabled:
|
||||
type: toggle
|
||||
label: Caching
|
||||
label: PLUGIN_ADMIN.CACHING
|
||||
help: PLUGIN_ADMIN.CACHING_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
@@ -150,7 +418,8 @@ form:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Cache Check Method
|
||||
label: PLUGIN_ADMIN.CACHE_CHECK_METHOD
|
||||
help: PLUGIN_ADMIN.CACHE_CHECK_METHOD_HELP
|
||||
options:
|
||||
file: File
|
||||
folder: Folder
|
||||
@@ -160,7 +429,8 @@ form:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Cache driver
|
||||
label: PLUGIN_ADMIN.CACHE_DRIVER
|
||||
help: PLUGIN_ADMIN.CACHE_DRIVER_HELP
|
||||
options:
|
||||
auto: Auto detect
|
||||
file: File
|
||||
@@ -172,193 +442,393 @@ form:
|
||||
cache.prefix:
|
||||
type: text
|
||||
size: x-small
|
||||
label: Cache Prefix
|
||||
placeholder: "Derived from base URL (override by entering random string)"
|
||||
label: PLUGIN_ADMIN.CACHE_PREFIX
|
||||
help: PLUGIN_ADMIN.CACHE_PREFIX_HELP
|
||||
placeholder: PLUGIN_ADMIN.CACHE_PREFIX_PLACEHOLDER
|
||||
|
||||
cache.lifetime:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.LIFETIME
|
||||
help: PLUGIN_ADMIN.LIFETIME_HELP
|
||||
validate:
|
||||
type: number
|
||||
|
||||
cache.gzip:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.GZIP_COMPRESSION
|
||||
help: PLUGIN_ADMIN.GZIP_COMPRESSION_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
twig:
|
||||
type: section
|
||||
title: Twig Templating
|
||||
title: PLUGIN_ADMIN.TWIG_TEMPLATING
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
twig.cache:
|
||||
type: toggle
|
||||
label: Twig caching
|
||||
label: PLUGIN_ADMIN.TWIG_CACHING
|
||||
help: PLUGIN_ADMIN.TWIG_CACHING_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.debug:
|
||||
type: toggle
|
||||
label: Twig debug
|
||||
highlight: 1
|
||||
label: PLUGIN_ADMIN.TWIG_DEBUG
|
||||
help: PLUGIN_ADMIN.TWIG_DEBUG_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.auto_reload:
|
||||
type: toggle
|
||||
label: Detect changes
|
||||
label: PLUGIN_ADMIN.DETECT_CHANGES
|
||||
help: PLUGIN_ADMIN.DETECT_CHANGES_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.autoescape:
|
||||
type: toggle
|
||||
label: Autoescape variables
|
||||
highlight: 1
|
||||
label: PLUGIN_ADMIN.AUTOESCAPE_VARIABLES
|
||||
help: PLUGIN_ADMIN.AUTOESCAPE_VARIABLES_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.umask_fix:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TWIG_UMASK_FIX
|
||||
help: PLUGIN_ADMIN.TWIG_UMASK_FIX_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets:
|
||||
type: section
|
||||
title: Assets
|
||||
title: PLUGIN_ADMIN.ASSETS
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
assets.css_pipeline:
|
||||
type: toggle
|
||||
label: CSS Pipeline
|
||||
highlight: 1
|
||||
label: PLUGIN_ADMIN.CSS_PIPELINE
|
||||
help: PLUGIN_ADMIN.CSS_PIPELINE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.css_minify:
|
||||
type: toggle
|
||||
label: CSS Minify
|
||||
label: PLUGIN_ADMIN.CSS_MINIFY
|
||||
help: PLUGIN_ADMIN.CSS_MINIFY_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.css_minify_windows:
|
||||
type: toggle
|
||||
label: CSS Minify Windows Override
|
||||
highlight: 1
|
||||
label: PLUGIN_ADMIN.CSS_MINIFY_WINDOWS_OVERRIDE
|
||||
help: PLUGIN_ADMIN.CSS_MINIFY_WINDOWS_OVERRIDE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.css_rewrite:
|
||||
type: toggle
|
||||
label: CSS Rewrite
|
||||
label: PLUGIN_ADMIN.CSS_REWRITE
|
||||
help: PLUGIN_ADMIN.CSS_REWRITE_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.js_pipeline:
|
||||
type: toggle
|
||||
label: JavaScript Pipeline
|
||||
highlight: 01
|
||||
label: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE
|
||||
help: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.js_minify:
|
||||
type: toggle
|
||||
label: JavaScript Minify
|
||||
label: PLUGIN_ADMIN.JAVASCRIPT_MINIFY
|
||||
help: PLUGIN_ADMIN.JAVASCRIPT_MINIFY_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.enable_asset_timestamp:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ENABLED_TIMESTAMPS_ON_ASSETS
|
||||
help: PLUGIN_ADMIN.ENABLED_TIMESTAMPS_ON_ASSETS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.collections:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.COLLECTIONS
|
||||
placeholder_key: collection_name
|
||||
placeholder_value: collection_path
|
||||
|
||||
errors:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ERROR_HANDLER
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
errors.display:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.DISPLAY_ERRORS
|
||||
help: PLUGIN_ADMIN.DISPLAY_ERRORS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
errors.log:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.LOG_ERRORS
|
||||
help: PLUGIN_ADMIN.LOG_ERRORS_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger:
|
||||
type: section
|
||||
title: Debugger
|
||||
title: PLUGIN_ADMIN.DEBUGGER
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
debugger.enabled:
|
||||
type: toggle
|
||||
label: Debugger
|
||||
highlight: 1
|
||||
label: PLUGIN_ADMIN.DEBUGGER
|
||||
help: PLUGIN_ADMIN.DEBUGGER_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger.mode:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Mode
|
||||
options:
|
||||
detect: Auto-Detect
|
||||
development: Development
|
||||
production: Production
|
||||
|
||||
debugger.strict:
|
||||
type: toggle
|
||||
label: Strict
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger.max_depth:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Detail Level
|
||||
placeholder: "How many nested levels to display for objects or arrays"
|
||||
options:
|
||||
1: 1 level
|
||||
2: 2 levels
|
||||
3: 3 levels
|
||||
4: 4 levels
|
||||
5: 5 levels
|
||||
6: 6 levels
|
||||
7: 7 levels
|
||||
8: 8 levels
|
||||
9: 9 levels
|
||||
10: 10 levels
|
||||
validate:
|
||||
type: number
|
||||
|
||||
debugger.log.enabled:
|
||||
type: toggle
|
||||
label: Logging
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger.shutdown.close_connection:
|
||||
type: toggle
|
||||
label: Shutdown Close Connection
|
||||
label: PLUGIN_ADMIN.SHUTDOWN_CLOSE_CONNECTION
|
||||
help: PLUGIN_ADMIN.SHUTDOWN_CLOSE_CONNECTION_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
media:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.MEDIA
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
images.default_image_quality:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.DEFAULT_IMAGE_QUALITY
|
||||
help: PLUGIN_ADMIN.DEFAULT_IMAGE_QUALITY_HELP
|
||||
classes: x-small
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
max: 100
|
||||
|
||||
images.cache_all:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.CACHE_ALL
|
||||
help: PLUGIN_ADMIN.CACHE_ALL_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
images.cache_perms:
|
||||
type: select
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.CACHE_PERMS
|
||||
help: PLUGIN_ADMIN.CACHE_PERMS_HELP
|
||||
highlight: '0755'
|
||||
options:
|
||||
1: '0755'
|
||||
0: '0775'
|
||||
|
||||
|
||||
images.debug:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.IMAGES_DEBUG
|
||||
help: PLUGIN_ADMIN.IMAGES_DEBUG_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
media.upload_limit:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.UPLOAD_LIMIT
|
||||
help: PLUGIN_ADMIN.UPLOAD_LIMIT_HELP
|
||||
classes: small
|
||||
validate:
|
||||
type: number
|
||||
|
||||
media.enable_media_timestamp:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ENABLE_MEDIA_TIMESTAMP
|
||||
help: PLUGIN_ADMIN.ENABLE_MEDIA_TIMESTAMP_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
|
||||
media.allowed_fallback_types:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.FALLBACK_TYPES
|
||||
help: PLUGIN_ADMIN.FALLBACK_TYPES_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
media.unsupported_inline_types:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.INLINE_TYPES
|
||||
help: PLUGIN_ADMIN.INLINE_TYPES_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
session:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.SESSION
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
session.enabled:
|
||||
type: hidden
|
||||
label: PLUGIN_ADMIN.ENABLED
|
||||
help: PLUGIN_ADMIN.SESSION_ENABLED_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
default: true
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
session.timeout:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.TIMEOUT
|
||||
help: PLUGIN_ADMIN.TIMEOUT_HELP
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
|
||||
session.name:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.NAME
|
||||
help: PLUGIN_ADMIN.SESSION_NAME_HELP
|
||||
|
||||
|
||||
advanced:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ADVANCED
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
wrapped_site:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.WRAPPED_SITE
|
||||
highlight: 0
|
||||
help: PLUGIN_ADMIN.WRAPPED_SITE_HELP
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
absolute_urls:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ABSOLUTE_URLS
|
||||
highlight: 0
|
||||
help: PLUGIN_ADMIN.ABSOLUTE_URLS_HELP
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
param_sep:
|
||||
type: select
|
||||
size: medium
|
||||
label: PLUGIN_ADMIN.PARAMETER_SEPARATOR
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.PARAMETER_SEPARATOR_HELP
|
||||
default: ''
|
||||
options:
|
||||
':': ': (default)'
|
||||
';': '; (for Apache running on Windows)'
|
||||
|
||||
7
system/blueprints/media/meta.yaml
Normal file
7
system/blueprints/media/meta.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
alt_text:
|
||||
type: string
|
||||
label: Alt Text
|
||||
8
system/blueprints/media/move.yaml
Normal file
8
system/blueprints/media/move.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PAGE
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
8
system/blueprints/media/rename.yaml
Normal file
8
system/blueprints/media/rename.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
new_file_name:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN_PRO.NEW_FILE_NAME
|
||||
validate:
|
||||
required: true
|
||||
281
system/blueprints/pages/default.yaml
Normal file
281
system/blueprints/pages/default.yaml
Normal file
@@ -0,0 +1,281 @@
|
||||
title: PLUGIN_ADMIN.DEFAULT
|
||||
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
fields:
|
||||
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
|
||||
fields:
|
||||
header.title:
|
||||
type: text
|
||||
autofocus: true
|
||||
style: vertical
|
||||
label: PLUGIN_ADMIN.TITLE
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
validate:
|
||||
type: textarea
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
||||
|
||||
options:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.OPTIONS
|
||||
|
||||
fields:
|
||||
|
||||
publishing:
|
||||
type: section
|
||||
title: Publishing
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.published:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.PUBLISHED
|
||||
help: PLUGIN_ADMIN.PUBLISHED_HELP
|
||||
highlight: 1
|
||||
size: medium
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.date:
|
||||
type: datetime
|
||||
label: PLUGIN_ADMIN.DATE
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.DATE_HELP
|
||||
|
||||
header.publish_date:
|
||||
type: datetime
|
||||
label: PLUGIN_ADMIN.PUBLISHED_DATE
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.PUBLISHED_DATE_HELP
|
||||
|
||||
header.unpublish_date:
|
||||
type: datetime
|
||||
label: PLUGIN_ADMIN.UNPUBLISHED_DATE
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.UNPUBLISHED_DATE_HELP
|
||||
|
||||
header.metadata:
|
||||
toggleable: true
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.METADATA
|
||||
help: PLUGIN_ADMIN.METADATA_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.METADATA_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.METADATA_VALUE
|
||||
|
||||
taxonomies:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.TAXONOMIES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.taxonomy:
|
||||
type: taxonomy
|
||||
label: PLUGIN_ADMIN.TAXONOMY
|
||||
multiple: true
|
||||
validate:
|
||||
type: array
|
||||
|
||||
advanced:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.ADVANCED
|
||||
|
||||
fields:
|
||||
columns:
|
||||
type: columns
|
||||
fields:
|
||||
column1:
|
||||
type: column
|
||||
fields:
|
||||
|
||||
settings:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.SETTINGS
|
||||
underline: true
|
||||
|
||||
ordering:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
validate:
|
||||
type: slug
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.PAGE_FILE
|
||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
||||
default: default
|
||||
'@data-options': '\Grav\Common\Page\Pages::pageTypes'
|
||||
|
||||
header.body_classes:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.BODY_CLASSES
|
||||
|
||||
|
||||
column2:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
order_title:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ORDERING
|
||||
underline: true
|
||||
|
||||
order:
|
||||
type: order
|
||||
label: PLUGIN_ADMIN.PAGE_ORDER
|
||||
sitemap:
|
||||
|
||||
overrides:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.OVERRIDES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
|
||||
header.menu:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.MENU
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.MENU_HELP
|
||||
|
||||
header.slug:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.SLUG
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.SLUG_HELP
|
||||
validate:
|
||||
message: PLUGIN_ADMIN.SLUG_VALIDATE_MESSAGE
|
||||
rule: slug
|
||||
|
||||
header.redirect:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.REDIRECT
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.REDIRECT_HELP
|
||||
|
||||
header.process:
|
||||
type: checkboxes
|
||||
label: PLUGIN_ADMIN.PROCESS
|
||||
toggleable: true
|
||||
'@config-default': system.pages.process
|
||||
default:
|
||||
markdown: true
|
||||
twig: false
|
||||
options:
|
||||
markdown: Markdown
|
||||
twig: Twig
|
||||
use: keys
|
||||
|
||||
header.child_type:
|
||||
type: select
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.DEFAULT_CHILD_TYPE
|
||||
default: default
|
||||
placeholder: PLUGIN_ADMIN.USE_GLOBAL
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
|
||||
header.routable:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.ROUTABLE
|
||||
help: PLUGIN_ADMIN.ROUTABLE_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.cache_enable:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.CACHING
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.visible:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.VISIBLE
|
||||
help: PLUGIN_ADMIN.VISIBLE_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.template:
|
||||
type: select
|
||||
toggleable: true
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.DISPLAY_TEMPLATE
|
||||
default: default
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
|
||||
header.append_url_extension:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.APPEND_URL_EXT
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
|
||||
|
||||
header.order_by:
|
||||
type: hidden
|
||||
|
||||
header.order_manual:
|
||||
type: hidden
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
47
system/blueprints/pages/modular.yaml
Normal file
47
system/blueprints/pages/modular.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
title: PLUGIN_ADMIN.MODULAR
|
||||
@extends:
|
||||
type: default
|
||||
context: blueprints://pages
|
||||
|
||||
form:
|
||||
fields:
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
fields:
|
||||
|
||||
header.content.items:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.ITEMS
|
||||
default: '@self.modular'
|
||||
options:
|
||||
'@self.modular': Children
|
||||
|
||||
header.content.order.by:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.ORDER_BY
|
||||
default: date
|
||||
options:
|
||||
folder: PLUGIN_ADMIN.FOLDER
|
||||
title: PLUGIN_ADMIN.TITLE
|
||||
date: PLUGIN_ADMIN.DATE
|
||||
default: PLUGIN_ADMIN.DEFAULT
|
||||
|
||||
header.content.order.dir:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.ORDER
|
||||
default: desc
|
||||
options:
|
||||
asc: PLUGIN_ADMIN.ASCENDING
|
||||
desc: PLUGIN_ADMIN.DESCENDING
|
||||
|
||||
header.process:
|
||||
type: ignore
|
||||
content:
|
||||
type: ignore
|
||||
uploads:
|
||||
type: ignore
|
||||
|
||||
@@ -10,40 +10,39 @@ form:
|
||||
|
||||
section:
|
||||
type: section
|
||||
title: Add Modular Content
|
||||
title: PLUGIN_ADMIN.ADD_MODULAR_CONTENT
|
||||
|
||||
title:
|
||||
type: text
|
||||
label: Page Title
|
||||
label: PLUGIN_ADMIN.PAGE_TITLE
|
||||
validate:
|
||||
required: true
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: Folder Name
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Page
|
||||
label: PLUGIN_ADMIN.PAGE
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'': '- Select -'
|
||||
'': PLUGIN_ADMIN.DEFAULT_OPTION_SELECT
|
||||
validate:
|
||||
required: true
|
||||
|
||||
type:
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Modular Template
|
||||
label: PLUGIN_ADMIN.MODULAR_TEMPLATE
|
||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::modularTypes'
|
||||
'@data-options': '\Grav\Common\Page\Pages::modularTypes'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
@@ -52,3 +51,6 @@ form:
|
||||
default: 1
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
@@ -15,26 +15,26 @@ form:
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: Content
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
|
||||
fields:
|
||||
frontmatter:
|
||||
type: frontmatter
|
||||
label: Frontmatter
|
||||
label: PLUGIN_ADMIN.FRONTMATTER
|
||||
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
label: Content
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: uploads
|
||||
label: Page Media
|
||||
type: pagemedia
|
||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
||||
|
||||
|
||||
options:
|
||||
type: tab
|
||||
title: Options
|
||||
title: PLUGIN_ADMIN.OPTIONS
|
||||
|
||||
fields:
|
||||
|
||||
@@ -47,30 +47,41 @@ form:
|
||||
|
||||
fields:
|
||||
|
||||
ordering:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: Filename
|
||||
label: PLUGIN_ADMIN.FILENAME
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
'': PLUGIN_ADMIN.DEFAULT_OPTION_SELECT
|
||||
validate:
|
||||
required: true
|
||||
|
||||
type:
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Modular Template
|
||||
label: PLUGIN_ADMIN.MODULAR_TEMPLATE
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::modularTypes'
|
||||
'@data-options': '\Grav\Common\Page\Pages::modularTypes'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
@@ -80,5 +91,7 @@ form:
|
||||
fields:
|
||||
order:
|
||||
type: order
|
||||
label: Ordering
|
||||
label: PLUGIN_ADMIN.ORDERING
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
17
system/blueprints/pages/move.yaml
Normal file
17
system/blueprints/pages/move.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
@@ -10,39 +10,57 @@ form:
|
||||
|
||||
section:
|
||||
type: section
|
||||
title: Add Page
|
||||
title: PLUGIN_ADMIN.ADD_PAGE
|
||||
|
||||
title:
|
||||
type: text
|
||||
label: Page Title
|
||||
label: PLUGIN_ADMIN.PAGE_TITLE
|
||||
help: PLUGIN_ADMIN.PAGE_TITLE_HELP
|
||||
validate:
|
||||
required: true
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: Folder Name
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent Page
|
||||
label: PLUGIN_ADMIN.PARENT_PAGE
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::getLastPageRoute'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
validate:
|
||||
required: true
|
||||
|
||||
type:
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Display Template
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
label: PLUGIN_ADMIN.PAGE_FILE
|
||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
'@data-default': '\Grav\Plugin\admin::getLastPageName'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
visible:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.VISIBLE
|
||||
help: PLUGIN_ADMIN.VISIBLE_HELP
|
||||
highlight: ''
|
||||
default: ''
|
||||
options:
|
||||
'': Auto
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
required: true
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
title:
|
||||
type: text
|
||||
label: Title
|
||||
validate:
|
||||
required: true
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: Folder
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
type:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Display Template
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
validate:
|
||||
required: true
|
||||
@@ -15,26 +15,25 @@ form:
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: Content
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
|
||||
fields:
|
||||
frontmatter:
|
||||
type: frontmatter
|
||||
label: Frontmatter
|
||||
|
||||
label: PLUGIN_ADMIN.FRONTMATTER
|
||||
autofocus: true
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
label: Content
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: uploads
|
||||
label: Page Media
|
||||
|
||||
type: pagemedia
|
||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
||||
|
||||
options:
|
||||
type: tab
|
||||
title: Options
|
||||
title: PLUGIN_ADMIN.OPTIONS
|
||||
|
||||
fields:
|
||||
|
||||
@@ -47,30 +46,41 @@ form:
|
||||
|
||||
fields:
|
||||
|
||||
ordering:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: Folder Name
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
validate:
|
||||
required: true
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
|
||||
type:
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Display Template
|
||||
label: PLUGIN_ADMIN.DISPLAY_TEMPLATE
|
||||
help: PLUGIN_ADMIN.DISPLAY_TEMPLATE_HELP
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
@@ -80,5 +90,7 @@ form:
|
||||
fields:
|
||||
order:
|
||||
type: order
|
||||
label: Ordering
|
||||
label: PLUGIN_ADMIN.ORDERING
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
@@ -5,82 +5,81 @@ form:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: Account
|
||||
title: PLUGIN_ADMIN.ACCOUNT
|
||||
|
||||
fields:
|
||||
username:
|
||||
type: text
|
||||
size: large
|
||||
label: Username
|
||||
label: PLUGIN_ADMIN.USERNAME
|
||||
disabled: true
|
||||
readonly: true
|
||||
|
||||
email:
|
||||
type: text
|
||||
type: email
|
||||
size: large
|
||||
label: Email
|
||||
label: PLUGIN_ADMIN.EMAIL
|
||||
validate:
|
||||
type: email
|
||||
message: PLUGIN_ADMIN.EMAIL_VALIDATION_MESSAGE
|
||||
required: true
|
||||
|
||||
password:
|
||||
type: password
|
||||
size: large
|
||||
label: Password
|
||||
label: PLUGIN_ADMIN.PASSWORD
|
||||
validate:
|
||||
required: true
|
||||
|
||||
|
||||
required: false
|
||||
message: PLUGIN_ADMIN.PASSWORD_VALIDATION_MESSAGE
|
||||
pattern: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}'
|
||||
|
||||
fullname:
|
||||
type: text
|
||||
size: large
|
||||
label: Full name
|
||||
label: PLUGIN_ADMIN.FULL_NAME
|
||||
validate:
|
||||
required: true
|
||||
|
||||
title:
|
||||
type: text
|
||||
size: large
|
||||
label: Title
|
||||
label: PLUGIN_ADMIN.TITLE
|
||||
|
||||
admin:
|
||||
type: section
|
||||
title: Admin Access
|
||||
language:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.LANGUAGE
|
||||
size: medium
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Plugin\admin::adminLanguages'
|
||||
default: 'en'
|
||||
help: PLUGIN_ADMIN.LANGUAGE_HELP
|
||||
|
||||
fields:
|
||||
access.admin.super:
|
||||
type: toggle
|
||||
label: Super user
|
||||
default: 0
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
security:
|
||||
title: Security
|
||||
type: section
|
||||
security: admin.super
|
||||
|
||||
access.admin.login:
|
||||
type: toggle
|
||||
label: Admin login
|
||||
default: 0
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
fields:
|
||||
groups:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.GROUPS
|
||||
'@data-options': '\Grav\User\Groups::groups'
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.GROUPS_HELP
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
site:
|
||||
type: section
|
||||
title: Site Access
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
fields:
|
||||
access.site.login:
|
||||
type: toggle
|
||||
label: Site login
|
||||
default: 1
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
@@ -1,4 +1,4 @@
|
||||
title: Add Account
|
||||
title: PLUGIN_ADMIN.ADD_ACCOUNT
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
@@ -6,10 +6,11 @@ form:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: Add Account
|
||||
title: PLUGIN_ADMIN.ADD_ACCOUNT
|
||||
|
||||
username:
|
||||
type: text
|
||||
label: Username
|
||||
label: PLUGIN_ADMIN.USERNAME
|
||||
help: PLUGIN_ADMIN.USERNAME_HELP
|
||||
validate:
|
||||
required: true
|
||||
|
||||
44
system/blueprints/user/group.yaml
Normal file
44
system/blueprints/user/group.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
title: Group
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
fields:
|
||||
spacer:
|
||||
type: spacer
|
||||
text: '<br>'
|
||||
|
||||
groupname:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.NAME
|
||||
disabled: true
|
||||
readonly: true
|
||||
|
||||
readableName:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN_PRO.READABLE_NAME
|
||||
|
||||
description:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.DESCRIPTION
|
||||
|
||||
icon:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN_PRO.ICON
|
||||
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
16
system/blueprints/user/group_new.yaml
Normal file
16
system/blueprints/user/group_new.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
title: PLUGIN_ADMIN_PRO.ADD_GROUP
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN_PRO.ADD_GROUP
|
||||
|
||||
groupname:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN_PRO.GROUP_NAME
|
||||
help: PLUGIN_ADMIN_PRO.GROUP_NAME_HELP
|
||||
validate:
|
||||
required: true
|
||||
@@ -11,6 +11,10 @@ jpg:
|
||||
type: image
|
||||
thumb: media/thumb-jpg.png
|
||||
mime: image/jpeg
|
||||
jpe:
|
||||
type: image
|
||||
thumb: media/thumb-jpg.png
|
||||
mime: image/jpeg
|
||||
jpeg:
|
||||
type: image
|
||||
thumb: media/thumb-jpeg.png
|
||||
@@ -20,10 +24,15 @@ png:
|
||||
thumb: media/thumb-png.png
|
||||
mime: image/png
|
||||
gif:
|
||||
type: image
|
||||
type: animated
|
||||
thumb: media/thumb-gif.png
|
||||
mime: image/gif
|
||||
|
||||
svg:
|
||||
type: vector
|
||||
thumb: media/thumb-gif.png
|
||||
mime: image/svg+xml
|
||||
|
||||
mp4:
|
||||
type: video
|
||||
thumb: media/thumb-mp4.png
|
||||
@@ -65,19 +74,92 @@ wav:
|
||||
type: audio
|
||||
thumb: media/thumb-wav.png
|
||||
mime: audio/wav
|
||||
aiff:
|
||||
type: audio
|
||||
mime: audio/aiff
|
||||
aif:
|
||||
type: audio
|
||||
mime: audio/aif
|
||||
|
||||
txt:
|
||||
type: file
|
||||
thumb: media/thumb-txt.png
|
||||
mime: text/plain
|
||||
xml:
|
||||
type: file
|
||||
thumb: media/thumb-xml.png
|
||||
mime: application/xml
|
||||
doc:
|
||||
type: file
|
||||
thumb: media/thumb-doc.png
|
||||
mime: application/msword
|
||||
docx:
|
||||
type: file
|
||||
mime: application/msword
|
||||
xls:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlt:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlm:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xld:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xla:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlc:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlw:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xll:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
ppt:
|
||||
type: file
|
||||
mime: application/vnd.ms-powerpoint
|
||||
pps:
|
||||
type: file
|
||||
mime: application/vnd.ms-powerpoint
|
||||
rtf:
|
||||
type: file
|
||||
mime: application/rtf
|
||||
|
||||
bmp:
|
||||
type: file
|
||||
mime: image/bmp
|
||||
tiff:
|
||||
type: file
|
||||
mime: image/tiff
|
||||
mpeg:
|
||||
type: file
|
||||
mime: video/mpeg
|
||||
mpg:
|
||||
type: file
|
||||
mime: video/mpeg
|
||||
mpe:
|
||||
type: file
|
||||
mime: video/mpeg
|
||||
avi:
|
||||
type: file
|
||||
mime: video/msvideo
|
||||
wmv:
|
||||
type: file
|
||||
mime: video/x-ms-wmv
|
||||
|
||||
html:
|
||||
type: file
|
||||
thumb: media/thumb-html.png
|
||||
mime: text/html
|
||||
htm:
|
||||
type: file
|
||||
thumb: media/thumb-html.png
|
||||
mime: text/html
|
||||
pdf:
|
||||
type: file
|
||||
thumb: media/thumb-pdf.png
|
||||
@@ -90,3 +172,19 @@ gz:
|
||||
type: file
|
||||
thumb: media/thumb-gz.png
|
||||
mime: application/gzip
|
||||
tar:
|
||||
type: file
|
||||
mime: application/x-tar
|
||||
css:
|
||||
type: file
|
||||
thumb: media/thumb-css.png
|
||||
mime: text/css
|
||||
js:
|
||||
type: file
|
||||
thumb: media/thumb-js.png
|
||||
mime: application/javascript
|
||||
json:
|
||||
type: file
|
||||
thumb: media/thumb-json.png
|
||||
mime: application/json
|
||||
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
title: Grav # Name of the site
|
||||
|
||||
author:
|
||||
name: John Appleseed # Default author name
|
||||
email: 'john@email.com' # Default author email
|
||||
|
||||
taxonomies: [category,tag] # Arbitrary list of taxonomy types
|
||||
blog:
|
||||
route: '/blog' # Route to blog
|
||||
|
||||
metadata:
|
||||
description: 'My Grav Site' # Site description
|
||||
|
||||
summary:
|
||||
enabled: true # enable or disable summary of page
|
||||
format: short # long = summary delimiter will be ignored; short = use the first occurence of delimter or size
|
||||
format: short # long = summary delimiter will be ignored; short = use the first occurrence of delimiter or size
|
||||
size: 300 # Maximum length of summary (characters)
|
||||
delimiter: === # The summary delimiter
|
||||
|
||||
redirects:
|
||||
/redirect-test: / # Redirect test goes to home page
|
||||
/old/(.*): /new/$1 # Would redirect /old/my-page to /new/my-page
|
||||
|
||||
routes:
|
||||
/something/else: '/blog/sample-3' # Alias for /blog/sample-3
|
||||
/another/one/here: '/blog/sample-3' # Another alias for /blog/sample-3
|
||||
/new/*: '/blog/*' # Wildcard any /new/my-page URL to /blog/my-page Route
|
||||
/new/(.*): '/blog/$1' # Regex any /new/my-page URL to /blog/my-page Route
|
||||
|
||||
blog:
|
||||
route: '/blog' # Custom value added (accessible via system.blog.route)
|
||||
|
||||
#menu: # Sample Menu Example
|
||||
# - text: Source
|
||||
# icon: github
|
||||
# url: https://github.com/getgrav/grav
|
||||
# - icon: twitter
|
||||
# url: http://twitter.com/getgrav
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
schemes:
|
||||
asset:
|
||||
type: ReadOnlyStream
|
||||
paths:
|
||||
- assets
|
||||
|
||||
image:
|
||||
type: ReadOnlyStream
|
||||
paths:
|
||||
- user://images
|
||||
- system://images
|
||||
|
||||
page:
|
||||
type: ReadOnlyStream
|
||||
|
||||
@@ -1,72 +1,114 @@
|
||||
absolute_urls: false # Absolute or relative URLs for `base_url`
|
||||
timezone: '' # Valid values: http://php.net/manual/en/timezones.php
|
||||
param_sep: ':' # Parameter separator
|
||||
absolute_urls: false # Absolute or relative URLs for `base_url`
|
||||
timezone: '' # Valid values: http://php.net/manual/en/timezones.php
|
||||
default_locale: # Default locale (defaults to system)
|
||||
param_sep: ':' # Parameter separator, use ';' for Apache on windows
|
||||
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
|
||||
|
||||
languages:
|
||||
supported: [] # List of languages supported. eg: [en, fr, de]
|
||||
include_default_lang: true # Include the default lang prefix in all URLs
|
||||
translations: true # Enable translations by default
|
||||
translations_fallback: true # Fallback through supported translations if active lang doesn't exist
|
||||
session_store_active: false # Store active language in session
|
||||
http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser
|
||||
override_locale: false # Override the default or system locale with language specific one
|
||||
|
||||
home:
|
||||
alias: '/home' # Default path for home, ie /
|
||||
alias: '/home' # Default path for home, ie /
|
||||
|
||||
pages:
|
||||
theme: antimatter # Default theme (defaults to "antimatter" theme)
|
||||
theme: antimatter # Default theme (defaults to "antimatter" theme)
|
||||
order:
|
||||
by: defaults # Order pages by "default", "alpha" or "date"
|
||||
dir: asc # Default ordering direction, "asc" or "desc"
|
||||
by: default # Order pages by "default", "alpha" or "date"
|
||||
dir: asc # Default ordering direction, "asc" or "desc"
|
||||
list:
|
||||
count: 20 # Default item count per page
|
||||
count: 20 # Default item count per page
|
||||
dateformat:
|
||||
short: 'jS M Y' # Short date format
|
||||
long: 'F jS \a\t g:ia' # Long date format
|
||||
publish_dates: true # automatically publish/unpublish based on dates
|
||||
default: # The default date format Grav expects in the `date: ` field
|
||||
short: 'jS M Y' # Short date format
|
||||
long: 'F jS \a\t g:ia' # Long date format
|
||||
publish_dates: true # automatically publish/unpublish based on dates
|
||||
process:
|
||||
markdown: true # Process Markdown
|
||||
twig: false # Process Twig
|
||||
markdown: true # Process Markdown
|
||||
twig: false # Process Twig
|
||||
events:
|
||||
page: true # Enable page level events
|
||||
twig: true # Enable twig level events
|
||||
page: true # Enable page level events
|
||||
twig: true # Enable twig level events
|
||||
markdown:
|
||||
extra: false # Enable support for Markdown Extra support (GFM by default)
|
||||
auto_line_breaks: false # Enable automatic line breaks
|
||||
auto_url_links: false # Enable automatic HTML links
|
||||
escape_markup: false # Escape markup tags into entities
|
||||
special_chars: # List of special characters to automatically convert to entities
|
||||
extra: false # Enable support for Markdown Extra support (GFM by default)
|
||||
auto_line_breaks: false # Enable automatic line breaks
|
||||
auto_url_links: false # Enable automatic HTML links
|
||||
escape_markup: false # Escape markup tags into entities
|
||||
special_chars: # List of special characters to automatically convert to entities
|
||||
'>': 'gt'
|
||||
'<': 'lt'
|
||||
types: [txt,xml,html,htm,json,rss,atom] # list of valid page types
|
||||
append_url_extension: '' # Append page's extension in Page urls (e.g. '.html' results in /path/page.html)
|
||||
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
|
||||
last_modified: false # Set the last modified date header based on file modifcation timestamp
|
||||
etag: false # Set the etag header tag
|
||||
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
|
||||
redirect_default_route: false # Automatically redirect to a page's default route
|
||||
redirect_default_code: 301 # Default code to use for redirects
|
||||
redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL
|
||||
ignore_files: [.DS_Store] # Files to ignore in Pages
|
||||
ignore_folders: [.git, .idea] # Folders to ignore in Pages
|
||||
ignore_hidden: true # Ignore all Hidden files and folders
|
||||
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections
|
||||
|
||||
cache:
|
||||
enabled: true # Set to true to enable caching
|
||||
enabled: true # Set to true to enable caching
|
||||
check:
|
||||
method: file # Method to check for updates in pages: file|folder|none
|
||||
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
|
||||
prefix: 'g' # Cache prefix string (prevents cache conflicts)
|
||||
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
|
||||
gzip: false # GZip compress the page output
|
||||
method: file # Method to check for updates in pages: file|folder|none
|
||||
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
|
||||
prefix: 'g' # Cache prefix string (prevents cache conflicts)
|
||||
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
|
||||
gzip: false # GZip compress the page output
|
||||
|
||||
twig:
|
||||
cache: true # Set to true to enable twig caching
|
||||
debug: false # Enable Twig debug
|
||||
auto_reload: true # Refresh cache on changes
|
||||
autoescape: false # Autoescape Twig vars
|
||||
undefined_functions: true # Allow undefined functions
|
||||
undefined_filters: true # Allow undefined filters
|
||||
cache: true # Set to true to enable twig caching
|
||||
debug: false # Enable Twig debug
|
||||
auto_reload: true # Refresh cache on changes
|
||||
autoescape: false # Autoescape Twig vars
|
||||
undefined_functions: true # Allow undefined functions
|
||||
undefined_filters: true # Allow undefined filters
|
||||
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
|
||||
|
||||
assets: # Configuration for Assets Manager (JS, CSS)
|
||||
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
|
||||
css_minify: true # Minify the CSS during pipelining
|
||||
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
|
||||
css_rewrite: true # Rewrite any CSS relative URLs during pipelining
|
||||
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
|
||||
js_minify: true # Minify the JS during pipelining
|
||||
assets: # Configuration for Assets Manager (JS, CSS)
|
||||
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
|
||||
css_minify: true # Minify the CSS during pipelining
|
||||
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
|
||||
css_rewrite: true # Rewrite any CSS relative URLs during pipelining
|
||||
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
|
||||
js_minify: true # Minify the JS during pipelining
|
||||
enable_asset_timestamp: false # Enable asset timestamps
|
||||
collections:
|
||||
jquery: system://assets/jquery/jquery-2.1.3.min.js
|
||||
jquery: system://assets/jquery/jquery-2.1.4.min.js
|
||||
|
||||
errors:
|
||||
display: true # Display full backtrace-style error page
|
||||
log: true # Log errors to /logs folder
|
||||
display: false # Display full backtrace-style error page
|
||||
log: true # Log errors to /logs folder
|
||||
|
||||
debugger:
|
||||
enabled: false # Enable Grav debugger and following settings
|
||||
twig: true # Enable debugging of Twig templates
|
||||
enabled: false # Enable Grav debugger and following settings
|
||||
shutdown:
|
||||
close_connection: true # Close the connection before calling onShutdown(). false for debugging
|
||||
close_connection: true # Close the connection before calling onShutdown(). false for debugging
|
||||
|
||||
images:
|
||||
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
|
||||
default_image_quality: 85 # Default image quality to use when resampling images (85%)
|
||||
cache_all: false # Cache all image by default
|
||||
cache_perms: 0755 # Default cache folder perms. Usually 0755 or 0775 depending on setup
|
||||
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
|
||||
|
||||
media:
|
||||
enable_media_timestamp: false # Enable media timetsamps
|
||||
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
|
||||
unsupported_inline_types: [] # Array of supported media types to try to display inline
|
||||
allowed_fallback_types: [] # Array of allowed media types of files found if accessed via Page route
|
||||
|
||||
session:
|
||||
enabled: true # Enable Session support
|
||||
timeout: 1800 # Timeout in seconds
|
||||
name: grav-site # Name prefix of the session cookie. Use alphanumeric, dashes or underscores only. Do not use dots in the session name
|
||||
|
||||
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '0.9.19');
|
||||
define('GRAV_VERSION', '1.0.0');
|
||||
define('DS', '/');
|
||||
|
||||
// Directories and Paths
|
||||
if (!defined('GRAV_ROOT')) {
|
||||
define('GRAV_ROOT', getcwd());
|
||||
define('GRAV_ROOT', str_replace(DIRECTORY_SEPARATOR, DS, getcwd()));
|
||||
}
|
||||
define('ROOT_DIR', GRAV_ROOT . '/');
|
||||
define('USER_PATH', 'user/');
|
||||
define('USER_DIR', ROOT_DIR . USER_PATH);
|
||||
define('SYSTEM_DIR', ROOT_DIR .'system/');
|
||||
define('ASSETS_DIR', ROOT_DIR . 'assets/');
|
||||
define('CACHE_DIR', ROOT_DIR . 'cache/');
|
||||
define('IMAGES_DIR', ROOT_DIR . 'images/');
|
||||
define('LOG_DIR', ROOT_DIR .'logs/');
|
||||
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
|
||||
define('PAGES_DIR', USER_DIR .'pages/');
|
||||
|
||||
// DEPRECATED: Do not use!
|
||||
define('ASSETS_DIR', ROOT_DIR . 'assets/');
|
||||
define('IMAGES_DIR', ROOT_DIR . 'images/');
|
||||
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
|
||||
define('PAGES_DIR', USER_DIR .'pages/');
|
||||
define('DATA_DIR', USER_DIR .'data/');
|
||||
define('LIB_DIR', SYSTEM_DIR .'src/');
|
||||
define('PLUGINS_DIR', USER_DIR .'plugins/');
|
||||
|
||||
37
system/languages/cs.yaml
Normal file
37
system/languages/cs.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Datum nebylo vloženo
|
||||
BAD_DATE: Chybné datum
|
||||
AGO: zpět
|
||||
FROM_NOW: od teď
|
||||
SECOND: sekunda
|
||||
MINUTE: minuta
|
||||
HOUR: hodina
|
||||
DAY: den
|
||||
WEEK: týden
|
||||
MONTH: měsíc
|
||||
YEAR: rok
|
||||
DECADE: dekáda
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: hod
|
||||
DAY: den
|
||||
WK: t
|
||||
MO: m
|
||||
YR: r
|
||||
DEC: dek
|
||||
SECOND_PLURAL: sekundy
|
||||
MINUTE_PLURAL: minuty
|
||||
HOUR_PLURAL: hodiny
|
||||
DAY_PLURAL: dny
|
||||
WEEK_PLURAL: týdny
|
||||
MONTH_PLURAL: měsíce
|
||||
YEAR_PLURAL: roky
|
||||
DECADE_PLURAL: dekády
|
||||
SEC_PLURAL: sek
|
||||
MIN_PLURAL: min
|
||||
HR_PLURAL: hod
|
||||
DAY_PLURAL: dny
|
||||
WK_PLURAL: t
|
||||
MO_PLURAL: m
|
||||
YR_PLURAL: r
|
||||
DEC_PLURAL: dek
|
||||
43
system/languages/de.yaml
Normal file
43
system/languages/de.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'Personen'
|
||||
'man': 'Menschen'
|
||||
'child': 'Kinder'
|
||||
'sex': 'Geschlecht'
|
||||
'move': 'Züge'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Keine Daten vorhanden
|
||||
BAD_DATE: Falsches Datum
|
||||
AGO: her
|
||||
FROM_NOW: ab jetzt
|
||||
SECOND: Sekunde
|
||||
MINUTE: Minute
|
||||
HOUR: Stunde
|
||||
DAY: Tag
|
||||
WEEK: Woche
|
||||
MONTH: Monat
|
||||
YEAR: Jahr
|
||||
DECADE: Dekade
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: std
|
||||
DAY: Tag
|
||||
WK: wo
|
||||
MO: mo
|
||||
YR: yh
|
||||
DEC: dec
|
||||
SECOND_PLURAL: Sekunden
|
||||
MINUTE_PLURAL: Minuten
|
||||
HOUR_PLURAL: Stunden
|
||||
DAY_PLURAL: Tage
|
||||
WEEK_PLURAL: Wochen
|
||||
MONTH_PLURAL: Monate
|
||||
YEAR_PLURAL: Jahre
|
||||
DECADE_PLURAL: Dekaden
|
||||
SEC_PLURAL: Sekunden
|
||||
MIN_PLURAL: Minuten
|
||||
HR_PLURAL: Stunden
|
||||
DAY_PLURAL: Tage
|
||||
WK_PLURAL: Wochen
|
||||
MO_PLURAL: Monate
|
||||
YR_PLURAL: Jahre
|
||||
DEC_PLURAL: Dekaden
|
||||
98
system/languages/en.yaml
Normal file
98
system/languages/en.yaml
Normal file
@@ -0,0 +1,98 @@
|
||||
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Error: Invalid Frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_PLURALS:
|
||||
'/(quiz)$/i': '\1zes'
|
||||
'/^(ox)$/i': '\1en'
|
||||
'/([m|l])ouse$/i': '\1ice'
|
||||
'/(matr|vert|ind)ix|ex$/i': '\1ices'
|
||||
'/(x|ch|ss|sh)$/i': '\1es'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([^aeiouy]|qu)y$/i': '\1ies'
|
||||
'/(hive)$/i': '\1s'
|
||||
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
|
||||
'/sis$/i': 'ses'
|
||||
'/([ti])um$/i': '\1a'
|
||||
'/(buffal|tomat)o$/i': '\1oes'
|
||||
'/(bu)s$/i': '\1ses'
|
||||
'/(alias|status)/i': '\1es'
|
||||
'/(octop|vir)us$/i': '\1i'
|
||||
'/(ax|test)is$/i': '\1es'
|
||||
'/s$/i': 's'
|
||||
'/$/': 's'
|
||||
INFLECTOR_SINGULAR:
|
||||
'/(quiz)zes$/i': '\1'
|
||||
'/(matr)ices$/i': '\1ix'
|
||||
'/(vert|ind)ices$/i': '\1ex'
|
||||
'/^(ox)en/i': '\1'
|
||||
'/(alias|status)es$/i': '\1'
|
||||
'/([octop|vir])i$/i': '\1us'
|
||||
'/(cris|ax|test)es$/i': '\1is'
|
||||
'/(shoe)s$/i': '\1'
|
||||
'/(o)es$/i': '\1'
|
||||
'/(bus)es$/i': '\1'
|
||||
'/([m|l])ice$/i': '\1ouse'
|
||||
'/(x|ch|ss|sh)es$/i': '\1'
|
||||
'/(m)ovies$/i': '\1ovie'
|
||||
'/(s)eries$/i': '\1eries'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([lr])ves$/i': '\1f'
|
||||
'/(tive)s$/i': '\1'
|
||||
'/(hive)s$/i': '\1'
|
||||
'/([^f])ves$/i': '\1fe'
|
||||
'/(^analy)ses$/i': '\1sis'
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
|
||||
'/([ti])a$/i': '\1um'
|
||||
'/(n)ews$/i': '\1ews'
|
||||
'/s$/i': ''
|
||||
INFLECTOR_UNCOUNTABLE: ['equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep']
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'people'
|
||||
'man': 'men'
|
||||
'child': 'children'
|
||||
'sex': 'sexes'
|
||||
'move': 'moves'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': 'th'
|
||||
'first': 'st'
|
||||
'second': 'nd'
|
||||
'third': 'rd'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: No date provided
|
||||
BAD_DATE: Bad date
|
||||
AGO: ago
|
||||
FROM_NOW: from now
|
||||
SECOND: second
|
||||
MINUTE: minute
|
||||
HOUR: hour
|
||||
DAY: day
|
||||
WEEK: week
|
||||
MONTH: month
|
||||
YEAR: year
|
||||
DECADE: decade
|
||||
SEC: sec
|
||||
MIN: min
|
||||
HR: hr
|
||||
DAY: day
|
||||
WK: wk
|
||||
MO: mo
|
||||
YR: yr
|
||||
DEC: dec
|
||||
SECOND_PLURAL: seconds
|
||||
MINUTE_PLURAL: minutes
|
||||
HOUR_PLURAL: hours
|
||||
DAY_PLURAL: days
|
||||
WEEK_PLURAL: weeks
|
||||
MONTH_PLURAL: months
|
||||
YEAR_PLURAL: years
|
||||
DECADE_PLURAL: decades
|
||||
SEC_PLURAL: secs
|
||||
MIN_PLURAL: mins
|
||||
HR_PLURAL: hrs
|
||||
DAY_PLURAL: days
|
||||
WK_PLURAL: wks
|
||||
MO_PLURAL: mos
|
||||
YR_PLURAL: yrs
|
||||
DEC_PLURAL: decs
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Validation failed:</b>
|
||||
INVALID_INPUT: Invalid input in
|
||||
MISSING_REQUIRED_FIELD: Missing required field:
|
||||
42
system/languages/es.yaml
Normal file
42
system/languages/es.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: No se proporcionó fecha
|
||||
BAD_DATE: Fecha erronea
|
||||
AGO: antes
|
||||
FROM_NOW: desde ahora
|
||||
SECOND: segundo
|
||||
MINUTE: minuto
|
||||
HOUR: hora
|
||||
DAY: dia
|
||||
WEEK: semana
|
||||
MONTH: mes
|
||||
YEAR: año
|
||||
DECADE: decada
|
||||
SEC: seg
|
||||
MIN: min
|
||||
HR: hr
|
||||
DAY: dia
|
||||
WK: sem
|
||||
MO: mes
|
||||
YR: yr
|
||||
DEC: dec
|
||||
SECOND_PLURAL: segundos
|
||||
MINUTE_PLURAL: minutos
|
||||
HOUR_PLURAL: horas
|
||||
DAY_PLURAL: días
|
||||
WEEK_PLURAL: semanas
|
||||
MONTH_PLURAL: meses
|
||||
YEAR_PLURAL: años
|
||||
DECADE_PLURAL: decadas
|
||||
SEC_PLURAL: segs
|
||||
MIN_PLURAL: mins
|
||||
HR_PLURAL: hrs
|
||||
DAY_PLURAL: dias
|
||||
WK_PLURAL: sem
|
||||
MO_PLURAL: mes
|
||||
YR_PLURAL: años
|
||||
DEC_PLURAL: decs
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Falló la validación. </b>
|
||||
INVALID_INPUT: "Dato inválido en: "
|
||||
MISSING_REQUIRED_FIELD: "Falta el campo requerido: "
|
||||
|
||||
98
system/languages/fr.yaml
Normal file
98
system/languages/fr.yaml
Normal file
@@ -0,0 +1,98 @@
|
||||
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Erreur : Frontmatter invalide\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_PLURALS:
|
||||
'/(quiz)$/i': '\1zes'
|
||||
'/^(ox)$/i': '\1en'
|
||||
'/([m|l])ouse$/i': '\1ice'
|
||||
'/(matr|vert|ind)ix|ex$/i': '\1ices'
|
||||
'/(x|ch|ss|sh)$/i': '\1es'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([^aeiouy]|qu)y$/i': '\1ies'
|
||||
'/(hive)$/i': '\1s'
|
||||
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
|
||||
'/sis$/i': 'ses'
|
||||
'/([ti])um$/i': '\1a'
|
||||
'/(buffal|tomat)o$/i': '\1oes'
|
||||
'/(bu)s$/i': '\1ses'
|
||||
'/(alias|status)/i': '\1es'
|
||||
'/(octop|vir)us$/i': '\1i'
|
||||
'/(ax|test)is$/i': '\1es'
|
||||
'/s$/i': 's'
|
||||
'/$/': 's'
|
||||
INFLECTOR_SINGULAR:
|
||||
'/(quiz)zes$/i': '\1'
|
||||
'/(matr)ices$/i': '\1ix'
|
||||
'/(vert|ind)ices$/i': '\1ex'
|
||||
'/^(ox)en/i': '\1'
|
||||
'/(alias|status)es$/i': '\1'
|
||||
'/([octop|vir])i$/i': '\1us'
|
||||
'/(cris|ax|test)es$/i': '\1is'
|
||||
'/(shoe)s$/i': '\1'
|
||||
'/(o)es$/i': '\1'
|
||||
'/(bus)es$/i': '\1'
|
||||
'/([m|l])ice$/i': '\1ouse'
|
||||
'/(x|ch|ss|sh)es$/i': '\1'
|
||||
'/(m)ovies$/i': '\1ovie'
|
||||
'/(s)eries$/i': '\1eries'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([lr])ves$/i': '\1f'
|
||||
'/(tive)s$/i': '\1'
|
||||
'/(hive)s$/i': '\1'
|
||||
'/([^f])ves$/i': '\1fe'
|
||||
'/(^analy)ses$/i': '\1sis'
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
|
||||
'/([ti])a$/i': '\1um'
|
||||
'/(n)ews$/i': '\1ews'
|
||||
'/s$/i': ''
|
||||
INFLECTOR_UNCOUNTABLE: ['équipment', 'information', 'riz', 'argent', 'espèces', 'séries', 'poisson', 'mouton']
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'personnes'
|
||||
'man': 'Hommes'
|
||||
'child': 'enfants'
|
||||
'sex': 'sexes'
|
||||
'move': 'déplacemements'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': 'ème'
|
||||
'first': 'er'
|
||||
'second': 'nd'
|
||||
'third': 'ème'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Aucune date
|
||||
BAD_DATE: Date erronée
|
||||
AGO: plus tôt
|
||||
FROM_NOW: à partir de maintenant
|
||||
SECOND: seconde
|
||||
MINUTE: minute
|
||||
HOUR: heure
|
||||
DAY: jour
|
||||
WEEK: semaine
|
||||
MONTH: mois
|
||||
YEAR: an
|
||||
DECADE: décennie
|
||||
SEC: s
|
||||
MIN: m
|
||||
HR: h
|
||||
DAY: j
|
||||
WK: s
|
||||
MO: m
|
||||
YR: a
|
||||
DEC: d
|
||||
SECOND_PLURAL: secondes
|
||||
MINUTE_PLURAL: minutes
|
||||
HOUR_PLURAL: heures
|
||||
DAY_PLURAL: jours
|
||||
WEEK_PLURAL: semaines
|
||||
MONTH_PLURAL: mois
|
||||
YEAR_PLURAL: années
|
||||
DECADE_PLURAL: décennies
|
||||
SEC_PLURAL: s
|
||||
MIN_PLURAL: m
|
||||
HR_PLURAL: h
|
||||
DAY_PLURAL: j
|
||||
WK_PLURAL: s
|
||||
MO_PLURAL: m
|
||||
YR_PLURAL: a
|
||||
DEC_PLURAL: d
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>La validation a échoué :</b>
|
||||
INVALID_INPUT: Saisie non valide
|
||||
MISSING_REQUIRED_FIELD: Champ obligatoire manquant :
|
||||
52
system/languages/hr.yaml
Normal file
52
system/languages/hr.yaml
Normal file
@@ -0,0 +1,52 @@
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'Osoba'
|
||||
'man': 'Čovjek'
|
||||
'child': 'Dijete'
|
||||
'sex': 'Spol'
|
||||
'move': 'Pomakni'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Datum nije upisan
|
||||
BAD_DATE: Pogrešan datum
|
||||
AGO: prije
|
||||
FROM_NOW: od sad
|
||||
SECOND: sekundi
|
||||
MINUTE: minuta
|
||||
HOUR: godina
|
||||
DAY: dan
|
||||
WEEK: tjedan
|
||||
MONTH: mjesec
|
||||
YEAR: godina
|
||||
DECADE: desetljeće
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: sat
|
||||
DAY: dan
|
||||
WK: t
|
||||
MO: m
|
||||
YR: g
|
||||
DEC: des
|
||||
SECOND_PLURAL: sekundi
|
||||
SECOND_PLURAL_MORE_THAN_TWO: sekunde
|
||||
MINUTE_PLURAL: minuta
|
||||
MINUTE_PLURAL_MORE_THAN_TWO: minute
|
||||
HOUR_PLURAL: sati
|
||||
HOUR_PLURAL_MORE_THAN_TWO: sata
|
||||
DAY_PLURAL: dana
|
||||
WEEK_PLURAL: tjedana
|
||||
WEEK_PLURAL_MORE_THAN_TWO: tjedna
|
||||
MONTH_PLURAL: mjeseci
|
||||
MONTH_PLURAL_MORE_THAN_TWO: mjeseca
|
||||
YEAR_PLURAL: godina
|
||||
YEAR_PLURAL_MORE_THAN_TWO: godine
|
||||
DECADE_PLURAL: desetljeća
|
||||
SEC_PLURAL: sek
|
||||
MIN_PLURAL: min
|
||||
HR_PLURAL: sat
|
||||
DAY_PLURAL: dan
|
||||
WK_PLURAL: t
|
||||
MO_PLURAL: m
|
||||
YR_PLURAL: g
|
||||
DEC_PLURAL: des
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Validacija nije uspjela:</b>
|
||||
INVALID_INPUT: Unos nije valjan
|
||||
53
system/languages/hu.yaml
Normal file
53
system/languages/hu.yaml
Normal file
@@ -0,0 +1,53 @@
|
||||
FRONTMATTER_ERROR_PAGE: "---\ncím: %1$s\n---\n\n# Hiba: Érvénytelen Frontmatter\n\nElérési út: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'személyek'
|
||||
'man': 'férfiak'
|
||||
'child': 'gyerekek'
|
||||
'sex': 'nemek'
|
||||
'move': 'lépések'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': '.'
|
||||
'first': '.'
|
||||
'second': '.'
|
||||
'third': '.'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Nincs dátum megadva
|
||||
BAD_DATE: Hibás dátum
|
||||
AGO: elteltével
|
||||
FROM_NOW: mostantól
|
||||
SECOND: másodperc
|
||||
MINUTE: perc
|
||||
HOUR: óra
|
||||
DAY: nap
|
||||
WEEK: hét
|
||||
MONTH: hónap
|
||||
YEAR: év
|
||||
DECADE: évtized
|
||||
SEC: mp
|
||||
MIN: p
|
||||
HR: ó
|
||||
DAY: nap
|
||||
WK: hét
|
||||
MO: hó
|
||||
YR: év
|
||||
DEC: évt
|
||||
SECOND_PLURAL: másodperc
|
||||
MINUTE_PLURAL: perc
|
||||
HOUR_PLURAL: óra
|
||||
DAY_PLURAL: nap
|
||||
WEEK_PLURAL: hét
|
||||
MONTH_PLURAL: hónap
|
||||
YEAR_PLURAL: év
|
||||
DECADE_PLURAL: évtized
|
||||
SEC_PLURAL: mp
|
||||
MIN_PLURAL: perc
|
||||
HR_PLURAL: ó
|
||||
DAY_PLURAL: nap
|
||||
WK_PLURAL: hét
|
||||
MO_PLURAL: hó
|
||||
YR_PLURAL: év
|
||||
DEC_PLURAL: évt
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>A validáció hibát talált:</b>
|
||||
INVALID_INPUT: Az itt megadott érték érvénytelen:
|
||||
MISSING_REQUIRED_FIELD: Ez a kötelező mező nincs kitöltve:
|
||||
25
system/languages/it.yaml
Normal file
25
system/languages/it.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Nessuna data fornita
|
||||
BAD_DATE: Data errata
|
||||
AGO: fa
|
||||
FROM_NOW: da adesso
|
||||
SECOND: secondo
|
||||
MINUTE: minuto
|
||||
HOUR: ora
|
||||
DAY: giorno
|
||||
WEEK: settimana
|
||||
MONTH: mese
|
||||
YEAR: anno
|
||||
DECADE: decade
|
||||
SECOND_PLURAL: secondi
|
||||
MINUTE_PLURAL: minuti
|
||||
HOUR_PLURAL: ore
|
||||
DAY_PLURAL: giorni
|
||||
WEEK_PLURAL: settimane
|
||||
MONTH_PLURAL: mesi
|
||||
YEAR_PLURAL: anni
|
||||
DECADE_PLURAL: decadi
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Validazione fallita:</b>
|
||||
INVALID_INPUT: Input invalido in
|
||||
MISSING_REQUIRED_FIELD: Campo richiesto mancante:
|
||||
43
system/languages/nl.yaml
Normal file
43
system/languages/nl.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'personen'
|
||||
'man': 'mensen'
|
||||
'child': 'kinderen'
|
||||
'sex': 'geslacht'
|
||||
'move': 'verplaatsen'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: geen datum opgegeven
|
||||
BAD_DATE: Datumformaat onjuist
|
||||
AGO: geleden
|
||||
FROM_NOW: vanaf nu
|
||||
SECOND: seconde
|
||||
MINUTE: minuut
|
||||
HOUR: uur
|
||||
DAY: dag
|
||||
WEEK: week
|
||||
MONTH: maand
|
||||
YEAR: jaar
|
||||
DECADE: decenium
|
||||
SEC: sec
|
||||
MIN: min
|
||||
HR: hr
|
||||
DAY: dag
|
||||
WK: wk
|
||||
MO: ma
|
||||
YR: yr
|
||||
DEC: dec
|
||||
SECOND_PLURAL: seconden
|
||||
MINUTE_PLURAL: minuten
|
||||
HOUR_PLURAL: uren
|
||||
DAY_PLURAL: dagen
|
||||
WEEK_PLURAL: weken
|
||||
MONTH_PLURAL: maanden
|
||||
YEAR_PLURAL: jaren
|
||||
DECADE_PLURAL: decennia
|
||||
SEC_PLURAL: seconden
|
||||
MIN_PLURAL: minuten
|
||||
HR_PLURAL: uren
|
||||
DAY_PLURAL: dagen
|
||||
WK_PLURAL: weken
|
||||
MO_PLURAL: maanden
|
||||
YR_PLURAL: jaren
|
||||
DEC_PLURAL: decs
|
||||
43
system/languages/ru.yaml
Normal file
43
system/languages/ru.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'люди'
|
||||
'man': 'человек'
|
||||
'child': 'ребенок'
|
||||
'sex': 'пол'
|
||||
'move': 'движется'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Дата не указана
|
||||
BAD_DATE: Неверная дата
|
||||
AGO: назад
|
||||
FROM_NOW: теперь
|
||||
SECOND: секунда
|
||||
MINUTE: минута
|
||||
HOUR: час
|
||||
DAY: день
|
||||
WEEK: неделя
|
||||
MONTH: месяц
|
||||
YEAR: год
|
||||
DECADE: десятилетие
|
||||
SEC: с
|
||||
MIN: мин
|
||||
HR: ч
|
||||
DAY: д
|
||||
WK: нед
|
||||
MO: мес
|
||||
YR: г.
|
||||
DEC: гг.
|
||||
SECOND_PLURAL: секунды
|
||||
MINUTE_PLURAL: минуты
|
||||
HOUR_PLURAL: часы
|
||||
DAY_PLURAL: дни
|
||||
WEEK_PLURAL: недели
|
||||
MONTH_PLURAL: месяцы
|
||||
YEAR_PLURAL: годы
|
||||
DECADE_PLURAL: десятилетия
|
||||
SEC_PLURAL: с
|
||||
MIN_PLURAL: мин
|
||||
HR_PLURAL: ч
|
||||
DAY_PLURAL: д
|
||||
WK_PLURAL: нед
|
||||
MO_PLURAL: мес
|
||||
YR_PLURAL: г.
|
||||
DEC_PLURAL: гг.
|
||||
37
system/languages/tr.yaml
Normal file
37
system/languages/tr.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Tarih yok
|
||||
BAD_DATE: Yanlış tarih
|
||||
AGO: önce
|
||||
FROM_NOW: (şimdiden)
|
||||
SECOND: saniye
|
||||
MINUTE: dakika
|
||||
HOUR: saat
|
||||
DAY: gün
|
||||
WEEK: hafta
|
||||
MONTH: ay
|
||||
YEAR: yıl
|
||||
DECADE: onyıl
|
||||
SEC: sn
|
||||
MIN: dk
|
||||
HR: sa
|
||||
DAY: gün
|
||||
WK: hft
|
||||
MO: ay
|
||||
YR: yl
|
||||
DEC: onyl
|
||||
SECOND_PLURAL: saniye
|
||||
MINUTE_PLURAL: dakika
|
||||
HOUR_PLURAL: saat
|
||||
DAY_PLURAL: gün
|
||||
WEEK_PLURAL: hafta
|
||||
MONTH_PLURAL: ay
|
||||
YEAR_PLURAL: yıl
|
||||
DECADE_PLURAL: onyıl
|
||||
SEC_PLURAL: sn
|
||||
MIN_PLURAL: dk
|
||||
HR_PLURAL: sa
|
||||
DAY_PLURAL: gün
|
||||
WK_PLURAL: hft
|
||||
MO_PLURAL: ay
|
||||
YR_PLURAL: yl
|
||||
DEC_PLURAL: onyl
|
||||
@@ -42,12 +42,14 @@ class Assets
|
||||
/** @const Regex to match CSS import content */
|
||||
const CSS_IMPORT_REGEX = '{@import(.*);}';
|
||||
|
||||
const HTML_TAG_REGEX = '#(<([A-Z][A-Z0-9]*)>)+(.*)(<\/\2>)#is';
|
||||
|
||||
|
||||
/**
|
||||
* Closure used by the pipeline to fetch assets.
|
||||
*
|
||||
* Useful when file_get_contents() function is not available in your PHP
|
||||
* instalation or when you want to apply any kind of preprocessing to
|
||||
* installation or when you want to apply any kind of preprocessing to
|
||||
* your assets before they get pipelined.
|
||||
*
|
||||
* The closure will receive as the only parameter a string with the path/URL of the asset and
|
||||
@@ -71,6 +73,9 @@ class Assets
|
||||
// Some configuration variables
|
||||
protected $config;
|
||||
protected $base_url;
|
||||
protected $timestamp = '';
|
||||
protected $assets_dir;
|
||||
protected $assets_url;
|
||||
|
||||
// Default values for pipeline settings
|
||||
protected $css_minify = true;
|
||||
@@ -82,7 +87,6 @@ class Assets
|
||||
protected $css_no_pipeline = array();
|
||||
protected $js_no_pipeline = array();
|
||||
|
||||
|
||||
public function __construct(array $options = array())
|
||||
{
|
||||
// Forward config options
|
||||
@@ -115,7 +119,7 @@ class Assets
|
||||
}
|
||||
|
||||
// Pipeline requires public dir
|
||||
if (($this->js_pipeline || $this->css_pipeline) && !is_dir(ASSETS_DIR)) {
|
||||
if (($this->js_pipeline || $this->css_pipeline) && !is_dir($this->assets_dir)) {
|
||||
throw new \Exception('Assets: Public dir not found');
|
||||
}
|
||||
|
||||
@@ -154,6 +158,12 @@ class Assets
|
||||
}
|
||||
}
|
||||
|
||||
// Set timestamp
|
||||
if (isset($config['enable_asset_timestamp']) && $config['enable_asset_timestamp'] === true) {
|
||||
$this->timestamp = '?' . self::getGrav()['cache']->getKey();
|
||||
}
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -167,6 +177,11 @@ class Assets
|
||||
$base_url = self::getGrav()['base_url'];
|
||||
$asset_config = (array)$config->get('system.assets');
|
||||
|
||||
/** @var Locator $locator */
|
||||
$locator = self::$grav['locator'];
|
||||
$this->assets_dir = self::getGrav()['locator']->findResource('asset://') . DS;
|
||||
$this->assets_url = self::getGrav()['locator']->findResource('asset://', false);
|
||||
|
||||
$this->config($asset_config);
|
||||
$this->base_url = $base_url . '/';
|
||||
|
||||
@@ -188,7 +203,7 @@ class Assets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add($asset, $priority = 10, $pipeline = true)
|
||||
public function add($asset, $priority = null, $pipeline = true)
|
||||
{
|
||||
// More than one asset
|
||||
if (is_array($asset)) {
|
||||
@@ -222,20 +237,21 @@ class Assets
|
||||
* You may add more than one asset passing an array as argument.
|
||||
*
|
||||
* @param mixed $asset
|
||||
* @param int $priority the priority, bigger comes first
|
||||
* @param bool $pipeline false if this should not be pipelined
|
||||
* @param int $priority the priority, bigger comes first
|
||||
* @param bool $pipeline false if this should not be pipelined
|
||||
* @param null $group
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addCss($asset, $priority = 10, $pipeline = true)
|
||||
public function addCss($asset, $priority = null, $pipeline = true, $group = null)
|
||||
{
|
||||
if (is_array($asset)) {
|
||||
foreach ($asset as $a) {
|
||||
$this->addCss($a, $priority, $pipeline);
|
||||
$this->addCss($a, $priority, $pipeline, $group);
|
||||
}
|
||||
return $this;
|
||||
} elseif (isset($this->collections[$asset])) {
|
||||
$this->add($this->collections[$asset], $priority, $pipeline);
|
||||
$this->add($this->collections[$asset], $priority, $pipeline, $group);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -243,14 +259,30 @@ class Assets
|
||||
$asset = $this->buildLocalLink($asset);
|
||||
}
|
||||
|
||||
// Check for existence
|
||||
if ($asset === false) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'asset' => $asset,
|
||||
'priority' => intval($priority ?: 10),
|
||||
'order' => count($this->css),
|
||||
'pipeline' => (bool) $pipeline,
|
||||
'group' => $group ?: 'head'
|
||||
];
|
||||
|
||||
// check for dynamic array and merge with defaults
|
||||
if (func_num_args() == 2) {
|
||||
$dynamic_arg = func_get_arg(1);
|
||||
if (is_array($dynamic_arg)) {
|
||||
$data = array_merge($data, $dynamic_arg);
|
||||
}
|
||||
}
|
||||
|
||||
$key = md5($asset);
|
||||
if ($asset && !array_key_exists($key, $this->css)) {
|
||||
$this->css[$key] = [
|
||||
'asset' => $asset,
|
||||
'priority' => $priority,
|
||||
'order' => count($this->css),
|
||||
'pipeline' => $pipeline
|
||||
];
|
||||
if ($asset) {
|
||||
$this->css[$key] = $data;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -263,20 +295,21 @@ class Assets
|
||||
* You may add more than one asset passing an array as argument.
|
||||
*
|
||||
* @param mixed $asset
|
||||
* @param int $priority the priority, bigger comes first
|
||||
* @param bool $pipeline false if this should not be pipelined
|
||||
*
|
||||
* @param int $priority the priority, bigger comes first
|
||||
* @param bool $pipeline false if this should not be pipelined
|
||||
* @param string $loading how the asset is loaded (async/defer)
|
||||
* @param string $group name of the group
|
||||
* @return $this
|
||||
*/
|
||||
public function addJs($asset, $priority = 10, $pipeline = true)
|
||||
public function addJs($asset, $priority = null, $pipeline = true, $loading = null, $group = null)
|
||||
{
|
||||
if (is_array($asset)) {
|
||||
foreach ($asset as $a) {
|
||||
$this->addJs($a, $priority, $pipeline);
|
||||
$this->addJs($a, $priority, $pipeline, $loading, $group);
|
||||
}
|
||||
return $this;
|
||||
} elseif (isset($this->collections[$asset])) {
|
||||
$this->add($this->collections[$asset], $priority, $pipeline);
|
||||
$this->add($this->collections[$asset], $priority, $pipeline, $loading, $group);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -284,19 +317,70 @@ class Assets
|
||||
$asset = $this->buildLocalLink($asset);
|
||||
}
|
||||
|
||||
// Check for existence
|
||||
if ($asset === false) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'asset' => $asset,
|
||||
'priority' => intval($priority ?: 10),
|
||||
'order' => count($this->js),
|
||||
'pipeline' => (bool) $pipeline,
|
||||
'loading' => $loading ?: '',
|
||||
'group' => $group ?: 'head'
|
||||
];
|
||||
|
||||
// check for dynamic array and merge with defaults
|
||||
if (func_num_args() == 2) {
|
||||
$dynamic_arg = func_get_arg(1);
|
||||
if (is_array($dynamic_arg)) {
|
||||
$data = array_merge($data, $dynamic_arg);
|
||||
}
|
||||
}
|
||||
|
||||
$key = md5($asset);
|
||||
if ($asset && !array_key_exists($key, $this->js)) {
|
||||
$this->js[$key] = [
|
||||
'asset' => $asset,
|
||||
'priority' => $priority,
|
||||
'order' => count($this->js),
|
||||
'pipeline' => $pipeline
|
||||
];
|
||||
if ($asset) {
|
||||
$this->js[$key] = $data;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper for async loading of JavaScript
|
||||
*
|
||||
* @param $asset
|
||||
* @param int $priority
|
||||
* @param bool $pipeline
|
||||
* @param string $group name of the group
|
||||
*
|
||||
* @deprecated Please use dynamic method with ['loading' => 'async']
|
||||
*
|
||||
* @return \Grav\Common\Assets
|
||||
*/
|
||||
public function addAsyncJs($asset, $priority = null, $pipeline = true, $group = null)
|
||||
{
|
||||
return $this->addJs($asset, $priority, $pipeline, 'async', $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper for deferred loading of JavaScript
|
||||
*
|
||||
* @param $asset
|
||||
* @param int $priority
|
||||
* @param bool $pipeline
|
||||
* @param string $group name of the group
|
||||
*
|
||||
* @deprecated Please use dynamic method with ['loading' => 'defer']
|
||||
*
|
||||
* @return \Grav\Common\Assets
|
||||
*/
|
||||
public function addDeferJs($asset, $priority = null, $pipeline = true, $group = null)
|
||||
{
|
||||
return $this->addJs($asset, $priority, $pipeline, 'defer', $group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an inline CSS asset.
|
||||
*
|
||||
@@ -304,22 +388,41 @@ class Assets
|
||||
* For adding chunks of string-based inline CSS
|
||||
*
|
||||
* @param mixed $asset
|
||||
* @param int $priority the priority, bigger comes first
|
||||
* @param int $priority the priority, bigger comes first
|
||||
* @param null $group
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addInlineCss($asset, $priority = 10)
|
||||
public function addInlineCss($asset, $priority = null, $group = null)
|
||||
{
|
||||
$asset = trim($asset);
|
||||
|
||||
if (is_a($asset, 'Twig_Markup')) {
|
||||
$asset = strip_tags((string)$asset);
|
||||
preg_match(self::HTML_TAG_REGEX, $asset, $matches );
|
||||
if (isset($matches[3])) {
|
||||
$asset = $matches[3];
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'priority' => intval($priority ?: 10),
|
||||
'order' => count($this->inline_css),
|
||||
'asset' => $asset,
|
||||
'group' => $group ?: 'head'
|
||||
];
|
||||
|
||||
// check for dynamic array and merge with defaults
|
||||
$count_args = func_num_args();
|
||||
if (func_num_args() == 2) {
|
||||
$dynamic_arg = func_get_arg(1);
|
||||
if (is_array($dynamic_arg)) {
|
||||
$data = array_merge($data, $dynamic_arg);
|
||||
}
|
||||
}
|
||||
|
||||
$key = md5($asset);
|
||||
if (is_string($asset) && !array_key_exists($key, $this->inline_css)) {
|
||||
$this->inline_css[$key] = [
|
||||
'priority' => $priority,
|
||||
'order' => count($this->inline_css),
|
||||
'asset' => $asset
|
||||
];
|
||||
if ($asset && is_string($asset) && !array_key_exists($key, $this->inline_css)) {
|
||||
$this->inline_css[$key] = $data;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -333,21 +436,40 @@ class Assets
|
||||
*
|
||||
* @param mixed $asset
|
||||
* @param int $priority the priority, bigger comes first
|
||||
* @param string $group name of the group
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addInlineJs($asset, $priority = 10)
|
||||
public function addInlineJs($asset, $priority = null, $group = null)
|
||||
{
|
||||
$asset = trim($asset);
|
||||
|
||||
if (is_a($asset, 'Twig_Markup')) {
|
||||
$asset = strip_tags((string)$asset);
|
||||
preg_match(self::HTML_TAG_REGEX, $asset, $matches );
|
||||
if (isset($matches[3])) {
|
||||
$asset = $matches[3];
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'asset' => $asset,
|
||||
'priority' => intval($priority ?: 10),
|
||||
'order' => count($this->js),
|
||||
'group' => $group ?: 'head'
|
||||
];
|
||||
|
||||
// check for dynamic array and merge with defaults
|
||||
$count_args = func_num_args();
|
||||
if (func_num_args() == 2) {
|
||||
$dynamic_arg = func_get_arg(1);
|
||||
if (is_array($dynamic_arg)) {
|
||||
$data = array_merge($data, $dynamic_arg);
|
||||
}
|
||||
}
|
||||
|
||||
$key = md5($asset);
|
||||
if (is_string($asset) && !array_key_exists($key, $this->inline_js)) {
|
||||
$this->inline_js[$key] = [
|
||||
'priority' => $priority,
|
||||
'order' => count($this->inline_js),
|
||||
'asset' => $asset
|
||||
];
|
||||
if ($asset && is_string($asset) && !array_key_exists($key, $this->inline_js)) {
|
||||
$this->inline_js[$key] = $data;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -356,11 +478,12 @@ class Assets
|
||||
/**
|
||||
* Build the CSS link tags.
|
||||
*
|
||||
* @param string $group name of the group
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function css($attributes = [])
|
||||
public function css($group = 'head', $attributes = [])
|
||||
{
|
||||
if (!$this->css) {
|
||||
return null;
|
||||
@@ -388,25 +511,37 @@ class Assets
|
||||
$attributes = $this->attributes(array_merge(['type' => 'text/css', 'rel' => 'stylesheet'], $attributes));
|
||||
|
||||
$output = '';
|
||||
if ($this->css_pipeline) {
|
||||
$output .= '<link href="' . $this->pipeline(CSS_ASSET) . '"' . $attributes . ' />' . "\n";
|
||||
$inline_css = '';
|
||||
|
||||
if ($this->css_pipeline) {
|
||||
$pipeline_result = $this->pipelineCss($group);
|
||||
if ($pipeline_result) {
|
||||
$output .= '<link href="' . $pipeline_result . '"' . $attributes . ' />' . "\n";
|
||||
}
|
||||
foreach ($this->css_no_pipeline as $file) {
|
||||
$output .= '<link href="' . $file['asset'] . '"' . $attributes . ' />' . "\n";
|
||||
if ($group && $file['group'] == $group) {
|
||||
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
|
||||
$output .= '<link href="' . $file['asset'] . $this->timestamp . '"' . $attributes . $media . ' />' . "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($this->css as $file) {
|
||||
$output .= '<link href="' . $file['asset'] . '"' . $attributes . ' />' . "\n";
|
||||
if ($group && $file['group'] == $group) {
|
||||
$media = isset($file['media']) ? sprintf(' media="%s"', $file['media']) : '';
|
||||
$output .= '<link href="' . $file['asset'] . $this->timestamp . '"' . $attributes . $media . ' />' . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render Inline CSS
|
||||
if (count($this->inline_css) > 0) {
|
||||
$output .= "<style>\n";
|
||||
foreach ($this->inline_css as $inline) {
|
||||
$output .= $inline['asset'] . "\n";
|
||||
foreach ($this->inline_css as $inline) {
|
||||
if ($group && $inline['group'] == $group) {
|
||||
$inline_css .= $inline['asset'] . "\n";
|
||||
}
|
||||
$output .= "</style>\n";
|
||||
}
|
||||
|
||||
if ($inline_css) {
|
||||
$output .= "\n<style>\n" . $inline_css . "\n</style>\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -416,11 +551,12 @@ class Assets
|
||||
/**
|
||||
* Build the JavaScript script tags.
|
||||
*
|
||||
* @param string $group name of the group
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function js($attributes = [])
|
||||
public function js($group = 'head', $attributes = [])
|
||||
{
|
||||
if (!$this->js) {
|
||||
return null;
|
||||
@@ -447,68 +583,83 @@ class Assets
|
||||
$attributes = $this->attributes(array_merge(['type' => 'text/javascript'], $attributes));
|
||||
|
||||
$output = '';
|
||||
$inline_js = '';
|
||||
|
||||
if ($this->js_pipeline) {
|
||||
$output .= '<script src="' . $this->pipeline(JS_ASSET) . '"' . $attributes . ' ></script>' . "\n";
|
||||
$pipeline_result = $this->pipelineJs($group);
|
||||
if ($pipeline_result) {
|
||||
$output .= '<script src="' . $pipeline_result . '"' . $attributes . ' ></script>' . "\n";
|
||||
}
|
||||
foreach ($this->js_no_pipeline as $file) {
|
||||
$output .= '<script src="' . $file['asset'] . '"' . $attributes . ' ></script>' . "\n";
|
||||
if ($group && $file['group'] == $group) {
|
||||
$output .= '<script src="' . $file['asset'] . $this->timestamp . '"' . $attributes . ' ' . $file['loading']. '></script>' . "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($this->js as $file) {
|
||||
$output .= '<script src="' . $file['asset'] . '"' . $attributes . ' ></script>' . "\n";
|
||||
if ($group && $file['group'] == $group) {
|
||||
$output .= '<script src="' . $file['asset'] . $this->timestamp . '"' . $attributes . ' ' . $file['loading'] . '></script>' . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render Inline JS
|
||||
if (count($this->inline_js) > 0) {
|
||||
$output .= "<script>\n";
|
||||
foreach ($this->inline_js as $inline) {
|
||||
$output .= $inline['asset'] . "\n";
|
||||
foreach ($this->inline_js as $inline) {
|
||||
if ($group && $inline['group'] == $group) {
|
||||
$inline_js .= $inline['asset'] . "\n";
|
||||
}
|
||||
$output .= "</script>\n";
|
||||
}
|
||||
|
||||
if ($inline_js) {
|
||||
$output .= "\n<script>\n" . $inline_js . "\n</script>\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Minifiy and concatenate CSS / JS files.
|
||||
* Minify and concatenate CSS.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function pipeline($css = true)
|
||||
protected function pipelineCss($group = 'head')
|
||||
{
|
||||
/** @var Cache $cache */
|
||||
$cache = self::getGrav()['cache'];
|
||||
$key = '?' . $cache->getKey();
|
||||
|
||||
if ($css) {
|
||||
$file = md5(json_encode($this->css) . $this->js_minify . $this->css_minify . $this->css_rewrite) . '.css';
|
||||
foreach ($this->css as $id => $asset) {
|
||||
if (!$asset['pipeline']) {
|
||||
$this->css_no_pipeline[] = $asset;
|
||||
unset($this->css[$id]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$file = md5(json_encode($this->js) . $this->js_minify . $this->css_minify . $this->css_rewrite) . '.js';
|
||||
foreach ($this->js as $id => $asset) {
|
||||
if (!$asset['pipeline']) {
|
||||
$this->js_no_pipeline[] = $asset;
|
||||
unset($this->js[$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// temporary list of assets to pipeline
|
||||
$temp_css = [];
|
||||
|
||||
$relative_path = "{$this->base_url}" . basename(ASSETS_DIR) . "/{$file}";
|
||||
$absolute_path = ASSETS_DIR . $file;
|
||||
// clear no-pipeline assets lists
|
||||
$this->css_no_pipeline = [];
|
||||
|
||||
$file = md5(json_encode($this->css) . $this->css_minify . $this->css_rewrite . $group) . '.css';
|
||||
|
||||
$relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
|
||||
$absolute_path = $this->assets_dir . $file;
|
||||
|
||||
// If pipeline exist return it
|
||||
if (file_exists($absolute_path)) {
|
||||
return $relative_path . $key;
|
||||
}
|
||||
|
||||
// Remove any non-pipeline files
|
||||
foreach ($this->css as $id => $asset) {
|
||||
if ($asset['group'] == $group) {
|
||||
if (!$asset['pipeline']) {
|
||||
$this->css_no_pipeline[$id] = $asset;
|
||||
} else {
|
||||
$temp_css[$id] = $asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (count($temp_css) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$css_minify = $this->css_minify;
|
||||
|
||||
// If this is a Windows server, and minify_windows is false (default value) skip the
|
||||
@@ -519,23 +670,77 @@ class Assets
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
if ($css) {
|
||||
$buffer = $this->gatherLinks($this->css, CSS_ASSET);
|
||||
if ($css_minify) {
|
||||
$min = new \CSSmin();
|
||||
$buffer = $min->run($buffer);
|
||||
}
|
||||
} else {
|
||||
$buffer = $this->gatherLinks($this->js, JS_ASSET);
|
||||
if ($this->js_minify) {
|
||||
$buffer = \JSMin::minify($buffer);
|
||||
}
|
||||
$buffer = $this->gatherLinks($temp_css, CSS_ASSET);
|
||||
if ($css_minify) {
|
||||
$min = new \CSSmin();
|
||||
$buffer = $min->run($buffer);
|
||||
}
|
||||
|
||||
// Write file
|
||||
file_put_contents($absolute_path, $buffer);
|
||||
if (strlen(trim($buffer)) > 0) {
|
||||
file_put_contents($absolute_path, $buffer);
|
||||
return $relative_path . $key;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $relative_path . $key;
|
||||
/**
|
||||
* Minify and concatenate JS files.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function pipelineJs($group = 'head')
|
||||
{
|
||||
/** @var Cache $cache */
|
||||
$cache = self::getGrav()['cache'];
|
||||
$key = '?' . $cache->getKey();
|
||||
|
||||
// temporary list of assets to pipeline
|
||||
$temp_js = [];
|
||||
|
||||
// clear no-pipeline assets lists
|
||||
$this->js_no_pipeline = [];
|
||||
|
||||
$file = md5(json_encode($this->js) . $this->js_minify . $group) . '.js';
|
||||
|
||||
$relative_path = "{$this->base_url}{$this->assets_url}/{$file}";
|
||||
$absolute_path = $this->assets_dir . $file;
|
||||
|
||||
// If pipeline exist return it
|
||||
if (file_exists($absolute_path)) {
|
||||
return $relative_path . $key;
|
||||
}
|
||||
|
||||
// Remove any non-pipeline files
|
||||
foreach ($this->js as $id => $asset) {
|
||||
if ($asset['group'] == $group) {
|
||||
if (!$asset['pipeline']) {
|
||||
$this->js_no_pipeline[] = $asset;
|
||||
} else {
|
||||
$temp_js[$id] = $asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if nothing found get out of here!
|
||||
if (count($temp_js) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Concatenate files
|
||||
$buffer = $this->gatherLinks($temp_js, JS_ASSET);
|
||||
if ($this->js_minify) {
|
||||
$buffer = \JSMin::minify($buffer);
|
||||
}
|
||||
|
||||
// Write file
|
||||
if (strlen(trim($buffer)) > 0) {
|
||||
file_put_contents($absolute_path, $buffer);
|
||||
return $relative_path . $key;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -662,12 +867,12 @@ class Assets
|
||||
public function addDir($directory, $pattern = self::DEFAULT_REGEX)
|
||||
{
|
||||
// Check if public_dir exists
|
||||
if (!is_dir(ASSETS_DIR)) {
|
||||
if (!is_dir($this->assets_dir)) {
|
||||
throw new Exception('Assets: Public dir not found');
|
||||
}
|
||||
|
||||
// Get files
|
||||
$files = $this->rglob(ASSETS_DIR . DIRECTORY_SEPARATOR . $directory, $pattern, ASSETS_DIR);
|
||||
$files = $this->rglob($this->assets_dir . DIRECTORY_SEPARATOR . $directory, $pattern, $this->assets_dir);
|
||||
|
||||
// No luck? Nothing to do
|
||||
if (!$files) {
|
||||
@@ -705,7 +910,7 @@ class Assets
|
||||
/**
|
||||
* Determine whether a link is local or remote.
|
||||
*
|
||||
* Undestands both "http://" and "https://" as well as protocol agnostic links "//"
|
||||
* Understands both "http://" and "https://" as well as protocol agnostic links "//"
|
||||
*
|
||||
* @param string $link
|
||||
*
|
||||
@@ -767,6 +972,7 @@ class Assets
|
||||
* Download and concatenate the content of several links.
|
||||
*
|
||||
* @param array $links
|
||||
* @param bool $css
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -789,14 +995,20 @@ class Assets
|
||||
} else {
|
||||
// Fix to remove relative dir if grav is in one
|
||||
if (($this->base_url != '/') && (strpos($this->base_url, $link) == 0)) {
|
||||
$relative_path = str_replace($this->base_url, '/', $link);
|
||||
$base_url = '#' . preg_quote($this->base_url, '#') . '#';
|
||||
$relative_path = ltrim(preg_replace($base_url, '/', $link, 1), '/');
|
||||
}
|
||||
|
||||
$relative_dir = dirname($relative_path);
|
||||
$link = ROOT_DIR . $relative_path;
|
||||
}
|
||||
|
||||
$file = ($this->fetch_command instanceof Closure) ? $this->fetch_command->__invoke($link) : file_get_contents($link);
|
||||
$file = ($this->fetch_command instanceof Closure) ? @$this->fetch_command->__invoke($link) : @file_get_contents($link);
|
||||
|
||||
// No file found, skip it...
|
||||
if ($file === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Double check last character being
|
||||
if (!$css) {
|
||||
@@ -845,18 +1057,7 @@ class Assets
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$newpath = array();
|
||||
$paths = explode('/', $old_url);
|
||||
|
||||
foreach ($paths as $path) {
|
||||
if ($path == '..') {
|
||||
$relative_path = dirname($relative_path);
|
||||
} else {
|
||||
$newpath[] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
$new_url = rtrim($this->base_url, '/') . $relative_path . '/' . implode('/', $newpath);
|
||||
$new_url = $this->base_url . ltrim(Utils::normalizePath($relative_path . '/' . $old_url), '/');
|
||||
|
||||
return str_replace($old_url, $new_url, $matches[0]);
|
||||
},
|
||||
@@ -894,7 +1095,7 @@ class Assets
|
||||
*
|
||||
* @param string $directory
|
||||
* @param string $pattern (regex)
|
||||
* @param string $ltrim Will be trimed from the left of the file path
|
||||
* @param string $ltrim Will be trimmed from the left of the file path
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -931,6 +1132,36 @@ class Assets
|
||||
return $this->addDir($directory, self::JS_REGEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of CSS Pipeline
|
||||
*
|
||||
* @param boolean $value
|
||||
*/
|
||||
public function setCssPipeline($value)
|
||||
{
|
||||
$this->css_pipeline = (bool) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of JS Pipeline
|
||||
*
|
||||
* @param boolean $value
|
||||
*/
|
||||
public function setJsPipeline($value)
|
||||
{
|
||||
$this->js_pipeline = (bool) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set's a timestamp for assets
|
||||
*
|
||||
* @param $value
|
||||
*/
|
||||
public function setTimestamp($value)
|
||||
{
|
||||
$this->timestamp = '?'.$value;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return '';
|
||||
|
||||
130
system/src/Grav/Common/Backup/ZipBackup.php
Normal file
130
system/src/Grav/Common/Backup/ZipBackup.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
namespace Grav\Common\Backup;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Inflector;
|
||||
|
||||
/**
|
||||
* The ZipBackup class lets you create simple zip-backups of a grav site
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class ZipBackup
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected static $ignorePaths = [
|
||||
'backup',
|
||||
'cache',
|
||||
'images',
|
||||
'logs'
|
||||
];
|
||||
|
||||
protected static $ignoreFolders = [
|
||||
'.git',
|
||||
'.svn',
|
||||
'.hg',
|
||||
'.idea'
|
||||
];
|
||||
|
||||
public static function backup($destination = null, callable $messager = null)
|
||||
{
|
||||
if (!$destination) {
|
||||
$destination = self::getGrav()['locator']->findResource('backup://', true);
|
||||
|
||||
if (!$destination)
|
||||
throw new \RuntimeException('The backup folder is missing.');
|
||||
|
||||
Folder::mkdir($destination);
|
||||
}
|
||||
|
||||
$name = self::getGrav()['config']->get('site.title', basename(GRAV_ROOT));
|
||||
|
||||
$inflector = new Inflector();
|
||||
|
||||
if (is_dir($destination)) {
|
||||
$date = date('YmdHis', time());
|
||||
$filename = trim($inflector->hyphenize($name), '-') . '-' . $date . '.zip';
|
||||
$destination = rtrim($destination, DS) . DS . $filename;
|
||||
}
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => 'Creating new Backup "' . $destination . '"'
|
||||
]);
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => ''
|
||||
]);
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($destination, \ZipArchive::CREATE);
|
||||
|
||||
static::folderToZip(GRAV_ROOT, $zip, strlen(rtrim(GRAV_ROOT, DS) . DS), $messager);
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'progress',
|
||||
'percentage' => false,
|
||||
'complete' => true
|
||||
]);
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => ''
|
||||
]);
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => 'Saving and compressing archive...'
|
||||
]);
|
||||
|
||||
$zip->close();
|
||||
|
||||
return $destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $folder
|
||||
* @param $zipFile
|
||||
* @param $exclusiveLength
|
||||
* @param $messager
|
||||
*/
|
||||
private static function folderToZip($folder, \ZipArchive &$zipFile, $exclusiveLength, callable $messager = null)
|
||||
{
|
||||
$handle = opendir($folder);
|
||||
while (false !== $f = readdir($handle)) {
|
||||
if ($f != '.' && $f != '..') {
|
||||
$filePath = "$folder/$f";
|
||||
// Remove prefix from file path before add to zip.
|
||||
$localPath = substr($filePath, $exclusiveLength);
|
||||
|
||||
if (in_array($f, static::$ignoreFolders)) {
|
||||
continue;
|
||||
} elseif (in_array($localPath, static::$ignorePaths)) {
|
||||
$zipFile->addEmptyDir($f);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($filePath)) {
|
||||
$zipFile->addFile($filePath, $localPath);
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'progress',
|
||||
'percentage' => false,
|
||||
'complete' => false
|
||||
]);
|
||||
} elseif (is_dir($filePath)) {
|
||||
// Add sub-directory.
|
||||
$zipFile->addEmptyDir($localPath);
|
||||
static::folderToZip($filePath, $zipFile, $exclusiveLength, $messager);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
}
|
||||
@@ -38,4 +38,21 @@ class Browser
|
||||
$version = explode('.', $this->getLongVersion());
|
||||
return intval($version[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the request comes from a human, or from a bot/crawler
|
||||
*/
|
||||
public function isHuman()
|
||||
{
|
||||
$browser = $this->getBrowser();
|
||||
if (empty($browser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('~(bot|crawl)~i', $browser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ use Grav\Common\Filesystem\Folder;
|
||||
*/
|
||||
class Cache extends Getters
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* @var string Cache key.
|
||||
*/
|
||||
@@ -36,6 +38,8 @@ class Cache extends Getters
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
protected $driver_name;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@@ -44,30 +48,30 @@ class Cache extends Getters
|
||||
protected $cache_dir;
|
||||
|
||||
protected static $standard_remove = [
|
||||
'cache/twig/',
|
||||
'cache/doctrine/',
|
||||
'cache/compiled/',
|
||||
'cache/validated-',
|
||||
'images/',
|
||||
'assets/',
|
||||
'cache://twig/',
|
||||
'cache://doctrine/',
|
||||
'cache://compiled/',
|
||||
'cache://validated-',
|
||||
'cache://images',
|
||||
'asset://',
|
||||
];
|
||||
|
||||
protected static $all_remove = [
|
||||
'cache/',
|
||||
'images/',
|
||||
'assets/'
|
||||
'cache://',
|
||||
'cache://images',
|
||||
'asset://'
|
||||
];
|
||||
|
||||
protected static $assets_remove = [
|
||||
'assets/'
|
||||
'asset://'
|
||||
];
|
||||
|
||||
protected static $images_remove = [
|
||||
'images/'
|
||||
'cache://images'
|
||||
];
|
||||
|
||||
protected static $cache_remove = [
|
||||
'cache/'
|
||||
'cache://'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -102,12 +106,16 @@ class Cache extends Getters
|
||||
$this->enabled = (bool) $this->config->get('system.cache.enabled');
|
||||
|
||||
// Cache key allows us to invalidate all cache on configuration changes.
|
||||
$this->key = substr(md5(($prefix ? $prefix : 'g') . $uri->rootUrl(true) . $this->config->key() . GRAV_VERSION), 2, 8);
|
||||
$this->key = ($prefix ? $prefix : 'g') . '-' . substr(md5($uri->rootUrl(true) . $this->config->key() . GRAV_VERSION), 2, 8);
|
||||
|
||||
$this->driver = $this->getCacheDriver();
|
||||
|
||||
// Set the cache namespace to our unique key
|
||||
$this->driver->setNamespace($this->key);
|
||||
|
||||
// Dump Cache state
|
||||
$grav['debugger']->addMessage('Cache: [' . ($this->enabled ? 'true' : 'false') . '] Driver: [' . $this->driver_name . ']');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,6 +142,8 @@ class Cache extends Getters
|
||||
$driver_name = $setting;
|
||||
}
|
||||
|
||||
$this->driver_name = $driver_name;
|
||||
|
||||
switch ($driver_name) {
|
||||
case 'apc':
|
||||
$driver = new \Doctrine\Common\Cache\ApcCache();
|
||||
@@ -155,6 +165,15 @@ class Cache extends Getters
|
||||
$driver->setMemcache($memcache);
|
||||
break;
|
||||
|
||||
case 'redis':
|
||||
$redis = new \Redis();
|
||||
$redis->connect($this->config->get('system.cache.redis.server','localhost'),
|
||||
$this->config->get('system.cache.redis.port', 6379));
|
||||
|
||||
$driver = new \Doctrine\Common\Cache\RedisCache();
|
||||
$driver->setRedis($redis);
|
||||
break;
|
||||
|
||||
default:
|
||||
$driver = new \Doctrine\Common\Cache\FilesystemCache($this->cache_dir);
|
||||
break;
|
||||
@@ -212,7 +231,7 @@ class Cache extends Getters
|
||||
*/
|
||||
public static function clearCache($remove = 'standard')
|
||||
{
|
||||
|
||||
$locator = self::getGrav()['locator'];
|
||||
$output = [];
|
||||
$user_config = USER_DIR . 'config/system.yaml';
|
||||
|
||||
@@ -234,26 +253,33 @@ class Cache extends Getters
|
||||
}
|
||||
|
||||
|
||||
foreach ($remove_paths as $path) {
|
||||
foreach ($remove_paths as $stream) {
|
||||
|
||||
// Convert stream to a real path
|
||||
$path = $locator->findResource($stream, true, true);
|
||||
// Make sure path exists before proceeding, otherwise we would wipe ROOT_DIR
|
||||
if (!$path)
|
||||
throw new \RuntimeException("Stream '{$stream}' not found", 500);
|
||||
|
||||
$anything = false;
|
||||
$files = glob(ROOT_DIR . $path . '*');
|
||||
$files = glob($path . '/*');
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
if (@unlink($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
if (@Folder::delete($file)) {
|
||||
$anything = true;
|
||||
if (is_array($files)) {
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
if (@unlink($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
if (@Folder::delete($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($anything) {
|
||||
$output[] = '<red>Cleared: </red>' . $path . '*';
|
||||
$output[] = '<red>Cleared: </red>' . $path . '/*';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +297,7 @@ class Cache extends Getters
|
||||
|
||||
|
||||
/**
|
||||
* Set the cache lifetime programatically
|
||||
* Set the cache lifetime programmatically
|
||||
*
|
||||
* @param int $future timestamp
|
||||
*/
|
||||
|
||||
55
system/src/Grav/Common/Composer.php
Normal file
55
system/src/Grav/Common/Composer.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Common;
|
||||
|
||||
/**
|
||||
* Offers composer helper methods.
|
||||
*
|
||||
* @author eschmar
|
||||
* @license MIT
|
||||
*/
|
||||
class Composer
|
||||
{
|
||||
/** @const Default composer location */
|
||||
const DEFAULT_PATH = "bin/composer.phar";
|
||||
|
||||
/**
|
||||
* Returns the location of composer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getComposerLocation()
|
||||
{
|
||||
if (!function_exists('shell_exec') || strtolower(substr(PHP_OS, 0, 3)) === 'win') {
|
||||
return self::DEFAULT_PATH;
|
||||
}
|
||||
|
||||
// check for global composer install
|
||||
$path = trim(shell_exec("command -v composer"));
|
||||
|
||||
// fall back to grav bundled composer
|
||||
if (!$path || !preg_match('/(composer|composer\.phar)$/', $path)) {
|
||||
$path = self::DEFAULT_PATH;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
public static function getComposerExecutor()
|
||||
{
|
||||
$executor = PHP_BINARY . ' ';
|
||||
$composer = static::getComposerLocation();
|
||||
|
||||
if ($composer !== static::DEFAULT_PATH && is_executable($composer)) {
|
||||
$file = fopen($composer, 'r');
|
||||
$firstLine = fgets($file);
|
||||
fclose($file);
|
||||
|
||||
if (!preg_match('/^#!.+php/i', $firstLine)) {
|
||||
$executor = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $executor . $composer;
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints as BaseBlueprints;
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* The Blueprints class contains configuration rules.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Blueprints extends BaseBlueprints
|
||||
{
|
||||
protected $grav;
|
||||
protected $files = [];
|
||||
protected $blueprints;
|
||||
|
||||
public function __construct(array $serialized = null, Grav $grav = null)
|
||||
{
|
||||
parent::__construct($serialized);
|
||||
$this->grav = $grav ?: Grav::instance();
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
$blueprints = $locator->findResources('blueprints://config');
|
||||
$plugins = $locator->findResources('plugins://');
|
||||
|
||||
$blueprintFiles = $this->getBlueprintFiles($blueprints, $plugins);
|
||||
|
||||
$this->loadCompiledBlueprints($plugins + $blueprints, $blueprintFiles);
|
||||
}
|
||||
|
||||
protected function loadCompiledBlueprints($blueprints, $blueprintFiles)
|
||||
{
|
||||
$checksum = md5(serialize($blueprints));
|
||||
$filename = CACHE_DIR . 'compiled/blueprints/' . $checksum .'.php';
|
||||
$checksum .= ':'.md5(serialize($blueprintFiles));
|
||||
$class = get_class($this);
|
||||
$file = PhpFile::instance($filename);
|
||||
|
||||
if ($file->exists()) {
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
} else {
|
||||
$cache = null;
|
||||
}
|
||||
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| empty($cache['checksum'])
|
||||
|| empty($cache['$class'])
|
||||
|| $cache['checksum'] != $checksum
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
|
||||
// Load blueprints.
|
||||
$this->blueprints = new Blueprints();
|
||||
foreach ($blueprintFiles as $key => $files) {
|
||||
$this->loadBlueprints($key);
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'checksum' => $checksum,
|
||||
'files' => $blueprintFiles,
|
||||
'data' => $this->blueprints->toArray()
|
||||
];
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
} else {
|
||||
$this->blueprints = new Blueprints($cache['data']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load global blueprints.
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $files
|
||||
*/
|
||||
public function loadBlueprints($key, array $files = null)
|
||||
{
|
||||
if (is_null($files)) {
|
||||
$files = $this->files[$key];
|
||||
}
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->blueprints->embed($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all blueprint files (including plugins).
|
||||
*
|
||||
* @param array $blueprints
|
||||
* @param array $plugins
|
||||
* @return array
|
||||
*/
|
||||
protected function getBlueprintFiles(array $blueprints, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectPlugins($folder, true);
|
||||
}
|
||||
foreach (array_reverse($blueprints) as $folder) {
|
||||
$list += $this->detectConfig($folder, true);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns last modification time.
|
||||
*
|
||||
* @param string $lookup Location to look up from.
|
||||
* @param bool $blueprints
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectPlugins($lookup = SYSTEM_DIR, $blueprints = false)
|
||||
{
|
||||
$find = $blueprints ? 'blueprints.yaml' : '.yaml';
|
||||
$location = $blueprints ? 'blueprintFiles' : 'configFiles';
|
||||
$path = trim(Folder::getRelativePath($lookup), '/');
|
||||
if (isset($this->{$location}[$path])) {
|
||||
return [$path => $this->{$location}[$path]];
|
||||
}
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($lookup)) {
|
||||
$iterator = new \DirectoryIterator($lookup);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$filename = "{$path}/{$name}/" . ($find && $find[0] != '.' ? $find : $name . $find);
|
||||
|
||||
if (is_file($filename)) {
|
||||
$list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->{$location}[$path] = $list;
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns last modification time.
|
||||
*
|
||||
* @param string $lookup Location to look up from.
|
||||
* @param bool $blueprints
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectConfig($lookup = SYSTEM_DIR, $blueprints = false)
|
||||
{
|
||||
$location = $blueprints ? 'blueprintFiles' : 'configFiles';
|
||||
$path = trim(Folder::getRelativePath($lookup), '/');
|
||||
if (isset($this->{$location}[$path])) {
|
||||
return [$path => $this->{$location}[$path]];
|
||||
}
|
||||
|
||||
if (is_dir($lookup)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|',
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
|
||||
}],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($lookup, $options);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
$this->{$location}[$path] = $list;
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
}
|
||||
236
system/src/Grav/Common/Config/CompiledBase.php
Normal file
236
system/src/Grav/Common/Config/CompiledBase.php
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
|
||||
/**
|
||||
* The Compiled base class.
|
||||
*/
|
||||
abstract class CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var string Filename (base name) of the compiled configuration.
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string|bool Configuration checksum.
|
||||
*/
|
||||
public $checksum;
|
||||
|
||||
/**
|
||||
* @var string Cache folder to be used.
|
||||
*/
|
||||
protected $cacheFolder;
|
||||
|
||||
/**
|
||||
* @var array List of files to load.
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* @var mixed Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* @param string $cacheFolder Cache folder to be used.
|
||||
* @param array $files List of files as returned from ConfigFileFinder class.
|
||||
* @param string $path Base path for the file list.
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __construct($cacheFolder, array $files, $path)
|
||||
{
|
||||
if (!$cacheFolder) {
|
||||
throw new \BadMethodCallException('Cache folder not defined.');
|
||||
}
|
||||
|
||||
$this->cacheFolder = $cacheFolder;
|
||||
$this->files = $files;
|
||||
$this->path = $path ? rtrim($path, '\\/') . '/' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename for the compiled PHP file.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function name($name = null)
|
||||
{
|
||||
if (!$this->name) {
|
||||
$this->name = $name ?: md5(json_encode(array_keys($this->files)));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified() {}
|
||||
|
||||
/**
|
||||
* Load the configuration.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function load()
|
||||
{
|
||||
if ($this->object) {
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
$filename = $this->createFilename();
|
||||
if (!$this->loadCompiledFile($filename) && $this->loadFiles()) {
|
||||
$this->saveCompiledFile($filename);
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns checksum from the configuration files.
|
||||
*
|
||||
* You can set $this->checksum = false to disable this check.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function checksum()
|
||||
{
|
||||
if (!isset($this->checksum)) {
|
||||
$this->checksum = md5(json_encode($this->files) . $this->version);
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
protected function createFilename()
|
||||
{
|
||||
return "{$this->cacheFolder}/{$this->name()->name}.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
abstract protected function createObject(array $data = []);
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
abstract protected function finalizeObject();
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
abstract protected function loadFile($name, $filename);
|
||||
|
||||
/**
|
||||
* Load and join all configuration files.
|
||||
*
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected function loadFiles()
|
||||
{
|
||||
$this->createObject();
|
||||
|
||||
$list = array_reverse($this->files);
|
||||
foreach ($list as $files) {
|
||||
foreach ($files as $name => $item) {
|
||||
$this->loadFile($name, $this->path . $item['file']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->finalizeObject();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load compiled file.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected function loadCompiledFile($filename)
|
||||
{
|
||||
if (!file_exists($filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache = include $filename;
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['data'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['@class'] != get_class($this)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if ($cache['checksum'] !== $this->checksum()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->createObject($cache['data']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save compiled file.
|
||||
*
|
||||
* @param string $filename
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function saveCompiledFile($filename)
|
||||
{
|
||||
$file = PhpFile::instance($filename);
|
||||
|
||||
// Attempt to lock the file for writing.
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
}
|
||||
|
||||
if ($file->locked() === false) {
|
||||
// File was already locked by another process.
|
||||
return;
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => get_class($this),
|
||||
'timestamp' => time(),
|
||||
'checksum' => $this->checksum(),
|
||||
'files' => $this->files,
|
||||
'data' => $this->object->toArray()
|
||||
];
|
||||
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
$file->free();
|
||||
|
||||
$this->modified();
|
||||
}
|
||||
}
|
||||
49
system/src/Grav/Common/Config/CompiledBlueprints.php
Normal file
49
system/src/Grav/Common/Config/CompiledBlueprints.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
|
||||
/**
|
||||
* The Compiled Blueprints class.
|
||||
*/
|
||||
class CompiledBlueprints extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Blueprints Blueprints object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
$this->object = new Blueprints($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject() {}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$this->object->embed($name, $file->content(), '/');
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
98
system/src/Grav/Common/Config/CompiledConfig.php
Normal file
98
system/src/Grav/Common/Config/CompiledConfig.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
|
||||
/**
|
||||
* The Compiled Configuration class.
|
||||
*/
|
||||
class CompiledConfig extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Config Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* @var callable Blueprints loader.
|
||||
*/
|
||||
protected $callable;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $withDefaults;
|
||||
|
||||
/**
|
||||
* Set blueprints for the configuration.
|
||||
*
|
||||
* @param callable $blueprints
|
||||
* @return $this
|
||||
*/
|
||||
public function setBlueprints(callable $blueprints)
|
||||
{
|
||||
$this->callable = $blueprints;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $withDefaults
|
||||
* @return mixed
|
||||
*/
|
||||
public function load($withDefaults = false)
|
||||
{
|
||||
$this->withDefaults = $withDefaults;
|
||||
|
||||
return parent::load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
if ($this->withDefaults && empty($data) && is_callable($this->callable)) {
|
||||
$blueprints = $this->callable;
|
||||
$data = $blueprints()->getDefaults();
|
||||
}
|
||||
|
||||
$this->object = new Config($data, $this->callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject()
|
||||
{
|
||||
$this->object->checksum($this->checksum());
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$this->object->modified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$this->object->join($name, $file->content(), '/');
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
64
system/src/Grav/Common/Config/CompiledLanguages.php
Normal file
64
system/src/Grav/Common/Config/CompiledLanguages.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
|
||||
/**
|
||||
* The Compiled Languages class.
|
||||
*/
|
||||
class CompiledLanguages extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Languages Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
$this->object = new Languages($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject()
|
||||
{
|
||||
$this->object->checksum($this->checksum());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$this->object->modified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
if (preg_match('|languages\.yaml$|', $filename)) {
|
||||
$this->object->mergeRecursive($file->content());
|
||||
} else {
|
||||
$this->object->join($name, $file->content(), '/');
|
||||
}
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Data\Data;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
use Grav\Common\Service\ConfigServiceProvider;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
@@ -16,368 +14,84 @@ use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
*/
|
||||
class Config extends Data
|
||||
{
|
||||
protected $grav;
|
||||
protected $streams = [
|
||||
'system' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['system'],
|
||||
]
|
||||
],
|
||||
'user' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user'],
|
||||
]
|
||||
],
|
||||
'blueprints' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://blueprints', 'system/blueprints'],
|
||||
]
|
||||
],
|
||||
'config' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://config', 'system/config'],
|
||||
]
|
||||
],
|
||||
'plugins' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'plugin' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'themes' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://themes'],
|
||||
]
|
||||
],
|
||||
'cache' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['cache'],
|
||||
'images' => ['images']
|
||||
]
|
||||
],
|
||||
'log' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['logs']
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
protected $blueprintFiles = [];
|
||||
protected $configFiles = [];
|
||||
protected $checksum;
|
||||
protected $timestamp;
|
||||
|
||||
protected $configLookup;
|
||||
protected $blueprintLookup;
|
||||
protected $pluginLookup;
|
||||
|
||||
protected $finder;
|
||||
protected $environment;
|
||||
protected $messages = [];
|
||||
|
||||
public function __construct(array $items = array(), Grav $grav = null, $environment = null)
|
||||
{
|
||||
$this->grav = $grav ?: Grav::instance();
|
||||
$this->finder = new ConfigFinder;
|
||||
$this->environment = $environment ?: 'localhost';
|
||||
$this->messages[] = 'Environment Name: ' . $this->environment;
|
||||
|
||||
if (isset($items['@class'])) {
|
||||
if ($items['@class'] != get_class($this)) {
|
||||
throw new \InvalidArgumentException('Unrecognized config cache file!');
|
||||
}
|
||||
// Loading pre-compiled configuration.
|
||||
$this->timestamp = (int) $items['timestamp'];
|
||||
$this->checksum = $items['checksum'];
|
||||
$this->items = (array) $items['data'];
|
||||
} else {
|
||||
// Make sure that
|
||||
if (!isset($items['streams']['schemes'])) {
|
||||
$items['streams']['schemes'] = [];
|
||||
}
|
||||
$items['streams']['schemes'] += $this->streams;
|
||||
|
||||
$items = $this->autoDetectEnvironmentConfig($items);
|
||||
$this->messages[] = $items['streams']['schemes']['config']['prefixes'][''];
|
||||
|
||||
parent::__construct($items);
|
||||
}
|
||||
$this->check();
|
||||
}
|
||||
protected $modified = false;
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->checksum();
|
||||
}
|
||||
|
||||
public function checksum($checksum = null)
|
||||
{
|
||||
if ($checksum !== null) {
|
||||
$this->checksum = $checksum;
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
public function modified($modified = null)
|
||||
{
|
||||
if ($modified !== null) {
|
||||
$this->modified = $modified;
|
||||
}
|
||||
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
public function reload()
|
||||
{
|
||||
$this->check();
|
||||
$this->init();
|
||||
$grav = Grav::instance();
|
||||
|
||||
// Load new configuration.
|
||||
$config = ConfigServiceProvider::load($grav);
|
||||
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = $grav['debugger'];
|
||||
|
||||
if ($config->modified()) {
|
||||
// Update current configuration.
|
||||
$this->items = $config->toArray();
|
||||
$this->checksum($config->checksum());
|
||||
$this->modified(true);
|
||||
|
||||
$debugger->addMessage('Configuration was changed and saved.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function check()
|
||||
{
|
||||
$streams = isset($this->items['streams']['schemes']) ? $this->items['streams']['schemes'] : null;
|
||||
if (!is_array($streams)) {
|
||||
throw new \InvalidArgumentException('Configuration is missing streams.schemes!');
|
||||
}
|
||||
$diff = array_keys(array_diff_key($this->streams, $streams));
|
||||
if ($diff) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Configuration is missing keys %s from streams.schemes!', implode(', ', $diff))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function debug()
|
||||
{
|
||||
foreach ($this->messages as $message) {
|
||||
$this->grav['debugger']->addMessage($message);
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = Grav::instance()['debugger'];
|
||||
|
||||
$debugger->addMessage('Environment Name: ' . $this->environment);
|
||||
if ($this->modified()) {
|
||||
$debugger->addMessage('Configuration reloaded and cached.');
|
||||
}
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $this->grav['locator'];
|
||||
|
||||
$this->configLookup = $locator->findResources('config://');
|
||||
$this->blueprintLookup = $locator->findResources('blueprints://config');
|
||||
$this->pluginLookup = $locator->findResources('plugins://');
|
||||
|
||||
if (!isset($this->checksum)) {
|
||||
$this->messages[] = 'No cached configuration, compiling new configuration..';
|
||||
} elseif ($this->checksum() != $this->checksum) {
|
||||
$this->messages[] = 'Configuration checksum mismatch, reloading configuration..';
|
||||
} else {
|
||||
$this->messages[] = 'Configuration checksum matches, using cached version.';
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loadCompiledBlueprints($this->blueprintLookup, $this->pluginLookup, 'master');
|
||||
$this->loadCompiledConfig($this->configLookup, $this->pluginLookup, 'master');
|
||||
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
public function checksum()
|
||||
{
|
||||
$checkBlueprints = $this->get('system.cache.check.blueprints', false);
|
||||
$checkConfig = $this->get('system.cache.check.config', true);
|
||||
$checkSystem = $this->get('system.cache.check.system', true);
|
||||
|
||||
if (!$checkBlueprints && !$checkConfig && !$checkSystem) {
|
||||
$this->messages[] = 'Skip configuration timestamp check.';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate checksum according to the configuration settings.
|
||||
if (!$checkConfig) {
|
||||
$this->messages[] = 'Check configuration timestamps from system.yaml files.';
|
||||
// Just check changes in system.yaml files and ignore all the other files.
|
||||
$cc = $checkSystem ? $this->finder->locateConfigFile($this->configLookup, 'system') : [];
|
||||
} else {
|
||||
$this->messages[] = 'Check configuration timestamps from all configuration files.';
|
||||
// Check changes in all configuration files.
|
||||
$cc = $this->finder->locateConfigFiles($this->configLookup, $this->pluginLookup);
|
||||
}
|
||||
|
||||
if ($checkBlueprints) {
|
||||
$this->messages[] = 'Check blueprint timestamps from all blueprint files.';
|
||||
$cb = $this->finder->locateBlueprintFiles($this->blueprintLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cb = [];
|
||||
}
|
||||
|
||||
return md5(json_encode([$cc, $cb]));
|
||||
}
|
||||
|
||||
protected function autoDetectEnvironmentConfig($items)
|
||||
{
|
||||
$environment = $this->environment;
|
||||
$env_stream = 'user://'.$environment.'/config';
|
||||
|
||||
if (file_exists(USER_DIR.$environment.'/config')) {
|
||||
array_unshift($items['streams']['schemes']['config']['prefixes'][''], $env_stream);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
protected function loadCompiledBlueprints($blueprints, $plugins, $filename = null)
|
||||
{
|
||||
$checksum = md5(json_encode($blueprints));
|
||||
$filename = $filename
|
||||
? CACHE_DIR . 'compiled/blueprints/' . $filename . '-' . $this->environment . '.php'
|
||||
: CACHE_DIR . 'compiled/blueprints/' . $checksum . '-' . $this->environment . '.php';
|
||||
$file = PhpFile::instance($filename);
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
$blueprintFiles = $this->finder->locateBlueprintFiles($blueprints, $plugins);
|
||||
$checksum .= ':'.md5(json_encode($blueprintFiles));
|
||||
$class = get_class($this);
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['checksum'] != $checksum
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
|
||||
// Load blueprints.
|
||||
$this->blueprints = new Blueprints;
|
||||
foreach ($blueprintFiles as $files) {
|
||||
$this->loadBlueprintFiles($files);
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'checksum' => $checksum,
|
||||
'files' => $blueprintFiles,
|
||||
'data' => $this->blueprints->toArray()
|
||||
];
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$this->messages[] = 'Saving compiled blueprints.';
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
} else {
|
||||
$this->blueprints = new Blueprints($cache['data']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadCompiledConfig($configs, $plugins, $filename = null)
|
||||
{
|
||||
$checksum = md5(json_encode($configs));
|
||||
$filename = $filename
|
||||
? CACHE_DIR . 'compiled/config/' . $filename . '-' . $this->environment . '.php'
|
||||
: CACHE_DIR . 'compiled/config/' . $checksum . '-' . $this->environment . '.php';
|
||||
$file = PhpFile::instance($filename);
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
$configFiles = $this->finder->locateConfigFiles($configs, $plugins);
|
||||
$checksum .= ':'.md5(json_encode($configFiles));
|
||||
$class = get_class($this);
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['checksum'] != $checksum
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
|
||||
// Load configuration.
|
||||
foreach ($configFiles as $files) {
|
||||
$this->loadConfigFiles($files);
|
||||
}
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'timestamp' => time(),
|
||||
'checksum' => $this->checksum(),
|
||||
'data' => $this->toArray()
|
||||
];
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$this->messages[] = 'Saving compiled configuration.';
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
$this->items = $cache['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load blueprints.
|
||||
*
|
||||
* @param array $files
|
||||
*/
|
||||
public function loadBlueprintFiles(array $files)
|
||||
{
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->blueprints->embed($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load configuration.
|
||||
*
|
||||
* @param array $files
|
||||
*/
|
||||
public function loadConfigFiles(array $files)
|
||||
{
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->join($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
* @param UniformResourceLocator $locator
|
||||
*/
|
||||
public function initializeLocator(UniformResourceLocator $locator)
|
||||
{
|
||||
$locator->reset();
|
||||
|
||||
$schemes = (array) $this->get('streams.schemes', []);
|
||||
|
||||
foreach ($schemes as $scheme => $config) {
|
||||
if (isset($config['paths'])) {
|
||||
$locator->addPath($scheme, '', $config['paths']);
|
||||
}
|
||||
if (isset($config['prefixes'])) {
|
||||
foreach ($config['prefixes'] as $prefix => $paths) {
|
||||
$locator->addPath($scheme, $prefix, $paths);
|
||||
}
|
||||
$setup = Grav::instance()['setup']->toArray();
|
||||
foreach ($setup as $key => $value) {
|
||||
if ($key === 'streams' || !is_array($value)) {
|
||||
// Optimized as streams and simple values are fully defined in setup.
|
||||
$this->items[$key] = $value;
|
||||
} else {
|
||||
$this->joinDefaults($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available streams and their types from the configuration.
|
||||
*
|
||||
* @return array
|
||||
* @return mixed
|
||||
* @deprecated
|
||||
*/
|
||||
public function getStreams()
|
||||
public function getLanguages()
|
||||
{
|
||||
$schemes = [];
|
||||
foreach ((array) $this->get('streams.schemes') as $scheme => $config) {
|
||||
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
|
||||
if ($type[0] != '\\') {
|
||||
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
|
||||
}
|
||||
|
||||
$schemes[$scheme] = $type;
|
||||
}
|
||||
|
||||
return $schemes;
|
||||
return Grav::instance()['languages'];
|
||||
}
|
||||
}
|
||||
|
||||
258
system/src/Grav/Common/Config/ConfigFileFinder.php
Normal file
258
system/src/Grav/Common/Config/ConfigFileFinder.php
Normal file
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
|
||||
/**
|
||||
* The Configuration & Blueprints Finder class.
|
||||
*/
|
||||
class ConfigFileFinder
|
||||
{
|
||||
protected $base = '';
|
||||
|
||||
/**
|
||||
* @param string $base
|
||||
* @return $this
|
||||
*/
|
||||
public function setBase($base)
|
||||
{
|
||||
$this->base = $base ? "{$base}/" : '';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all locations for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function locateFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$list += $this->detectRecursive($folder, $pattern, $levels);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all locations for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function getFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
$files = $this->detectRecursive($folder, $pattern, $levels);
|
||||
|
||||
$list += $files[trim($path, '/')];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all paths for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function listFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$list = array_merge_recursive($list, $this->detectAll($folder, $pattern, $levels));
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find filename from a list of folders.
|
||||
*
|
||||
* Note: Only finds the last override.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param array $folders
|
||||
* @return array
|
||||
*/
|
||||
public function locateFileInFolder($filename, array $folders)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$list += $this->detectInFolder($folder, $filename);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find filename from a list of folders.
|
||||
*
|
||||
* @param array $folders
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
public function locateInFolders(array $folders, $filename = null)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
$list[$path] = $this->detectInFolder($folder, $filename);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all existing locations for a single file with a timestamp.
|
||||
*
|
||||
* @param array $paths Filesystem paths to look up from.
|
||||
* @param string $name Configuration file to be located.
|
||||
* @param string $ext File extension (optional, defaults to .yaml).
|
||||
* @return array
|
||||
*/
|
||||
public function locateFile(array $paths, $name, $ext = '.yaml')
|
||||
{
|
||||
$filename = preg_replace('|[.\/]+|', '/', $name) . $ext;
|
||||
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_file("{$folder}/{$filename}")) {
|
||||
$modified = filemtime("{$folder}/{$filename}");
|
||||
} else {
|
||||
$modified = 0;
|
||||
}
|
||||
$basename = $this->base . $name;
|
||||
$list[$path] = [$basename => ['file' => "{$path}/{$filename}", 'modified' => $modified]];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all directories with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectRecursive($folder, $pattern, $levels)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'levels' => $levels,
|
||||
'compare' => 'Filename',
|
||||
'pattern' => $pattern,
|
||||
'filters' => [
|
||||
'pre-key' => $this->base,
|
||||
'key' => $pattern,
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
|
||||
ksort($list);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all directories with the lookup file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $lookup Filename to be located (defaults to directory name).
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectInFolder($folder, $lookup = null)
|
||||
{
|
||||
$folder = rtrim($folder, '/');
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
$base = $path === $folder ? '' : ($path ? substr($folder, 0, -strlen($path)) : $folder . '/');
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \DirectoryIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$find = ($lookup ?: $name) . '.yaml';
|
||||
$filename = "{$path}/{$name}/{$find}";
|
||||
|
||||
if (file_exists($base . $filename)) {
|
||||
$basename = $this->base . $name;
|
||||
$list[$basename] = ['file' => $filename, 'modified' => filemtime($base . $filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectAll($folder, $pattern, $levels)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'levels' => $levels,
|
||||
'compare' => 'Filename',
|
||||
'pattern' => $pattern,
|
||||
'filters' => [
|
||||
'pre-key' => $this->base,
|
||||
'key' => $pattern,
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ["{$path}/{$file->getSubPathname()}" => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
|
||||
ksort($list);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
|
||||
/**
|
||||
* The Configuration Finder class.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class ConfigFinder
|
||||
{
|
||||
/**
|
||||
* Get all locations for blueprint files (including plugins).
|
||||
*
|
||||
* @param array $blueprints
|
||||
* @param array $plugins
|
||||
* @return array
|
||||
*/
|
||||
public function locateBlueprintFiles(array $blueprints, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectInFolder($folder, 'blueprints');
|
||||
}
|
||||
foreach (array_reverse($blueprints) as $folder) {
|
||||
$list += $this->detectRecursive($folder);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all locations for configuration files (including plugins).
|
||||
*
|
||||
* @param array $configs
|
||||
* @param array $plugins
|
||||
* @return array
|
||||
*/
|
||||
public function locateConfigFiles(array $configs, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectInFolder($folder);
|
||||
}
|
||||
foreach (array_reverse($configs) as $folder) {
|
||||
$list += $this->detectRecursive($folder);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all locations for a single configuration file.
|
||||
*
|
||||
* @param array $folders Locations to look up from.
|
||||
* @param string $name Filename to be located.
|
||||
* @return array
|
||||
*/
|
||||
public function locateConfigFile(array $folders, $name)
|
||||
{
|
||||
$filename = "{$name}.yaml";
|
||||
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_file("{$folder}/{$filename}")) {
|
||||
$modified = filemtime("{$folder}/{$filename}");
|
||||
} else {
|
||||
$modified = 0;
|
||||
}
|
||||
$list[$path] = [$name => ['file' => "{$path}/{$filename}", 'modified' => $modified]];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $lookup Filename to be located.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectInFolder($folder, $lookup = null)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \DirectoryIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$find = ($lookup ?: $name) . '.yaml';
|
||||
$filename = "{$path}/{$name}/$find";
|
||||
|
||||
if (file_exists($filename)) {
|
||||
$list["plugins/{$name}"] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectRecursive($folder)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|',
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
}
|
||||
44
system/src/Grav/Common/Config/Languages.php
Normal file
44
system/src/Grav/Common/Config/Languages.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
|
||||
/**
|
||||
* The Languages class contains configuration rules.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Languages extends Data
|
||||
{
|
||||
public function checksum($checksum = null)
|
||||
{
|
||||
if ($checksum !== null) {
|
||||
$this->checksum = $checksum;
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
public function modified($modified = null)
|
||||
{
|
||||
if ($modified !== null) {
|
||||
$this->modified = $modified;
|
||||
}
|
||||
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
public function reformat()
|
||||
{
|
||||
if (isset($this->items['plugins'])) {
|
||||
$this->items = array_merge_recursive($this->items, $this->items['plugins']);
|
||||
unset($this->items['plugins']);
|
||||
}
|
||||
}
|
||||
|
||||
public function mergeRecursive(array $data)
|
||||
{
|
||||
$this->items = array_merge_recursive($this->items, $data);
|
||||
}
|
||||
}
|
||||
254
system/src/Grav/Common/Config/Setup.php
Normal file
254
system/src/Grav/Common/Config/Setup.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Utils;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Setup extends Data
|
||||
{
|
||||
protected $streams = [
|
||||
'system' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['system'],
|
||||
]
|
||||
],
|
||||
'user' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user'],
|
||||
]
|
||||
],
|
||||
'environment' => [
|
||||
'type' => 'ReadOnlyStream'
|
||||
// If not defined, environment will be set up in the constructor.
|
||||
],
|
||||
'asset' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['assets'],
|
||||
]
|
||||
],
|
||||
'blueprints' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://blueprints', 'user://blueprints', 'system/blueprints'],
|
||||
]
|
||||
],
|
||||
'config' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://config', 'user://config', 'system/config'],
|
||||
]
|
||||
],
|
||||
'plugins' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'plugin' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'themes' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://themes'],
|
||||
]
|
||||
],
|
||||
'languages' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://languages', 'user://languages', 'system/languages'],
|
||||
]
|
||||
],
|
||||
'cache' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['cache'],
|
||||
'images' => ['images']
|
||||
]
|
||||
],
|
||||
'log' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['logs']
|
||||
]
|
||||
],
|
||||
'backup' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['backup']
|
||||
]
|
||||
],
|
||||
'image' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://images', 'system://images']
|
||||
]
|
||||
],
|
||||
'page' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://pages']
|
||||
]
|
||||
],
|
||||
'account' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://accounts']
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$environment = $container['uri']->environment();
|
||||
if (!$environment) {
|
||||
$environment = 'localhost';
|
||||
}
|
||||
|
||||
// Pre-load setup.php which contains our initial configuration.
|
||||
// Configuration may contain dynamic parts, which is why we need to always load it.
|
||||
$file = GRAV_ROOT . '/setup.php';
|
||||
$setup = is_file($file) ? (array) include $file : [];
|
||||
|
||||
// Add default streams defined in beginning of the class.
|
||||
if (!isset($setup['streams']['schemes'])) {
|
||||
$setup['streams']['schemes'] = [];
|
||||
}
|
||||
$setup['streams']['schemes'] += $this->streams;
|
||||
|
||||
// Initialize class.
|
||||
parent::__construct($setup);
|
||||
|
||||
// Set up environment.
|
||||
$this->def('environment', $environment);
|
||||
$this->def('streams.schemes.environment.prefixes', ['' => ["user://{$this->environment}"]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$locator = new UniformResourceLocator(GRAV_ROOT);
|
||||
$files = [];
|
||||
|
||||
$guard = 5;
|
||||
do {
|
||||
$check = $files;
|
||||
$this->initializeLocator($locator);
|
||||
$files = $locator->findResources('config://streams.yaml');
|
||||
|
||||
if ($check === $files) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update streams.
|
||||
foreach ($files as $path) {
|
||||
$file = CompiledYamlFile::instance($path);
|
||||
$content = $file->content();
|
||||
if (!empty($content['schemes'])) {
|
||||
$this->items['streams']['schemes'] = $content['schemes'] + $this->items['streams']['schemes'];
|
||||
}
|
||||
}
|
||||
} while (--$guard);
|
||||
|
||||
if (!$guard) {
|
||||
throw new \RuntimeException('Setup: Configuration reload loop detected!');
|
||||
}
|
||||
|
||||
// Make sure we have valid setup.
|
||||
$this->check($locator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
* @param UniformResourceLocator $locator
|
||||
*/
|
||||
public function initializeLocator(UniformResourceLocator $locator)
|
||||
{
|
||||
$locator->reset();
|
||||
|
||||
$schemes = (array) $this->get('streams.schemes', []);
|
||||
|
||||
foreach ($schemes as $scheme => $config) {
|
||||
if (isset($config['paths'])) {
|
||||
$locator->addPath($scheme, '', $config['paths']);
|
||||
}
|
||||
if (isset($config['prefixes'])) {
|
||||
foreach ($config['prefixes'] as $prefix => $paths) {
|
||||
$locator->addPath($scheme, $prefix, $paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available streams and their types from the configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getStreams()
|
||||
{
|
||||
$schemes = [];
|
||||
foreach ((array) $this->get('streams.schemes') as $scheme => $config) {
|
||||
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
|
||||
if ($type[0] != '\\') {
|
||||
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
|
||||
}
|
||||
|
||||
$schemes[$scheme] = $type;
|
||||
}
|
||||
|
||||
return $schemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UniformResourceLocator $locator
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function check(UniformResourceLocator $locator)
|
||||
{
|
||||
$streams = isset($this->items['streams']['schemes']) ? $this->items['streams']['schemes'] : null;
|
||||
if (!is_array($streams)) {
|
||||
throw new \InvalidArgumentException('Configuration is missing streams.schemes!');
|
||||
}
|
||||
$diff = array_keys(array_diff_key($this->streams, $streams));
|
||||
if ($diff) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Configuration is missing keys %s from streams.schemes!', implode(', ', $diff))
|
||||
);
|
||||
}
|
||||
|
||||
if (!$locator->findResource('environment://config', true)) {
|
||||
// If environment does not have its own directory, remove it from the lookup.
|
||||
$this->set('streams.schemes.environment.prefixes', ['config' => []]);
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
// Create security.yaml if it doesn't exist.
|
||||
$filename = $locator->findResource('config://security.yaml', true, true);
|
||||
$file = YamlFile::instance($filename);
|
||||
if (!$file->exists()) {
|
||||
$file->save(['salt' => Utils::generateRandomString(14)]);
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
|
||||
/**
|
||||
* Blueprint handles the inside logic of blueprints.
|
||||
@@ -9,9 +12,9 @@ use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Blueprint
|
||||
class Blueprint implements \ArrayAccess, ExportInterface
|
||||
{
|
||||
use Export, DataMutatorTrait;
|
||||
use Export, NestedArrayAccessWithGetters, GravTrait;
|
||||
|
||||
public $name;
|
||||
|
||||
@@ -75,7 +78,9 @@ class Blueprint
|
||||
try {
|
||||
$this->validateArray($data, $this->nested);
|
||||
} catch (\RuntimeException $e) {
|
||||
throw new \RuntimeException(sprintf('Page validation failed: %s', $e->getMessage()));
|
||||
$language = self::getGrav()['language'];
|
||||
$message = sprintf($language->translate('FORM.VALIDATION_FAIL', null, true) . ' %s', $e->getMessage());
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +122,17 @@ class Blueprint
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
return $this->extraArray($data, $this->nested, $prefix);
|
||||
$rules = $this->nested;
|
||||
|
||||
// Drill down to prefix level
|
||||
if (!empty($prefix)) {
|
||||
$parts = explode('.', trim($prefix, '.'));
|
||||
foreach ($parts as $part) {
|
||||
$rules = isset($rules[$part]) ? $rules[$part] : [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->extraArray($data, $rules, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +301,7 @@ class Blueprint
|
||||
// Item has been defined in blueprints.
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$array += $this->ExtraArray($field, $val, $prefix);
|
||||
$array += $this->ExtraArray($field, $val, $prefix . $key . '.');
|
||||
} else {
|
||||
// Undefined/extra item.
|
||||
$array[$prefix.$key] = $field;
|
||||
@@ -296,81 +311,105 @@ class Blueprint
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all field definitions from the blueprints.
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $params
|
||||
* @param string $prefix
|
||||
* @param array $current
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
|
||||
{
|
||||
// Go though all the fields in current level.
|
||||
foreach ($fields as $key => &$field) {
|
||||
$current[$key] = &$field;
|
||||
// Set name from the array key.
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
* Gets all field definitions from the blueprints.
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $params
|
||||
* @param string $prefix
|
||||
* @param array $current
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
|
||||
{
|
||||
// Go though all the fields in current level.
|
||||
foreach ($fields as $key => &$field) {
|
||||
$current[$key] = &$field;
|
||||
// Set name from the array key.
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
// Recursively get all the nested fields.
|
||||
$newParams = array_intersect_key($this->filter, $field);
|
||||
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
|
||||
} else {
|
||||
// Add rule.
|
||||
if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) {
|
||||
// Recursively get all the nested fields.
|
||||
$newParams = array_intersect_key($this->filter, $field);
|
||||
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
|
||||
} else if ($field['type'] !== 'ignore') {
|
||||
$this->rules[$prefix . $key] = &$field;
|
||||
$this->addProperty($prefix . $key);
|
||||
|
||||
foreach ($field as $name => $value) {
|
||||
// Support nested blueprints.
|
||||
if ($this->context && $name == '@import') {
|
||||
$values = (array) $value;
|
||||
if (!isset($field['fields'])) {
|
||||
$field['fields'] = array();
|
||||
}
|
||||
foreach ($values as $bname) {
|
||||
$b = $this->context->get($bname);
|
||||
$field['fields'] = array_merge($field['fields'], $b->fields());
|
||||
}
|
||||
}
|
||||
|
||||
// Support for callable data values.
|
||||
elseif (substr($name, 0, 6) == '@data-') {
|
||||
$property = substr($name, 6);
|
||||
if (is_array($value)) {
|
||||
$func = array_shift($value);
|
||||
} else {
|
||||
$func = $value;
|
||||
$value = array();
|
||||
}
|
||||
list($o, $f) = preg_split('/::/', $func);
|
||||
if (!$f && function_exists($o)) {
|
||||
$data = call_user_func_array($o, $value);
|
||||
} elseif ($f && method_exists($o, $f)) {
|
||||
$data = call_user_func_array(array($o, $f), $value);
|
||||
}
|
||||
|
||||
// If function returns a value,
|
||||
if (isset($data)) {
|
||||
if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
|
||||
// Combine field and @data-field together.
|
||||
$field[$property] += $data;
|
||||
} else {
|
||||
// Or create/replace field with @data-field.
|
||||
$field[$property] = $data;
|
||||
}
|
||||
}
|
||||
if ($field['type'] === 'list') {
|
||||
// we loop through list to get the actual field
|
||||
foreach($field['fields'] as $subName => &$subField) {
|
||||
$this->parseFormField($subField);
|
||||
}
|
||||
} else {
|
||||
$this->parseFormField($field);
|
||||
}
|
||||
|
||||
// Initialize predefined validation rule.
|
||||
if (isset($field['validate']['rule'])) {
|
||||
if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
|
||||
$field['validate'] += $this->getRule($field['validate']['rule']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Parses individual field definition
|
||||
*
|
||||
* @param array $field
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormField(&$field) {
|
||||
foreach ($field as $name => $value) {
|
||||
// Support nested blueprints.
|
||||
if ($this->context && $name == '@import') {
|
||||
$values = (array) $value;
|
||||
if (!isset($field['fields'])) {
|
||||
$field['fields'] = array();
|
||||
}
|
||||
foreach ($values as $bname) {
|
||||
$b = $this->context->get($bname);
|
||||
$field['fields'] = array_merge($field['fields'], $b->fields());
|
||||
}
|
||||
}
|
||||
|
||||
// Support for callable data values.
|
||||
elseif (substr($name, 0, 6) == '@data-') {
|
||||
$property = substr($name, 6);
|
||||
if (is_array($value)) {
|
||||
$func = array_shift($value);
|
||||
} else {
|
||||
$func = $value;
|
||||
$value = array();
|
||||
}
|
||||
list($o, $f) = preg_split('/::/', $func);
|
||||
if (!$f && function_exists($o)) {
|
||||
$data = call_user_func_array($o, $value);
|
||||
} elseif ($f && method_exists($o, $f)) {
|
||||
$data = call_user_func_array(array($o, $f), $value);
|
||||
}
|
||||
|
||||
// If function returns a value,
|
||||
if (isset($data)) {
|
||||
if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
|
||||
// Combine field and @data-field together.
|
||||
$field[$property] += $data;
|
||||
} else {
|
||||
// Or create/replace field with @data-field.
|
||||
$field[$property] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif (substr($name, 0, 8) == '@config-') {
|
||||
$property = substr($name, 8);
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = self::getGrav()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add property to the definition.
|
||||
@@ -425,7 +464,10 @@ class Blueprint
|
||||
if (isset($field['validate']['required'])
|
||||
&& $field['validate']['required'] === true
|
||||
&& empty($data[$name])) {
|
||||
throw new \RuntimeException("Missing required field: {$field['name']}");
|
||||
$value = isset($field['label']) ? $field['label'] : $field['name'];
|
||||
$language = self::getGrav()['language'];
|
||||
$message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $value);
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\GravTrait;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* Blueprints class keeps track on blueprint instances.
|
||||
@@ -11,6 +13,8 @@ use Grav\Common\File\CompiledYamlFile;
|
||||
*/
|
||||
class Blueprints
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected $search;
|
||||
protected $types;
|
||||
protected $instances = array();
|
||||
@@ -20,11 +24,7 @@ class Blueprints
|
||||
*/
|
||||
public function __construct($search)
|
||||
{
|
||||
if (!is_string($search)) {
|
||||
$this->search = $search;
|
||||
} else {
|
||||
$this->search = rtrim($search, '\\/') . '/';
|
||||
}
|
||||
$this->search = $search;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,8 +37,18 @@ class Blueprints
|
||||
public function get($type)
|
||||
{
|
||||
if (!isset($this->instances[$type])) {
|
||||
$parents = [];
|
||||
if (is_string($this->search)) {
|
||||
$filename = $this->search . $type . YAML_EXT;
|
||||
|
||||
// Check if search is a stream and resolve the path.
|
||||
if (strpos($filename, '://')) {
|
||||
$grav = static::getGrav();
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$parents = $locator->findResources($filename);
|
||||
$filename = array_shift($parents);
|
||||
}
|
||||
} else {
|
||||
$filename = isset($this->search[$type]) ? $this->search[$type] : '';
|
||||
}
|
||||
@@ -55,8 +65,41 @@ class Blueprints
|
||||
if (isset($blueprints['@extends'])) {
|
||||
// Extend blueprint by other blueprints.
|
||||
$extends = (array) $blueprints['@extends'];
|
||||
foreach ($extends as $extendType) {
|
||||
$blueprint->extend($this->get($extendType));
|
||||
|
||||
if (is_string(key($extends))) {
|
||||
$extends = [ $extends ];
|
||||
}
|
||||
|
||||
foreach ($extends as $extendConfig) {
|
||||
$extendType = !is_string($extendConfig) ? empty($extendConfig['type']) ? false : $extendConfig['type'] : $extendConfig;
|
||||
|
||||
if (!$extendType) {
|
||||
continue;
|
||||
} elseif ($extendType === '@parent') {
|
||||
$parentFile = array_shift($parents);
|
||||
if (!$parentFile || !is_file($parentFile)) {
|
||||
continue;
|
||||
}
|
||||
$blueprints = CompiledYamlFile::instance($parentFile)->content();
|
||||
$parent = new Blueprint($type.'-parent', $blueprints, $this);
|
||||
$blueprint->extend($parent);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_string($extendConfig) || empty($extendConfig['context'])) {
|
||||
$context = $this;
|
||||
} else {
|
||||
// Load blueprints from external context.
|
||||
$array = explode('://', $extendConfig['context'], 2);
|
||||
$scheme = array_shift($array);
|
||||
$path = array_shift($array);
|
||||
if ($path) {
|
||||
$scheme .= '://';
|
||||
$extendType = $path ? "{$path}/{$extendType}" : $extendType;
|
||||
}
|
||||
$context = new self($scheme);
|
||||
}
|
||||
$blueprint->extend($context->get($extendType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +119,18 @@ class Blueprints
|
||||
if ($this->types === null) {
|
||||
$this->types = array();
|
||||
|
||||
$iterator = new \DirectoryIterator($this->search);
|
||||
// Check if search is a stream.
|
||||
if (strpos($this->search, '://')) {
|
||||
// Stream: use UniformResourceIterator.
|
||||
$grav = static::getGrav();
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$iterator = $locator->getIterator($this->search, null);
|
||||
} else {
|
||||
// Not a stream: use DirectoryIterator.
|
||||
$iterator = new \DirectoryIterator($this->search);
|
||||
}
|
||||
|
||||
/** @var \DirectoryIterator $file */
|
||||
foreach ($iterator as $file) {
|
||||
if (!$file->isFile() || '.' . $file->getExtension() != YAML_EXT) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Countable;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use RocketTheme\Toolbox\File\File;
|
||||
use RocketTheme\Toolbox\File\FileInterface;
|
||||
|
||||
@@ -13,9 +15,9 @@ use RocketTheme\Toolbox\File\FileInterface;
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Data implements DataInterface
|
||||
class Data implements DataInterface, \ArrayAccess, \Countable, ExportInterface
|
||||
{
|
||||
use ArrayAccessWithGetters, Countable, Export, DataMutatorTrait;
|
||||
use NestedArrayAccessWithGetters, Countable, Export;
|
||||
|
||||
protected $gettersVariable = 'items';
|
||||
protected $items;
|
||||
@@ -32,12 +34,11 @@ class Data implements DataInterface
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
* @param Blueprint $blueprints
|
||||
* @param Blueprint|callable $blueprints
|
||||
*/
|
||||
public function __construct(array $items = array(), Blueprint $blueprints = null)
|
||||
public function __construct(array $items = array(), $blueprints = null)
|
||||
{
|
||||
$this->items = $items;
|
||||
|
||||
$this->blueprints = $blueprints;
|
||||
}
|
||||
|
||||
@@ -57,126 +58,150 @@ class Data implements DataInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $data->def('this.is.my.nested.variable', 'default');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
*/
|
||||
public function def($name, $default = null, $separator = '.')
|
||||
{
|
||||
$this->set($name, $this->get($name, $default, $separator), $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two values together by using blueprints if available.
|
||||
* Join nested values together by using blueprints.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function join($name, $value, $separator = '.')
|
||||
{
|
||||
$old = $this->get($name, null, $separator);
|
||||
if ($old === null) {
|
||||
// Variable does not exist yet: just use the incoming value.
|
||||
} elseif ($this->blueprints) {
|
||||
// Blueprints: join values by using blueprints.
|
||||
$value = $this->blueprints->mergeData($old, $value, $name, $separator);
|
||||
} else {
|
||||
// No blueprints: replace existing top level variables with the new ones.
|
||||
$value = array_merge($old, $value);
|
||||
if ($old !== null) {
|
||||
if (!is_array($old)) {
|
||||
throw new \RuntimeException('Value ' . $old);
|
||||
}
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
} elseif (!is_array($value)) {
|
||||
throw new \RuntimeException('Value ' . $value);
|
||||
}
|
||||
$value = $this->blueprints()->mergeData($old, $value, $name, $separator);
|
||||
}
|
||||
|
||||
$this->set($name, $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join two values together by using blueprints if available.
|
||||
* Get nested structure containing default values defined in the blueprints.
|
||||
*
|
||||
* Fields without default value are ignored in the list.
|
||||
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaults()
|
||||
{
|
||||
return $this->blueprints()->getDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default values by using blueprints.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
*/
|
||||
public function joinDefaults($name, $value, $separator = '.')
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
$old = $this->get($name, null, $separator);
|
||||
if ($old === null) {
|
||||
// Variable does not exist yet: just use the incoming value.
|
||||
} elseif ($this->blueprints) {
|
||||
// Blueprints: join values by using blueprints.
|
||||
$value = $this->blueprints->mergeData($value, $old, $name, $separator);
|
||||
} else {
|
||||
// No blueprints: replace existing top level variables with the new ones.
|
||||
$value = array_merge($value, $old);
|
||||
if ($old !== null) {
|
||||
$value = $this->blueprints()->mergeData($value, $old, $name, $separator);
|
||||
}
|
||||
|
||||
$this->set($name, $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from the configuration and join it with given data.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param array $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getJoined($name, $value, $separator = '.')
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
} elseif (!is_array($value)) {
|
||||
throw new \RuntimeException('Value ' . $value);
|
||||
}
|
||||
|
||||
$old = $this->get($name, null, $separator);
|
||||
|
||||
if ($old === null) {
|
||||
// No value set; no need to join data.
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!is_array($old)) {
|
||||
throw new \RuntimeException('Value ' . $old);
|
||||
}
|
||||
|
||||
// Return joined data.
|
||||
return $this->blueprints()->mergeData($old, $value, $name, $separator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge two sets of data together.
|
||||
* Merge two configurations together.
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(array $data)
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->items = $this->blueprints->mergeData($this->items, $data);
|
||||
} else {
|
||||
$this->items = array_merge($this->items, $data);
|
||||
}
|
||||
$this->items = $this->blueprints()->mergeData($this->items, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default data to the set.
|
||||
* Set default values to the configuration if variables were not set.
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
* @return $this
|
||||
*/
|
||||
public function setDefaults(array $data)
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->items = $this->blueprints->mergeData($data, $this->items);
|
||||
} else {
|
||||
$this->items = array_merge($data, $this->items);
|
||||
}
|
||||
}
|
||||
$this->items = $this->blueprints()->mergeData($data, $this->items);
|
||||
|
||||
/**
|
||||
* Return blueprints.
|
||||
*
|
||||
* @return Blueprint
|
||||
*/
|
||||
public function blueprints()
|
||||
{
|
||||
return $this->blueprints;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate by blueprints.
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->blueprints->validate($this->items);
|
||||
}
|
||||
$this->blueprints()->validate($this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* Filter all items by using blueprints.
|
||||
*/
|
||||
public function filter()
|
||||
{
|
||||
if ($this->blueprints) {
|
||||
$this->items = $this->blueprints->filter($this->items);
|
||||
}
|
||||
$this->items = $this->blueprints()->filter($this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +211,24 @@ class Data implements DataInterface
|
||||
*/
|
||||
public function extra()
|
||||
{
|
||||
return $this->blueprints ? $this->blueprints->extra($this->items) : array();
|
||||
return $this->blueprints()->extra($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return blueprints.
|
||||
*
|
||||
* @return Blueprints
|
||||
*/
|
||||
public function blueprints()
|
||||
{
|
||||
if (!$this->blueprints){
|
||||
$this->blueprints = new Blueprints;
|
||||
} elseif (is_callable($this->blueprints)) {
|
||||
// Lazy load blueprints.
|
||||
$blueprints = $this->blueprints;
|
||||
$this->blueprints = $blueprints();
|
||||
}
|
||||
return $this->blueprints;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
trait DataMutatorTrait
|
||||
{
|
||||
|
||||
/**
|
||||
* Get value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $data->get('this.is.my.nested.variable');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return mixed Value.
|
||||
*/
|
||||
public function get($name, $default = null, $separator = '.')
|
||||
{
|
||||
$path = explode($separator, $name);
|
||||
$current = $this->items;
|
||||
foreach ($path as $field) {
|
||||
if (is_object($current) && isset($current->{$field})) {
|
||||
$current = $current->{$field};
|
||||
} elseif (is_array($current) && isset($current[$field])) {
|
||||
$current = $current[$field];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sey value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $data->set('this.is.my.nested.variable', true);
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value New value.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
*/
|
||||
public function set($name, $value, $separator = '.')
|
||||
{
|
||||
$path = explode($separator, $name);
|
||||
$current = &$this->items;
|
||||
foreach ($path as $field) {
|
||||
if (is_object($current)) {
|
||||
// Handle objects.
|
||||
if (!isset($current->{$field})) {
|
||||
$current->{$field} = array();
|
||||
}
|
||||
$current = &$current->{$field};
|
||||
} else {
|
||||
// Handle arrays and scalars.
|
||||
if (!is_array($current)) {
|
||||
$current = array($field => array());
|
||||
} elseif (!isset($current[$field])) {
|
||||
$current[$field] = array();
|
||||
}
|
||||
$current = &$current[$field];
|
||||
}
|
||||
}
|
||||
|
||||
$current = $value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Parser;
|
||||
|
||||
/**
|
||||
* Data validation.
|
||||
*
|
||||
@@ -9,6 +13,8 @@ namespace Grav\Common\Data;
|
||||
*/
|
||||
class Validation
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* Validate value against a blueprint field definition.
|
||||
*
|
||||
@@ -25,17 +31,27 @@ class Validation
|
||||
return;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get language class
|
||||
$language = self::getGrav()['language'];
|
||||
|
||||
// Validate type with fallback type text.
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'type'.strtr($type, '-', '_');
|
||||
$name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
|
||||
$message = (string) isset($field['validate']['message']) ? $language->translate($field['validate']['message']) : $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
|
||||
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $validate, $field);
|
||||
} else {
|
||||
$success = self::typeText($value, $validate, $field);
|
||||
}
|
||||
if (!$success) {
|
||||
$name = $field['label'] ? $field['label'] : $field['name'];
|
||||
throw new \RuntimeException("invalid input in {$name}");
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
|
||||
// Check individual rules
|
||||
@@ -43,8 +59,9 @@ class Validation
|
||||
$method = 'validate'.strtr($rule, '-', '_');
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $params);
|
||||
|
||||
if (!$success) {
|
||||
throw new \RuntimeException('Failed');
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +83,21 @@ class Validation
|
||||
return null;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if this is a YAML field, simply parse it and return the value
|
||||
if (isset($field['yaml']) && $field['yaml'] === true) {
|
||||
try {
|
||||
$yaml = new Parser();
|
||||
return $yaml->parse($value);
|
||||
} catch (ParseException $e) {
|
||||
throw new \RuntimeException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Validate type with fallback type text.
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'filter'.strtr($type, '-', '_');
|
||||
@@ -236,6 +268,24 @@ class Validation
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: file
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeFile($value, array $params, array $field)
|
||||
{
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
protected static function filterFile($value, array $params, array $field)
|
||||
{
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: select
|
||||
*
|
||||
@@ -285,6 +335,17 @@ class Validation
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
protected static function filterDateTime($value, array $params, array $field)
|
||||
{
|
||||
$format = self::getGrav()['config']->get('system.pages.dateformat.default');
|
||||
if ($format) {
|
||||
$converted = new \DateTime($value);
|
||||
return $converted->format($format);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* HTML5 input: range
|
||||
*
|
||||
@@ -353,7 +414,6 @@ class Validation
|
||||
*/
|
||||
public static function typeDatetime($value, array $params, array $field)
|
||||
{
|
||||
// TODO: add min, max and range.
|
||||
if ($value instanceof \DateTime) {
|
||||
return true;
|
||||
} elseif (!is_string($value)) {
|
||||
@@ -489,6 +549,7 @@ class Validation
|
||||
{
|
||||
$values = (array) $value;
|
||||
$options = isset($field['options']) ? array_keys($field['options']) : array();
|
||||
$multi = isset($field['multiple']) ? $field['multiple'] : false;
|
||||
|
||||
if ($options) {
|
||||
$useKey = isset($field['use']) && $field['use'] == 'keys';
|
||||
@@ -497,9 +558,43 @@ class Validation
|
||||
}
|
||||
}
|
||||
|
||||
if ($multi) {
|
||||
foreach ($values as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$value = implode(',', $value);
|
||||
}
|
||||
|
||||
$values[$key] = array_map('trim', explode(',', $value));
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function typeList($value, array $params, array $field)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
foreach ($value as $key => $item) {
|
||||
foreach ($field['fields'] as $subKey => $subField) {
|
||||
$subKey = trim($subKey, '.');
|
||||
$subValue = isset($item[$subKey]) ? $item[$subKey] : null;
|
||||
self::validate($subValue, $subField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function filterList($value, array $params, array $field)
|
||||
{
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: ignore (will not validate)
|
||||
*
|
||||
@@ -513,10 +608,19 @@ class Validation
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function filterIgnore($value, array $params, array $field)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
// HTML5 attributes (min, max and range are handled inside the types)
|
||||
|
||||
public static function validateRequired($value, $params)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$value = trim($value);
|
||||
}
|
||||
|
||||
return (bool) $params !== true || !empty($value);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,10 +94,10 @@ class Debugger
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function startTimer($name, $desription = null)
|
||||
public function startTimer($name, $description = null)
|
||||
{
|
||||
if ($name[0] == '_' || $this->grav['config']->get('system.debugger.enabled')) {
|
||||
$this->debugbar['time']->startMeasure($name, $desription);
|
||||
$this->debugbar['time']->startMeasure($name, $description);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use Whoops\Run;
|
||||
* Class Debugger
|
||||
* @package Grav\Common
|
||||
*/
|
||||
class Errors extends \Whoops\Run
|
||||
class Errors extends Run
|
||||
{
|
||||
|
||||
public function pushHandler($handler, $key = null)
|
||||
|
||||
@@ -48,4 +48,5 @@ h6 {
|
||||
|
||||
code {
|
||||
font-weight: bold;
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
|
||||
@@ -16,10 +16,14 @@
|
||||
<header>
|
||||
Server Error
|
||||
</header>
|
||||
<p>We're sorry! The server has encountered an internal error and was unable to complete your request.
|
||||
Please contact the system administrator for more information.</p>
|
||||
<h6>For further details please review your <code>logs/</code> folder, or enable displaying of errors in your system configuration.</h6>
|
||||
<h6>Error Code: <b><?php echo $code ?></b></h6>
|
||||
|
||||
|
||||
|
||||
<p>Sorry, something went terribly wrong!</p>
|
||||
|
||||
<h3><?php echo $code ?> - <?php echo $message ?></h3>
|
||||
|
||||
<h5>For further details please review your <code>logs/</code> folder, or enable displaying of errors in your system configuration.</h5>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -28,6 +28,7 @@ class SimplePageHandler extends Handler
|
||||
$cssFile = $this->getResource("error.css");
|
||||
|
||||
$code = $inspector->getException()->getCode();
|
||||
$message = $inspector->getException()->getMessage();
|
||||
|
||||
if ($inspector->getException() instanceof \ErrorException) {
|
||||
$code = Misc::translateErrorCode($code);
|
||||
@@ -36,6 +37,7 @@ class SimplePageHandler extends Handler
|
||||
$vars = array(
|
||||
"stylesheet" => file_get_contents($cssFile),
|
||||
"code" => $code,
|
||||
"message" => $message,
|
||||
);
|
||||
|
||||
$helper->setVariables($vars);
|
||||
|
||||
@@ -22,10 +22,13 @@ trait CompiledFile
|
||||
*/
|
||||
public function content($var = null)
|
||||
{
|
||||
// Set some options
|
||||
$this->settings(['native' => true, 'compat' => true]);
|
||||
|
||||
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
|
||||
if ($var === null && $this->raw === null && $this->content === null) {
|
||||
$key = md5($this->filename);
|
||||
$file = PhpFile::instance(CACHE_DIR . "/compiled/files/{$key}{$this->extension}.php");
|
||||
$file = PhpFile::instance(CACHE_DIR . "compiled/files/{$key}{$this->extension}.php");
|
||||
$modified = $this->modified();
|
||||
|
||||
if (!$modified) {
|
||||
@@ -44,10 +47,14 @@ trait CompiledFile
|
||||
|| $cache['filename'] != $this->filename
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
}
|
||||
|
||||
// Decode RAW file into compiled array.
|
||||
$data = $this->decode($this->raw());
|
||||
$data = (array) $this->decode($this->raw());
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'filename' => $this->filename,
|
||||
@@ -61,6 +68,7 @@ trait CompiledFile
|
||||
$file->unlock();
|
||||
}
|
||||
}
|
||||
$file->free();
|
||||
|
||||
$this->content = $cache['data'];
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ abstract class Folder
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$dirItr = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$filterItr = new RecursiveFolderFilterIterator($dirItr);
|
||||
$itr = new \RecursiveIteratorIterator($filterItr, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$filter = new RecursiveFolderFilterIterator($directory);
|
||||
$iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($itr as $dir) {
|
||||
foreach ($iterator as $dir) {
|
||||
$dir_modified = $dir->getMTime();
|
||||
if ($dir_modified > $last_modified) {
|
||||
$last_modified = $dir_modified;
|
||||
@@ -38,21 +38,20 @@ abstract class Folder
|
||||
* Recursively find the last modified time under given path by file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $extensions which files to search for specifically
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function lastModifiedFile($path)
|
||||
public static function lastModifiedFile($path, $extensions = 'md|yaml')
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$dirItr = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$filterItr = new RecursiveFileFilterIterator($dirItr);
|
||||
$itr = new \RecursiveIteratorIterator($filterItr, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$recursive = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator = new \RegexIterator($recursive, '/^.+\.'.$extensions.'$/i');
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($itr as $file) {
|
||||
if ($file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
foreach ($iterator as $filepath => $file) {
|
||||
$file_modified = $file->getMTime();
|
||||
if ($file_modified > $last_modified) {
|
||||
$last_modified = $file_modified;
|
||||
@@ -72,8 +71,8 @@ abstract class Folder
|
||||
public static function getRelativePath($path, $base = GRAV_ROOT)
|
||||
{
|
||||
if ($base) {
|
||||
$base = preg_replace('![\\|/]+!', '/', $base);
|
||||
$path = preg_replace('![\\|/]+!', '/', $path);
|
||||
$base = preg_replace('![\\\/]+!', '/', $base);
|
||||
$path = preg_replace('![\\\/]+!', '/', $path);
|
||||
if (strpos($path, $base) === 0) {
|
||||
$path = ltrim(substr($path, strlen($base)), '/');
|
||||
}
|
||||
@@ -82,6 +81,43 @@ abstract class Folder
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relative path between target and base path. If path isn't relative, return full path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $base
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativePathDotDot($path, $base)
|
||||
{
|
||||
$base = preg_replace('![\\\/]+!', '/', $base);
|
||||
$path = preg_replace('![\\\/]+!', '/', $path);
|
||||
|
||||
if ($path === $base) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$baseParts = explode('/', isset($base[0]) && '/' === $base[0] ? substr($base, 1) : $base);
|
||||
$pathParts = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
|
||||
|
||||
array_pop($baseParts);
|
||||
$lastPart = array_pop($pathParts);
|
||||
foreach ($baseParts as $i => $directory) {
|
||||
if (isset($pathParts[$i]) && $pathParts[$i] === $directory) {
|
||||
unset($baseParts[$i], $pathParts[$i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$pathParts[] = $lastPart;
|
||||
$path = str_repeat('../', count($baseParts)) . implode('/', $pathParts);
|
||||
|
||||
return '' === $path
|
||||
|| '/' === $path[0]
|
||||
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
|
||||
? "./$path" : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift first directory out of the path.
|
||||
*
|
||||
@@ -97,8 +133,6 @@ abstract class Folder
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return recursive list of all files and directories under given path.
|
||||
*
|
||||
@@ -117,13 +151,17 @@ abstract class Folder
|
||||
$pattern = isset($params['pattern']) ? $params['pattern'] : null;
|
||||
$filters = isset($params['filters']) ? $params['filters'] : null;
|
||||
$recursive = isset($params['recursive']) ? $params['recursive'] : true;
|
||||
$levels = isset($params['levels']) ? $params['levels'] : -1;
|
||||
$key = isset($params['key']) ? 'get' . $params['key'] : null;
|
||||
$value = isset($params['value']) ? 'get' . $params['value'] : ($recursive ? 'getSubPathname' : 'getFilename');
|
||||
$folders = isset($params['folders']) ? $params['folders'] : true;
|
||||
$files = isset($params['files']) ? $params['files'] : true;
|
||||
|
||||
if ($recursive) {
|
||||
$directory = new \RecursiveDirectoryIterator($path,
|
||||
\RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
|
||||
$iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator->setMaxDepth(max($levels, -1));
|
||||
} else {
|
||||
$iterator = new \FilesystemIterator($path);
|
||||
}
|
||||
@@ -132,6 +170,16 @@ abstract class Folder
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($iterator as $file) {
|
||||
// Ignore hidden files.
|
||||
if ($file->getFilename()[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (!$folders && $file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
if (!$files && $file->isFile()) {
|
||||
continue;
|
||||
}
|
||||
if ($compare && $pattern && !preg_match($pattern, $file->{$compare}())) {
|
||||
continue;
|
||||
}
|
||||
@@ -139,7 +187,8 @@ abstract class Folder
|
||||
$filePath = $file->{$value}();
|
||||
if ($filters) {
|
||||
if (isset($filters['key'])) {
|
||||
$fileKey = preg_replace($filters['key'], '', $fileKey);
|
||||
$pre = !empty($filters['pre-key']) ? $filters['pre-key'] : '';
|
||||
$fileKey = $pre . preg_replace($filters['key'], '', $fileKey);
|
||||
}
|
||||
if (isset($filters['value'])) {
|
||||
$filter = $filters['value'];
|
||||
@@ -147,12 +196,12 @@ abstract class Folder
|
||||
$filePath = call_user_func($filter, $file);
|
||||
} else {
|
||||
$filePath = preg_replace($filter, '', $filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($fileKey !== null) {
|
||||
$results[$fileKey] = $filePath;
|
||||
$results[$fileKey] = $filePath;
|
||||
} else {
|
||||
$results[] = $filePath;
|
||||
}
|
||||
@@ -164,11 +213,12 @@ abstract class Folder
|
||||
/**
|
||||
* Recursively copy directory in filesystem.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $ignore Ignore files matching pattern (regular expression).
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function copy($source, $target)
|
||||
public static function copy($source, $target, $ignore = null)
|
||||
{
|
||||
$source = rtrim($source, '\\/');
|
||||
$target = rtrim($target, '\\/');
|
||||
@@ -178,19 +228,24 @@ abstract class Folder
|
||||
}
|
||||
|
||||
// Make sure that path to the target exists before copying.
|
||||
self::mkdir($target);
|
||||
self::create($target);
|
||||
|
||||
$success = true;
|
||||
|
||||
// Go through all sub-directories and copy everything.
|
||||
$files = self::all($source);
|
||||
foreach ($files as $file) {
|
||||
if ($ignore && preg_match($ignore, $file)) {
|
||||
continue;
|
||||
}
|
||||
$src = $source .'/'. $file;
|
||||
$dst = $target .'/'. $file;
|
||||
|
||||
if (is_dir($src)) {
|
||||
// Create current directory.
|
||||
$success &= @mkdir($dst);
|
||||
// Create current directory (if it doesn't exist).
|
||||
if (!is_dir($dst)) {
|
||||
$success &= @mkdir($dst, 0777, true);
|
||||
}
|
||||
} else {
|
||||
// Or copy current file.
|
||||
$success &= @copy($src, $dst);
|
||||
@@ -209,8 +264,8 @@ abstract class Folder
|
||||
/**
|
||||
* Move directory in filesystem.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function move($source, $target)
|
||||
@@ -219,8 +274,13 @@ abstract class Folder
|
||||
throw new \RuntimeException('Cannot move non-existing folder.');
|
||||
}
|
||||
|
||||
// Don't do anything if the source is the same as the new target
|
||||
if ($source == $target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that path to the target exists before moving.
|
||||
self::mkdir(dirname($target));
|
||||
self::create(dirname($target));
|
||||
|
||||
// Just rename the directory.
|
||||
$success = @rename($source, $target);
|
||||
@@ -239,16 +299,16 @@ abstract class Folder
|
||||
* Recursively delete directory from filesystem.
|
||||
*
|
||||
* @param string $target
|
||||
* @throws \RuntimeException
|
||||
* @param bool $include_target
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($target)
|
||||
public static function delete($target, $include_target = true)
|
||||
{
|
||||
if (!is_dir($target)) {
|
||||
throw new \RuntimeException('Cannot delete non-existing folder.');
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = self::doDelete($target);
|
||||
$success = self::doDelete($target, $include_target);
|
||||
|
||||
if (!$success) {
|
||||
$error = error_get_last();
|
||||
@@ -256,16 +316,31 @@ abstract class Folder
|
||||
}
|
||||
|
||||
// Make sure that the change will be detected when caching.
|
||||
@touch(dirname($target));
|
||||
if ($include_target) {
|
||||
@touch(dirname($target));
|
||||
} else {
|
||||
@touch($target);
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function mkdir($folder)
|
||||
{
|
||||
self::create($folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function create($folder)
|
||||
{
|
||||
if (is_dir($folder)) {
|
||||
return;
|
||||
@@ -279,25 +354,77 @@ abstract class Folder
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive copy of one directory to another
|
||||
*
|
||||
* @param $src
|
||||
* @param $dest
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function rcopy($src, $dest)
|
||||
{
|
||||
|
||||
// If the src is not a directory do a simple file copy
|
||||
if (!is_dir($src)) {
|
||||
copy($src, $dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the destination directory does not exist create it
|
||||
if (!is_dir($dest)) {
|
||||
if (!mkdir($dest)) {
|
||||
// If the destination directory could not be created stop processing
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Open the source directory to read in files
|
||||
$i = new \DirectoryIterator($src);
|
||||
/** @var \DirectoryIterator $f */
|
||||
foreach ($i as $f) {
|
||||
if ($f->isFile()) {
|
||||
copy($f->getRealPath(), "$dest/" . $f->getFilename());
|
||||
} else {
|
||||
if (!$f->isDot() && $f->isDir()) {
|
||||
static::rcopy($f->getRealPath(), "$dest/$f");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @param bool $include_target
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected static function doDelete($folder)
|
||||
protected static function doDelete($folder, $include_target = true)
|
||||
{
|
||||
// Special case for symbolic links.
|
||||
if (is_link($folder)) {
|
||||
return @unlink($folder);
|
||||
}
|
||||
|
||||
// Go through all items in filesystem and recursively remove everything.
|
||||
$files = array_diff(scandir($folder), array('.', '..'));
|
||||
foreach ($files as $file) {
|
||||
$path = "{$folder}/{$file}";
|
||||
(is_dir($path)) ? self::doDelete($path) : @unlink($path);
|
||||
$files = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($folder, \RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
/** @var \DirectoryIterator $fileinfo */
|
||||
foreach ($files as $fileinfo) {
|
||||
if ($fileinfo->isDir()) {
|
||||
if (false === @rmdir($fileinfo->getRealPath())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (false === @unlink($fileinfo->getRealPath())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @rmdir($folder);
|
||||
return $include_target ? @rmdir($folder) : true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
namespace Grav\Common\Filesystem;
|
||||
|
||||
class RecursiveFileFilterIterator extends \RecursiveFilterIterator
|
||||
{
|
||||
public static $FILTERS = ['.DS_Store'];
|
||||
|
||||
public function accept()
|
||||
{
|
||||
// Ensure any filtered file names are skipped
|
||||
return !in_array($this->current()->getFilename(), self::$FILTERS, true);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,31 @@
|
||||
<?php
|
||||
namespace Grav\Common\Filesystem;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
|
||||
class RecursiveFolderFilterIterator extends \RecursiveFilterIterator
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected static $folder_ignores;
|
||||
|
||||
public function __construct(\RecursiveIterator $iterator)
|
||||
{
|
||||
parent::__construct($iterator);
|
||||
if (empty($this::$folder_ignores)) {
|
||||
$this::$folder_ignores = self::getGrav()['config']->get('system.pages.ignore_folders');
|
||||
}
|
||||
}
|
||||
|
||||
public function accept()
|
||||
{
|
||||
// only accept directories
|
||||
return $this->current()->isDir();
|
||||
|
||||
/** @var $current \SplFileInfo */
|
||||
$current = $this->current();
|
||||
|
||||
if ($current->isDir() && !in_array($current->getFilename(), $this::$folder_ignores)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Local;
|
||||
namespace Grav\Common\GPM;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Iterator;
|
||||
|
||||
class Collection extends Iterator
|
||||
{
|
||||
abstract class AbstractCollection extends Iterator {
|
||||
|
||||
use GravTrait;
|
||||
|
||||
public function toJson()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $theme) {
|
||||
$items[$name] = $theme->toArray();
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return json_encode($items);
|
||||
@@ -23,8 +23,8 @@ class Collection extends Iterator
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $theme) {
|
||||
$items[$name] = $theme->toArray();
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return $items;
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Common;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Iterator;
|
||||
|
||||
abstract class AbstractPackageCollection extends Iterator {
|
||||
|
||||
use GravTrait;
|
||||
|
||||
protected $type;
|
||||
|
||||
public function toJson()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return json_encode($items);
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
21
system/src/Grav/Common/GPM/Common/CachedCollection.php
Normal file
21
system/src/Grav/Common/GPM/Common/CachedCollection.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Common;
|
||||
|
||||
use Grav\Common\Iterator;
|
||||
|
||||
class CachedCollection extends Iterator {
|
||||
|
||||
protected static $cache;
|
||||
|
||||
public function __construct($items)
|
||||
{
|
||||
// local cache to speed things up
|
||||
if (!isset(self::$cache[get_called_class().__METHOD__])) {
|
||||
self::$cache[get_called_class().__METHOD__] = $items;
|
||||
}
|
||||
|
||||
foreach (self::$cache[get_called_class().__METHOD__] as $name => $item) {
|
||||
$this->append([$name => $item]);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
system/src/Grav/Common/GPM/Common/Package.php
Normal file
42
system/src/Grav/Common/GPM/Common/Package.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Common;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
|
||||
class Package {
|
||||
|
||||
protected $data;
|
||||
|
||||
public function __construct(Data $package, $type = null) {
|
||||
$this->data = $package;
|
||||
|
||||
if ($type) {
|
||||
$this->data->set('package_type', $type);
|
||||
}
|
||||
}
|
||||
|
||||
public function getData() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function __get($key) {
|
||||
return $this->data->get($key);
|
||||
}
|
||||
|
||||
public function __isset($key) {
|
||||
return isset($this->data->$key);
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return $this->toJson();
|
||||
}
|
||||
|
||||
public function toJson() {
|
||||
return $this->data->toJson();
|
||||
}
|
||||
|
||||
public function toArray() {
|
||||
return $this->data->toArray();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,8 +40,11 @@ class GPM extends Iterator
|
||||
public function __construct($refresh = false, $callback = null)
|
||||
{
|
||||
$this->installed = new Local\Packages();
|
||||
$this->repository = new Remote\Packages($refresh, $callback);
|
||||
$this->grav = new Remote\Grav($refresh, $callback);
|
||||
try {
|
||||
$this->repository = new Remote\Packages($refresh, $callback);
|
||||
$this->grav = new Remote\Grav($refresh, $callback);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,6 +352,7 @@ class GPM extends Iterator
|
||||
public function findPackages($searches = [])
|
||||
{
|
||||
$packages = ['total' => 0, 'not_found' => []];
|
||||
$inflector = new Inflector();
|
||||
|
||||
foreach ($searches as $search) {
|
||||
$repository = '';
|
||||
@@ -361,7 +365,7 @@ class GPM extends Iterator
|
||||
}
|
||||
|
||||
if ($found = $this->findPackage($search)) {
|
||||
// set override respository if provided
|
||||
// set override repository if provided
|
||||
if ($repository) {
|
||||
$found->override_repository = $repository;
|
||||
}
|
||||
@@ -380,7 +384,7 @@ class GPM extends Iterator
|
||||
}
|
||||
|
||||
$not_found = new \stdClass();
|
||||
$not_found->name = Inflector::camelize($search);
|
||||
$not_found->name = $inflector->camelize($search);
|
||||
$not_found->slug = $search;
|
||||
$not_found->package_type = $type;
|
||||
$not_found->install_path = str_replace('%name%', $search, $this->install_paths[$type]);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Grav\Common\GPM;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class Installer
|
||||
{
|
||||
@@ -42,6 +43,7 @@ class Installer
|
||||
'overwrite' => true,
|
||||
'ignore_symlinks' => true,
|
||||
'sophisticated' => false,
|
||||
'theme' => false,
|
||||
'install_path' => '',
|
||||
'exclude_checks' => [self::EXISTS, self::NOT_FOUND, self::IS_LINK]
|
||||
];
|
||||
@@ -70,9 +72,12 @@ class Installer
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pre install checks
|
||||
static::flightProcessing('pre_install', $install_path);
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$archive = $zip->open($package);
|
||||
$tmp = CACHE_DIR . DS . 'tmp/Grav-' . uniqid();
|
||||
$tmp = CACHE_DIR . 'tmp/Grav-' . uniqid();
|
||||
|
||||
if ($archive !== true) {
|
||||
self::$error = self::ZIP_OPEN_ERROR;
|
||||
@@ -95,7 +100,11 @@ class Installer
|
||||
|
||||
|
||||
if (!$options['sophisticated']) {
|
||||
self::nonSophisticatedInstall($zip, $install_path, $tmp);
|
||||
if ($options['theme']) {
|
||||
self::copyInstall($zip, $install_path, $tmp);
|
||||
} else {
|
||||
self::moveInstall($zip, $install_path, $tmp);
|
||||
}
|
||||
} else {
|
||||
self::sophisticatedInstall($zip, $install_path, $tmp);
|
||||
}
|
||||
@@ -103,15 +112,37 @@ class Installer
|
||||
Folder::delete($tmp);
|
||||
$zip->close();
|
||||
|
||||
// Post install checks
|
||||
static::flightProcessing('post_install', $install_path);
|
||||
|
||||
self::$error = self::OK;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public static function nonSophisticatedInstall(\ZipArchive $zip, $install_path, $tmp)
|
||||
protected static function flightProcessing($state, $install_path)
|
||||
{
|
||||
$container = $zip->getNameIndex(0); // TODO: better way of determining if zip has container folder
|
||||
$blueprints_path = $install_path . DS . 'blueprints.yaml';
|
||||
|
||||
if (file_exists($blueprints_path)) {
|
||||
$package_yaml = Yaml::parse(file_get_contents($blueprints_path));
|
||||
if (isset($package_yaml['install'][$state]['create'])) {
|
||||
foreach ((array) $package_yaml['install']['pre_install']['create'] as $file) {
|
||||
Folder::mkdir($install_path . '/' . ltrim($file, '/'));
|
||||
}
|
||||
}
|
||||
if (isset($package_yaml['install'][$state]['remove'])) {
|
||||
foreach ((array) $package_yaml['install']['pre_install']['remove'] as $file) {
|
||||
Folder::delete($install_path . '/' . ltrim($file, '/'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function moveInstall(\ZipArchive $zip, $install_path, $tmp)
|
||||
{
|
||||
$container = $zip->getNameIndex(0);
|
||||
if (file_exists($install_path)) {
|
||||
Folder::delete($install_path);
|
||||
}
|
||||
@@ -121,6 +152,19 @@ class Installer
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function copyInstall(\ZipArchive $zip, $install_path, $tmp)
|
||||
{
|
||||
$firstDir = $zip->getNameIndex(0);
|
||||
if (empty($firstDir)) {
|
||||
throw new \RuntimeException("Directory $firstDir is missing");
|
||||
} else {
|
||||
$tmp = realpath($tmp . DS . $firstDir);
|
||||
Folder::rcopy($tmp, $install_path);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function sophisticatedInstall(\ZipArchive $zip, $install_path, $tmp)
|
||||
{
|
||||
for ($i = 0, $l = $zip->numFiles; $i < $l; $i++) {
|
||||
@@ -156,11 +200,10 @@ class Installer
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unnstalls one or more given package
|
||||
* Uninstalls one or more given package
|
||||
*
|
||||
* @param string $package The slug of the package(s)
|
||||
* @param string $path The slug of the package(s)
|
||||
* @param array $options Options to use for uninstalling
|
||||
*
|
||||
* @return boolean True if everything went fine, False otherwise.
|
||||
@@ -287,4 +330,14 @@ class Installer
|
||||
{
|
||||
return self::$error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to manually set an error
|
||||
* @param $error the Error code
|
||||
*/
|
||||
|
||||
public static function setError($error)
|
||||
{
|
||||
self::$error = $error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Common\GPM\Local;
|
||||
|
||||
use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection;
|
||||
|
||||
abstract class AbstractPackageCollection extends BaseCollection
|
||||
{
|
||||
public function __construct($items)
|
||||
{
|
||||
foreach ($items as $name => $data) {
|
||||
$data->set('slug', $name);
|
||||
$this->items[$name] = new Package($data, $this->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,39 +2,24 @@
|
||||
namespace Grav\Common\GPM\Local;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\GPM\Common\Package as BasePackage;
|
||||
|
||||
/**
|
||||
* Class Package
|
||||
* @package Grav\Common\GPM\Local
|
||||
*/
|
||||
class Package
|
||||
class Package extends BasePackage
|
||||
{
|
||||
/**
|
||||
* @var Data
|
||||
*/
|
||||
protected $data;
|
||||
/**
|
||||
* @var \Grav\Common\Data\Blueprint
|
||||
*/
|
||||
protected $blueprints;
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @param Data $package
|
||||
* @param bool $package_type
|
||||
*/
|
||||
public function __construct(Data $package, $package_type = false)
|
||||
public function __construct(Data $package, $package_type = null)
|
||||
{
|
||||
$this->data = $package;
|
||||
$this->blueprints = $this->data->blueprints();
|
||||
$data = new Data($package->blueprints()->toArray());
|
||||
parent::__construct($data, $package_type);
|
||||
|
||||
if ($package_type) {
|
||||
$html_description = \Parsedown::instance()->line($this->blueprints->get('description'));
|
||||
$this->blueprints->set('package_type', $package_type);
|
||||
$this->blueprints->set('slug', $this->blueprints->name);
|
||||
$this->blueprints->set('description_html', $html_description);
|
||||
$this->blueprints->set('description_plain', strip_tags($html_description));
|
||||
$this->blueprints->set('symlink', is_link(USER_DIR . $package_type . DS . $this->blueprints->name));
|
||||
}
|
||||
$this->settings = $package->toArray();
|
||||
|
||||
$html_description = \Parsedown::instance()->line($this->description);
|
||||
$this->data->set('slug', $package->slug);
|
||||
$this->data->set('description_html', $html_description);
|
||||
$this->data->set('description_plain', strip_tags($html_description));
|
||||
$this->data->set('symlink', is_link(USER_DIR . $package_type . DS . $this->name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,47 +27,6 @@ class Package
|
||||
*/
|
||||
public function isEnabled()
|
||||
{
|
||||
return $this->data['enabled'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Data
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
return $this->blueprints->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toJson()
|
||||
{
|
||||
return $this->blueprints->toJson();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->blueprints->toArray();
|
||||
return $this->settings['enabled'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Local;
|
||||
|
||||
use Grav\Common\Iterator;
|
||||
use Grav\Common\GPM\Common\CachedCollection;
|
||||
|
||||
class Packages extends Iterator
|
||||
class Packages extends CachedCollection
|
||||
{
|
||||
private $plugins;
|
||||
private $themes;
|
||||
protected static $cache;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// local cache to speed things up
|
||||
if (!isset(self::$cache[__METHOD__])) {
|
||||
self::$cache[__METHOD__] = [
|
||||
'plugins' => new Plugins(),
|
||||
'themes' => new Themes()
|
||||
];
|
||||
}
|
||||
$items = [
|
||||
'plugins' => new Plugins(),
|
||||
'themes' => new Themes()
|
||||
];
|
||||
|
||||
$this->plugins = self::$cache[__METHOD__]['plugins'];
|
||||
$this->themes = self::$cache[__METHOD__]['themes'];
|
||||
|
||||
$this->append(['plugins' => $this->plugins]);
|
||||
$this->append(['themes' => $this->themes]);
|
||||
parent::__construct($items);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,22 +5,18 @@ namespace Grav\Common\GPM\Local;
|
||||
* Class Plugins
|
||||
* @package Grav\Common\GPM\Local
|
||||
*/
|
||||
class Plugins extends Collection
|
||||
class Plugins extends AbstractPackageCollection
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $type = 'plugins';
|
||||
protected $type = 'plugins';
|
||||
|
||||
/**
|
||||
* Local Plugins Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$grav = self::getGrav();
|
||||
|
||||
foreach ($grav['plugins']->all() as $name => $data) {
|
||||
$this->items[$name] = new Package($data, $this->type);
|
||||
}
|
||||
parent::__construct(self::getGrav()['plugins']->all());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Local;
|
||||
|
||||
class Themes extends Collection
|
||||
/**
|
||||
* Class Themes
|
||||
* @package Grav\Common\GPM\Local
|
||||
*/
|
||||
class Themes extends AbstractPackageCollection
|
||||
{
|
||||
private $type = 'themes';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'themes';
|
||||
|
||||
/**
|
||||
* Local Themes Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$grav = self::getGrav();
|
||||
|
||||
foreach ($grav['themes']->all() as $name => $data) {
|
||||
$this->items[$name] = new Package($data, $this->type);
|
||||
}
|
||||
parent::__construct(self::getGrav()['themes']->all());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Remote;
|
||||
|
||||
use Grav\Common\GPM\Common\AbstractPackageCollection as BaseCollection;
|
||||
use Grav\Common\GPM\Response;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Iterator;
|
||||
use \Doctrine\Common\Cache\Cache as DoctrineCache;
|
||||
use \Doctrine\Common\Cache\FilesystemCache;
|
||||
|
||||
class Collection extends Iterator {
|
||||
use GravTrait;
|
||||
|
||||
class AbstractPackageCollection extends BaseCollection
|
||||
{
|
||||
/**
|
||||
* The cached data previously fetched
|
||||
* @var string
|
||||
@@ -21,13 +18,15 @@ class Collection extends Iterator {
|
||||
* @var integer
|
||||
*/
|
||||
private $lifetime = 86400;
|
||||
private $repository;
|
||||
private $cache;
|
||||
|
||||
public function __construct($repository = null)
|
||||
protected $repository;
|
||||
|
||||
protected $cache;
|
||||
|
||||
public function __construct($repository = null, $refresh = false, $callback = null)
|
||||
{
|
||||
if ($repository === null) {
|
||||
throw new \RuntimeException("A repository is required for storing the cache");
|
||||
throw new \RuntimeException("A repository is required to indicate the origin of the remote collection");
|
||||
}
|
||||
|
||||
$cache_dir = self::getGrav()['locator']->findResource('cache://gpm', true, true);
|
||||
@@ -35,28 +34,11 @@ class Collection extends Iterator {
|
||||
|
||||
$this->repository = $repository;
|
||||
$this->raw = $this->cache->fetch(md5($this->repository));
|
||||
}
|
||||
|
||||
public function toJson()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $theme) {
|
||||
$items[$name] = $theme->toArray();
|
||||
$this->fetch($refresh, $callback);
|
||||
foreach (json_decode($this->raw, true) as $slug => $data) {
|
||||
$this->items[$slug] = new Package($data, $this->type);
|
||||
}
|
||||
|
||||
return json_encode($items);
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $theme) {
|
||||
$items[$name] = $theme->toArray();
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
public function fetch($refresh = false, $callback = null)
|
||||
@@ -1,9 +1,11 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Remote;
|
||||
|
||||
class Grav extends Collection
|
||||
use \Doctrine\Common\Cache\FilesystemCache;
|
||||
|
||||
class Grav extends AbstractPackageCollection
|
||||
{
|
||||
private $repository = 'http://getgrav.org/downloads/grav.json';
|
||||
protected $repository = 'http://getgrav.org/downloads/grav.json';
|
||||
private $data;
|
||||
|
||||
private $version;
|
||||
@@ -15,15 +17,17 @@ class Grav extends Collection
|
||||
*/
|
||||
public function __construct($refresh = false, $callback = null)
|
||||
{
|
||||
parent::__construct($this->repository);
|
||||
$cache_dir = self::getGrav()['locator']->findResource('cache://gpm', true, true);
|
||||
$this->cache = new FilesystemCache($cache_dir);
|
||||
$this->raw = $this->cache->fetch(md5($this->repository));
|
||||
|
||||
$this->fetch($refresh, $callback);
|
||||
$this->data = json_decode($this->raw);
|
||||
|
||||
$this->version = @$this->data->version ?: '-';
|
||||
$this->date = @$this->data->date ?: '-';
|
||||
$this->data = json_decode($this->raw, true);
|
||||
$this->version = isset($this->data['version']) ? $this->data['version'] : '-';
|
||||
$this->date = isset($this->data['date']) ? $this->data['date'] : '-';
|
||||
|
||||
foreach ($this->data->assets as $slug => $data) {
|
||||
if (isset($this->data['assets'])) foreach ($this->data['assets'] as $slug => $data) {
|
||||
$this->items[$slug] = new Package($data);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +38,7 @@ class Grav extends Collection
|
||||
*/
|
||||
public function getAssets()
|
||||
{
|
||||
return $this->data->assets;
|
||||
return $this->data['assets'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -46,12 +50,12 @@ class Grav extends Collection
|
||||
public function getChangelog($diff = null)
|
||||
{
|
||||
if (!$diff) {
|
||||
return $this->data->changelog;
|
||||
return $this->data['changelog'];
|
||||
}
|
||||
|
||||
$diffLog = [];
|
||||
foreach ($this->data->changelog as $version => $changelog) {
|
||||
preg_match("/[\d\.]+/", $version, $cleanVersion);
|
||||
foreach ($this->data['changelog'] as $version => $changelog) {
|
||||
preg_match("/[\w-\.]+/", $version, $cleanVersion);
|
||||
|
||||
if (!$cleanVersion || version_compare($diff, $cleanVersion[0], ">=")) { continue; }
|
||||
|
||||
@@ -83,4 +87,9 @@ class Grav extends Collection
|
||||
{
|
||||
return version_compare(GRAV_VERSION, $this->getVersion(), '<');
|
||||
}
|
||||
|
||||
public function isSymlink()
|
||||
{
|
||||
return is_link(GRAV_ROOT . DS . 'index.php');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,12 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Remote;
|
||||
|
||||
class Package {
|
||||
public function __construct($package, $package_type = false) {
|
||||
$this->data = $package;
|
||||
if ($package_type) {
|
||||
$this->data->package_type = $package_type;
|
||||
}
|
||||
}
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\GPM\Common\Package as BasePackage;
|
||||
|
||||
public function getData() {
|
||||
return $this->data;
|
||||
class Package extends BasePackage {
|
||||
public function __construct($package, $package_type = null) {
|
||||
$data = new Data($package);
|
||||
parent::__construct($data, $package_type);
|
||||
}
|
||||
|
||||
public function __get($key) {
|
||||
return $this->data->$key;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return $this->toJson();
|
||||
}
|
||||
|
||||
public function toJson() {
|
||||
return json_encode($this->data);
|
||||
}
|
||||
|
||||
public function toArray() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,28 +1,17 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Remote;
|
||||
|
||||
use Grav\Common\Iterator;
|
||||
use Grav\Common\GPM\Common\CachedCollection;
|
||||
|
||||
class Packages extends Iterator
|
||||
class Packages extends CachedCollection
|
||||
{
|
||||
private $plugins;
|
||||
private $themes;
|
||||
protected static $cache;
|
||||
|
||||
public function __construct($refresh = false, $callback = null)
|
||||
{
|
||||
// local cache to speed things up
|
||||
if (!isset(self::$cache[__METHOD__])) {
|
||||
self::$cache[__METHOD__] = [
|
||||
'plugins' => new Plugins($refresh, $callback),
|
||||
'themes' => new Themes($refresh, $callback)
|
||||
];
|
||||
}
|
||||
$items = [
|
||||
'plugins' => new Plugins($refresh, $callback),
|
||||
'themes' => new Themes($refresh, $callback)
|
||||
];
|
||||
|
||||
$this->plugins = self::$cache[__METHOD__]['plugins']->toArray();
|
||||
$this->themes = self::$cache[__METHOD__]['themes']->toArray();
|
||||
|
||||
$this->append(['plugins' => $this->plugins]);
|
||||
$this->append(['themes' => $this->themes]);
|
||||
parent::__construct($items);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user