Linux webm002.cluster120.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
Apache
: 10.120.20.2 | : 216.73.216.49
Cant Read [ /etc/named.conf ]
8.5.7
verseaumee
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
README
+ Create Folder
+ Create File
/
home /
verseaumee /
123click /
assets /
[ HOME SHELL ]
Name
Size
Permission
Action
css
[ DIR ]
drwx---r-x
fonts
[ DIR ]
drwx---r-x
images
[ DIR ]
drwx---r-x
js
[ DIR ]
drwx---r-x
.bash_logout.bash_logout.tar.g...
126
B
-rw-r--r--
.bash_logout.tar
2
KB
-rw-r--r--
.bash_profile.bash_profile.tar...
273
B
-rw-r--r--
.bash_profile.tar
2
KB
-rw-r--r--
.bashrc.bashrc.tar.gz
190
B
-rw-r--r--
.bashrc.tar
2
KB
-rw-r--r--
.ftpquota.ftpquota.tar.gz
135
B
-rw-r--r--
.ftpquota.tar
2
KB
-rw-r--r--
.hta.hta.tar.gz
3.15
KB
-rw-r--r--
.hta.tar
6
KB
-rw-r--r--
.htaccess.bak.htaccess.bak.tar...
428
B
-rw-r--r--
.htaccess.bak.tar
2.5
KB
-rw-r--r--
.htaccess.htaccess.tar.gz
194
B
-rw-r--r--
.htaccess.tar
41.5
KB
-rw-r--r--
.htaccess_10125.htaccess_10125...
1.93
KB
-rw-r--r--
.htaccess_10125.tar
6
KB
-rw-r--r--
.htaccess_2608.htaccess_2608.t...
1.83
KB
-rw-r--r--
.htaccess_2608.tar
5.5
KB
-rw-r--r--
.htaccess_old.htaccess_old.tar...
1.71
KB
-rw-r--r--
.htaccess_old.tar
9.5
KB
-rw-r--r--
.htaccess_old2.htaccess_old2.t...
1.81
KB
-rw-r--r--
.htaccess_old2.tar
5.5
KB
-rw-r--r--
.htaccessx.htaccessx.tar.gz
479
B
-rw-r--r--
.htaccessx.tar
2.5
KB
-rw-r--r--
.htaccessxx.htaccessxx.tar.gz
427
B
-rw-r--r--
.htaccessxx.tar
2.5
KB
-rw-r--r--
.mad-root
0
B
-rw-r--r--
.ovhconfig.ovhconfig.tar.gz
188
B
-rw-r--r--
.ovhconfig.tar
2
KB
-rw-r--r--
.tmb.tar
221
KB
-rw-r--r--
.tmb.tar.gz
41.33
KB
-rw-r--r--
.tmb.zip
201.6
KB
-rw-r--r--
.user.ini.tar
3
KB
-rw-r--r--
.user.ini.user.ini.tar.gz
220
B
-rw-r--r--
.well-known.tar
158.5
KB
-rw-r--r--
.well-known.tar.gz
69.8
KB
-rw-r--r--
.well-known.zip
152.89
KB
-rw-r--r--
----index.html.html.tar.gz
8.28
KB
-rw-r--r--
----index.html.tar
40
KB
-rw-r--r--
01.jpg.jpg.tar.gz
2.27
KB
-rw-r--r--
01.jpg.tar
4
KB
-rw-r--r--
10pourcent.zip
212.54
MB
-rw-r--r--
404.html.html.tar.gz
1.19
KB
-rw-r--r--
404.html.tar
5
KB
-rw-r--r--
888index.php.php.tar.gz
8.52
KB
-rw-r--r--
888index.php.tar
42.5
KB
-rw-r--r--
ANE_MOULIN.jpg.jpg.tar.gz
12.53
KB
-rw-r--r--
ANE_MOULIN.jpg.tar
14
KB
-rw-r--r--
Association.zip
6.54
KB
-rw-r--r--
CALES.jpg.jpg.tar.gz
13.84
KB
-rw-r--r--
CALES.jpg.tar
15.5
KB
-rw-r--r--
CONDITIONS.pdf.pdf.tar.gz
592.22
KB
-rw-r--r--
CONDITIONS.pdf.tar
753.5
KB
-rw-r--r--
Cache.zip
39.59
KB
-rw-r--r--
Demo.tar
17.37
MB
-rw-r--r--
Demo.tar.gz
16.59
MB
-rw-r--r--
Demo.zip
17.31
MB
-rw-r--r--
Diff.php.php.tar.gz
3.15
KB
-rw-r--r--
Diff.php.tar
14.5
KB
-rw-r--r--
Downloads.tar
868.5
KB
-rw-r--r--
Downloads.tar.gz
790.18
KB
-rw-r--r--
Downloads.zip
865.8
KB
-rw-r--r--
Filter.zip
41.03
KB
-rw-r--r--
FontAwesome.otf.otf.tar.gz
108.08
KB
-rw-r--r--
FontAwesome.otf.tar
133.5
KB
-rw-r--r--
HTTP.tar
13
KB
-rw-r--r--
HTTP.tar.gz
3.32
KB
-rw-r--r--
ID3.tar
1.12
MB
-rw-r--r--
ID3.tar.gz
233.46
KB
-rw-r--r--
ID3.zip
1.1
MB
-rw-r--r--
IXR.tar
43
KB
-rw-r--r--
IXR.tar.gz
7.69
KB
-rw-r--r--
IXR.zip
34.92
KB
-rw-r--r--
JEANJEAN.jpg.jpg.tar.gz
14.03
KB
-rw-r--r--
JEANJEAN.jpg.tar
15.5
KB
-rw-r--r--
LA.png.png.tar.gz
3.38
KB
-rw-r--r--
LA.png.tar
5
KB
-rw-r--r--
LICENSE.txt.tar
93.5
KB
-rw-r--r--
LICENSE.txt.txt.tar.gz
6.78
KB
-rw-r--r--
LOGO A LA MAZE ON 17 NOVEMBRE ...
1.36
MB
-rw-r--r--
LOGO A LA MAZE ON 17 NOVEMBRE ...
1.41
MB
-rw-r--r--
LOGO ARCEP 2.jpg.jpg.tar.gz
399.9
KB
-rw-r--r--
LOGO ARCEP 2.jpg.tar
1.38
MB
-rw-r--r--
LOGO ARCEP 2.psd.psd.tar.gz
3.66
MB
-rw-r--r--
LOGO ARCEP 2.psd.tar
9.75
MB
-rw-r--r--
Log.tar
45
KB
-rw-r--r--
Log.tar.gz
8.58
KB
-rw-r--r--
Log.zip
37.62
KB
-rw-r--r--
Net.tar
9
KB
-rw-r--r--
Net.tar.gz
2.68
KB
-rw-r--r--
PHPMailer.tar
227.5
KB
-rw-r--r--
PHPMailer.tar.gz
47.75
KB
-rw-r--r--
PHPMailer.zip
223.7
KB
-rw-r--r--
PTITE_FERME.png.png.tar.gz
70.39
KB
-rw-r--r--
PTITE_FERME.png.tar
73.5
KB
-rw-r--r--
PayPal.PNG.PNG.tar.gz
18.47
KB
-rw-r--r--
PayPal.PNG.tar
24
KB
-rw-r--r--
README.txt.tar
34
KB
-rw-r--r--
README.txt.txt.tar.gz
1.83
KB
-rw-r--r--
Requests.tar
427
KB
-rw-r--r--
Requests.tar.gz
30.97
KB
-rw-r--r--
Requests.zip
220.53
KB
-rw-r--r--
SimplePie.tar
474
KB
-rw-r--r--
SimplePie.tar.gz
77.41
KB
-rw-r--r--
SimplePie.zip
456.69
KB
-rw-r--r--
TF89388.tar
958.4
MB
-rw-r--r--
TF89388.tar.gz
20
B
-rw-r--r--
Tate-tuker-web.jpg.jpg.tar.gz
97.22
KB
-rw-r--r--
Tate-tuker-web.jpg.tar
101
KB
-rw-r--r--
Text.tar
63.5
KB
-rw-r--r--
Text.tar.gz
12.67
KB
-rw-r--r--
Text.zip
57.09
KB
-rw-r--r--
UA.png.png.tar.gz
3.24
KB
-rw-r--r--
UA.png.tar
5
KB
-rw-r--r--
XML.zip
7.11
KB
-rw-r--r--
_contact.html.html.tar.gz
4.61
KB
-rw-r--r--
_contact.html.tar
17.5
KB
-rw-r--r--
_index.html.html.tar.gz
8.52
KB
-rw-r--r--
_index.html.tar
40.5
KB
-rw-r--r--
ab1.jpg.jpg.tar.gz
19.2
KB
-rw-r--r--
ab1.jpg.tar
21
KB
-rw-r--r--
ab2.jpg.jpg.tar.gz
19.28
KB
-rw-r--r--
ab2.jpg.tar
21
KB
-rw-r--r--
about-blog.jpg.jpg.tar.gz
61
KB
-rw-r--r--
about-blog.jpg.tar
65.5
KB
-rw-r--r--
about-us.jpg.jpg.tar.gz
27.54
KB
-rw-r--r--
about-us.jpg.tar
31
KB
-rw-r--r--
about.html.html.tar.gz
3.86
KB
-rw-r--r--
about.html.tar
38.5
KB
-rw-r--r--
about.php.php.tar.gz
5.35
KB
-rw-r--r--
about.php.tar
80
KB
-rw-r--r--
actionlog.tar
40
KB
-rw-r--r--
actionlog.tar.gz
4.46
KB
-rw-r--r--
actionlog.zip
36.47
KB
-rw-r--r--
actionlogs.tar
18.5
KB
-rw-r--r--
actionlogs.tar.gz
1.25
KB
-rw-r--r--
actionlogs.zip
2.82
KB
-rw-r--r--
acymailing.tar
338.5
KB
-rw-r--r--
acymailing.tar.gz
48.94
KB
-rw-r--r--
acymailing.zip
308.85
KB
-rw-r--r--
admin-ajax.php.php.tar.gz
1.89
KB
-rw-r--r--
admin-ajax.php.tar
7
KB
-rw-r--r--
admin-bar.php.php.tar.gz
8.22
KB
-rw-r--r--
admin-bar.php.tar
38
KB
-rw-r--r--
admin-footer.php.php.tar.gz
1.14
KB
-rw-r--r--
admin-footer.php.tar
4.5
KB
-rw-r--r--
admin-functions.php.php.tar.gz
333
B
-rw-r--r--
admin-functions.php.tar
3
KB
-rw-r--r--
admin-get.php.php.tar.gz
980
B
-rw-r--r--
admin-get.php.tar
3.5
KB
-rw-r--r--
admin-header.php.php.tar.gz
2.97
KB
-rw-r--r--
admin-header.php.tar
30
KB
-rw-r--r--
admin-post.php.php.tar.gz
847
B
-rw-r--r--
admin-post.php.tar
4
KB
-rw-r--r--
admin.php.php.tar.gz
3.79
KB
-rw-r--r--
admin.php.tar
27
KB
-rw-r--r--
adminer.php
0
B
-rw-r--r--
administrator.tar
83.32
MB
-rw-r--r--
administrator.tar.gz
4.57
MB
-rw-r--r--
administrator.zip
41.74
MB
-rw-r--r--
afrikavio.jpg.jpg.tar.gz
300.69
KB
-rw-r--r--
afrikavio.jpg.tar
323.5
KB
-rw-r--r--
ai1wm-backups.tar
717.78
MB
-rw-r--r--
ai1wm-backups.tar.gz
20
B
-rw-r--r--
akismet.tar
258
KB
-rw-r--r--
akismet.tar.gz
67.37
KB
-rw-r--r--
akismet.zip
240.29
KB
-rw-r--r--
all.js.js.tar.gz
818
B
-rw-r--r--
all.js.tar
3.5
KB
-rw-r--r--
android-chrome-192x192.png.png...
5.04
KB
-rw-r--r--
android-chrome-192x192.png.tar
7
KB
-rw-r--r--
android-chrome-512x512.png.png...
18.64
KB
-rw-r--r--
android-chrome-512x512.png.tar
23.5
KB
-rw-r--r--
android-icon-144x144.png.png.t...
14.3
KB
-rw-r--r--
android-icon-144x144.png.tar
16
KB
-rw-r--r--
android-icon-192x192.png.png.t...
19.65
KB
-rw-r--r--
android-icon-192x192.png.tar
21.5
KB
-rw-r--r--
android-icon-36x36.png.png.tar...
2.67
KB
-rw-r--r--
android-icon-36x36.png.tar
4.5
KB
-rw-r--r--
android-icon-48x48.png.png.tar...
3.76
KB
-rw-r--r--
android-icon-48x48.png.tar
5.5
KB
-rw-r--r--
android-icon-72x72.png.png.tar...
5.93
KB
-rw-r--r--
android-icon-72x72.png.tar
7.5
KB
-rw-r--r--
android-icon-96x96.png.png.tar...
8.36
KB
-rw-r--r--
android-icon-96x96.png.tar
10
KB
-rw-r--r--
android.png.png.tar.gz
2.47
KB
-rw-r--r--
android.png.tar
4
KB
-rw-r--r--
angular-icon.svg.svg.tar.gz
559
B
-rw-r--r--
angular-icon.svg.tar
2.5
KB
-rw-r--r--
angular.png.png.tar.gz
10.65
KB
-rw-r--r--
angular.png.tar
13
KB
-rw-r--r--
api.tar
383.5
KB
-rw-r--r--
api.tar.gz
77.41
KB
-rw-r--r--
api.zip
345.17
KB
-rw-r--r--
app.js.js.tar.gz
501
B
-rw-r--r--
app.js.tar
2.5
KB
-rw-r--r--
app.php.php.tar.gz
1.05
KB
-rw-r--r--
app.php.tar
4
KB
-rw-r--r--
app.tar
199
KB
-rw-r--r--
app.tar.gz
34.34
KB
-rw-r--r--
app.zip
171.56
KB
-rw-r--r--
apple-icon-114x114.png.png.tar...
10.47
KB
-rw-r--r--
apple-icon-114x114.png.tar
12
KB
-rw-r--r--
apple-icon-144x144.png.png.tar...
14.3
KB
-rw-r--r--
apple-icon-144x144.png.tar
16
KB
-rw-r--r--
apple-icon-152x152.png.png.tar...
15.31
KB
-rw-r--r--
apple-icon-152x152.png.tar
17
KB
-rw-r--r--
apple-icon-180x180.png.png.tar...
19.25
KB
-rw-r--r--
apple-icon-180x180.png.tar
21
KB
-rw-r--r--
apple-icon-57x57.png.png.tar.g...
4.53
KB
-rw-r--r--
apple-icon-57x57.png.tar
6
KB
-rw-r--r--
apple-icon-60x60.png.png.tar.g...
4.77
KB
-rw-r--r--
apple-icon-60x60.png.tar
6.5
KB
-rw-r--r--
apple-icon-76x76.png.png.tar.g...
6.29
KB
-rw-r--r--
apple-icon-76x76.png.tar
8
KB
-rw-r--r--
apple-icon-precomposed.png.png...
20.06
KB
-rw-r--r--
apple-icon-precomposed.png.tar
22
KB
-rw-r--r--
apple-touch-icon.png.png.tar.g...
3.99
KB
-rw-r--r--
apple-touch-icon.png.tar
11
KB
-rw-r--r--
apple.png.png.tar.gz
3.5
KB
-rw-r--r--
apple.png.tar
5.5
KB
-rw-r--r--
apps.tar
266
KB
-rw-r--r--
apps.tar.gz
223.94
KB
-rw-r--r--
apps.zip
251.66
KB
-rw-r--r--
archives.tar
11
KB
-rw-r--r--
archives.tar.gz
826
B
-rw-r--r--
archives.zip
2.92
KB
-rw-r--r--
assets.tar
151.49
MB
-rw-r--r--
assets.tar.gz
101.02
MB
-rw-r--r--
assets.zip
88.82
MB
-rw-r--r--
async-upload.php.php.tar.gz
1.96
KB
-rw-r--r--
async-upload.php.tar
12
KB
-rw-r--r--
atomlib.php.php.tar.gz
3.27
KB
-rw-r--r--
atomlib.php.tar
13.5
KB
-rw-r--r--
attachments.tar
2
KB
-rw-r--r--
attachments.tar.gz
124
B
-rw-r--r--
audio.tar
707.5
KB
-rw-r--r--
audio.tar.gz
674.05
KB
-rw-r--r--
authentication.tar
51
KB
-rw-r--r--
authentication.tar.gz
8.78
KB
-rw-r--r--
authentication.zip
40.29
KB
-rw-r--r--
authorize-application.php.php....
3.16
KB
-rw-r--r--
authorize-application.php.tar
12
KB
-rw-r--r--
avatar.zip
3.48
KB
-rw-r--r--
banners.tar
35
KB
-rw-r--r--
banners.tar.gz
29.58
KB
-rw-r--r--
banners.zip
31.48
KB
-rw-r--r--
beez3.tar
630.5
KB
-rw-r--r--
beez3.tar.gz
264.69
KB
-rw-r--r--
beez3.zip
535.04
KB
-rw-r--r--
bg-testinomial.jpg.jpg.tar.gz
461.34
KB
-rw-r--r--
bg-testinomial.jpg.tar
927
KB
-rw-r--r--
bg.jpg.jpg.tar.gz
110.06
KB
-rw-r--r--
bg.jpg.tar
112
KB
-rw-r--r--
bg1.jpg.jpg.tar.gz
150.09
KB
-rw-r--r--
bg1.jpg.tar
152
KB
-rw-r--r--
bg2.jpg.jpg.tar.gz
124.53
KB
-rw-r--r--
bg2.jpg.tar
127.5
KB
-rw-r--r--
bg3.jpg.jpg.tar.gz
669.84
KB
-rw-r--r--
bg3.jpg.tar
711
KB
-rw-r--r--
bg4.jpg.jpg.tar.gz
139.9
KB
-rw-r--r--
bg4.jpg.tar
142
KB
-rw-r--r--
bg5.jpg.jpg.tar.gz
192.52
KB
-rw-r--r--
bg5.jpg.tar
194.5
KB
-rw-r--r--
bighearts-child.tar
1.38
MB
-rw-r--r--
bighearts-child.tar.gz
1.37
MB
-rw-r--r--
bighearts-child.zip
1.37
MB
-rw-r--r--
bighearts.zip
34.41
MB
-rw-r--r--
bin.tar
107.5
KB
-rw-r--r--
bin.tar.gz
27.21
KB
-rw-r--r--
bin.zip
100.81
KB
-rw-r--r--
bizone.tar
4.88
MB
-rw-r--r--
bizone.tar.gz
1.62
MB
-rw-r--r--
bizone.zip
4.8
MB
-rw-r--r--
block-bindings.php.php.tar.gz
1.74
KB
-rw-r--r--
block-bindings.php.tar
7
KB
-rw-r--r--
block-bindings.tar
6
KB
-rw-r--r--
block-bindings.tar.gz
1.1
KB
-rw-r--r--
block-bindings.zip
3.83
KB
-rw-r--r--
block-editor.php.php.tar.gz
6.39
KB
-rw-r--r--
block-editor.php.tar
29.5
KB
-rw-r--r--
block-i18n.json.json.tar.gz
257
B
-rw-r--r--
block-i18n.json.tar
3
KB
-rw-r--r--
block-patterns.php.php.tar.gz
3.16
KB
-rw-r--r--
block-patterns.php.tar
14.5
KB
-rw-r--r--
block-patterns.tar
39.5
KB
-rw-r--r--
block-patterns.tar.gz
3.96
KB
-rw-r--r--
block-patterns.zip
28.32
KB
-rw-r--r--
block-supports.tar
145
KB
-rw-r--r--
block-supports.tar.gz
26.36
KB
-rw-r--r--
block-supports.zip
131.98
KB
-rw-r--r--
block-template-utils.php.php.t...
11.88
KB
-rw-r--r--
block-template-utils.php.tar
57
KB
-rw-r--r--
block-template.php.php.tar.gz
4.16
KB
-rw-r--r--
block-template.php.tar
14
KB
-rw-r--r--
blocks.php.php.tar.gz
4
KB
-rw-r--r--
blocks.php.tar
113
KB
-rw-r--r--
blocks.tar
1.96
MB
-rw-r--r--
blocks.tar.gz
235.75
KB
-rw-r--r--
blocks.zip
1.54
MB
-rw-r--r--
blog.html.html.tar.gz
2.52
KB
-rw-r--r--
blog.html.tar
13.5
KB
-rw-r--r--
blog.tar
5.77
MB
-rw-r--r--
blog.tar.gz
4.87
MB
-rw-r--r--
blog.zip
5.71
MB
-rw-r--r--
blueversiontg.tar
89.5
KB
-rw-r--r--
blueversiontg.tar.gz
26.37
KB
-rw-r--r--
blueversiontg.zip
85.9
KB
-rw-r--r--
bookmark-template.php.php.tar....
3.3
KB
-rw-r--r--
bookmark-template.php.tar
14.5
KB
-rw-r--r--
bookmark.php.php.tar.gz
4.24
KB
-rw-r--r--
bookmark.php.tar
17
KB
-rw-r--r--
bootstrap.min.js.min.js.tar.gz
15.19
KB
-rw-r--r--
bootstrap.min.js.tar
58.5
KB
-rw-r--r--
bootstrap.tar
535
KB
-rw-r--r--
bootstrap.tar.gz
90.49
KB
-rw-r--r--
bootstrap.zip
530.83
KB
-rw-r--r--
browserconfig.xml.tar
2
KB
-rw-r--r--
browserconfig.xml.xml.tar.gz
264
B
-rw-r--r--
button.zip
15.31
KB
-rw-r--r--
buttons.tar
19
KB
-rw-r--r--
buttons.tar.gz
1.45
KB
-rw-r--r--
bv_connector_a3384bc41af663dc2...
5.65
KB
-rw-r--r--
bv_connector_a3384bc41af663dc2...
20.5
KB
-rw-r--r--
c1.jpg.jpg.tar.gz
19.79
KB
-rw-r--r--
c1.jpg.tar
21.5
KB
-rw-r--r--
c2.jpg.jpg.tar.gz
18.15
KB
-rw-r--r--
c2.jpg.tar
20
KB
-rw-r--r--
c3.jpg.jpg.tar.gz
3.26
KB
-rw-r--r--
c3.jpg.tar
5
KB
-rw-r--r--
cache-compat.php.php.tar.gz
1.43
KB
-rw-r--r--
cache-compat.php.tar
7.5
KB
-rw-r--r--
cache.php.php.tar.gz
2.6
KB
-rw-r--r--
cache.php.tar
15
KB
-rw-r--r--
cache.tar
84
KB
-rw-r--r--
cache.tar.gz
24.89
KB
-rw-r--r--
cache.zip
11.15
MB
-rw-r--r--
calendar.zip
4.4
KB
-rw-r--r--
call-to-action-bg-2.jpg.jpg.ta...
68.28
KB
-rw-r--r--
call-to-action-bg-2.jpg.tar
88
KB
-rw-r--r--
call-to-action-bg-20.jpg.jpg.t...
150.06
KB
-rw-r--r--
call-to-action-bg-20.jpg.tar
169.5
KB
-rw-r--r--
call-to-action-bg-222.jpg.jpg....
855.71
KB
-rw-r--r--
call-to-action-bg-222.jpg.tar
873
KB
-rw-r--r--
call-to-action-bg.jpg.jpg.tar....
14.97
KB
-rw-r--r--
call-to-action-bg.jpg.tar
23.5
KB
-rw-r--r--
call-to-action.tar
1.57
MB
-rw-r--r--
call-to-action.tar.gz
1.51
MB
-rw-r--r--
capabilities.php.php.tar.gz
7.1
KB
-rw-r--r--
capabilities.php.tar
83.5
KB
-rw-r--r--
captcha.tar
26
KB
-rw-r--r--
captcha.tar.gz
5.67
KB
-rw-r--r--
captcha.zip
17.58
KB
-rw-r--r--
carapattes.jpg.jpg.tar.gz
184.61
KB
-rw-r--r--
carapattes.jpg.tar
200.5
KB
-rw-r--r--
carousel.less.less.tar.gz
985
B
-rw-r--r--
carousel.less.tar
10
KB
-rw-r--r--
category-template.php.php.tar....
13
KB
-rw-r--r--
category-template.php.tar
57.5
KB
-rw-r--r--
category.php.php.tar.gz
3.54
KB
-rw-r--r--
category.php.tar
41.5
KB
-rw-r--r--
certificates.tar
229.5
KB
-rw-r--r--
certificates.tar.gz
127.51
KB
-rw-r--r--
certificates.zip
227.92
KB
-rw-r--r--
certs.tar
83
KB
-rw-r--r--
certs.tar.gz
24.92
KB
-rw-r--r--
certs.zip
80.85
KB
-rw-r--r--
checkbex.php.php.tar.gz
10.37
KB
-rw-r--r--
checkbex.php.tar
145
KB
-rw-r--r--
class-IXR.php.php.tar.gz
1.19
KB
-rw-r--r--
class-IXR.php.tar
7.5
KB
-rw-r--r--
class-avif-info.php.php.tar.gz
6
KB
-rw-r--r--
class-avif-info.php.tar
30.5
KB
-rw-r--r--
class-feed.php.php.tar.gz
364
B
-rw-r--r--
class-feed.php.tar
5.5
KB
-rw-r--r--
class-http.php.php.tar.gz
341
B
-rw-r--r--
class-http.php.tar
4
KB
-rw-r--r--
class-json.php.php.tar.gz
8.54
KB
-rw-r--r--
class-json.php.tar
44.5
KB
-rw-r--r--
class-oembed.php.php.tar.gz
354
B
-rw-r--r--
class-oembed.php.tar
5
KB
-rw-r--r--
class-phpass.php.php.tar.gz
2.52
KB
-rw-r--r--
class-phpass.php.tar
16
KB
-rw-r--r--
class-phpmailer.php.php.tar.gz
394
B
-rw-r--r--
class-phpmailer.php.tar
4
KB
-rw-r--r--
class-pop3.php.php.tar.gz
4.79
KB
-rw-r--r--
class-pop3.php.tar
64.5
KB
-rw-r--r--
class-requests.php.php.tar.gz
954
B
-rw-r--r--
class-requests.php.tar
10
KB
-rw-r--r--
class-simplepie.php.php.tar.gz
20.46
KB
-rw-r--r--
class-simplepie.php.tar
388
KB
-rw-r--r--
class-smtp.php.php.tar.gz
341
B
-rw-r--r--
class-smtp.php.tar
4
KB
-rw-r--r--
class-snoopy.php.php.tar.gz
7.95
KB
-rw-r--r--
class-snoopy.php.tar
113.5
KB
-rw-r--r--
class-walker-category-dropdown...
1.16
KB
-rw-r--r--
class-walker-category-dropdown...
13
KB
-rw-r--r--
class-walker-category.php.php....
2.45
KB
-rw-r--r--
class-walker-category.php.tar
19
KB
-rw-r--r--
class-walker-comment.php.php.t...
3.27
KB
-rw-r--r--
class-walker-comment.php.tar
15.5
KB
-rw-r--r--
class-walker-nav-menu.php.php....
2.25
KB
-rw-r--r--
class-walker-nav-menu.php.tar
47.5
KB
-rw-r--r--
class-walker-page-dropdown.php...
1.2
KB
-rw-r--r--
class-walker-page-dropdown.php...
14.5
KB
-rw-r--r--
class-walker-page.php.php.tar....
2.11
KB
-rw-r--r--
class-walker-page.php.tar
25
KB
-rw-r--r--
class-wp-admin-bar.php.php.tar...
4.86
KB
-rw-r--r--
class-wp-admin-bar.php.tar
37
KB
-rw-r--r--
class-wp-ajax-response.php.php...
1.81
KB
-rw-r--r--
class-wp-ajax-response.php.tar
12.5
KB
-rw-r--r--
class-wp-application-passwords...
2.74
KB
-rw-r--r--
class-wp-application-passwords...
14.5
KB
-rw-r--r--
class-wp-block-bindings-regist...
2.38
KB
-rw-r--r--
class-wp-block-bindings-regist...
10.5
KB
-rw-r--r--
class-wp-block-bindings-source...
926
B
-rw-r--r--
class-wp-block-bindings-source...
4
KB
-rw-r--r--
class-wp-block-editor-context....
670
B
-rw-r--r--
class-wp-block-editor-context....
3
KB
-rw-r--r--
class-wp-block-list.php.php.ta...
1.26
KB
-rw-r--r--
class-wp-block-list.php.tar
17.5
KB
-rw-r--r--
class-wp-block-parser-block.ph...
880
B
-rw-r--r--
class-wp-block-parser-block.ph...
7
KB
-rw-r--r--
class-wp-block-parser-frame.ph...
680
B
-rw-r--r--
class-wp-block-parser-frame.ph...
6
KB
-rw-r--r--
class-wp-block-parser.php.php....
4.08
KB
-rw-r--r--
class-wp-block-parser.php.tar
52.5
KB
-rw-r--r--
class-wp-block-pattern-categor...
1.4
KB
-rw-r--r--
class-wp-block-pattern-categor...
13
KB
-rw-r--r--
class-wp-block-patterns-regist...
2.9
KB
-rw-r--r--
class-wp-block-patterns-regist...
13
KB
-rw-r--r--
class-wp-block-styles-registry...
1.59
KB
-rw-r--r--
class-wp-block-styles-registry...
21.5
KB
-rw-r--r--
class-wp-block-supports.php.ph...
1.7
KB
-rw-r--r--
class-wp-block-supports.php.ta...
19
KB
-rw-r--r--
class-wp-block-template.php.ph...
693
B
-rw-r--r--
class-wp-block-template.php.ta...
3.5
KB
-rw-r--r--
class-wp-block-type-registry.p...
1.41
KB
-rw-r--r--
class-wp-block-type-registry.p...
17.5
KB
-rw-r--r--
class-wp-block-type.php.php.ta...
3.95
KB
-rw-r--r--
class-wp-block-type.php.tar
36
KB
-rw-r--r--
class-wp-block.php.php.tar.gz
2.14
KB
-rw-r--r--
class-wp-block.php.tar
61
KB
-rw-r--r--
class-wp-classic-to-block-menu...
1.37
KB
-rw-r--r--
class-wp-classic-to-block-menu...
10
KB
-rw-r--r--
class-wp-comment-query.php.php...
10.21
KB
-rw-r--r--
class-wp-comment-query.php.tar
49
KB
-rw-r--r--
class-wp-comment.php.php.tar.g...
2.59
KB
-rw-r--r--
class-wp-comment.php.tar
31
KB
-rw-r--r--
class-wp-customize-control.php...
5.7
KB
-rw-r--r--
class-wp-customize-control.php...
27
KB
-rw-r--r--
class-wp-customize-manager.php...
44.55
KB
-rw-r--r--
class-wp-customize-manager.php...
199.5
KB
-rw-r--r--
class-wp-customize-nav-menu-se...
4.98
KB
-rw-r--r--
class-wp-customize-nav-menu-se...
20
KB
-rw-r--r--
class-wp-customize-panel.php.p...
3.12
KB
-rw-r--r--
class-wp-customize-panel.php.t...
23
KB
-rw-r--r--
class-wp-customize-section.php...
3.25
KB
-rw-r--r--
class-wp-customize-section.php...
12.5
KB
-rw-r--r--
class-wp-customize-setting.php...
6.58
KB
-rw-r--r--
class-wp-customize-setting.php...
31
KB
-rw-r--r--
class-wp-customize-widgets.php...
15.96
KB
-rw-r--r--
class-wp-customize-widgets.php...
277.5
KB
-rw-r--r--
class-wp-date-query.php.php.ta...
8.43
KB
-rw-r--r--
class-wp-date-query.php.tar
36.5
KB
-rw-r--r--
class-wp-dependencies.php.php....
3.37
KB
-rw-r--r--
class-wp-dependencies.php.tar
15.5
KB
-rw-r--r--
class-wp-dependency.php.php.ta...
1.01
KB
-rw-r--r--
class-wp-dependency.php.tar
4.5
KB
-rw-r--r--
class-wp-duotone.php.php.tar.g...
9.24
KB
-rw-r--r--
class-wp-duotone.php.tar
41.5
KB
-rw-r--r--
class-wp-editor.php.php.tar.gz
16.58
KB
-rw-r--r--
class-wp-editor.php.tar
285.5
KB
-rw-r--r--
class-wp-embed.php.php.tar.gz
4.77
KB
-rw-r--r--
class-wp-embed.php.tar
50.5
KB
-rw-r--r--
class-wp-error.php.php.tar.gz
1.93
KB
-rw-r--r--
class-wp-error.php.tar
9
KB
-rw-r--r--
class-wp-fatal-error-handler.p...
2.76
KB
-rw-r--r--
class-wp-fatal-error-handler.p...
9.5
KB
-rw-r--r--
class-wp-feed-cache-transient....
918
B
-rw-r--r--
class-wp-feed-cache-transient....
7.5
KB
-rw-r--r--
class-wp-feed-cache.php.php.ta...
631
B
-rw-r--r--
class-wp-feed-cache.php.tar
4
KB
-rw-r--r--
class-wp-hook.php.php.tar.gz
3.43
KB
-rw-r--r--
class-wp-hook.php.tar
48.5
KB
-rw-r--r--
class-wp-http-cookie.php.php.t...
2.55
KB
-rw-r--r--
class-wp-http-cookie.php.tar
9
KB
-rw-r--r--
class-wp-http-curl.php.php.tar...
3.68
KB
-rw-r--r--
class-wp-http-curl.php.tar
40
KB
-rw-r--r--
class-wp-http-encoding.php.php...
2.21
KB
-rw-r--r--
class-wp-http-encoding.php.tar
8.5
KB
-rw-r--r--
class-wp-http-ixr-client.php.p...
1.45
KB
-rw-r--r--
class-wp-http-ixr-client.php.t...
13
KB
-rw-r--r--
class-wp-http-netfilter.php.ph...
321
B
-rw-r--r--
class-wp-http-netfilter.php.ta...
2
KB
-rw-r--r--
class-wp-http-proxy.php.php.ta...
2.02
KB
-rw-r--r--
class-wp-http-proxy.php.tar
20.5
KB
-rw-r--r--
class-wp-http-requests-respons...
1.35
KB
-rw-r--r--
class-wp-http-requests-respons...
6
KB
-rw-r--r--
class-wp-http-response.php.php...
1.04
KB
-rw-r--r--
class-wp-http-response.php.tar
4.5
KB
-rw-r--r--
class-wp-http-streams.php.php....
4.62
KB
-rw-r--r--
class-wp-http-streams.php.tar
120
KB
-rw-r--r--
class-wp-http.php.php.tar.gz
11.09
KB
-rw-r--r--
class-wp-http.php.tar
123.5
KB
-rw-r--r--
class-wp-image-editor-gd.php.p...
3.94
KB
-rw-r--r--
class-wp-image-editor-gd.php.t...
16
KB
-rw-r--r--
class-wp-image-editor.php.php....
4.85
KB
-rw-r--r--
class-wp-image-editor.php.tar
19
KB
-rw-r--r--
class-wp-list-util.php.php.tar...
1.96
KB
-rw-r--r--
class-wp-list-util.php.tar
32
KB
-rw-r--r--
class-wp-locale-switcher.php.p...
1.87
KB
-rw-r--r--
class-wp-locale-switcher.php.t...
15.5
KB
-rw-r--r--
class-wp-locale.php.php.tar.gz
3.36
KB
-rw-r--r--
class-wp-locale.php.tar
67.5
KB
-rw-r--r--
class-wp-matchesmapregex.php.p...
818
B
-rw-r--r--
class-wp-matchesmapregex.php.t...
8.5
KB
-rw-r--r--
class-wp-meta-query.php.php.ta...
7.19
KB
-rw-r--r--
class-wp-meta-query.php.tar
170.5
KB
-rw-r--r--
class-wp-metadata-lazyloader.p...
1.75
KB
-rw-r--r--
class-wp-metadata-lazyloader.p...
32.5
KB
-rw-r--r--
class-wp-navigation-fallback.p...
2.33
KB
-rw-r--r--
class-wp-navigation-fallback.p...
20
KB
-rw-r--r--
class-wp-network-query.php.php...
4.88
KB
-rw-r--r--
class-wp-network-query.php.tar
39.5
KB
-rw-r--r--
class-wp-network.php.php.tar.g...
3.78
KB
-rw-r--r--
class-wp-network.php.tar
39
KB
-rw-r--r--
class-wp-object-cache.php.php....
3.76
KB
-rw-r--r--
class-wp-object-cache.php.tar
79
KB
-rw-r--r--
class-wp-oembed-controller.php...
2.19
KB
-rw-r--r--
class-wp-oembed-controller.php...
8.5
KB
-rw-r--r--
class-wp-oembed.php.php.tar.gz
7.33
KB
-rw-r--r--
class-wp-oembed.php.tar
185.5
KB
-rw-r--r--
class-wp-paused-extensions-sto...
1.33
KB
-rw-r--r--
class-wp-paused-extensions-sto...
6.5
KB
-rw-r--r--
class-wp-phpmailer.php.php.tar...
1.23
KB
-rw-r--r--
class-wp-phpmailer.php.tar
5.5
KB
-rw-r--r--
class-wp-plugin-dependencies.p...
5.1
KB
-rw-r--r--
class-wp-plugin-dependencies.p...
26.5
KB
-rw-r--r--
class-wp-post-type.php.php.tar...
6.61
KB
-rw-r--r--
class-wp-post-type.php.tar
31.5
KB
-rw-r--r--
class-wp-post.php.php.tar.gz
1.76
KB
-rw-r--r--
class-wp-post.php.tar
29
KB
-rw-r--r--
class-wp-query.php.php.tar.gz
29.76
KB
-rw-r--r--
class-wp-query.php.tar
734.5
KB
-rw-r--r--
class-wp-recovery-mode-email-s...
3.41
KB
-rw-r--r--
class-wp-recovery-mode-email-s...
34.5
KB
-rw-r--r--
class-wp-recovery-mode-key-ser...
1.38
KB
-rw-r--r--
class-wp-recovery-mode-key-ser...
6
KB
-rw-r--r--
class-wp-recovery-mode-link-se...
1.23
KB
-rw-r--r--
class-wp-recovery-mode-link-se...
5
KB
-rw-r--r--
class-wp-recovery-mode.php.php...
3.2
KB
-rw-r--r--
class-wp-recovery-mode.php.tar
13
KB
-rw-r--r--
class-wp-rewrite.php.php.tar.g...
14.56
KB
-rw-r--r--
class-wp-rewrite.php.tar
63.5
KB
-rw-r--r--
class-wp-role.php.php.tar.gz
868
B
-rw-r--r--
class-wp-role.php.tar
10
KB
-rw-r--r--
class-wp-roles.php.php.tar.gz
2.38
KB
-rw-r--r--
class-wp-roles.php.tar
28
KB
-rw-r--r--
class-wp-script-modules.php.ph...
3.02
KB
-rw-r--r--
class-wp-script-modules.php.ta...
35
KB
-rw-r--r--
class-wp-scripts.php.php.tar.g...
6.52
KB
-rw-r--r--
class-wp-scripts.php.tar
57.5
KB
-rw-r--r--
class-wp-session-tokens.php.ph...
1.95
KB
-rw-r--r--
class-wp-session-tokens.php.ta...
33
KB
-rw-r--r--
class-wp-simplepie-file.php.ph...
1.45
KB
-rw-r--r--
class-wp-simplepie-file.php.ta...
9
KB
-rw-r--r--
class-wp-simplepie-sanitize-ks...
964
B
-rw-r--r--
class-wp-simplepie-sanitize-ks...
6
KB
-rw-r--r--
class-wp-site-query.php.php.ta...
6.63
KB
-rw-r--r--
class-wp-site-query.php.tar
64
KB
-rw-r--r--
class-wp-site.php.php.tar.gz
2.12
KB
-rw-r--r--
class-wp-site.php.tar
33
KB
-rw-r--r--
class-wp-styles.php.php.tar.gz
3.06
KB
-rw-r--r--
class-wp-styles.php.tar
35.5
KB
-rw-r--r--
class-wp-tax-query.php.php.tar...
5.11
KB
-rw-r--r--
class-wp-tax-query.php.tar
60.5
KB
-rw-r--r--
class-wp-taxonomy.php.php.tar....
4.47
KB
-rw-r--r--
class-wp-taxonomy.php.tar
20
KB
-rw-r--r--
class-wp-term-query.php.php.ta...
8.14
KB
-rw-r--r--
class-wp-term-query.php.tar
71
KB
-rw-r--r--
class-wp-term.php.php.tar.gz
1.86
KB
-rw-r--r--
class-wp-term.php.tar
13
KB
-rw-r--r--
class-wp-text-diff-renderer-in...
611
B
-rw-r--r--
class-wp-text-diff-renderer-in...
2.5
KB
-rw-r--r--
class-wp-text-diff-renderer-ta...
4.78
KB
-rw-r--r--
class-wp-text-diff-renderer-ta...
37
KB
-rw-r--r--
class-wp-textdomain-registry.p...
2.92
KB
-rw-r--r--
class-wp-textdomain-registry.p...
22.5
KB
-rw-r--r--
class-wp-theme-json.php.php.ta...
13.41
KB
-rw-r--r--
class-wp-theme-json.php.tar
63
KB
-rw-r--r--
class-wp-theme.php.php.tar.gz
14.06
KB
-rw-r--r--
class-wp-theme.php.tar
65.5
KB
-rw-r--r--
class-wp-token-map.php.php.tar...
7.84
KB
-rw-r--r--
class-wp-token-map.php.tar
58
KB
-rw-r--r--
class-wp-user-meta-session-tok...
999
B
-rw-r--r--
class-wp-user-meta-session-tok...
22
KB
-rw-r--r--
class-wp-user-query.php.php.ta...
9.26
KB
-rw-r--r--
class-wp-user-query.php.tar
44.5
KB
-rw-r--r--
class-wp-user-request.php.php....
726
B
-rw-r--r--
class-wp-user-request.php.tar
13
KB
-rw-r--r--
class-wp-user.php.php.tar.gz
5.65
KB
-rw-r--r--
class-wp-user.php.tar
47
KB
-rw-r--r--
class-wp-walker.php.php.tar.gz
3.15
KB
-rw-r--r--
class-wp-walker.php.tar
42.5
KB
-rw-r--r--
class-wp-widget-factory.php.ph...
1.09
KB
-rw-r--r--
class-wp-widget-factory.php.ta...
5
KB
-rw-r--r--
class-wp-widget.php.php.tar.gz
4.41
KB
-rw-r--r--
class-wp-widget.php.tar
56.5
KB
-rw-r--r--
class-wp-xmlrpc-server.php.php...
34.01
KB
-rw-r--r--
class-wp-xmlrpc-server.php.tar
420
KB
-rw-r--r--
class-wp.php.php.tar.gz
7.18
KB
-rw-r--r--
class-wp.php.tar
131.5
KB
-rw-r--r--
class-wpdb.php.php.tar.gz
28.19
KB
-rw-r--r--
class-wpdb.php.tar
468
KB
-rw-r--r--
class.wp-dependencies.php.tar
2
KB
-rw-r--r--
class.wp-dependencies.php.wp-d...
321
B
-rw-r--r--
class.wp-scripts.php.tar
3
KB
-rw-r--r--
class.wp-scripts.php.wp-script...
318
B
-rw-r--r--
class.wp-styles.php.tar
4
KB
-rw-r--r--
class.wp-styles.php.wp-styles....
318
B
-rw-r--r--
cli.tar
133.5
KB
-rw-r--r--
cli.tar.gz
26.04
KB
-rw-r--r--
cli.zip
124.09
KB
-rw-r--r--
client-logo.tar
91
KB
-rw-r--r--
client-logo.tar.gz
49.92
KB
-rw-r--r--
client-logo.zip
84.41
KB
-rw-r--r--
clients.zip
28.76
KB
-rw-r--r--
clipboard.min.js.min.js.tar.gz
3.19
KB
-rw-r--r--
clipboard.min.js.tar
10.5
KB
-rw-r--r--
cms.tar
276.5
KB
-rw-r--r--
cms.tar.gz
1.01
KB
-rw-r--r--
cms.zip
3.35
KB
-rw-r--r--
code.tar
15
KB
-rw-r--r--
code.tar.gz
1.08
KB
-rw-r--r--
colors.tar
661.5
KB
-rw-r--r--
colors.tar.gz
56.18
KB
-rw-r--r--
com_acymailing.tar
1.73
MB
-rw-r--r--
com_acymailing.tar.gz
85.93
KB
-rw-r--r--
com_acymailing.zip
1.56
MB
-rw-r--r--
com_ajax.tar
8
KB
-rw-r--r--
com_ajax.tar.gz
2.12
KB
-rw-r--r--
com_ajax.zip
6.41
KB
-rw-r--r--
com_akeeba.tar
222.5
KB
-rw-r--r--
com_akeeba.tar.gz
0
B
-rw-r--r--
com_akeeba.zip
172.83
KB
-rw-r--r--
com_associations.tar
85.5
KB
-rw-r--r--
com_associations.tar.gz
18.65
KB
-rw-r--r--
com_associations.zip
68.85
KB
-rw-r--r--
com_banners.tar
24.5
KB
-rw-r--r--
com_banners.tar.gz
4.86
KB
-rw-r--r--
com_banners.zip
19.06
KB
-rw-r--r--
com_blue_pagebuilder.tar
33.5
KB
-rw-r--r--
com_blue_pagebuilder.tar.gz
5.23
KB
-rw-r--r--
com_blue_pagebuilder.zip
19.04
KB
-rw-r--r--
com_categories.tar
15
KB
-rw-r--r--
com_categories.tar.gz
3.24
KB
-rw-r--r--
com_config.tar
114.5
KB
-rw-r--r--
com_config.tar.gz
16.39
KB
-rw-r--r--
com_config.zip
89.48
KB
-rw-r--r--
com_contact.tar
523.5
KB
-rw-r--r--
com_contact.tar.gz
40.36
KB
-rw-r--r--
com_contact.zip
466.35
KB
-rw-r--r--
com_content.tar
365
KB
-rw-r--r--
com_content.tar.gz
59.99
KB
-rw-r--r--
com_content.zip
334.19
KB
-rw-r--r--
com_contenthistory.tar
3.5
KB
-rw-r--r--
com_contenthistory.tar.gz
603
B
-rw-r--r--
com_contenthistory.zip
839
B
-rw-r--r--
com_falang.tar
28
KB
-rw-r--r--
com_falang.tar.gz
6.08
KB
-rw-r--r--
com_fields.tar
12
KB
-rw-r--r--
com_fields.tar.gz
2.45
KB
-rw-r--r--
com_fields.zip
7.84
KB
-rw-r--r--
com_finder.tar
109
KB
-rw-r--r--
com_finder.tar.gz
20.25
KB
-rw-r--r--
com_finder.zip
121.6
KB
-rw-r--r--
com_gantry5.tar
14.5
KB
-rw-r--r--
com_gantry5.tar.gz
3.09
KB
-rw-r--r--
com_gantry5.zip
10.35
KB
-rw-r--r--
com_icagenda.tar
1.56
MB
-rw-r--r--
com_icagenda.tar.gz
252.83
KB
-rw-r--r--
com_icagenda.zip
1.4
MB
-rw-r--r--
com_jce.tar
4.82
MB
-rw-r--r--
com_jce.tar.gz
1.2
MB
-rw-r--r--
com_jce.zip
4.39
MB
-rw-r--r--
com_k2.tar
650
KB
-rw-r--r--
com_k2.tar.gz
115.57
KB
-rw-r--r--
com_k2.zip
587.73
KB
-rw-r--r--
com_login.zip
11.37
KB
-rw-r--r--
com_mailto.tar
23.5
KB
-rw-r--r--
com_mailto.tar.gz
4.42
KB
-rw-r--r--
com_mailto.zip
15.79
KB
-rw-r--r--
com_media.tar
2.5
KB
-rw-r--r--
com_media.tar.gz
484
B
-rw-r--r--
com_media.zip
776
B
-rw-r--r--
com_menus.tar
14
KB
-rw-r--r--
com_menus.tar.gz
1.34
KB
-rw-r--r--
com_menus.zip
10.05
KB
-rw-r--r--
com_messages.tar
80.5
KB
-rw-r--r--
com_messages.tar.gz
13.21
KB
-rw-r--r--
com_modules.tar
12.5
KB
-rw-r--r--
com_modules.tar.gz
1.75
KB
-rw-r--r--
com_modules.zip
8.49
KB
-rw-r--r--
com_newsfeeds.tar
98.5
KB
-rw-r--r--
com_newsfeeds.tar.gz
16.45
KB
-rw-r--r--
com_newsfeeds.zip
83.79
KB
-rw-r--r--
com_privacy.tar
109.5
KB
-rw-r--r--
com_privacy.tar.gz
7.42
KB
-rw-r--r--
com_privacy.zip
87.26
KB
-rw-r--r--
com_search.tar
38
KB
-rw-r--r--
com_search.tar.gz
8.07
KB
-rw-r--r--
com_search.zip
31.14
KB
-rw-r--r--
com_solidres.tar
1.65
MB
-rw-r--r--
com_solidres.tar.gz
264.5
KB
-rw-r--r--
com_solidres.zip
1.59
MB
-rw-r--r--
com_tags.tar
107.5
KB
-rw-r--r--
com_tags.tar.gz
16.49
KB
-rw-r--r--
com_tags.zip
90.96
KB
-rw-r--r--
com_templates.tar
69.5
KB
-rw-r--r--
com_templates.tar.gz
12.41
KB
-rw-r--r--
com_templates.zip
51.97
KB
-rw-r--r--
com_uniterevolution2.tar
1.08
MB
-rw-r--r--
com_uniterevolution2.tar.gz
425.96
KB
-rw-r--r--
com_uniterevolution2.zip
1.4
KB
-rw-r--r--
com_users.tar
201.5
KB
-rw-r--r--
com_users.tar.gz
27.25
KB
-rw-r--r--
com_users.zip
167.94
KB
-rw-r--r--
com_virtuemart_allinone.tar
35.5
KB
-rw-r--r--
com_virtuemart_allinone.tar.gz
8.84
KB
-rw-r--r--
com_wrapper.tar
21
KB
-rw-r--r--
com_wrapper.tar.gz
391
B
-rw-r--r--
com_wrapper.zip
13.73
KB
-rw-r--r--
coming_soon.zip
5.16
MB
-rw-r--r--
comment-reply-link.tar
2.5
KB
-rw-r--r--
comment-reply-link.tar.gz
515
B
-rw-r--r--
comment-template.php.php.tar.g...
8.54
KB
-rw-r--r--
comment-template.php.tar
239.5
KB
-rw-r--r--
comment.php.php.tar.gz
27.88
KB
-rw-r--r--
comment.php.tar
389.5
KB
-rw-r--r--
compat.php.php.tar.gz
4.28
KB
-rw-r--r--
compat.php.tar
34.5
KB
-rw-r--r--
components.html.html.tar.gz
3.12
KB
-rw-r--r--
components.html.tar
14.5
KB
-rw-r--r--
components.tar
52.99
MB
-rw-r--r--
components.tar.gz
3.27
MB
-rw-r--r--
components.zip
51.21
MB
-rw-r--r--
composer.json.json.tar.gz
168
B
-rw-r--r--
composer.json.tar
2
KB
-rw-r--r--
composer.lock.lock.tar.gz
1.38
KB
-rw-r--r--
composer.lock.tar
5.5
KB
-rw-r--r--
conditions.docx.docx.tar.gz
40.58
KB
-rw-r--r--
conditions.docx.tar
48.5
KB
-rw-r--r--
configuration.php.php.tar.gz
1.17
KB
-rw-r--r--
configuration.php.tar
28.5
KB
-rw-r--r--
configuration_old.php.php.tar....
1.18
KB
-rw-r--r--
configuration_old.php.tar
5
KB
-rw-r--r--
configuration_old2.php.php.tar...
1.25
KB
-rw-r--r--
configuration_old2.php.tar
5.5
KB
-rw-r--r--
configuration_old33.php.php.ta...
1.27
KB
-rw-r--r--
configuration_old33.php.tar
5.5
KB
-rw-r--r--
construction-prev-arrow.png.pn...
3.88
KB
-rw-r--r--
construction-prev-arrow.png.ta...
5.5
KB
-rw-r--r--
contact-sec.jpg.jpg.tar.gz
66.15
KB
-rw-r--r--
contact-sec.jpg.tar
67.5
KB
-rw-r--r--
contact.html.html.tar.gz
3.29
KB
-rw-r--r--
contact.html.tar
37
KB
-rw-r--r--
contact.php.php.tar.gz
5.84
KB
-rw-r--r--
contact.php.tar
28
KB
-rw-r--r--
contact.tar
4.5
KB
-rw-r--r--
contact.tar.gz
1.28
KB
-rw-r--r--
contactFR.html.html.tar.gz
3.18
KB
-rw-r--r--
contactFR.html.tar
12.5
KB
-rw-r--r--
contactform-fr.php.php.tar.gz
505
B
-rw-r--r--
contactform-fr.php.tar
2.5
KB
-rw-r--r--
contactfr.html.html.tar.gz
3.21
KB
-rw-r--r--
contactfr.html.tar
13
KB
-rw-r--r--
contacts.tar
5.34
MB
-rw-r--r--
contacts.tar.gz
2.1
MB
-rw-r--r--
contacts.zip
5.29
MB
-rw-r--r--
contacts_1.json.json.tar.gz
9.95
KB
-rw-r--r--
contacts_1.json.tar
63
KB
-rw-r--r--
content.tar
57
KB
-rw-r--r--
content.tar.gz
6.4
KB
-rw-r--r--
controller.php.php.tar.gz
897
B
-rw-r--r--
controller.php.tar
3
KB
-rw-r--r--
core.tar
1.05
MB
-rw-r--r--
core.tar.gz
197.59
KB
-rw-r--r--
core.zip
955.12
KB
-rw-r--r--
counterup.tar
30.5
KB
-rw-r--r--
counterup.tar.gz
7.66
KB
-rw-r--r--
counterup.zip
26.86
KB
-rw-r--r--
cover.tar
89.5
KB
-rw-r--r--
cover.tar.gz
5.54
KB
-rw-r--r--
cover.zip
82.63
KB
-rw-r--r--
credits.php.php.tar.gz
1.25
KB
-rw-r--r--
credits.php.tar
10
KB
-rw-r--r--
cron.php.php.tar.gz
162
B
-rw-r--r--
cron.php.tar
118
KB
-rw-r--r--
crystal.tar
24
KB
-rw-r--r--
crystal.tar.gz
15.15
KB
-rw-r--r--
css.png.png.tar.gz
2.8
KB
-rw-r--r--
css.png.tar
4.5
KB
-rw-r--r--
css.tar
11.84
MB
-rw-r--r--
css.tar.gz
44.02
KB
-rw-r--r--
css.zip
11.76
MB
-rw-r--r--
css1.tar
186.5
KB
-rw-r--r--
css1.tar.gz
41.71
KB
-rw-r--r--
css1.zip
183.94
KB
-rw-r--r--
css3.png.png.tar.gz
7.46
KB
-rw-r--r--
css3.png.tar
9.5
KB
-rw-r--r--
custom-background.php.php.tar....
376
B
-rw-r--r--
custom-background.php.tar
3
KB
-rw-r--r--
custom-header.php.php.tar.gz
10.61
KB
-rw-r--r--
custom-header.php.tar
48
KB
-rw-r--r--
customize-nav-menus.min.css.mi...
3.46
KB
-rw-r--r--
customize-nav-menus.min.css.ta...
19.5
KB
-rw-r--r--
customize.php.php.tar.gz
3.68
KB
-rw-r--r--
customize.php.tar
35.5
KB
-rw-r--r--
customize.tar
197.5
KB
-rw-r--r--
customize.tar.gz
38.7
KB
-rw-r--r--
customize.zip
173.55
KB
-rw-r--r--
d82fd3.tar
15.5
KB
-rw-r--r--
d82fd3.tar.gz
3.86
KB
-rw-r--r--
d82fd3.zip
13.78
KB
-rw-r--r--
dashboard.js.js.tar.gz
8.4
KB
-rw-r--r--
dashboard.js.tar
28.5
KB
-rw-r--r--
dashboard.min.js.min.js.tar.gz
3.11
KB
-rw-r--r--
dashboard.min.js.tar
10.5
KB
-rw-r--r--
dashicons.eot.eot.tar.gz
31.91
KB
-rw-r--r--
dashicons.eot.tar
57
KB
-rw-r--r--
dashicons.ttf.tar
57
KB
-rw-r--r--
dashicons.ttf.ttf.tar.gz
31.84
KB
-rw-r--r--
data.tar
230.5
KB
-rw-r--r--
data.tar.gz
11.82
KB
-rw-r--r--
data.zip
217.5
KB
-rw-r--r--
database.json.json.tar.gz
654
B
-rw-r--r--
database.json.tar
7
KB
-rw-r--r--
date.php.php.tar.gz
356
B
-rw-r--r--
date.php.tar
4
KB
-rw-r--r--
de-DE.tar
415.5
KB
-rw-r--r--
de-DE.tar.gz
92.58
KB
-rw-r--r--
default-constants.php.php.tar....
2.82
KB
-rw-r--r--
default-constants.php.tar
55.5
KB
-rw-r--r--
default-filters.php.php.tar.gz
7.89
KB
-rw-r--r--
default-filters.php.tar
223
KB
-rw-r--r--
default-widgets.php.php.tar.gz
508
B
-rw-r--r--
default-widgets.php.tar
16
KB
-rw-r--r--
default.php.php.tar.gz
1.45
KB
-rw-r--r--
default.php.tar
9
KB
-rw-r--r--
default.png.png.tar.gz
616
B
-rw-r--r--
default.png.tar
3
KB
-rw-r--r--
default1.jpg.jpg.tar.gz
322.01
KB
-rw-r--r--
default1.jpg.tar
335
KB
-rw-r--r--
defaults.php.php.tar.gz
826
B
-rw-r--r--
defaults.php.tar
3
KB
-rw-r--r--
deprecated.php.php.tar.gz
39.99
KB
-rw-r--r--
deprecated.php.tar
183.5
KB
-rw-r--r--
details.zip
3.22
KB
-rw-r--r--
devices.png.png.tar.gz
1.93
KB
-rw-r--r--
devices.png.tar
3.5
KB
-rw-r--r--
devices_2.png.png.tar.gz
1.89
KB
-rw-r--r--
devices_2.png.tar
3.5
KB
-rw-r--r--
dff24.jpg.jpg.tar.gz
302.87
KB
-rw-r--r--
dff24.jpg.tar
322
KB
-rw-r--r--
digital.tar
25.36
MB
-rw-r--r--
digital.tar.gz
0
B
-rw-r--r--
digital.zip
25.31
MB
-rw-r--r--
dimensions.php.php.tar.gz
1.72
KB
-rw-r--r--
dimensions.php.tar
13
KB
-rw-r--r--
dist.tar
23.44
MB
-rw-r--r--
dist.tar.gz
938.9
KB
-rw-r--r--
dist.zip
5.6
MB
-rw-r--r--
divider.png.png.tar.gz
5.7
KB
-rw-r--r--
divider.png.tar
8
KB
-rw-r--r--
document.html.html.tar.gz
1.79
KB
-rw-r--r--
document.html.tar
6
KB
-rw-r--r--
domicile.jpg.jpg.tar.gz
13.32
KB
-rw-r--r--
domicile.jpg.tar
24
KB
-rw-r--r--
dompdf.tar
21.82
MB
-rw-r--r--
dompdf.tar.gz
9.51
MB
-rw-r--r--
drupal.png.png.tar.gz
10.02
KB
-rw-r--r--
drupal.png.tar
12
KB
-rw-r--r--
duplicate-post.zip
344.54
KB
-rw-r--r--
edit-form-advanced.php.php.tar...
8.69
KB
-rw-r--r--
edit-form-advanced.php.tar
60
KB
-rw-r--r--
edit-form-blocks.php.php.tar.g...
5.15
KB
-rw-r--r--
edit-form-blocks.php.tar
29
KB
-rw-r--r--
edit-form-comment.php.php.tar....
2.71
KB
-rw-r--r--
edit-form-comment.php.tar
10
KB
-rw-r--r--
edit-link-form.php.php.tar.gz
2.17
KB
-rw-r--r--
edit-link-form.php.tar
29
KB
-rw-r--r--
edit-tag-form.php.php.tar.gz
2.86
KB
-rw-r--r--
edit-tag-form.php.tar
23
KB
-rw-r--r--
edit-tags.php.php.tar.gz
5.84
KB
-rw-r--r--
edit-tags.php.tar
23.5
KB
-rw-r--r--
edit.php.php.tar.gz
5.55
KB
-rw-r--r--
edit.php.tar
21
KB
-rw-r--r--
editors-xtd.tar
31.5
KB
-rw-r--r--
editors-xtd.tar.gz
3.47
KB
-rw-r--r--
editors-xtd.zip
21.58
KB
-rw-r--r--
editors.zip
114.5
KB
-rw-r--r--
elementor-pro.tar
14.63
MB
-rw-r--r--
elementor-pro.tar.gz
2.24
MB
-rw-r--r--
elementor-pro.zip
14.26
MB
-rw-r--r--
elementor.tar
45.46
MB
-rw-r--r--
elementor.tar.gz
7.96
MB
-rw-r--r--
elementor.zip
57.4
MB
-rw-r--r--
elementorx.tar
38.7
MB
-rw-r--r--
elementorx.tar.gz
9.19
MB
-rw-r--r--
elementorx.zip
38.1
MB
-rw-r--r--
elements.tar
9.02
MB
-rw-r--r--
elements.tar.gz
8.57
MB
-rw-r--r--
elements.zip
8.98
MB
-rw-r--r--
eleve2.jpg.jpg.tar.gz
633.68
KB
-rw-r--r--
eleve2.jpg.tar
650.5
KB
-rw-r--r--
embed-template.php.php.tar.gz
326
B
-rw-r--r--
embed-template.php.tar
2
KB
-rw-r--r--
embed.php.php.tar.gz
9.94
KB
-rw-r--r--
embed.php.tar
39
KB
-rw-r--r--
emglobal.tar
167.75
MB
-rw-r--r--
emglobal.tar.gz
90.82
MB
-rw-r--r--
eminvest.tar
89.48
MB
-rw-r--r--
eminvest.tar.gz
25.19
KB
-rw-r--r--
eminvest.zip
81.62
KB
-rw-r--r--
en-GB.tar
902
KB
-rw-r--r--
en-GB.tar.gz
120.63
KB
-rw-r--r--
en-GB.zip
795.95
KB
-rw-r--r--
erase-personal-data.php.php.ta...
2.78
KB
-rw-r--r--
erase-personal-data.php.tar
9
KB
-rw-r--r--
error-protection.php.php.tar.g...
1.48
KB
-rw-r--r--
error-protection.php.tar
6
KB
-rw-r--r--
exceptions.tar
6
KB
-rw-r--r--
exceptions.tar.gz
790
B
-rw-r--r--
export.php.php.tar.gz
3.19
KB
-rw-r--r--
export.php.tar
25
KB
-rw-r--r--
extension.tar
186.5
KB
-rw-r--r--
extension.tar.gz
4.19
KB
-rw-r--r--
extension.zip
168.25
KB
-rw-r--r--
f0f.tar
2.09
MB
-rw-r--r--
f0f.tar.gz
490.91
KB
-rw-r--r--
f0f.zip
1.98
MB
-rw-r--r--
fail.php.php.tar.gz
213
B
-rw-r--r--
fail.php.tar
2
KB
-rw-r--r--
favicon-16x16.png.png.tar.gz
1.44
KB
-rw-r--r--
favicon-16x16.png.tar
3.5
KB
-rw-r--r--
favicon-32x32.png.png.tar.gz
2.33
KB
-rw-r--r--
favicon-32x32.png.tar
4
KB
-rw-r--r--
favicon-96x96.png.png.tar.gz
8.35
KB
-rw-r--r--
favicon-96x96.png.tar
10
KB
-rw-r--r--
favicon.ico.ico.tar.gz
905
B
-rw-r--r--
favicon.ico.tar
6.5
KB
-rw-r--r--
favicon.png.png.tar.gz
1.94
KB
-rw-r--r--
favicon.png.tar
9.5
KB
-rw-r--r--
favicon2.png.png.tar.gz
1.48
KB
-rw-r--r--
favicon2.png.tar
6
KB
-rw-r--r--
feed-atom-comments.php.php.tar...
1.85
KB
-rw-r--r--
feed-atom-comments.php.tar
7
KB
-rw-r--r--
feed-atom.php.php.tar.gz
1.26
KB
-rw-r--r--
feed-atom.php.tar
8.5
KB
-rw-r--r--
feed-rdf.php.php.tar.gz
1.1
KB
-rw-r--r--
feed-rdf.php.tar
8
KB
-rw-r--r--
feed-rss.php.php.tar.gz
700
B
-rw-r--r--
feed-rss.php.tar
7
KB
-rw-r--r--
feed-rss2-comments.php.php.tar...
1.55
KB
-rw-r--r--
feed-rss2-comments.php.tar
6
KB
-rw-r--r--
feed-rss2.php.php.tar.gz
1.5
KB
-rw-r--r--
feed-rss2.php.tar
10
KB
-rw-r--r--
feed.php.php.tar.gz
5.91
KB
-rw-r--r--
feed.php.tar
48
KB
-rw-r--r--
fef.tar
409
KB
-rw-r--r--
fef.tar.gz
108.82
KB
-rw-r--r--
fef.zip
398.19
KB
-rw-r--r--
fields.tar
26.5
KB
-rw-r--r--
fields.tar.gz
4.84
KB
-rw-r--r--
file.php
80.47
KB
-rw-r--r--
file.php.php.tar.gz
24.83
KB
-rw-r--r--
file.php.tar
3.72
MB
-rw-r--r--
file.tar
22.5
KB
-rw-r--r--
file.tar.gz
3.07
KB
-rw-r--r--
flex.tar
6.17
MB
-rw-r--r--
flex.tar.gz
1.69
MB
-rw-r--r--
fof.zip
2
MB
-rw-r--r--
fontawesome-webfont.eot.eot.ta...
96.31
KB
-rw-r--r--
fontawesome-webfont.eot.tar
163.5
KB
-rw-r--r--
fontawesome-webfont.svg.svg.ta...
132.93
KB
-rw-r--r--
fontawesome-webfont.svg.tar
435.5
KB
-rw-r--r--
fontawesome-webfont.ttf.tar
163.5
KB
-rw-r--r--
fontawesome-webfont.ttf.ttf.ta...
96.22
KB
-rw-r--r--
fontawesome-webfont.woff.tar
97.5
KB
-rw-r--r--
fontawesome-webfont.woff.woff....
95.75
KB
-rw-r--r--
fontawesome-webfont.woff2.tar
77
KB
-rw-r--r--
fontawesome-webfont.woff2.woff...
75.51
KB
-rw-r--r--
fonts.php.php.tar.gz
2.69
KB
-rw-r--r--
fonts.php.tar
11
KB
-rw-r--r--
fonts.tar
2.93
MB
-rw-r--r--
fonts.tar.gz
608.17
KB
-rw-r--r--
fonts.zip
2.91
MB
-rw-r--r--
footnotes.zip
3.27
KB
-rw-r--r--
form.tar
2.5
KB
-rw-r--r--
form.tar.gz
475
B
-rw-r--r--
form.zip
1.14
KB
-rw-r--r--
formatting.php.php.tar.gz
65.1
KB
-rw-r--r--
formatting.php.tar
329.5
KB
-rw-r--r--
forms-rtl.min.css.min.css.tar....
6.69
KB
-rw-r--r--
forms-rtl.min.css.tar
29.5
KB
-rw-r--r--
fr-FR.zip
432.44
KB
-rw-r--r--
framework.php.php.tar.gz
1.38
KB
-rw-r--r--
framework.php.tar
14
KB
-rw-r--r--
freeform.zip
41.54
KB
-rw-r--r--
freepik_edit_3d-model-octane-r...
573.77
KB
-rw-r--r--
freepik_edit_3d-model-octane-r...
646
KB
-rw-r--r--
full-responsive.png.png.tar.gz
1.11
MB
-rw-r--r--
full-responsive.png.tar
1.12
MB
-rw-r--r--
functions.php.php.tar.gz
71.93
KB
-rw-r--r--
functions.php.tar
557.5
KB
-rw-r--r--
functions.wp-scripts.php.tar
16
KB
-rw-r--r--
functions.wp-scripts.php.wp-sc...
3.98
KB
-rw-r--r--
functions.wp-styles.php.tar
19
KB
-rw-r--r--
functions.wp-styles.php.wp-sty...
2.29
KB
-rw-r--r--
gallery.tar
1.24
MB
-rw-r--r--
gallery.tar.gz
933.8
KB
-rw-r--r--
gallery.zip
1.23
MB
-rw-r--r--
gantry.zip
42.42
KB
-rw-r--r--
gantry5.tar
9.78
MB
-rw-r--r--
gantry5.tar.gz
521.58
KB
-rw-r--r--
gantry5.zip
6.48
MB
-rw-r--r--
general-template.php.php.tar.g...
34.11
KB
-rw-r--r--
general-template.php.tar
490.5
KB
-rw-r--r--
genieprevention.jpg.jpg.tar.gz
224.21
KB
-rw-r--r--
genieprevention.jpg.tar
250.5
KB
-rw-r--r--
genieprevention.png.png.tar.gz
1.14
MB
-rw-r--r--
genieprevention.png.tar
1.17
MB
-rw-r--r--
genieprevention.tar
127.85
MB
-rw-r--r--
genieprevention.tar.gz
59.62
MB
-rw-r--r--
getid3.lib.php.lib.php.tar.gz
12.36
KB
-rw-r--r--
getid3.lib.php.tar
55
KB
-rw-r--r--
global-styles-and-settings.php...
5.27
KB
-rw-r--r--
global-styles-and-settings.php...
22.5
KB
-rw-r--r--
google-map.tar
15
KB
-rw-r--r--
google-map.tar.gz
4.24
KB
-rw-r--r--
google-map.zip
12.63
KB
-rw-r--r--
google13cccd2253d2ff59.html.ht...
151
B
-rw-r--r--
google13cccd2253d2ff59.html.ta...
2
KB
-rw-r--r--
google9d63adf694ce55d9.html.ht...
155
B
-rw-r--r--
google9d63adf694ce55d9.html.ta...
2
KB
-rw-r--r--
googleaa8106a26df5450e.html.ht...
152
B
-rw-r--r--
googleaa8106a26df5450e.html.ta...
2
KB
-rw-r--r--
grid1.jpg.jpg.tar.gz
39.16
KB
-rw-r--r--
grid1.jpg.tar
40.5
KB
-rw-r--r--
group.tar
21
KB
-rw-r--r--
group.tar.gz
1.69
KB
-rw-r--r--
group.zip
10.62
KB
-rw-r--r--
header.php.php.tar.gz
989
B
-rw-r--r--
header.php.tar
4
KB
-rw-r--r--
headers.tar
153.5
KB
-rw-r--r--
headers.tar.gz
147.74
KB
-rw-r--r--
headers.zip
149.11
KB
-rw-r--r--
heading.php.php.tar.gz
700
B
-rw-r--r--
heading.php.tar
3
KB
-rw-r--r--
help.tar
8
KB
-rw-r--r--
help.tar.gz
1.14
KB
-rw-r--r--
help.zip
5.76
KB
-rw-r--r--
helpers.tar
14
KB
-rw-r--r--
helpers.tar.gz
2.92
KB
-rw-r--r--
hightlight.css.css.tar.gz
541
B
-rw-r--r--
hightlight.css.tar
2.5
KB
-rw-r--r--
hikashoppayment.tar
1.63
MB
-rw-r--r--
hikashoppayment.tar.gz
433.55
KB
-rw-r--r--
hikashoppayment.zip
1.45
MB
-rw-r--r--
home-link.tar
3
KB
-rw-r--r--
home-link.tar.gz
598
B
-rw-r--r--
home-link.zip
1.25
KB
-rw-r--r--
hover.css.css.tar.gz
4.2
KB
-rw-r--r--
hover.css.tar
47
KB
-rw-r--r--
htaccess.txt.tar
28.5
KB
-rw-r--r--
htaccess.txt.txt.tar.gz
1.53
KB
-rw-r--r--
html-api.tar
535.5
KB
-rw-r--r--
html-api.tar.gz
90.01
KB
-rw-r--r--
html-api.zip
526.46
KB
-rw-r--r--
html.png.png.tar.gz
5.08
KB
-rw-r--r--
html.png.tar
7
KB
-rw-r--r--
html.tar
33.5
KB
-rw-r--r--
html.tar.gz
966
B
-rw-r--r--
http.php.php.tar.gz
5.53
KB
-rw-r--r--
http.php.tar
52
KB
-rw-r--r--
http:.tar
82
KB
-rw-r--r--
http:.tar.gz
24.81
KB
-rw-r--r--
http:.zip
80.62
KB
-rw-r--r--
https-migration.php.php.tar.gz
1.65
KB
-rw-r--r--
https-migration.php.tar
12
KB
-rw-r--r--
https:.tar
82
KB
-rw-r--r--
https:.tar.gz
24.81
KB
-rw-r--r--
https:.zip
80.62
KB
-rw-r--r--
ibd.html.tar
1.5
KB
-rw-r--r--
icagenda.tar
14
KB
-rw-r--r--
icagenda.tar.gz
3.01
KB
-rw-r--r--
icon_fonts.tar
3.44
MB
-rw-r--r--
icon_fonts.tar.gz
1.48
MB
-rw-r--r--
icon_fonts.zip
3.43
MB
-rw-r--r--
ident.tar
1.84
MB
-rw-r--r--
ident.tar.gz
1.69
MB
-rw-r--r--
ident.zip
1.84
MB
-rw-r--r--
identification_qr_code_joe007....
426.41
KB
-rw-r--r--
identification_qr_code_joe007....
452.5
KB
-rw-r--r--
identification_qrcode_suly007....
425.82
KB
-rw-r--r--
identification_qrcode_suly007....
452
KB
-rw-r--r--
idna_convert.zip
142.7
KB
-rw-r--r--
image.php.php.tar.gz
4.05
KB
-rw-r--r--
image.php.tar
13.5
KB
-rw-r--r--
images.jfif.jfif.tar.gz
3.66
KB
-rw-r--r--
images.jfif.tar
5.5
KB
-rw-r--r--
images.tar
185.22
MB
-rw-r--r--
images.tar.gz
9.73
MB
-rw-r--r--
images.zip
204.64
MB
-rw-r--r--
img.tar
1.83
MB
-rw-r--r--
img.tar.gz
638.06
KB
-rw-r--r--
img.zip
1.77
MB
-rw-r--r--
import.php.php.tar.gz
2.68
KB
-rw-r--r--
import.php.tar
17.5
KB
-rw-r--r--
include-component.tar
342.5
KB
-rw-r--r--
include-component.tar.gz
319.18
KB
-rw-r--r--
includes.tar
2.8
MB
-rw-r--r--
includes.tar.gz
26.35
KB
-rw-r--r--
includes.zip
2.99
MB
-rw-r--r--
index-home.html.html.tar.gz
4.34
KB
-rw-r--r--
index-home.html.tar
22
KB
-rw-r--r--
index-slides.html.html.tar.gz
7.51
KB
-rw-r--r--
index-slides.html.tar
40.5
KB
-rw-r--r--
index-static.html.html.tar.gz
7.41
KB
-rw-r--r--
index-static.html.tar
40
KB
-rw-r--r--
index-text.html.html.tar.gz
6.78
KB
-rw-r--r--
index-text.html.tar
41.5
KB
-rw-r--r--
index.html.html.tar.gz
7.33
KB
-rw-r--r--
index.html.tar
99
KB
-rw-r--r--
index.jpg.jpg.tar.gz
11.13
KB
-rw-r--r--
index.jpg.tar
13
KB
-rw-r--r--
index.php.php.tar.gz
351
B
-rw-r--r--
index.php.tar
83.5
KB
-rw-r--r--
index.php0.php0.tar.gz
855
B
-rw-r--r--
index.php0.tar
3
KB
-rw-r--r--
index5.php.php.tar.gz
353
B
-rw-r--r--
index5.php.tar
2
KB
-rw-r--r--
indexFR.html.html.tar.gz
5.82
KB
-rw-r--r--
indexFR.html.tar
27.5
KB
-rw-r--r--
index_files.tar
1.22
MB
-rw-r--r--
index_files.tar.gz
838.85
KB
-rw-r--r--
index_files.zip
1.21
MB
-rw-r--r--
indexfr.html.html.tar.gz
6.01
KB
-rw-r--r--
indexfr.html.tar
29.5
KB
-rw-r--r--
indexx.html.html.tar.gz
2.01
KB
-rw-r--r--
indexx.html.tar
8
KB
-rw-r--r--
indexx.php.php.tar.gz
357
B
-rw-r--r--
indexx.php.tar
2
KB
-rw-r--r--
install-helper.php.php.tar.gz
1.97
KB
-rw-r--r--
install-helper.php.tar
37.5
KB
-rw-r--r--
install.html.html.tar.gz
160
B
-rw-r--r--
install.html.tar
2
KB
-rw-r--r--
install.php.php.tar.gz
5.21
KB
-rw-r--r--
install.php.tar
72.5
KB
-rw-r--r--
installer.tar
74
KB
-rw-r--r--
installer.tar.gz
14.3
KB
-rw-r--r--
installer.zip
70.91
KB
-rw-r--r--
interactivity-api.tar
57.5
KB
-rw-r--r--
interactivity-api.tar.gz
13.26
KB
-rw-r--r--
interactivity-api.zip
54.55
KB
-rw-r--r--
ion.rangeSlider.min.css.rangeS...
1.05
KB
-rw-r--r--
ion.rangeSlider.min.css.tar
5
KB
-rw-r--r--
ionicons.css.css.tar.gz
8.76
KB
-rw-r--r--
ionicons.css.tar
57.5
KB
-rw-r--r--
ionicons.eot.eot.tar.gz
67.46
KB
-rw-r--r--
ionicons.eot.tar
119.5
KB
-rw-r--r--
ionicons.min.css.min.css.tar.g...
8.19
KB
-rw-r--r--
ionicons.min.css.tar
52
KB
-rw-r--r--
ionicons.svg.svg.tar.gz
100.45
KB
-rw-r--r--
ionicons.svg.tar
328
KB
-rw-r--r--
ionicons.ttf.tar
186
KB
-rw-r--r--
ionicons.ttf.ttf.tar.gz
107.36
KB
-rw-r--r--
ionicons.woff.tar
68
KB
-rw-r--r--
ionicons.woff.woff.tar.gz
65.47
KB
-rw-r--r--
it_sanctum.tar
7.63
MB
-rw-r--r--
it_sanctum.tar.gz
3.36
MB
-rw-r--r--
it_sanctum.zip
7.36
MB
-rw-r--r--
java.png.png.tar.gz
4.57
KB
-rw-r--r--
java.png.tar
6
KB
-rw-r--r--
jce.tar
285
KB
-rw-r--r--
jce.tar.gz
258.77
KB
-rw-r--r--
jce.zip
263.86
KB
-rw-r--r--
jcrop.zip
24.83
KB
-rw-r--r--
joomla.png.png.tar.gz
10.05
KB
-rw-r--r--
joomla.png.tar
12
KB
-rw-r--r--
joomla.tar
2.09
MB
-rw-r--r--
joomla.tar.gz
34.7
KB
-rw-r--r--
joomla.zip
1.86
MB
-rw-r--r--
joomla_black.png.png.tar.gz
5.04
KB
-rw-r--r--
joomla_black.png.tar
6.5
KB
-rw-r--r--
jquery-1.10.2.js.10.2.js.tar.g...
79.27
KB
-rw-r--r--
jquery-1.10.2.js.tar
268.5
KB
-rw-r--r--
jquery-1.7.2.js.7.2.js.tar.gz
32.95
KB
-rw-r--r--
jquery-1.7.2.js.tar
94.5
KB
-rw-r--r--
jquery-3.1.1.min.js.1.1.min.js...
29.5
KB
-rw-r--r--
jquery-3.1.1.min.js.tar
86.5
KB
-rw-r--r--
jquery-3.3.1.min.js.3.1.min.js...
23.63
KB
-rw-r--r--
jquery-3.3.1.min.js.tar
70
KB
-rw-r--r--
jquery.prettyPhoto.js.prettyPh...
6.23
KB
-rw-r--r--
jquery.prettyPhoto.js.tar
37.5
KB
-rw-r--r--
jquery.quicksand.js.quicksand....
3.32
KB
-rw-r--r--
jquery.quicksand.js.tar
16
KB
-rw-r--r--
jquery.tar
1.31
MB
-rw-r--r--
jquery.tar.gz
354.74
KB
-rw-r--r--
js.png.png.tar.gz
5.12
KB
-rw-r--r--
js.png.tar
7
KB
-rw-r--r--
js.tar
28.98
MB
-rw-r--r--
js.tar.gz
88.56
KB
-rw-r--r--
js.zip
28.81
MB
-rw-r--r--
jui.tar
1.93
MB
-rw-r--r--
jui.tar.gz
608.39
KB
-rw-r--r--
jui.zip
1.86
MB
-rw-r--r--
jw_allvideos.tar
8.5
KB
-rw-r--r--
jw_allvideos.tar.gz
6.89
KB
-rw-r--r--
jw_allvideos.zip
6.93
KB
-rw-r--r--
k2.tar
19.06
MB
-rw-r--r--
k2.tar.gz
12.15
MB
-rw-r--r--
k2.zip
20.62
MB
-rw-r--r--
keychain.php.php.tar.gz
2.5
KB
-rw-r--r--
keychain.php.tar
10
KB
-rw-r--r--
keys.tar
83
KB
-rw-r--r--
keys.tar.gz
24.92
KB
-rw-r--r--
keys.zip
80.85
KB
-rw-r--r--
kses.php.php.tar.gz
15.21
KB
-rw-r--r--
kses.php.tar
137
KB
-rw-r--r--
l10n.php.php.tar.gz
10.36
KB
-rw-r--r--
l10n.php.tar
123
KB
-rw-r--r--
l10n.tar
35.5
KB
-rw-r--r--
l10n.tar.gz
6.3
KB
-rw-r--r--
l10n.zip
31.37
KB
-rw-r--r--
langmetadata.xml.tar
4
KB
-rw-r--r--
langmetadata.xml.xml.tar.gz
602
B
-rw-r--r--
language.tar
4.46
MB
-rw-r--r--
language.tar.gz
712.33
KB
-rw-r--r--
language.zip
901.86
KB
-rw-r--r--
languages.tar
45.74
MB
-rw-r--r--
languages.tar.gz
10.09
MB
-rw-r--r--
languages.zip
45.4
MB
-rw-r--r--
latest-posts.tar
18
KB
-rw-r--r--
latest-posts.tar.gz
1.95
KB
-rw-r--r--
latest-posts.zip
12.74
KB
-rw-r--r--
layerslider.tar
742.5
KB
-rw-r--r--
layerslider.tar.gz
377.05
KB
-rw-r--r--
layerslider.zip
702.11
KB
-rw-r--r--
layouts.tar
576
KB
-rw-r--r--
layouts.tar.gz
64.14
KB
-rw-r--r--
layouts.zip
472.05
KB
-rw-r--r--
libraries.tar
65.01
MB
-rw-r--r--
libraries.tar.gz
3.69
MB
-rw-r--r--
libraries.zip
65.53
MB
-rw-r--r--
library.tar
2
KB
-rw-r--r--
library.tar.gz
263
B
-rw-r--r--
license.txt.tar
241
KB
-rw-r--r--
license.txt.txt.tar.gz
7.23
KB
-rw-r--r--
link-add.php.php.tar.gz
590
B
-rw-r--r--
link-add.php.tar
2.5
KB
-rw-r--r--
link-manager.php.php.tar.gz
1.88
KB
-rw-r--r--
link-manager.php.tar
6
KB
-rw-r--r--
link-parse-opml.php.php.tar.gz
1.09
KB
-rw-r--r--
link-parse-opml.php.tar
4.5
KB
-rw-r--r--
link-template.php.php.tar.gz
25.97
KB
-rw-r--r--
link-template.php.tar
154
KB
-rw-r--r--
link.php.php.tar.gz
1.15
KB
-rw-r--r--
link.php.tar
4.5
KB
-rw-r--r--
list.php.php.tar.gz
699
B
-rw-r--r--
list.php.tar
3
KB
-rw-r--r--
load-scripts.php.php.tar.gz
939
B
-rw-r--r--
load-scripts.php.tar
6.5
KB
-rw-r--r--
load-styles.php.php.tar.gz
1.14
KB
-rw-r--r--
load-styles.php.tar
8
KB
-rw-r--r--
load.php.php.tar.gz
14.85
KB
-rw-r--r--
load.php.tar
56
KB
-rw-r--r--
loader.gif.gif.tar.gz
2.23
KB
-rw-r--r--
loader.gif.tar
4
KB
-rw-r--r--
loader.php.php.tar.gz
5.63
KB
-rw-r--r--
loader.php.tar
24
KB
-rw-r--r--
locale.php.php.tar.gz
245
B
-rw-r--r--
locale.php.tar
4
KB
-rw-r--r--
location.pdf.pdf.tar.gz
475.03
KB
-rw-r--r--
location.pdf.tar
495
KB
-rw-r--r--
log.tar
82
KB
-rw-r--r--
log.tar.gz
24.81
KB
-rw-r--r--
log.zip
80.62
KB
-rw-r--r--
login.tar
101.44
MB
-rw-r--r--
login.tar.gz
45.21
MB
-rw-r--r--
login.zip
96.15
MB
-rw-r--r--
loginout.zip
1.15
KB
-rw-r--r--
logo ala maze.ai.ai.tar.gz
1.36
MB
-rw-r--r--
logo ala maze.ai.tar
1.42
MB
-rw-r--r--
logo-white.png.png.tar.gz
4.59
KB
-rw-r--r--
logo-white.png.tar
6
KB
-rw-r--r--
logo.png.png.tar.gz
92.76
KB
-rw-r--r--
logo.png.tar
211.5
KB
-rw-r--r--
logo.tar
497
KB
-rw-r--r--
logo.tar.gz
96
B
-rw-r--r--
logo.zip
493.46
KB
-rw-r--r--
logo2.png.png.tar.gz
3.13
KB
-rw-r--r--
logo2.png.tar
4.5
KB
-rw-r--r--
logo_2x.png.png.tar.gz
1.9
KB
-rw-r--r--
logo_2x.png.tar
3.5
KB
-rw-r--r--
logo_sticky.png.png.tar.gz
1.24
KB
-rw-r--r--
logo_sticky.png.tar
3
KB
-rw-r--r--
logoindex2.png.png.tar.gz
3.89
KB
-rw-r--r--
logoindex2.png.tar
10
KB
-rw-r--r--
logos.tar
1.5
KB
-rw-r--r--
logos.tar.gz
97
B
-rw-r--r--
logowhite.png.png.tar.gz
3.98
KB
-rw-r--r--
logowhite.png.tar
6
KB
-rw-r--r--
logrotation.zip
8.03
KB
-rw-r--r--
logs.tar
117.5
KB
-rw-r--r--
logs.tar.gz
25.54
KB
-rw-r--r--
logs.zip
353.88
KB
-rw-r--r--
magento.png.png.tar.gz
50.73
KB
-rw-r--r--
magento.png.tar
60.5
KB
-rw-r--r--
mailto.tar
2
KB
-rw-r--r--
mailto.tar.gz
208
B
-rw-r--r--
mailto.zip
284
B
-rw-r--r--
main-banner_old2.jpg.jpg.tar.g...
61.7
KB
-rw-r--r--
main-banner_old2.jpg.tar
95.5
KB
-rw-r--r--
main.css.css.tar.gz
2.27
KB
-rw-r--r--
main.css.tar
10.5
KB
-rw-r--r--
main.js.js.tar.gz
1.83
KB
-rw-r--r--
main.js.tar
7
KB
-rw-r--r--
main.min.css.min.css.tar.gz
1.97
KB
-rw-r--r--
main.min.css.tar
8
KB
-rw-r--r--
main.min.js.min.js.tar.gz
1.66
KB
-rw-r--r--
main.min.js.tar
6
KB
-rw-r--r--
maint.tar
9
KB
-rw-r--r--
maint.tar.gz
2.66
KB
-rw-r--r--
maint.zip
7.56
KB
-rw-r--r--
manifest.json.json.tar.gz
294
B
-rw-r--r--
manifest.json.tar
2.5
KB
-rw-r--r--
mapmarker_func.jquery.js.jquer...
317
B
-rw-r--r--
mapmarker_func.jquery.js.tar
2
KB
-rw-r--r--
maps.tar
79.5
KB
-rw-r--r--
maps.tar.gz
19.9
KB
-rw-r--r--
maps.zip
77.71
KB
-rw-r--r--
media-audiovideo.js.js.tar.gz
6.02
KB
-rw-r--r--
media-audiovideo.js.tar
28.5
KB
-rw-r--r--
media-button-2x.png.png.tar.gz
1007
B
-rw-r--r--
media-button-2x.png.tar
2.5
KB
-rw-r--r--
media-button-image.gif.gif.tar...
325
B
-rw-r--r--
media-button-image.gif.tar
2
KB
-rw-r--r--
media-button-other.gif.gif.tar...
409
B
-rw-r--r--
media-button-other.gif.tar
2
KB
-rw-r--r--
media-button.png.png.tar.gz
475
B
-rw-r--r--
media-button.png.tar
2
KB
-rw-r--r--
media-new.php.php.tar.gz
1.57
KB
-rw-r--r--
media-new.php.tar
9
KB
-rw-r--r--
media-template.php.php.tar.gz
11.15
KB
-rw-r--r--
media-template.php.tar
184.5
KB
-rw-r--r--
media-text.tar
22
KB
-rw-r--r--
media-text.tar.gz
2.2
KB
-rw-r--r--
media-text.zip
15.34
KB
-rw-r--r--
media-upload.php.php.tar.gz
1.46
KB
-rw-r--r--
media-upload.php.tar
13
KB
-rw-r--r--
media.php.php.tar.gz
36.43
KB
-rw-r--r--
media.php.tar
368.5
KB
-rw-r--r--
media.tar
76.18
MB
-rw-r--r--
media.tar.gz
16.27
MB
-rw-r--r--
media.zip
69.29
MB
-rw-r--r--
mediaelement.tar
2.19
MB
-rw-r--r--
mediaelement.tar.gz
154.85
KB
-rw-r--r--
mediaelement.zip
2.17
MB
-rw-r--r--
member.jpg.jpg.tar.gz
8.99
KB
-rw-r--r--
member.jpg.tar
11
KB
-rw-r--r--
menu-header.php.php.tar.gz
2.89
KB
-rw-r--r--
menu-header.php.tar
11.5
KB
-rw-r--r--
menu.php.php.tar.gz
4.47
KB
-rw-r--r--
menu.php.tar
18.5
KB
-rw-r--r--
menu.tar
5.5
KB
-rw-r--r--
menu.tar.gz
1.26
KB
-rw-r--r--
meta-boxes.php.php.tar.gz
12.82
KB
-rw-r--r--
meta-boxes.php.tar
185.5
KB
-rw-r--r--
meta.php.php.tar.gz
9.97
KB
-rw-r--r--
meta.php.tar
290
KB
-rw-r--r--
metismenujs.tar
77
KB
-rw-r--r--
metismenujs.tar.gz
16.01
KB
-rw-r--r--
middletv.tar
17.4
MB
-rw-r--r--
middletv.tar.gz
9.32
MB
-rw-r--r--
middletv.zip
17.23
MB
-rw-r--r--
missing.tar
2.5
KB
-rw-r--r--
missing.tar.gz
396
B
-rw-r--r--
mod_acymailing.zip
60.47
KB
-rw-r--r--
mod_articles_latest.tar
13
KB
-rw-r--r--
mod_articles_latest.tar.gz
2.95
KB
-rw-r--r--
mod_articles_latest.zip
9.55
KB
-rw-r--r--
mod_articles_news.tar
23.5
KB
-rw-r--r--
mod_articles_news.tar.gz
4.22
KB
-rw-r--r--
mod_articles_popular.zip
9.37
KB
-rw-r--r--
mod_breadcrumbs.tar
13
KB
-rw-r--r--
mod_breadcrumbs.tar.gz
2.95
KB
-rw-r--r--
mod_breadcrumbs.zip
9.32
KB
-rw-r--r--
mod_custom.tar
7
KB
-rw-r--r--
mod_custom.tar.gz
1.57
KB
-rw-r--r--
mod_custom.zip
4.06
KB
-rw-r--r--
mod_falang.tar
50.5
KB
-rw-r--r--
mod_falang.tar.gz
9.35
KB
-rw-r--r--
mod_falang.zip
44.2
KB
-rw-r--r--
mod_feed.zip
10.14
KB
-rw-r--r--
mod_finder.tar
18
KB
-rw-r--r--
mod_finder.tar.gz
4.23
KB
-rw-r--r--
mod_hikashop_filter.tar
15
KB
-rw-r--r--
mod_hikashop_filter.tar.gz
2.09
KB
-rw-r--r--
mod_k2_tools.tar
88
KB
-rw-r--r--
mod_k2_tools.tar.gz
13.73
KB
-rw-r--r--
mod_k2_tools.zip
79.47
KB
-rw-r--r--
mod_languages.tar
18.5
KB
-rw-r--r--
mod_languages.tar.gz
3.59
KB
-rw-r--r--
mod_languages.zip
14.83
KB
-rw-r--r--
mod_multilangstatus.tar
8
KB
-rw-r--r--
mod_multilangstatus.tar.gz
1.17
KB
-rw-r--r--
mod_privacy_dashboard.tar
10.5
KB
-rw-r--r--
mod_privacy_dashboard.tar.gz
2.18
KB
-rw-r--r--
mod_privacy_dashboard.zip
6.72
KB
-rw-r--r--
mod_related_items.zip
8.91
KB
-rw-r--r--
mod_search.tar
13
KB
-rw-r--r--
mod_search.tar.gz
2.86
KB
-rw-r--r--
mod_search.zip
9.7
KB
-rw-r--r--
mod_spsimpleportfolio.tar
25.5
KB
-rw-r--r--
mod_spsimpleportfolio.tar.gz
5.22
KB
-rw-r--r--
mod_sr_currency.tar
30.5
KB
-rw-r--r--
mod_sr_currency.tar.gz
3.72
KB
-rw-r--r--
mod_stats.tar
16.5
KB
-rw-r--r--
mod_stats.tar.gz
2.36
KB
-rw-r--r--
mod_stats.zip
12.43
KB
-rw-r--r--
mod_submenu.tar
7
KB
-rw-r--r--
mod_submenu.tar.gz
1.56
KB
-rw-r--r--
mod_syndicate.tar
8.5
KB
-rw-r--r--
mod_syndicate.tar.gz
1.77
KB
-rw-r--r--
mod_syndicate.zip
5.02
KB
-rw-r--r--
mod_tags_popular.zip
13.4
KB
-rw-r--r--
mod_tags_similar.tar
14
KB
-rw-r--r--
mod_tags_similar.tar.gz
3.23
KB
-rw-r--r--
mod_tags_similar.zip
11.02
KB
-rw-r--r--
mod_users_latest.tar
9
KB
-rw-r--r--
mod_users_latest.tar.gz
2.01
KB
-rw-r--r--
mod_users_latest.zip
5.81
KB
-rw-r--r--
mod_wrapper.tar
11
KB
-rw-r--r--
mod_wrapper.tar.gz
2.21
KB
-rw-r--r--
mod_wrapper.zip
7.83
KB
-rw-r--r--
modal.zip
17.12
KB
-rw-r--r--
models.tar
6.5
KB
-rw-r--r--
models.tar.gz
1.57
KB
-rw-r--r--
moderation.php.php.tar.gz
303
B
-rw-r--r--
moderation.php.tar
2
KB
-rw-r--r--
modules.tar
2.56
MB
-rw-r--r--
modules.tar.gz
87.17
KB
-rw-r--r--
modules.zip
3.04
MB
-rw-r--r--
more.zip
4.38
KB
-rw-r--r--
ms-admin.php.php.tar.gz
263
B
-rw-r--r--
ms-admin.php.tar
2
KB
-rw-r--r--
ms-blogs.php.php.tar.gz
6.12
KB
-rw-r--r--
ms-blogs.php.tar
27
KB
-rw-r--r--
ms-default-constants.php.php.t...
1.66
KB
-rw-r--r--
ms-default-constants.php.tar
23
KB
-rw-r--r--
ms-default-filters.php.php.tar...
1.8
KB
-rw-r--r--
ms-default-filters.php.tar
27.5
KB
-rw-r--r--
ms-delete-site.php.php.tar.gz
1.87
KB
-rw-r--r--
ms-delete-site.php.tar
11
KB
-rw-r--r--
ms-deprecated.php.php.tar.gz
6.25
KB
-rw-r--r--
ms-deprecated.php.tar
23
KB
-rw-r--r--
ms-edit.php.php.tar.gz
280
B
-rw-r--r--
ms-edit.php.tar
3
KB
-rw-r--r--
ms-files.php.php.tar.gz
1.22
KB
-rw-r--r--
ms-files.php.tar
8
KB
-rw-r--r--
ms-functions.php.php.tar.gz
19.22
KB
-rw-r--r--
ms-functions.php.tar
91
KB
-rw-r--r--
ms-icon-144x144.png.png.tar.gz
14.3
KB
-rw-r--r--
ms-icon-144x144.png.tar
16
KB
-rw-r--r--
ms-icon-150x150.png.png.tar.gz
14.94
KB
-rw-r--r--
ms-icon-150x150.png.tar
16.5
KB
-rw-r--r--
ms-icon-310x310.png.png.tar.gz
43.67
KB
-rw-r--r--
ms-icon-310x310.png.tar
45.5
KB
-rw-r--r--
ms-icon-70x70.png.png.tar.gz
5.71
KB
-rw-r--r--
ms-icon-70x70.png.tar
7.5
KB
-rw-r--r--
ms-load.php.php.tar.gz
6.03
KB
-rw-r--r--
ms-load.php.tar
40.5
KB
-rw-r--r--
ms-network.php.php.tar.gz
1.47
KB
-rw-r--r--
ms-network.php.tar
10
KB
-rw-r--r--
ms-options.php.php.tar.gz
282
B
-rw-r--r--
ms-options.php.tar
2
KB
-rw-r--r--
ms-settings.php.php.tar.gz
1.62
KB
-rw-r--r--
ms-settings.php.tar
11
KB
-rw-r--r--
ms-site.php.php.tar.gz
9.44
KB
-rw-r--r--
ms-site.php.tar
41
KB
-rw-r--r--
ms-sites.php.php.tar.gz
273
B
-rw-r--r--
ms-sites.php.tar
3
KB
-rw-r--r--
ms-upgrade-network.php.php.tar...
281
B
-rw-r--r--
ms-upgrade-network.php.tar
2
KB
-rw-r--r--
ms-users.php.php.tar.gz
274
B
-rw-r--r--
ms-users.php.tar
3
KB
-rw-r--r--
mu-plugins.tar
2.5
KB
-rw-r--r--
mu-plugins.tar.gz
393
B
-rw-r--r--
mu-plugins.zip
791
B
-rw-r--r--
my-music.online.tar
636.9
MB
-rw-r--r--
my-music.online.tar.gz
20
B
-rw-r--r--
my-sites.php.php.tar.gz
2.04
KB
-rw-r--r--
my-sites.php.tar
6.5
KB
-rw-r--r--
mymusicpromo-online.zip
53.39
MB
-rw-r--r--
mysql.png.png.tar.gz
4.7
KB
-rw-r--r--
mysql.png.tar
7
KB
-rw-r--r--
nav-menu-template.php.php.tar....
6.24
KB
-rw-r--r--
nav-menu-template.php.tar
76.5
KB
-rw-r--r--
nav-menu.php.php.tar.gz
9.58
KB
-rw-r--r--
nav-menu.php.tar
45
KB
-rw-r--r--
nav-menus.php.php.tar.gz
10.56
KB
-rw-r--r--
nav-menus.php.tar
50
KB
-rw-r--r--
navigation-link.tar
19.5
KB
-rw-r--r--
navigation-link.tar.gz
1.97
KB
-rw-r--r--
navigation-submenu.zip
9.26
KB
-rw-r--r--
navigation.zip
131.13
KB
-rw-r--r--
network.php.php.tar.gz
2.23
KB
-rw-r--r--
network.php.tar
7
KB
-rw-r--r--
network.tar
145.5
KB
-rw-r--r--
network.tar.gz
27.6
KB
-rw-r--r--
network.zip
127.06
KB
-rw-r--r--
networks.php.php.tar.gz
1.07
KB
-rw-r--r--
networks.php.tar
3.5
KB
-rw-r--r--
newsletter.php.php.tar.gz
1.39
KB
-rw-r--r--
newsletter.php.tar
4
KB
-rw-r--r--
nl-NL.tar
354.5
KB
-rw-r--r--
nl-NL.tar.gz
79.1
KB
-rw-r--r--
nl-NL.zip
304
KB
-rw-r--r--
node.png.png.tar.gz
51.8
KB
-rw-r--r--
node.png.tar
57.5
KB
-rw-r--r--
node2.png.png.tar.gz
26.86
KB
-rw-r--r--
node2.png.tar
32
KB
-rw-r--r--
odfiafrica.jpg.jpg.tar.gz
384.95
KB
-rw-r--r--
odfiafrica.jpg.tar
417
KB
-rw-r--r--
onepage-slider.html.html.tar.g...
6.99
KB
-rw-r--r--
onepage-slider.html.tar
42.5
KB
-rw-r--r--
onepage-text.html.html.tar.gz
6.9
KB
-rw-r--r--
onepage-text.html.tar
42
KB
-rw-r--r--
option.php.php.tar.gz
13.11
KB
-rw-r--r--
option.php.tar
532.5
KB
-rw-r--r--
options-discussion.php.php.tar...
4.27
KB
-rw-r--r--
options-discussion.php.tar
82
KB
-rw-r--r--
options-general.php.php.tar.gz
6.41
KB
-rw-r--r--
options-general.php.tar
83
KB
-rw-r--r--
options-head.php.php.tar.gz
464
B
-rw-r--r--
options-head.php.tar
2.5
KB
-rw-r--r--
options-permalink.php.php.tar....
5.59
KB
-rw-r--r--
options-permalink.php.tar
88.5
KB
-rw-r--r--
options-privacy.php.php.tar.gz
2.71
KB
-rw-r--r--
options-privacy.php.tar
41
KB
-rw-r--r--
options-reading.php.php.tar.gz
3.1
KB
-rw-r--r--
options-reading.php.tar
12
KB
-rw-r--r--
options-writing.php.php.tar.gz
3.05
KB
-rw-r--r--
options-writing.php.tar
21
KB
-rw-r--r--
options.php.php.tar.gz
4.51
KB
-rw-r--r--
options.php.tar
56.5
KB
-rw-r--r--
overrider.tar
12.5
KB
-rw-r--r--
overrider.tar.gz
2.86
KB
-rw-r--r--
overrider.zip
9.83
KB
-rw-r--r--
overrides.tar
3
KB
-rw-r--r--
overrides.tar.gz
269
B
-rw-r--r--
overrides.zip
512
B
-rw-r--r--
owl.carousel.js.carousel.js.ta...
17.24
KB
-rw-r--r--
owl.carousel.js.tar
79
KB
-rw-r--r--
owl.carousel.min.js.carousel.m...
10.39
KB
-rw-r--r--
owl.carousel.min.js.tar
89
KB
-rw-r--r--
p1.jpg.jpg.tar.gz
237.02
KB
-rw-r--r--
p1.jpg.tar
243.5
KB
-rw-r--r--
p2.jpg.jpg.tar.gz
283.15
KB
-rw-r--r--
p2.jpg.tar
285
KB
-rw-r--r--
p3.jpg.jpg.tar.gz
287.59
KB
-rw-r--r--
p3.jpg.tar
289.5
KB
-rw-r--r--
p4.jpg.jpg.tar.gz
394.73
KB
-rw-r--r--
p4.jpg.tar
396.5
KB
-rw-r--r--
p5.jpg.jpg.tar.gz
177.65
KB
-rw-r--r--
p5.jpg.tar
181
KB
-rw-r--r--
p6.jpg.jpg.tar.gz
601.57
KB
-rw-r--r--
p6.jpg.tar
603
KB
-rw-r--r--
packageinstaller.zip
11.38
KB
-rw-r--r--
page-list-item.tar
3
KB
-rw-r--r--
page-list-item.tar.gz
576
B
-rw-r--r--
page-list.tar
15
KB
-rw-r--r--
page-list.tar.gz
1.39
KB
-rw-r--r--
pagebuilder.tar
6.09
MB
-rw-r--r--
pagebuilder.tar.gz
5.84
MB
-rw-r--r--
paralax-index1_old.jpg.jpg.tar...
794.32
KB
-rw-r--r--
paralax-index1_old.jpg.tar
807.5
KB
-rw-r--r--
particles.min.js.min.js.tar.gz
5.91
KB
-rw-r--r--
particles.min.js.tar
24.5
KB
-rw-r--r--
pattern.png.png.tar.gz
2.75
KB
-rw-r--r--
pattern.png.tar
4.5
KB
-rw-r--r--
pattern.svg.svg.tar.gz
17.24
KB
-rw-r--r--
pattern.svg.tar
53
KB
-rw-r--r--
pattern.zip
478
B
-rw-r--r--
payeer_1314567119.txt.tar
2
KB
-rw-r--r--
payeer_1314567119.txt.txt.tar....
128
B
-rw-r--r--
payments.png.png.tar.gz
10.04
KB
-rw-r--r--
payments.png.tar
11.5
KB
-rw-r--r--
payments_2x.png.png.tar.gz
31.26
KB
-rw-r--r--
payments_2x.png.tar
33
KB
-rw-r--r--
paypal_bt.png.png.tar.gz
13.5
KB
-rw-r--r--
paypal_bt.png.tar
15
KB
-rw-r--r--
paypaladvanced_2_6279148dd013c...
334
B
-rw-r--r--
paypaladvanced_2_6279148dd013c...
2.5
KB
-rw-r--r--
paypaladvanced_cancel_2.php.ph...
316
B
-rw-r--r--
paypaladvanced_cancel_2.php.ta...
2.5
KB
-rw-r--r--
paypaladvanced_return_2.php.ph...
316
B
-rw-r--r--
paypaladvanced_return_2.php.ta...
2.5
KB
-rw-r--r--
php-compat.tar
3
KB
-rw-r--r--
php-compat.tar.gz
649
B
-rw-r--r--
php-compat.zip
1.38
KB
-rw-r--r--
php-encryption.tar
26
KB
-rw-r--r--
php-encryption.tar.gz
6.52
KB
-rw-r--r--
php-encryption.zip
24.3
KB
-rw-r--r--
php.ini.ini.tar.gz
244
B
-rw-r--r--
php.ini.tar
3
KB
-rw-r--r--
php.png.png.tar.gz
4.91
KB
-rw-r--r--
php.png.tar
6.5
KB
-rw-r--r--
php_mail.log.log.tar.gz
6.45
KB
-rw-r--r--
php_mail.log.tar
100.5
KB
-rw-r--r--
pickapp.tar
83.5
KB
-rw-r--r--
pickapp.tar.gz
25.16
KB
-rw-r--r--
plg_installer_webinstaller.tar
34.5
KB
-rw-r--r--
plg_installer_webinstaller.tar...
6.53
KB
-rw-r--r--
plg_installer_webinstaller.zip
31.15
KB
-rw-r--r--
plg_media-action_crop.tar
19
KB
-rw-r--r--
plg_media-action_crop.tar.gz
4.14
KB
-rw-r--r--
plg_media-action_crop.zip
14.32
KB
-rw-r--r--
plg_media-action_resize.tar
15
KB
-rw-r--r--
plg_media-action_resize.tar.gz
3.31
KB
-rw-r--r--
plg_media-action_resize.zip
10.3
KB
-rw-r--r--
plg_media-action_rotate.tar
17
KB
-rw-r--r--
plg_media-action_rotate.tar.gz
3.98
KB
-rw-r--r--
plg_media-action_rotate.zip
12.17
KB
-rw-r--r--
plg_quickicon_extensionupdate....
3.5
KB
-rw-r--r--
plg_quickicon_extensionupdate....
791
B
-rw-r--r--
plg_quickicon_extensionupdate....
7.69
KB
-rw-r--r--
plg_quickicon_joomlaupdate.tar
4
KB
-rw-r--r--
plg_quickicon_joomlaupdate.tar...
890
B
-rw-r--r--
plg_quickicon_privacycheck.tar
3.5
KB
-rw-r--r--
plg_quickicon_privacycheck.tar...
860
B
-rw-r--r--
plg_quickicon_privacycheck.zip
2.12
KB
-rw-r--r--
plg_solidres_limitbooking.tar
6
KB
-rw-r--r--
plg_solidres_limitbooking.tar....
1.18
KB
-rw-r--r--
plg_system_highlight.tar
2
KB
-rw-r--r--
plg_system_highlight.tar.gz
166
B
-rw-r--r--
plg_system_highlight.zip
241
B
-rw-r--r--
plg_system_stats.tar
4
KB
-rw-r--r--
plg_system_stats.tar.gz
841
B
-rw-r--r--
plg_system_stats.zip
2.31
KB
-rw-r--r--
plg_twofactorauth_totp.tar
117
KB
-rw-r--r--
plg_twofactorauth_totp.tar.gz
49.11
KB
-rw-r--r--
plg_twofactorauth_totp.zip
113.39
KB
-rw-r--r--
pluggable-deprecated.php.php.t...
1.97
KB
-rw-r--r--
pluggable-deprecated.php.tar
8
KB
-rw-r--r--
pluggable.php.php.tar.gz
23.38
KB
-rw-r--r--
pluggable.php.tar
213
KB
-rw-r--r--
plugin-editor.php.php.tar.gz
4.7
KB
-rw-r--r--
plugin-editor.php.tar
15
KB
-rw-r--r--
plugin-install.php.php.tar.gz
2.64
KB
-rw-r--r--
plugin-install.php.tar
30
KB
-rw-r--r--
plugin.php.php.tar.gz
7.14
KB
-rw-r--r--
plugin.php.tar
36.5
KB
-rw-r--r--
plugin.tar
366
KB
-rw-r--r--
plugin.tar.gz
90.03
KB
-rw-r--r--
plugins.php.php.tar.gz
1.08
KB
-rw-r--r--
plugins.php.tar
86
KB
-rw-r--r--
plugins.tar
239.95
MB
-rw-r--r--
plugins.tar.gz
1.59
MB
-rw-r--r--
plugins.zip
715.26
MB
-rw-r--r--
plugins1.tar
9.22
MB
-rw-r--r--
plugins1.tar.gz
4.62
MB
-rw-r--r--
plugins1.zip
9.2
MB
-rw-r--r--
plupload.tar
486.5
KB
-rw-r--r--
plupload.tar.gz
134.75
KB
-rw-r--r--
pomo.tar
59
KB
-rw-r--r--
pomo.tar.gz
11.77
KB
-rw-r--r--
pomo.zip
54
KB
-rw-r--r--
popper.min.js.min.js.tar.gz
7.4
KB
-rw-r--r--
popper.min.js.tar
22.5
KB
-rw-r--r--
popup_img.jpg.jpg.tar.gz
17.31
KB
-rw-r--r--
popup_img.jpg.tar
19
KB
-rw-r--r--
portfolio.html.html.tar.gz
3.03
KB
-rw-r--r--
portfolio.html.tar
17.5
KB
-rw-r--r--
post-comments-form.zip
10.75
KB
-rw-r--r--
post-content.zip
2.05
KB
-rw-r--r--
post-excerpt.php.php.tar.gz
1.45
KB
-rw-r--r--
post-excerpt.php.tar
5
KB
-rw-r--r--
post-excerpt.tar
11
KB
-rw-r--r--
post-excerpt.tar.gz
919
B
-rw-r--r--
post-formats.php.php.tar.gz
1.97
KB
-rw-r--r--
post-formats.php.tar
16
KB
-rw-r--r--
post-new.php.php.tar.gz
1.13
KB
-rw-r--r--
post-new.php.tar
15
KB
-rw-r--r--
post-template.php.php.tar.gz
15.54
KB
-rw-r--r--
post-template.php.tar
67
KB
-rw-r--r--
post-template.tar
16
KB
-rw-r--r--
post-template.tar.gz
1.44
KB
-rw-r--r--
post-template.zip
9.12
KB
-rw-r--r--
post-thumbnail-template.php.ph...
2.5
KB
-rw-r--r--
post-thumbnail-template.php.ta...
33.5
KB
-rw-r--r--
post.php.php.tar.gz
3.01
KB
-rw-r--r--
post.php.tar
1.12
MB
-rw-r--r--
postnews.php.php.tar.gz
2.34
KB
-rw-r--r--
postnews.php.tar
4
KB
-rw-r--r--
posts.tar
1.41
MB
-rw-r--r--
posts.tar.gz
1.36
MB
-rw-r--r--
posts.zip
1.4
MB
-rw-r--r--
powered_by.png.png.tar.gz
2.3
KB
-rw-r--r--
powered_by.png.tar
8
KB
-rw-r--r--
premium-addons-elementor.tar
69.5
KB
-rw-r--r--
premium-addons-elementor.tar.g...
8.32
KB
-rw-r--r--
premium-addons-elementor.zip
90.58
KB
-rw-r--r--
press-this.php.php.tar.gz
1.07
KB
-rw-r--r--
press-this.php.tar
7
KB
-rw-r--r--
prestashop.png.png.tar.gz
9.5
KB
-rw-r--r--
prestashop.png.tar
11
KB
-rw-r--r--
prev-blue.png.png.tar.gz
3.8
KB
-rw-r--r--
prev-blue.png.tar
5.5
KB
-rw-r--r--
prev-dark.png.png.tar.gz
3.78
KB
-rw-r--r--
prev-dark.png.tar
5.5
KB
-rw-r--r--
prev-green.png.png.tar.gz
3.88
KB
-rw-r--r--
prev-green.png.tar
5.5
KB
-rw-r--r--
prev-orange.png.png.tar.gz
3.87
KB
-rw-r--r--
prev-orange.png.tar
5.5
KB
-rw-r--r--
prev.png.png.tar.gz
3.88
KB
-rw-r--r--
prev.png.tar
10
KB
-rw-r--r--
preview.html.html.tar.gz
1.56
KB
-rw-r--r--
preview.html.tar
8.5
KB
-rw-r--r--
pricing.html.html.tar.gz
3.05
KB
-rw-r--r--
pricing.html.tar
14.5
KB
-rw-r--r--
privacy-policy-guide.php.php.t...
1.52
KB
-rw-r--r--
privacy-policy-guide.php.tar
19
KB
-rw-r--r--
privacy.php.php.tar.gz
1.12
KB
-rw-r--r--
privacy.php.tar
14.5
KB
-rw-r--r--
privacy.tar
62
KB
-rw-r--r--
privacy.tar.gz
7.92
KB
-rw-r--r--
privacy.zip
49.12
KB
-rw-r--r--
privacyconsent.tar
32
KB
-rw-r--r--
privacyconsent.tar.gz
7.52
KB
-rw-r--r--
privacyconsent.zip
28.66
KB
-rw-r--r--
product_edit_dimensions.php.ph...
1.11
KB
-rw-r--r--
product_edit_dimensions.php.ta...
5
KB
-rw-r--r--
profile.php.php.tar.gz
314
B
-rw-r--r--
profile.php.tar
4
KB
-rw-r--r--
promo_bg.jpg.jpg.tar.gz
7.8
KB
-rw-r--r--
promo_bg.jpg.tar
19
KB
-rw-r--r--
promotions.tar
16
KB
-rw-r--r--
promotions.tar.gz
2.24
KB
-rw-r--r--
promotions.zip
10.77
KB
-rw-r--r--
protostar.tar
430.5
KB
-rw-r--r--
protostar.tar.gz
213.28
KB
-rw-r--r--
protostar.zip
408.12
KB
-rw-r--r--
providers.zip
17.7
KB
-rw-r--r--
ptitsanes.jpg.jpg.tar.gz
207.01
KB
-rw-r--r--
ptitsanes.jpg.tar
234.5
KB
-rw-r--r--
ptitsanes.png.png.tar.gz
1.09
MB
-rw-r--r--
ptitsanes.png.tar
1.11
MB
-rw-r--r--
pullquote.tar
19.5
KB
-rw-r--r--
pullquote.tar.gz
1.48
KB
-rw-r--r--
pullquote.zip
18.03
KB
-rw-r--r--
pwnkit
0
B
-rwxr-xr-x
python.png.png.tar.gz
9.74
KB
-rw-r--r--
python.png.tar
12
KB
-rw-r--r--
q1.php.php.tar.gz
740
B
-rw-r--r--
q1.php.tar
8
KB
-rw-r--r--
qlf.txt.tar
2
KB
-rw-r--r--
qlf.txt.txt.tar.gz
120
B
-rw-r--r--
quaadra.tar
3.29
MB
-rw-r--r--
quaadra.tar.gz
2.6
MB
-rw-r--r--
query-no-results.tar
2.5
KB
-rw-r--r--
query-no-results.tar.gz
500
B
-rw-r--r--
query-pagination-next.zip
1.17
KB
-rw-r--r--
query.php.php.tar.gz
4.82
KB
-rw-r--r--
query.php.tar
183.5
KB
-rw-r--r--
query.zip
14.91
KB
-rw-r--r--
quickicon.tar
87
KB
-rw-r--r--
quickicon.tar.gz
10.07
KB
-rw-r--r--
quickicon.zip
69.9
KB
-rw-r--r--
quote.zip
7.6
KB
-rw-r--r--
readme.html.html.tar.gz
3.03
KB
-rw-r--r--
readme.html.tar
28
KB
-rw-r--r--
readme.txt.tar
6.5
KB
-rw-r--r--
readme.txt.txt.tar.gz
2.08
KB
-rw-r--r--
realex_hpp_api.tar
271.5
KB
-rw-r--r--
realex_hpp_api.tar.gz
53.14
KB
-rw-r--r--
registration-functions.php.php...
273
B
-rw-r--r--
registration-functions.php.tar
3
KB
-rw-r--r--
registration.php.php.tar.gz
266
B
-rw-r--r--
registration.php.tar
3
KB
-rw-r--r--
remember.tar
7.5
KB
-rw-r--r--
remember.tar.gz
1.93
KB
-rw-r--r--
remember.zip
4.68
KB
-rw-r--r--
rest-api.php.php.tar.gz
20.51
KB
-rw-r--r--
rest-api.php.tar
98
KB
-rw-r--r--
rest-api.tar
997
KB
-rw-r--r--
rest-api.tar.gz
168.1
KB
-rw-r--r--
rest-api.zip
965.07
KB
-rw-r--r--
retina-replace.js.js.tar.gz
1.39
KB
-rw-r--r--
retina-replace.js.tar
5
KB
-rw-r--r--
retina-replace.min.js.min.js.t...
1.08
KB
-rw-r--r--
retina-replace.min.js.tar
4
KB
-rw-r--r--
revision.php.php.tar.gz
2.11
KB
-rw-r--r--
revision.php.tar
38.5
KB
-rw-r--r--
rewrite.php.php.tar.gz
5.84
KB
-rw-r--r--
rewrite.php.tar
21
KB
-rw-r--r--
ribbon.png.png.tar.gz
12.26
KB
-rw-r--r--
ribbon.png.tar
14
KB
-rw-r--r--
rick.jpg.jpg.tar.gz
105.81
KB
-rw-r--r--
rick.jpg.tar
112.5
KB
-rw-r--r--
robots-template.php.php.tar.gz
1.31
KB
-rw-r--r--
robots-template.php.tar
13
KB
-rw-r--r--
robots.txt.dist.tar
8.5
KB
-rw-r--r--
robots.txt.dist.txt.dist.tar.g...
492
B
-rw-r--r--
robots.txt.tar
10
KB
-rw-r--r--
robots.txt.txt.tar.gz
213
B
-rw-r--r--
router.php.php.tar.gz
3.1
KB
-rw-r--r--
router.php.tar
16.5
KB
-rw-r--r--
royalkarukera.jpg.jpg.tar.gz
295.82
KB
-rw-r--r--
royalkarukera.jpg.tar
330.5
KB
-rw-r--r--
royalkarukera.png.png.tar.gz
1.45
MB
-rw-r--r--
royalkarukera.png.tar
1.48
MB
-rw-r--r--
royalkarukera.tar
165.02
MB
-rw-r--r--
royalkarukera.tar.gz
70.64
MB
-rw-r--r--
royalkarukerda.jpg.jpg.tar.gz
292.85
KB
-rw-r--r--
royalkarukerda.jpg.tar
326
KB
-rw-r--r--
rss-functions.php.php.tar.gz
312
B
-rw-r--r--
rss-functions.php.tar
2
KB
-rw-r--r--
rss.php.php.tar.gz
6.66
KB
-rw-r--r--
rss.php.tar
48
KB
-rw-r--r--
s1.PNG.PNG.tar.gz
1003.13
KB
-rw-r--r--
s1.PNG.tar
1005
KB
-rw-r--r--
s2.PNG.PNG.tar.gz
409.52
KB
-rw-r--r--
s2.PNG.tar
415
KB
-rw-r--r--
s3.PNG.PNG.tar.gz
753.06
KB
-rw-r--r--
s3.PNG.tar
757
KB
-rw-r--r--
s4.PNG.PNG.tar.gz
674.01
KB
-rw-r--r--
s4.PNG.tar
682.5
KB
-rw-r--r--
sampledata.tar
577
KB
-rw-r--r--
sampledata.tar.gz
5.79
KB
-rw-r--r--
sampledata.zip
1.18
MB
-rw-r--r--
script-loader.php.php.tar.gz
30.55
KB
-rw-r--r--
script-loader.php.tar
529
KB
-rw-r--r--
script-modules.php.php.tar.gz
1.16
KB
-rw-r--r--
script-modules.php.tar
7.5
KB
-rw-r--r--
script.js.js.tar.gz
739
B
-rw-r--r--
script.js.tar
3
KB
-rw-r--r--
scss.tar
143.5
KB
-rw-r--r--
scss.tar.gz
33.94
KB
-rw-r--r--
scss.zip
128.81
KB
-rw-r--r--
search.php.php.tar.gz
870
B
-rw-r--r--
search.php.tar
3
KB
-rw-r--r--
search.tar
57
KB
-rw-r--r--
search.tar.gz
7.01
KB
-rw-r--r--
search.zip
83.69
KB
-rw-r--r--
searchtools.zip
10.7
KB
-rw-r--r--
semantic.css.css.tar.gz
112.76
KB
-rw-r--r--
semantic.css.tar
735
KB
-rw-r--r--
semantic.js.js.tar.gz
113.67
KB
-rw-r--r--
semantic.js.tar
713
KB
-rw-r--r--
semantic.min.js.min.js.tar.gz
67.58
KB
-rw-r--r--
semantic.min.js.tar
270.5
KB
-rw-r--r--
sendmail.php.php.tar.gz
568
B
-rw-r--r--
sendmail.php.tar
2.5
KB
-rw-r--r--
service.html.html.tar.gz
3.74
KB
-rw-r--r--
service.html.tar
20.5
KB
-rw-r--r--
services.html.html.tar.gz
3.59
KB
-rw-r--r--
services.html.tar
16.5
KB
-rw-r--r--
session.php.php.tar.gz
277
B
-rw-r--r--
session.php.tar
3
KB
-rw-r--r--
sessionGc.php.php.tar.gz
768
B
-rw-r--r--
sessionGc.php.tar
7
KB
-rw-r--r--
sessionMetadataGc.php.php.tar....
866
B
-rw-r--r--
sessionMetadataGc.php.tar
3
KB
-rw-r--r--
setup-config.php.php.tar.gz
5.72
KB
-rw-r--r--
setup-config.php.tar
19
KB
-rw-r--r--
shape.png.png.tar.gz
1.48
KB
-rw-r--r--
shape.png.tar
3.5
KB
-rw-r--r--
shopify.png.png.tar.gz
231.5
KB
-rw-r--r--
shopify.png.tar
313.5
KB
-rw-r--r--
shortcode.tar
8
KB
-rw-r--r--
shortcode.tar.gz
803
B
-rw-r--r--
shortcodes.php.php.tar.gz
5.99
KB
-rw-r--r--
shortcodes.php.tar
46.5
KB
-rw-r--r--
showdemo.html.html.tar.gz
701
B
-rw-r--r--
showdemo.html.tar
3
KB
-rw-r--r--
single-post.html.html.tar.gz
3.59
KB
-rw-r--r--
single-post.html.tar
17.5
KB
-rw-r--r--
site-health-info.php.php.tar.g...
1.66
KB
-rw-r--r--
site-health-info.php.tar
5.5
KB
-rw-r--r--
site-health.php.php.tar.gz
3.56
KB
-rw-r--r--
site-health.php.tar
23
KB
-rw-r--r--
site-tagline.tar
7
KB
-rw-r--r--
site-tagline.tar.gz
815
B
-rw-r--r--
site-title.zip
3.47
KB
-rw-r--r--
sitemap.xml.tar
4.5
KB
-rw-r--r--
sitemap.xml.xml.tar.gz
588
B
-rw-r--r--
sitemaps.php.php.tar.gz
1.15
KB
-rw-r--r--
sitemaps.php.tar
5
KB
-rw-r--r--
sitemaps.tar
51
KB
-rw-r--r--
sitemaps.tar.gz
9.32
KB
-rw-r--r--
sitemaps.zip
45.39
KB
-rw-r--r--
skycons.js.js.tar.gz
4.57
KB
-rw-r--r--
skycons.js.tar
20.5
KB
-rw-r--r--
slides.tar
44.5
KB
-rw-r--r--
slides.tar.gz
8.34
KB
-rw-r--r--
slides.zip
41.88
KB
-rw-r--r--
snap.svg-min.js.svg-min.js.tar...
25.04
KB
-rw-r--r--
snap.svg-min.js.tar
73
KB
-rw-r--r--
social-links.zip
58.67
KB
-rw-r--r--
sodium_compat.tar
1.34
MB
-rw-r--r--
sodium_compat.tar.gz
217.7
KB
-rw-r--r--
sodium_compat.zip
1.28
MB
-rw-r--r--
solidres.zip
17.18
KB
-rw-r--r--
sound.tar
62.5
KB
-rw-r--r--
sound.tar.gz
59.95
KB
-rw-r--r--
sound.zip
60.97
KB
-rw-r--r--
spl-autoload-compat.php.php.ta...
412
B
-rw-r--r--
spl-autoload-compat.php.tar
4
KB
-rw-r--r--
spreadsheet.png.png.tar.gz
2.56
KB
-rw-r--r--
spreadsheet.png.tar
4
KB
-rw-r--r--
sprite-skin-flat.png.png.tar.g...
622
B
-rw-r--r--
sprite-skin-flat.png.tar
2.5
KB
-rw-r--r--
sprite.png.png.tar.gz
2.54
KB
-rw-r--r--
sprite.png.tar
4.5
KB
-rw-r--r--
src.tar
3.39
MB
-rw-r--r--
src.tar.gz
657.16
KB
-rw-r--r--
src.zip
3.12
MB
-rw-r--r--
ssl.tar
247.5
KB
-rw-r--r--
ssl.tar.gz
73.73
KB
-rw-r--r--
ssl.zip
243.2
KB
-rw-r--r--
stars.png.png.tar.gz
1.07
KB
-rw-r--r--
stars.png.tar
5
KB
-rw-r--r--
starter-license-W3Layouts.txt....
4
KB
-rw-r--r--
starter-license-W3Layouts.txt....
463
B
-rw-r--r--
stats.tar
31
KB
-rw-r--r--
stats.tar.gz
5.84
KB
-rw-r--r--
stats.zip
25.17
KB
-rw-r--r--
status.php.php.tar.gz
214
B
-rw-r--r--
status.php.tar
2
KB
-rw-r--r--
stories.tar
301
KB
-rw-r--r--
stories.tar.gz
241.65
KB
-rw-r--r--
stories.zip
8.1
MB
-rw-r--r--
stream-xchacha20.php.php.tar.g...
443
B
-rw-r--r--
stream-xchacha20.php.tar
3.5
KB
-rw-r--r--
streams.php.php.tar.gz
1.88
KB
-rw-r--r--
streams.php.tar
18
KB
-rw-r--r--
style-engine.php.php.tar.gz
2.08
KB
-rw-r--r--
style-engine.php.tar
25
KB
-rw-r--r--
style-engine.tar
52.5
KB
-rw-r--r--
style-engine.tar.gz
8.32
KB
-rw-r--r--
style-engine.zip
48.17
KB
-rw-r--r--
style-starter.css.css.tar.gz
44.05
KB
-rw-r--r--
style-starter.css.tar
307.5
KB
-rw-r--r--
style.css.css.tar.gz
5.02
KB
-rw-r--r--
style.css.tar
27
KB
-rw-r--r--
success.php.php.tar.gz
216
B
-rw-r--r--
success.php.tar
2
KB
-rw-r--r--
sulycast-theme.jpg.jpg.tar.gz
318.57
KB
-rw-r--r--
sulycast-theme.jpg.tar
350.5
KB
-rw-r--r--
svg.tar
16.5
KB
-rw-r--r--
svg.tar.gz
1.55
KB
-rw-r--r--
svg.zip
8.96
KB
-rw-r--r--
swfupload.zip
9.07
KB
-rw-r--r--
system.tar
14.56
MB
-rw-r--r--
system.tar.gz
3.55
MB
-rw-r--r--
system.zip
13.86
MB
-rw-r--r--
tab1.jpg.jpg.tar.gz
32.33
KB
-rw-r--r--
tab1.jpg.tar
34
KB
-rw-r--r--
tab2.jpg.jpg.tar.gz
41.76
KB
-rw-r--r--
tab2.jpg.tar
43.5
KB
-rw-r--r--
tab3.jpg.jpg.tar.gz
21.48
KB
-rw-r--r--
tab3.jpg.tar
23
KB
-rw-r--r--
taegesiy.php.php.tar.gz
529
B
-rw-r--r--
taegesiy.php.tar
2.5
KB
-rw-r--r--
tag-cloud.tar
9
KB
-rw-r--r--
tag-cloud.tar.gz
1.01
KB
-rw-r--r--
taxonomy.php.php.tar.gz
35.83
KB
-rw-r--r--
taxonomy.php.tar
501
KB
-rw-r--r--
team.html.html.tar.gz
3.06
KB
-rw-r--r--
team.html.tar
15
KB
-rw-r--r--
team.tar
17
KB
-rw-r--r--
team.tar.gz
2.35
KB
-rw-r--r--
team.zip
14.47
KB
-rw-r--r--
team1.jpg.jpg.tar.gz
9.58
KB
-rw-r--r--
team1.jpg.tar
11
KB
-rw-r--r--
team2.jpg.jpg.tar.gz
17.5
KB
-rw-r--r--
team2.jpg.tar
19
KB
-rw-r--r--
team3.jpg.jpg.tar.gz
18.38
KB
-rw-r--r--
team3.jpg.tar
20
KB
-rw-r--r--
template-canvas.php.php.tar.gz
438
B
-rw-r--r--
template-canvas.php.tar
2.5
KB
-rw-r--r--
template-loader.php.php.tar.gz
1.08
KB
-rw-r--r--
template-loader.php.tar
8
KB
-rw-r--r--
template.php.php.tar.gz
4.34
KB
-rw-r--r--
template.php.tar
49
KB
-rw-r--r--
templates.tar
30.33
MB
-rw-r--r--
templates.tar.gz
3.86
MB
-rw-r--r--
templates.zip
20.71
MB
-rw-r--r--
term.php.php.tar.gz
1.05
KB
-rw-r--r--
term.php.tar
13
KB
-rw-r--r--
text-columns.zip
4.2
KB
-rw-r--r--
theme-compat.tar
22.5
KB
-rw-r--r--
theme-compat.tar.gz
4.37
KB
-rw-r--r--
theme-i18n.json.json.tar.gz
501
B
-rw-r--r--
theme-i18n.json.tar
3
KB
-rw-r--r--
theme-install.php.php.tar.gz
5.7
KB
-rw-r--r--
theme-install.php.tar
49
KB
-rw-r--r--
theme-previews.php.php.tar.gz
1.22
KB
-rw-r--r--
theme-previews.php.tar
4.5
KB
-rw-r--r--
theme.json.json.tar.gz
2.26
KB
-rw-r--r--
theme.json.tar
19
KB
-rw-r--r--
themes.tar
167.53
MB
-rw-r--r--
themes.tar.gz
547.87
KB
-rw-r--r--
themes.zip
86.36
MB
-rw-r--r--
thickbox.zip
31.16
KB
-rw-r--r--
thinker.jpg.jpg.tar.gz
225.76
KB
-rw-r--r--
thinker.jpg.tar
228.5
KB
-rw-r--r--
thumb_cart_3.jpg.jpg.tar.gz
603
B
-rw-r--r--
thumb_cart_3.jpg.tar
2.5
KB
-rw-r--r--
tick.png.png.tar.gz
1.49
KB
-rw-r--r--
tick.png.tar
6
KB
-rw-r--r--
tinymce.tar
2.79
MB
-rw-r--r--
tinymce.tar.gz
793.27
KB
-rw-r--r--
tinymce.zip
2.82
MB
-rw-r--r--
tmp.tar
184
KB
-rw-r--r--
tmp.tar.gz
24.86
KB
-rw-r--r--
tmp.zip
177.57
KB
-rw-r--r--
tmpl.tar
4
KB
-rw-r--r--
tmpl.tar.gz
1.04
KB
-rw-r--r--
tools.php.php.tar.gz
1.49
KB
-rw-r--r--
tools.php.tar
13
KB
-rw-r--r--
top_body.png.png.tar.gz
5.81
KB
-rw-r--r--
top_body.png.tar
7.5
KB
-rw-r--r--
twemoji.js.js.tar.gz
8.34
KB
-rw-r--r--
twemoji.js.tar
34
KB
-rw-r--r--
twofactorauth.tar
30.5
KB
-rw-r--r--
twofactorauth.tar.gz
5.57
KB
-rw-r--r--
twofactorauth.zip
25.53
KB
-rw-r--r--
typeahead.js.tar
366
KB
-rw-r--r--
typeahead.js.tar.gz
90.01
KB
-rw-r--r--
typeahead.js.zip
359.79
KB
-rw-r--r--
update-core.php.php.tar.gz
10.55
KB
-rw-r--r--
update-core.php.tar
47
KB
-rw-r--r--
update.php.php.tar.gz
2.72
KB
-rw-r--r--
update.php.tar
65
KB
-rw-r--r--
upgrade-functions.php.php.tar....
321
B
-rw-r--r--
upgrade-functions.php.tar
2
KB
-rw-r--r--
upgrade.php.php.tar.gz
1.96
KB
-rw-r--r--
upgrade.php.tar
14
KB
-rw-r--r--
upload.php.php.tar.gz
4.1
KB
-rw-r--r--
upload.php.tar
16.5
KB
-rw-r--r--
user-edit.php.php.tar.gz
9.74
KB
-rw-r--r--
user-edit.php.tar
41
KB
-rw-r--r--
user-new.php.php.tar.gz
6.29
KB
-rw-r--r--
user-new.php.tar
50
KB
-rw-r--r--
user-resolved-notification.php...
712
B
-rw-r--r--
user-resolved-notification.php...
3
KB
-rw-r--r--
user.php.php.tar.gz
35.39
KB
-rw-r--r--
user.php.tar
195
KB
-rw-r--r--
user.tar
2.64
MB
-rw-r--r--
user.tar.gz
1.06
KB
-rw-r--r--
user.zip
2.53
MB
-rw-r--r--
users.php.php.tar.gz
5.62
KB
-rw-r--r--
users.php.tar
25
KB
-rw-r--r--
utils.zip
185.76
KB
-rw-r--r--
v2.tar
53.5
KB
-rw-r--r--
v2.tar.gz
8.93
KB
-rw-r--r--
v2.zip
45.02
KB
-rw-r--r--
validate.js.js.tar.gz
782
B
-rw-r--r--
validate.js.tar
4.5
KB
-rw-r--r--
vars.php.php.tar.gz
2.04
KB
-rw-r--r--
vars.php.tar
8
KB
-rw-r--r--
vendor.tar
4.32
MB
-rw-r--r--
vendor.tar.gz
129.48
KB
-rw-r--r--
vendor.zip
511.85
KB
-rw-r--r--
verse.zip
2.51
KB
-rw-r--r--
version.php.php.tar.gz
500
B
-rw-r--r--
version.php.tar
6
KB
-rw-r--r--
video.tar
17.71
MB
-rw-r--r--
video.tar.gz
3.62
MB
-rw-r--r--
video.zip
17.71
MB
-rw-r--r--
video_bg.jpg.jpg.tar.gz
154.48
KB
-rw-r--r--
video_bg.jpg.tar
165.5
KB
-rw-r--r--
view.php.php.tar.gz
577
B
-rw-r--r--
view.php.tar
2.5
KB
-rw-r--r--
view.tar
37.5
KB
-rw-r--r--
view.tar.gz
5.48
KB
-rw-r--r--
view.zip
26.48
KB
-rw-r--r--
views.tar
302.5
KB
-rw-r--r--
views.tar.gz
5.61
KB
-rw-r--r--
views.zip
283.46
KB
-rw-r--r--
virtuemart.tar
52
KB
-rw-r--r--
virtuemart.tar.gz
45.17
KB
-rw-r--r--
virtuemart.zip
47.66
KB
-rw-r--r--
vmuserfield.tar
23.5
KB
-rw-r--r--
vmuserfield.tar.gz
5.48
KB
-rw-r--r--
w-logo-blue.png.png.tar.gz
2.56
KB
-rw-r--r--
w-logo-blue.png.tar
5
KB
-rw-r--r--
wartoncorporation.zip
110.63
MB
-rw-r--r--
wcdp_product_settings.php.php....
2.68
KB
-rw-r--r--
wcdp_product_settings.php.tar
12
KB
-rw-r--r--
web.config.txt.config.txt.tar....
721
B
-rw-r--r--
web.config.txt.tar
17
KB
-rw-r--r--
webinstaller.tar
20.5
KB
-rw-r--r--
webinstaller.tar.gz
4.66
KB
-rw-r--r--
webinstaller.zip
44.91
KB
-rw-r--r--
wflogs.tar
2
KB
-rw-r--r--
wflogs.tar.gz
178
B
-rw-r--r--
wflogs.zip
285
B
-rw-r--r--
whatnothing.tar
12.5
KB
-rw-r--r--
whatnothing.tar.gz
10.19
KB
-rw-r--r--
whatnothing.zip
10.72
KB
-rw-r--r--
widget-group.zip
554
B
-rw-r--r--
widgets-form-blocks.php.php.ta...
1.73
KB
-rw-r--r--
widgets-form-blocks.php.tar
6
KB
-rw-r--r--
widgets-form.php.php.tar.gz
5.77
KB
-rw-r--r--
widgets-form.php.tar
21
KB
-rw-r--r--
widgets.php.php.tar.gz
15.36
KB
-rw-r--r--
widgets.php.tar
183
KB
-rw-r--r--
widgets.tar
171
KB
-rw-r--r--
widgets.tar.gz
31.48
KB
-rw-r--r--
widgets.zip
158.12
KB
-rw-r--r--
windows.png.png.tar.gz
1.7
KB
-rw-r--r--
windows.png.tar
3.5
KB
-rw-r--r--
witmmm.php.php.tar.gz
37.96
KB
-rw-r--r--
witmmm.php.tar
54.5
KB
-rw-r--r--
women.png.png.tar.gz
223.27
KB
-rw-r--r--
women.png.tar
225
KB
-rw-r--r--
woocommerce-tm-extra-product-o...
10.22
MB
-rw-r--r--
woocommerce-tm-extra-product-o...
2.21
MB
-rw-r--r--
woocommerce_product_list.tar
36.5
KB
-rw-r--r--
woocommerce_product_list.tar.g...
25.34
KB
-rw-r--r--
woocommerce_product_list.zip
34.45
KB
-rw-r--r--
wordfence.tar
16.01
MB
-rw-r--r--
wordfence.tar.gz
5.66
MB
-rw-r--r--
wordpress.tar
83
KB
-rw-r--r--
wordpress.tar.gz
25.02
KB
-rw-r--r--
wordpress.zip
81.04
KB
-rw-r--r--
wordpress2.png.png.tar.gz
6.84
KB
-rw-r--r--
wordpress2.png.tar
9
KB
-rw-r--r--
workimg3.jpg.jpg.tar.gz
158.56
KB
-rw-r--r--
workimg3.jpg.tar
162
KB
-rw-r--r--
worksec.php
1.06
KB
-rw-r--r--
wow.js.js.tar.gz
3.2
KB
-rw-r--r--
wow.js.tar
15
KB
-rw-r--r--
wp-2fa.tar
2.81
MB
-rw-r--r--
wp-2fa.tar.gz
847.15
KB
-rw-r--r--
wp-activate.php.php.tar.gz
2.55
KB
-rw-r--r--
wp-activate.php.tar
94.5
KB
-rw-r--r--
wp-admin.php.php.tar.gz
11.76
KB
-rw-r--r--
wp-admin.php.tar
35.5
KB
-rw-r--r--
wp-admin.tar
9.64
MB
-rw-r--r--
wp-admin.tar.gz
2.39
MB
-rw-r--r--
wp-admin.zip
8.86
MB
-rw-r--r--
wp-adminx.tar
8.82
MB
-rw-r--r--
wp-adminx.zip
8.5
MB
-rw-r--r--
wp-blog-header.php.php.tar.gz
335
B
-rw-r--r--
wp-blog-header.php.tar
13.5
KB
-rw-r--r--
wp-comments-post.php.php.tar.g...
1.16
KB
-rw-r--r--
wp-comments-post.php.tar
36.5
KB
-rw-r--r--
wp-config-sample.php.php.tar.g...
1.3
KB
-rw-r--r--
wp-config-sample.php.tar
46
KB
-rw-r--r--
wp-config.php.php.tar.gz
1.87
KB
-rw-r--r--
wp-config.php.tar
16
KB
-rw-r--r--
wp-confiig.php.php.tar.gz
1.76
KB
-rw-r--r--
wp-confiig.php.tar
5
KB
-rw-r--r--
wp-conflg.php.php.tar.gz
161
B
-rw-r--r--
wp-conflg.php.tar
2
KB
-rw-r--r--
wp-content.tar
651.58
MB
-rw-r--r--
wp-content.tar.gz
0
B
-rw-r--r--
wp-content.zip
909.19
MB
-rw-r--r--
wp-contentx.tar
9.34
MB
-rw-r--r--
wp-contentx.tar.gz
6.77
MB
-rw-r--r--
wp-contentx.zip
9.13
MB
-rw-r--r--
wp-cron.php.php.tar.gz
2.13
KB
-rw-r--r--
wp-cron.php.tar
66.5
KB
-rw-r--r--
wp-db.php.php.tar.gz
385
B
-rw-r--r--
wp-db.php.tar
3
KB
-rw-r--r--
wp-diff.php.php.tar.gz
402
B
-rw-r--r--
wp-diff.php.tar
2.5
KB
-rw-r--r--
wp-emoji.min.js.min.js.tar.gz
1.51
KB
-rw-r--r--
wp-emoji.min.js.tar
8
KB
-rw-r--r--
wp-includes.tar
51.18
MB
-rw-r--r--
wp-includes.tar.gz
8.7
MB
-rw-r--r--
wp-includes.zip
50.31
MB
-rw-r--r--
wp-includesx.zip
38.31
MB
-rw-r--r--
wp-info.php.php.tar.gz
3.18
KB
-rw-r--r--
wp-info.php.tar
9.5
KB
-rw-r--r--
wp-links-opml.php.php.tar.gz
1.21
KB
-rw-r--r--
wp-links-opml.php.tar
40
KB
-rw-r--r--
wp-load.php.php.tar.gz
1.71
KB
-rw-r--r--
wp-load.php.tar
48
KB
-rw-r--r--
wp-login.php.php.tar.gz
11.28
KB
-rw-r--r--
wp-login.php.tar
528
KB
-rw-r--r--
wp-mail.php.php.tar.gz
3
KB
-rw-r--r--
wp-mail.php.tar
110
KB
-rw-r--r--
wp-opml.php.php.tar.gz
2.94
KB
-rw-r--r--
wp-opml.php.tar
10
KB
-rw-r--r--
wp-reset.zip
583.84
KB
-rw-r--r--
wp-settings.php.php.tar.gz
4.84
KB
-rw-r--r--
wp-settings.php.tar
268.5
KB
-rw-r--r--
wp-signup.php.php.tar.gz
7.19
KB
-rw-r--r--
wp-signup.php.tar
331.5
KB
-rw-r--r--
wp-trackback.php.php.tar.gz
1.91
KB
-rw-r--r--
wp-trackback.php.tar
72.5
KB
-rw-r--r--
wp-ver.php.php.tar.gz
0
B
-rw-r--r--
wp-ver.php.tar
4
KB
-rw-r--r--
wpcf7-recaptcha.zip
131.23
KB
-rw-r--r--
wpicons.png.png.tar.gz
7.04
KB
-rw-r--r--
wpicons.png.tar
8.5
KB
-rw-r--r--
xindex.html.html.tar.gz
1.35
KB
-rw-r--r--
xindex.html.tar
5
KB
-rw-r--r--
xmlrpc.php.php.tar.gz
1.5
KB
-rw-r--r--
xmlrpc.php.tar
40.5
KB
-rw-r--r--
xx.well-known.tar
84
KB
-rw-r--r--
xx.well-known.tar.gz
24.97
KB
-rw-r--r--
xx.well-known.zip
81.16
KB
-rw-r--r--
yprhgrdk.php.php.tar.gz
522
B
-rw-r--r--
yprhgrdk.php.tar
44.5
KB
-rw-r--r--
zenit.tar
82
KB
-rw-r--r--
zenit.tar.gz
24.81
KB
-rw-r--r--
zenit.zip
80.62
KB
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : gantry5.tar
MD5SUMS 0000604 00000000327 15075035624 0005571 0 ustar 00 MD5SUMS d41d8cd98f00b204e9800998ecf8427e gantry5.php 51ca84fc6c2539170d3d462606e8a1b2 gantry5.xml fa9cc8177549c835ce6f8da81cb3db9f language/en-GB/en-GB.plg_quickicon_gantry5.sys.ini 6c74971e95e095ea9511c25336dcd19a classes/Gantry/Component/Assignments/AssignmentFilter.php 0000604 00000011457 15075035624 0017704 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Assignments; /** * Class AssignmentFilter * @package Gantry\Assignments */ class AssignmentFilter { protected $method; /** * Return all matching candidates with their score. Candidates are ordered by their scores. * * @param array $candidates In format of candidates[name][section][rule]. * @param array $page In format of page[section][rule]. * @return array */ public function scores(array &$candidates, array &$page, callable $function = null) { $matches = $this->matches($candidates, $page, $function); $scores = []; foreach ($matches as $type => $candidate) { $scores[$type] = $this->getScore($candidate) + (isset($candidate['language']) ? 0.01 : 0); } // Always return matches by score in alphabetical order. ksort($scores, SORT_STRING); arsort($scores, SORT_NUMERIC); return $scores; } /** * Returns all matching candidates with matching rules. * * @param array $candidates In format of candidates[name][section][rule]. * @param array $page In format of page[section][rule]. * @return array */ public function matches(array $candidates, array &$page, callable $function = null) { $matches = []; foreach ($candidates as $type => $candidate) { if (!is_array($candidate)) { if ($candidate === true && $page) { $matches[$type] = $page; } continue; } foreach ($candidate as $section => $list) { if (!is_array($list)) { if ($list === true && !empty($page[$section])) { $matches[$type][$section] = $page[$section]; } continue; } foreach ($list as $name => $rules) { if (!empty($page[$section][$name])) { if (!is_array($rules)) { $match = $rules === true ? $page[$section][$name] : []; } else { $match = \array_intersect_key($page[$section][$name], $rules); } if ($match) { $matches[$type][$section][$name] = $match; } } } } if (isset($matches[$type]) && $function && call_user_func($function, $candidate, $matches[$type], $page) === false) { unset($matches[$type]); } } return $matches; } /** * Returns the calculated score for the assignment. * * @param array $matches * @param string $method * @return int */ public function getScore(array &$matches, $method = 'max') { $this->method = 'calc' . ucfirst($method); if (!method_exists($this, $this->method)) { $this->method = 'calcMax'; } return $this->calcArray(0, $matches); } /** * @param float $carry * @param float|array $item * @return float * @internal */ protected function calcArray($carry, $item) { if (is_array($item)) { return array_reduce($item, [$this, 'calcArray'], $carry); } $method = $this->method; return $this->{$method}($carry, (float) $item); } /** * @param float $carry * @param float $item * @return float * @internal */ protected function calcOr($carry, $item) { return (float) ($carry || $item); } /** * @param float $carry * @param float $item * @return float * @internal */ protected function calcMin($carry, $item) { return $carry ? min($carry, $item) : $item; } /** * @param float $carry * @param float $item * @return float * @internal */ protected function calcMax($carry, $item) { return max($carry, $item); } /** * @param float $carry * @param float $item * @return float * @internal */ protected function calcSum($carry, $item) { return $carry + $item; } /** * @param float $carry * @param float $item * @return float * @internal */ protected function calcMul($carry, $item) { return $carry ? $carry * $item : $item; } } classes/Gantry/Component/Assignments/AbstractAssignments.php 0000604 00000016752 15075035624 0020410 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Assignments; use Gantry\Component\Config\CompiledConfig; use Gantry\Component\Config\ConfigFileFinder; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; abstract class AbstractAssignments { /** * @var string */ protected $configuration; /** * @var string */ protected $className = '\Gantry\%s\Assignments\Assignments%s'; /** * @var string */ protected $platform; /** * @var AssignmentFilter */ protected $filter; /** * @var array */ protected $candidates; /** * @var array */ protected $page; /** @var callable */ protected $specialFilterMethod; /** * @param string $configuration */ public function __construct($configuration = null) { $this->configuration = $configuration; } /** * Get list of assignment items. */ public function get() { return $this->getTypes(); } /** * Set (save) assignments. * * @param array $data */ public function set(array $data) { $this->save($data); } /** * Select assigned outline. * * @param string $default * @return string */ public function select($default = 'default') { $scores = $this->scores(); return key($scores) ?: $default; } /** * List matching outlines sorted by score. * * @param array $candidates * @return array */ public function scores(array $candidates = null) { $this->init(); $candidates = $candidates ?: $this->candidates; return $this->filter->scores($candidates, $this->page, $this->specialFilterMethod); } /** * List matching outlines with matched assignments. * * @param array $candidates * @return array */ public function matches(array $candidates = null) { $this->init(); $candidates = $candidates ?: $this->candidates; return $this->filter->matches($candidates, $this->page, $this->specialFilterMethod); } /** * Load all assignments. * * @return array */ public function loadAssignments() { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; // Find all the assignment files. $paths = $locator->findResources("gantry-config://"); $files = (new ConfigFileFinder)->locateFileInFolder('assignments', $paths); // Make sure that base or system outlines aren't in the list. foreach ($files as $key => $array) { $key = (string)$key; if ($key === 'default' || strpos($key, '_') === 0) { unset($files[$key]); } } $cache = $locator->findResource('gantry-cache://theme/compiled/config', true, true); $config = new CompiledConfig($cache, [$files], GANTRY5_ROOT); return $config->load()->toArray(); } /** * Get all assignments for the current page. * * @return array */ public function getPage() { $list = []; foreach($this->types() as $class => $type) { $class = is_numeric($class) ? sprintf($this->className, $this->platform, ucfirst($type)) : $class; if (!class_exists($class)) { throw new \RuntimeException("Assignment type {$type} is missing"); } /** @var AssignmentsInterface $instance */ $instance = new $class; $list[$type] = $instance->getRules(); unset($instance); } return $list; } /** * Filter assignments data. * * @param array $data * @param bool $minimize * @return array */ public function filter(array $data, $minimize = false) { $types = []; foreach ($this->types() as $type) { $types[$type] = []; } $data = array_replace($types, $data); foreach ($data as $tname => &$type) { if (is_array($type)) { foreach ($type as $gname => &$group) { if (is_array($group)) { foreach ($group as $key => $value) { if (!$value) { unset($group[$key]); } else { $group[$key] = (bool) $value; } } if (empty($group)) { unset($type[$gname]); } } else { $group = (bool) $group; } } unset($group); if ($minimize && empty($type)) { unset($data[$tname]); } } else { $type = (bool) $type; } } return $data; } /** * Save assignments for the configuration. * * @param array $data */ public function save(array $data) { $data = $this->filter($data); $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; // Save layout into custom directory for the current theme. $save_dir = $locator->findResource("gantry-config://{$this->configuration}", true, true); $filename = "{$save_dir}/assignments.yaml"; $file = YamlFile::instance($filename); $file->save($data); $file->free(); } /** * Get list of all assignment types for assignments form. * * @return array */ public function getTypes() { $list = []; foreach ($this->types() as $class => $type) { $class = is_numeric($class) ? sprintf($this->className, $this->platform, ucfirst($type)) : $class; if (!class_exists($class)) { throw new \RuntimeException("Assignment type '{$type}' is missing"); } /** @var AssignmentsInterface $instance */ $instance = new $class; $list[$type] = $instance->listRules($this->configuration); unset($instance); } return $list; } /** * Get selected assignment option. * * @return string */ public function getAssignment() { return 'default'; } /** * Set extra options for assignments. * * @param $value */ public function setAssignment($value) { } /** * Get extra options for assignments. * * @return array */ public function assignmentOptions() { return []; } protected function init() { if (!$this->filter) { $this->filter = new AssignmentFilter; $this->candidates = $this->loadAssignments(); $this->page = $this->getPage(); } } /** * Return list of assignment types. * * @return array */ abstract public function types(); } classes/Gantry/Component/Assignments/AssignmentsInterface.php 0000604 00000001356 15075035624 0020537 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Assignments; interface AssignmentsInterface { /** * Returns list of rules which apply to the current page. * * @return array */ public function getRules(); /** * List all the rules available. * * @param string $configuration * @return array */ public function listRules($configuration); } classes/Gantry/Component/Layout/Version/Format1.php 0000604 00000021711 15075035624 0016340 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Layout\Version; /** * Read layout from simplified yaml file. */ class Format1 { protected $scopes = [0 => 'grid', 1 => 'block']; protected $data; protected $keys = []; public function __construct(array $data) { $this->data = $data; } public function load() { $data = &$this->data; // Check if we have preset. $preset = []; if (isset($data['preset']) && is_array($data['preset']) && isset($data['layout']) && is_array($data['layout'])) { $preset = $data['preset']; $data = $data['layout']; } // We have user entered file; let's build the layout. // Two last items are always offcanvas and atoms. $offcanvas = isset($data['offcanvas']) ? $data['offcanvas'] : []; $atoms = isset($data['atoms']) ? $data['atoms'] : []; unset($data['offcanvas'], $data['atoms']); $data['offcanvas'] = $offcanvas; if ($atoms) { $data['atoms'] = $atoms; } $result = []; foreach ($data as $field => $params) { $child = $this->parse($field, (array) $params, 0); unset($child->size); $result[] = $child; } return ['preset' => $preset] + $result; } public function store(array $preset, array $structure) { return ['preset' => $preset, 'children' => $structure]; } protected function normalize(&$item, $container = false) { if ($item->type === 'pagecontent') { // Update pagecontent to match the new standards. $item->type = 'system'; if (!$item->subtype || $item->subtype == 'pagecontent') { $item->subtype = 'content'; $item->title = 'Page Content'; } else { $item->subtype ='messages'; $item->title = 'System Messages'; } } if ($item->type === 'section') { // Update section to match the new standards. $section = strtolower($item->title); $item->id = $section; $item->subtype = (in_array($section, ['aside', 'nav', 'article', 'header', 'footer', 'main']) ? $section : 'section'); } elseif ($item->type === 'offcanvas') { $item->id = $item->subtype = $item->type; unset ($item->attributes->name, $item->attributes->boxed); return; } else { // Update all ids to match the new standards. $item->id = $this->id($item->type, $item->subtype); } if (!empty($item->attributes->extra)) { foreach ($item->attributes->extra as $i => $extra) { $v = reset($extra); $k = key($extra); if ($k === 'id') { $item->id = preg_replace('/^g-/', '', $v); $item->attributes->id = $v; unset ($item->attributes->extra[$i]); } } if (empty($item->attributes->extra)) { unset ($item->attributes->extra); } } $item->subtype = $item->subtype ?: $item->type; $item->layout = in_array($item->type, ['container', 'section', 'grid', 'block', 'offcanvas']); if (isset($item->attributes->boxed)) { // Boxed already set, just change boxed=0 to boxed='' to use default settings. $item->attributes->boxed = $item->attributes->boxed ?: ''; return; } if (!$container) { return; } // Update boxed model to match the new standards. if (isset($item->children) && count($item->children) === 1) { $child = reset($item->children); if ($item->type === 'container') { // Remove parent container only if the only child is a section. if ($child->type === 'section') { $child->attributes->boxed = 1; $item = $child; } $item->attributes->boxed = ''; } elseif ($child->type === 'container') { // Remove child container. $item->attributes->boxed = ''; $item->children = $child->children; } } } /** * @param int|string $field * @param array $content * @param int $scope * @param bool|null $container * @return array */ protected function parse($field, array $content, $scope, $container = true) { if (is_numeric($field)) { // Row or block $type = $this->scopes[$scope]; $result = (object) ['id' => null, 'type' => $type, 'subtype' => $type, 'layout' => true, 'attributes' => (object) []]; $scope = ($scope + 1) % 2; } elseif (substr($field, 0, 9) == 'container') { // Container $type = 'container'; $result = (object) ['id' => null, 'type' => $type, 'subtype' => $type, 'layout' => true, 'attributes' => (object) []]; $id = substr($field, 10) ?: null; if ($id !== null) { $result->attributes->id = $id; } } else { // Section $list = explode(' ', $field, 2); $field = array_shift($list); $size = ((float) array_shift($list)) ?: null; $type = in_array($field, ['atoms', 'offcanvas']) ? $field : 'section'; $subtype = in_array($field, ['aside', 'nav', 'article', 'header', 'footer', 'main']) ? $field : 'section'; $result = (object) [ 'id' => null, 'type' => $type, 'subtype' => $subtype, 'layout' => true, 'title' => ucfirst($field), 'attributes' => (object) ['id' => 'g-' . $field] ]; if ($size) { $result->size = $size; } } if (!empty($content)) { $result->children = []; foreach ($content as $child => $params) { if (is_array($params)) { $child = $this->parse($child, $params, $scope, false); } else { $child = $this->resolve($params, $scope); } if (!empty($child->size)) { $result->attributes->size = $child->size; } unset($child->size); $result->children[] = $child; } } $this->normalize($result, $container); return $result; } /** * @param string $field * @param int $scope * @return array */ protected function resolve($field, $scope) { $list = explode(' ', $field, 2); $list2 = explode('-', array_shift($list), 2); $size = ((float) array_shift($list)) ?: null; $type = array_shift($list2); $subtype = array_shift($list2) ?: false; $title = ucfirst($subtype ?: $type); $attributes = new \stdClass; $attributes->enabled = 1; if ($subtype && $type === 'position') { $attributes->key = $subtype; $subtype = false; } $result = (object) ['id' => $this->id($type, $subtype), 'title' => $title, 'type' => $type, 'subtype' => $subtype, 'attributes' => $attributes]; $this->normalize($result); if ($scope > 1) { if ($size) { $result->attributes->size = $size; } return $result; } if ($scope <= 1) { $result = (object) ['id' => $this->id('block'), 'type' => 'block', 'subtype' => 'block', 'layout' => true, 'children' => [$result], 'attributes' => new \stdClass]; if ($size) { $result->attributes->size = $size; } } if ($scope == 0) { $result = (object) ['id' => $this->id('grid'), 'type' => 'grid', 'subtype' => 'grid', 'layout' => true, 'children' => [$result], 'attributes' => new \stdClass]; } return $result; } protected function id($type, $subtype = null) { if ($type === 'atoms') { return $type; } $result = []; if ($type !== 'particle' && $type !== 'atom') { $result[] = $type; } if ($subtype && $subtype !== $type) { $result[] = $subtype; } $key = implode('-', $result); while ($id = rand(1000, 9999)) { if (!isset($this->keys[$key][$id])) { break; } } $this->keys[$key][$id] = true; return $key . '-'. $id; } } classes/Gantry/Component/Layout/Version/Format0.php 0000604 00000003601 15075035624 0016335 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Layout\Version; /** * Read layout from Layout Manager yaml file. */ class Format0 extends Format1 { /** * @return array */ public function load() { $data = &$this->data; $preset = isset($data['preset']) && is_array($data['preset']) ? $data['preset'] : []; $result = is_array($data['children']) ? $this->object($data['children']) : []; $invisible = [ 'offcanvas' => $this->parse('offcanvas', [], 0), 'atoms' => $this->parse('atoms', [], 0) ]; foreach ($result as $key => &$item) { if (isset($invisible[$item->type])) { $invisible[$item->type] = $item; unset($result[$key]); } } $result += $invisible; $result = array_values($result); return ['preset' => $preset] + $result; } protected function object(array $items, $container = true) { foreach ($items as &$item) { $item = (object) $item; if (isset($item->attributes) && (is_array($item->attributes) || is_object($item->attributes))) { $item->attributes = (object) $item->attributes; } else { $item->attributes = (object) []; } if (!empty($item->children) && is_array($item->children)) { $item->children = $this->object($item->children, false); } $this->normalize($item, $container); } return $items; } } classes/Gantry/Component/Layout/Version/Format2.php 0000604 00000042706 15075035624 0016350 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Layout\Version; /** * Read layout from simplified yaml file. */ class Format2 { protected $scopes = [0 => 'grid', 1 => 'block']; protected $sections = ['wrapper', 'container', 'section', 'grid', 'block', 'offcanvas']; protected $structures = ['div', 'section', 'aside', 'nav', 'article', 'header', 'footer', 'main']; protected $data; protected $structure; protected $content; protected $keys; /** * @param array $data */ public function __construct(array $data = []) { $this->data = $data; } /** * @return array */ public function load() { $data = &$this->data; // Parse layout. $result = []; foreach ($data['layout'] as $field => &$params) { if (!is_array($params)) { $params = []; } $child = $this->parse($field, $params); unset($child->size); $result[] = $child; } return ['preset' => $data['preset']] + $result; } /** * @param array $preset * @param array $structure * @return array */ public function store(array $preset, array $structure) { $this->structure = []; $this->content = []; $structure = ['children' => json_decode(json_encode($structure), true)]; $structure = $this->build($structure); $result = [ 'version' => 2, 'preset' => $preset, 'layout' => $structure ]; if ($this->structure) { $result['structure'] = $this->structure; } if ($this->content) { $result['content'] = $this->content; } return $result; } /** * @param int|string $field * @param array $content * @param int $scope * @param object $parent * @return array */ protected function parse($field, array &$content, $scope = 0, $parent = null) { if (is_numeric($field)) { // Row or block $result = (object)['id' => $this->id($this->scopes[$scope]), 'type' => $this->scopes[$scope], 'subtype' => $this->scopes[$scope], 'layout' => true, 'attributes' => (object)[]]; $scope = ($scope + 1) % 2; } else { list ($type, $subtype, $id, $size, $section_id, $boxed) = $this->parseSectionString($field); if ($type == 'grid') { $scope = 1; } if ($type == 'block') { $scope = 0; } // Build object. $result = isset($this->data['structure'][$section_id]) ? (array) $this->data['structure'][$section_id] : []; $result += [ 'id' => $section_id, 'layout' => true, 'type' => $type, 'subtype' => $subtype, 'title' => $this->getTitle($type, $subtype, $id), 'attributes' => [] ]; if (isset($boxed) && !isset($result['attributes']['boxed'])) { $result['attributes']['boxed'] = $boxed; } if ($parent && $parent->type === 'block' && !empty($result['block'])) { $parent->attributes = (object) ($result['block'] + (array) $parent->attributes); } unset ($result['block']); $result = (object) $result; $result->attributes = (object) $result->attributes; if (isset($result->inherit)) { $result->inherit = (object) $result->inherit; } if ($size) { $result->size = $size; } if (($type === 'grid' || $type === 'block') && !isset($result->attributes->id)) { $result->attributes->id = $section_id; } } if (!empty($content)) { $result->children = []; foreach ($content as $child => &$params) { if (!$params && !is_array($params)) { $params = []; } if (is_array($params)) { $child = $this->parse($child, $params, $scope, $result); } else { $child = $this->resolve($params, $scope, $result); } if (!empty($child->size)) { $result->attributes->size = $child->size; } unset($child->size); $result->children[] = $child; } } return $result; } /** * @param string $field * @param int $scope * @param object $parent * @return array */ protected function resolve($field, $scope, $parent) { list ($type, $subtype, $id, $size, $content_id) = $this->parseContentString($field); $title = $this->getTitle($type, $subtype, $id); $result = isset($this->data['content'][$content_id]) ? (array) $this->data['content'][$content_id] : []; $result += ['id' => $this->id($type, $subtype, $id), 'title' => $title, 'type' => $type, 'subtype' => $subtype, 'attributes' => []]; $result['attributes'] = (object) ($result['attributes'] + ['enabled' => 1]); if (isset($result['inherit'])) { $result['inherit'] = (object) $result['inherit']; } if (isset($result['block'])) { $block = $result['block']; unset ($result['block']); } $result = (object) $result; if ($type === 'position' && !isset($result->attributes->key) && !in_array($subtype, ['module', 'widget'])) { $result->attributes->key = $id; } if ($scope > 1) { if ($parent->type === 'block' && !empty($block)) { $parent->attributes = (object) ($block + (array) $parent->attributes); } if ($size) { $result->attributes->size = $size; } } if ($scope <= 1) { $result = (object) ['id' => $this->id('block'), 'type' => 'block', 'subtype' => 'block', 'layout' => true, 'children' => [$result], 'attributes' => new \stdClass]; if (!empty($block)) { $result->attributes = (object) $block; } if ($size) { $result->attributes->size = $size; } } if ($scope == 0) { $result = (object) ['id' => $this->id('grid'), 'type' => 'grid', 'subtype' => 'grid', 'layout' => true, 'children' => [$result], 'attributes' => new \stdClass]; } return $result; } /** * @param array $content * @return array|null */ protected function build(array &$content) { $result = []; $ctype = isset($content['type']) ? $content['type'] : null; if (in_array($ctype, ['grid', 'block'])) { if (empty($content['attributes']['id']) || $content['attributes']['id'] === $content['id']) { unset ($content['attributes']['id']); } } if ($ctype === 'block') { if (empty($content['attributes']['extra'])) { unset ($content['attributes']['extra']); } if (empty($content['attributes']['fixed'])) { unset ($content['attributes']['fixed']); } } if ($ctype === 'section') { if (empty($content['attributes']['extra'])) { unset ($content['attributes']['extra']); } } if (!isset($content['children'])) { $content['children'] = []; } unset ($content['layout']); // Clean up all items for saving. foreach ($content['children'] as &$child) { $size = null; $id = $child['id']; $type = $child['type']; $subtype = $child['subtype']; $isSection = in_array($type, $this->sections); if (empty($child['inherit']['outline']) || empty($child['inherit']['include'])) { unset ($child['inherit']); } else { foreach ($child['inherit']['include'] as $include) { switch ($include) { case 'attributes': unset($child['attributes']); break; case 'block': if ($ctype === 'block') { // Keep block size and fixed status. $attributes = !empty($content['attributes']) ? $content['attributes'] : []; $content['attributes'] = array_intersect_key($attributes, ['fixed' => 1, 'size' => 1]); } break; case 'children': $child['children'] = []; break; } } } if (!$isSection) { // Special handling for positions. if ($type === 'position') { // TODO: we may want to simplify position id, but we need to take into account multiple instances of the same position key. /* if (!$subtype || $subtype === 'position') { $id = 'position-' . (isset($child['attributes']['key']) ? $child['attributes']['key'] : rand(1000,9999)); unset ($child['attributes']['key']); } */ unset ($child['attributes']['title']); } $value = $id; if (!empty($child['attributes']['enabled'])) { unset ($child['attributes']['enabled']); } } else { // Recursively handle structure. $value = $this->build($child); } // Clean up defaults. if (empty($child['title']) || $child['title'] === 'Untitled' || $child['title'] === $this->getTitle($type, $subtype, $id)) { unset ($child['title']); } if (!$subtype || $subtype === $type) { unset ($child['subtype']); } // Remove id and children as we store data in flat structure with id being the key. unset ($child['id'], $child['children']); if ($type === 'offcanvas' && isset($child['attributes']['name'])) { unset ($child['attributes']['name']); } if ($ctype === 'block') { // Embed size into array key/value. if (isset($content['attributes']['size']) && $content['attributes']['size'] != 100) { $size = $content['attributes']['size']; } unset ($content['attributes']['size']); // Embed parent block. if (!empty($content['attributes'])) { $child['block'] = $content['attributes']; unset ($content['attributes']); } } if (isset($child['attributes']['size'])) { if ($child['attributes']['size'] != 100 && is_string($value)) { $size = $child['attributes']['size']; } unset ($child['attributes']['size']); } // Remove attributes if there aren't any. if (empty($child['attributes'])) { unset ($child['attributes']); } // Special handling for grid and block elements. if (in_array($type, ['grid', 'block']) && count($child) === 1 && isset($child['type'])) { $id = null; } // Check if type and subtype can be generated from the id. if ($subtype && (preg_match("/^{$type}-{$subtype}(-|$)/", $id)) || (in_array($type, ['section', 'particle']) && preg_match("/^{$subtype}(-|$)/", $id))) { unset ($child['type'], $child['subtype']); } elseif (preg_match("/^{$type}(-|$)/", $id)) { unset ($child['type']); } // Add item configuration if not empty. if ($id && !empty($child)) { if (!is_string($value)) { $this->structure[$id] = $child; } else { $this->content[$id] = $child; } } // Add item to the layout. if (!is_string($value)) { // Add structural item. if ($id) { // Sections and other complex items. $id = isset($child['attributes']['boxed']) ? "/{$id}/" : $id; $result[trim("{$id} {$size}")] = $value; } elseif (!empty($value)) { // Simple grid / block item. $result[] = $value; } } else { // Add content item. $result[] = trim("{$value} {$size}"); } } // TODO: maybe collapse grid as well? if ($ctype && in_array($ctype, ['block']) && count($result) <= 1 && key($result) === 0) { unset ($this->structure[$content['id']]); return reset($result) ?: null; } return $result; } /** * @param string $string * @return array */ protected function parseSectionString($string) { // Extract: "[section-id] [size]". $list = explode(' ', $string, 2); $section_id = array_shift($list); $size = ((float) array_shift($list)) ?: null; // Extract slashes from "/[section-id]/". $boxedLeft = $section_id[0] === '/'; $boxedRight = $section_id[strlen($section_id)-1] === '/'; $boxed = ($boxedLeft && $boxedRight ? '' : ($boxedLeft ? '1' : ($boxedRight ? '0' : null))); $section_id = trim($section_id, '/'); // Extract section id if it exists: "[section]-[id]". $list = explode('-', $section_id, 2); // Get section and its type. $section = reset($list); $type = (in_array($section, $this->sections)) ? $section : 'section'; $subtype = ($type !== 'section' || in_array($section, $this->structures)) ? $section : 'section'; // Extract id. if ($type == 'section' && in_array($section, $this->structures)) { $id = array_pop($list); } else { $id = $section_id; } return [$type, $subtype, $id, $size, $section_id, $boxed]; } /** * @param string $string * @return array */ protected function parseContentString($string) { // Extract: "[type-subtype] [size]". $list = explode(' ', $string, 2); $content_id = array_shift($list); $size = ((float) array_shift($list)) ?: null; // Extract sub-type if it exists: "[type]-[subtype]-[id]". $list = explode('-', $content_id); // Get type, subtype and id. $type = reset($list); $test = end($list); $id = ((string)(int) $test === (string) $test) ? array_pop($list) : null; if (in_array($type, ['system', 'position', 'particle', 'spacer'])) { array_shift($list); } else { $type = 'particle'; } $subtype = implode('-', $list); if ($type === 'position' && !in_array($subtype, ['module', 'widget'])) { $id = ($subtype ?: $type) . ($id !== null ? "-{$id}" : ''); $subtype = 'position'; } return [$type, $subtype ?: $type, $id, $size, $content_id]; } /** * @param string $type * @param string $subtype * @param string $id * @return string */ protected function getTitle($type, $subtype, $id) { if (in_array($type, $this->sections)) { if ($type === 'offcanvas') { return 'Offcanvas'; } if ($type === 'grid' || $type === 'block') { return null; } return ucfirst((string)(int) $id === (string) $id ? ($subtype ?: $type) . "-{$id}" : $id); } if ($type === 'position' && !in_array($subtype, ['module', 'widget'])) { return ucfirst(preg_replace('/^position-(.*?[a-z])/ui', '\1', $id)); } if ($type === 'system') { if ($subtype === 'messages') { return 'System Messages'; } if ($subtype === 'content') { return 'Page Content'; } } return ucfirst($subtype ?: $type); } /** * @param string $type * @param string $subtype * @param string $id * @return string */ protected function id($type, $subtype = null, $id = null) { $result = []; if ($type !== 'particle') { $result[] = $type; } if ($subtype && $subtype !== $type) { $result[] = $subtype; } $key = implode('-', $result); if (!$id || isset($this->keys[$key][$id])) { while ($id = rand(1000, 9999)) { if (!isset($this->keys[$key][$id])) { break; } } } $this->keys[$key][$id] = true; return $key . '-'. $id; } } classes/Gantry/Component/Layout/LayoutReader.php 0000604 00000005011 15075035624 0015775 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Layout; use Gantry\Component\File\CompiledYamlFile; /** * Read layout from yaml file. */ class LayoutReader { /** * Get layout version. * * @param array $data * @return int */ public static function version(array &$data) { if (isset($data['version'])) { return $data['version']; } return isset($data['children']) && is_array($data['children']) ? 0 : 1; } /** * Make layout from array data. * * @param array $data * @return array */ public static function data(array $data) { $version = static::version($data); $reader = static::getClass($version, $data); $result = $reader->load(); // Make sure that all preset values are set by defining defaults. $result['preset'] += [ 'name' => '', 'image' => 'gantry-admin://images/layouts/default.png' ]; return $result; } /** * Read layout from yaml file and return parsed version of it. * * @param string $file * @return array */ public static function read($file) { if (!$file) { return []; } $file = CompiledYamlFile::instance($file); $content = (array) $file->content(); $file->free(); return static::data($content); } /** * Convert layout into file format. * * @param array $preset * @param array $structure * @param int $version * @return mixed */ public static function store(array $preset, array $structure, $version = 2) { $reader = static::getClass($version); return $reader->store($preset, $structure); } /** * @param int $version * @param array $data * @return object */ protected static function getClass($version, array $data = []) { $class = "Gantry\\Component\\Layout\\Version\\Format{$version}"; if (!class_exists($class)) { throw new \RuntimeException('Layout file cound not be read: unsupported version {$version}.'); } return new $class($data); } } classes/Gantry/Component/Layout/Layout.php 0000604 00000102773 15075035624 0014667 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Layout; use Gantry\Component\Config\Config; use Gantry\Component\File\CompiledYamlFile; use Gantry\Framework\Outlines; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ArrayTraits\ArrayAccess; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\ExportInterface; use RocketTheme\Toolbox\ArrayTraits\Iterator; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Layout */ class Layout implements \ArrayAccess, \Iterator, ExportInterface { use ArrayAccess, Iterator, Export; const VERSION = 7; protected static $instances = []; protected static $indexes = []; protected $layout = ['wrapper', 'container', 'section', 'grid', 'block', 'offcanvas']; public $name; public $timestamp = 0; public $preset = []; public $equalized = [3 => 33.3, 6 => 16.7, 7 => 14.3, 8 => 12.5, 9 => 11.1, 11 => 9.1, 12 => 8.3]; protected $exists; protected $items; protected $references; protected $parents; protected $blocks; protected $types; protected $inherit; /** * @return array */ public static function presets() { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; /** @var UniformResourceIterator $iterator */ $iterator = $locator->getIterator( 'gantry-layouts://', UniformResourceIterator::CURRENT_AS_SELF | UniformResourceIterator::UNIX_PATHS | UniformResourceIterator::SKIP_DOTS ); $files = []; /** @var UniformResourceIterator $info */ foreach ($iterator as $info) { $name = $info->getBasename('.yaml'); if (!$info->isFile() || $info->getExtension() !== 'yaml' || $name[0] === '.') { continue; } $files[] = $name; } sort($files); $results = ['user' => [], 'system' => []]; foreach ($files as $preset) { $scope = $preset && $preset[0] !== '_' ? 'user' : 'system'; $results[$scope][$preset] = ucwords(trim(preg_replace(['|_|', '|/|'], [' ', ' / '], $preset))); } return $results; } /** * @param string $name * @return array * @throws \RuntimeException */ public static function preset($name) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $filename = $locator->findResource("gantry-layouts://{$name}.yaml"); if (!$filename) { throw new \RuntimeException(sprintf("Preset '%s' not found", $name), 404); } $layout = LayoutReader::read($filename); $layout['preset']['name'] = $name; $layout['preset']['timestamp'] = filemtime($filename); return $layout; } /** * @param string $name * @return Layout */ public static function instance($name) { if (!isset(static::$instances[$name])) { static::$instances[$name] = static::load($name); } return static::$instances[$name]; } /** * @param string $name * @return Layout */ public static function index($name) { if (!isset(static::$indexes[$name])) { static::$indexes[$name] = static::loadIndex($name, true); } return static::$indexes[$name]; } /** * @param string $name * @param array $items * @param array $preset */ public function __construct($name, array $items = null, array $preset = null) { $this->name = $name; $this->items = (array) $items; $this->exists = $items !== null; // Add preset data from the layout. if ($preset) { $this->preset = $preset; } elseif (isset($this->items['preset'])) { $this->preset = (array) $this->items['preset']; } unset($this->items['preset']); $this->preset += [ 'name' => '', 'timestamp' => 0, 'image' => 'gantry-admin://images/layouts/default.png' ]; } /** * @return bool */ public function exists() { return $this->exists; } /** * Initialize layout. * * @param bool $force * @param bool $inherit * @return $this */ public function init($force = false, $inherit = true) { if ($force || $this->references === null) { $this->initReferences(); if ($inherit) { $this->initInheritance(); } } return $this; } /** * Build separate meta-information from the layout. * * @return array */ public function buildIndex() { return [ 'name' => $this->name, 'timestamp' => $this->timestamp, 'version' => static::VERSION, 'preset' => $this->preset, 'positions' => $this->positions(), 'sections' => $this->sections(), 'particles' => $this->particles(), 'inherit' => $this->inherit() ]; } /** * @return $this */ public function clean() { $this->references = null; $this->types = null; $this->inherit = null; $this->cleanLayout($this->items); return $this; } /** * @param string $old * @param string $new * @param array $ids * @return $this */ public function updateInheritance($old, $new = null, $ids = null) { $this->init(); $inherit = $this->inherit(); if (!empty($inherit[$old])) { foreach ($inherit[$old] as $id => $inheritId) { $element = $this->find($id, false); if ($element) { $inheritId = isset($element->inherit->particle) ? $element->inherit->particle : $id; if ($new && ($ids === null || isset($ids[$inheritId]))) { // Add or modify inheritance. if (!isset($element->inherit)) { $element->inherit = new \stdClass; } $element->inherit->outline = $new; } else { // Remove inheritance. $element->inherit = new \stdClass; unset($this->inherit[$element->id]); } } else { // Element does not exist anymore, remove its reference. unset($this->inherit[$id]); } } } return $this; } /** * Save layout. * * @param bool $cascade * @return $this */ public function save($cascade = true) { if (!$this->name) { throw new \LogicException('Cannot save unnamed layout'); } GANTRY_DEBUGGER && \Gantry\Debugger::addMessage("Saving layout for outline {$this->name}"); $name = strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $this->name)); $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; // If there are atoms in the layout, copy them into outline configuration. $atoms = $this->atoms(); if (is_array($atoms) && $cascade) { // Save layout into custom directory for the current theme. $filename = $locator->findResource("gantry-config://{$name}/page/head.yaml", true, true); $file = YamlFile::instance($filename); $config = new Config($file->content()); $file->save($config->set('atoms', json_decode(json_encode($atoms), true))->toArray()); $file->free(); } // Remove atoms from the layout. foreach ($this->items as $key => $section) { if ($section->type === 'atoms') { unset ($this->items[$key]); } } // Make sure that base outline never uses inheritance. if ($name === 'default') { $this->inheritNothing(); } $filename = $locator->findResource("gantry-config://{$name}/layout.yaml", true, true); $file = CompiledYamlFile::instance($filename); $file->settings(['inline' => 20]); $file->save(LayoutReader::store($this->preset, $this->items)); $file->free(); $this->timestamp = $file->modified(); $this->exists = true; static::$instances[$this->name] = $this; return $this; } public function export() { return LayoutReader::store($this->preset, $this->items); } /** * Save index. * * @return $this */ public function saveIndex($index = null) { if (!$this->name) { throw new \LogicException('Cannot save unnamed layout'); } GANTRY_DEBUGGER && \Gantry\Debugger::addMessage("Saving layout index for outline {$this->name}"); $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $filename = $locator->findResource("gantry-config://{$this->name}/index.yaml", true, true); $cache = $locator->findResource("gantry-cache://{$this->name}/compiled/yaml", true, true); $file = CompiledYamlFile::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. } $index = $index ? $index : $this->buildIndex(); // If file wasn't already locked by another process, save it. if ($file->locked() !== false) { $file->setCachePath($cache)->settings(['inline' => 20]); $file->save($index); $file->unlock(); } $file->free(); static::$indexes[$this->name] = $index; return $this; } /** * @return array */ public function getLayoutTypes() { return $this->layout; } /** * @param string $type * @return bool */ public function isLayoutType($type) { return in_array($type, $this->layout, true); } /** * @param $id * @return string|null */ public function getParentId($id) { return isset($this->parents[$id]) ? $this->parents[$id] : null; } /** * @return array */ public function references() { $this->init(); return $this->references; } /** * @param string $type * @param string $subtype * @return array */ public function referencesByType($type = null, $subtype = null) { $this->init(); if (!$type) { return $this->types; } if (!$subtype) { return isset($this->types[$type]) ? $this->types[$type] : []; } return isset($this->types[$type][$subtype]) ? $this->types[$type][$subtype] : []; } /** * Return list of positions (key) with their titles (value). * * @return array Array of position => title */ public function positions() { $positions = $this->referencesByType('position', 'position'); $list = []; foreach($positions as $position) { if (!isset($position->attributes->key)) { continue; } $list[$position->attributes->key] = $position->title; } return $list; } /** * Return list of positions (key) with their titles (value). * * @return array Array of position => title */ public function sections() { $list = []; foreach ($this->referencesByType('section') as $type => $sections) { foreach ($sections as $id => $section) { $list[$id] = $section->title; } } foreach ($this->referencesByType('offcanvas') as $type => $sections) { foreach ($sections as $id => $section) { $list[$id] = $section->title; } } return $list; } /** * Return list of particles with their titles. * * @param bool $grouped If true, group particles by type. * @return array Array of position => title */ public function particles($grouped = true) { $blocks = $this->referencesByType('block', 'block'); $list = []; foreach ($blocks as $blockId => $block) { if (!empty($block->children)) { foreach ($block->children as $id => $particle) { if (!empty($particle->layout) || in_array($particle->type, $this->layout, true)) { continue; } if ($grouped) { $list[$particle->subtype][$particle->id] = $particle->title; } else { $list[$particle->id] = $particle->title; } } } } return $list; } /** * @param string $outline * @return array */ public function inherit($outline = null) { $this->init(); $list = []; foreach ($this->inherit as $name => $item) { if (isset($item->inherit->outline)) { if (isset($item->inherit->particle)) { $list[$item->inherit->outline][$name] = $item->inherit->particle; } else { $list[$item->inherit->outline][$name] = $name; } } } return $outline ? (!empty($list[$outline]) ? $list[$outline] : []) : $list; } /** * Return atoms from the layout. * * @return array|null * @deprecated */ public function atoms() { $list = null; $atoms = array_filter($this->items, function ($section) { return $section->type === 'atoms' && !empty($section->children); }); $atoms = array_shift($atoms); if (!empty($atoms->children)) { $list = []; foreach ($atoms->children as $grid) { if (!empty($grid->children)) { foreach ($grid->children as $block) { if (isset($block->children[0])) { $item = $block->children[0]; $list[] = ['title' => $item->title, 'type' => $item->subtype, 'attributes' => $item->attributes]; } } } } } return $list; } /** * @param string $id * @param bool $createIfNotExists * @return object */ public function find($id, $createIfNotExists = true) { $this->init(); if (!isset($this->references[$id])) { return $createIfNotExists ? (object)['id' => $id, 'inherit' => new \stdClass] : null; } return $this->references[$id]; } /** * @param string $id * @return null */ public function block($id) { $this->init(); return isset($this->blocks[$id]) ? $this->blocks[$id] : null; } public function clearSections() { $this->items = $this->clearChildren($this->items); return $this; } protected function clearChildren(&$items) { foreach ($items as $key => $item) { if (!empty($item->children)) { $this->children = $this->clearChildren($item->children); } if (empty($item->children) && in_array($item->type, ['grid', 'block', 'particle', 'position', 'spacer', 'system'], true)) { unset($items[$key]); } } return array_values($items); } public function copySections(array $old) { $this->init(); /** @var Layout $old */ $old = new static('tmp', $old); $leftover = []; // Copy normal sections. $data = $old->referencesByType('section'); if (isset($this->types['section'])) { $sections = $this->types['section']; $this->copyData($data, $sections, $leftover); } // Copy offcanvas. $data = $old->referencesByType('offcanvas'); if (isset($this->types['offcanvas'])) { $offcanvas = $this->types['offcanvas']; $this->copyData($data, $offcanvas, $leftover); } // Copy atoms. $data = $old->referencesByType('atoms'); if (isset($this->types['atoms'])) { $atoms = $this->types['atoms']; $this->copyData($data, $atoms, $leftover); } return $leftover; } public function inheritAll() { foreach ($this->references() as $item) { if (!empty($item->inherit->outline)) { continue; } if (!$this->isLayoutType($item->type)) { $item->inherit = (object) ['outline' => $this->name, 'include' => ['attributes', 'block']]; } elseif ($item->type === 'section' || $item->type === 'offcanvas') { $item->inherit = (object) ['outline' => $this->name, 'include' => ['attributes', 'block', 'children']]; } } $this->init(true); return $this; } public function inheritNothing() { foreach ($this->references() as $item) { unset($item->inherit); } $this->init(true); return $this; } protected function copyData(array $data, array $sections, array &$leftover) { foreach ($data as $type => $items) { foreach ($items as $item) { $found = false; if (isset($sections[$type])) { foreach ($sections[$type] as $section) { if ($section->id === $item->id) { $found = true; $section->inherit = $this->cloneData($item->inherit); $section->children = $this->cloneData($item->children); break; } } } if (!$found && !empty($item->children)) { $leftover[$item->id] = $item->title; } } } } /** * Clone data which consists mixed set of arrays and stdClass objects. * * @param mixed $data * @return mixed */ protected function cloneData($data) { if (!($isObject = is_object($data)) && !is_array($data)) { return $data; } $clone = []; foreach((array) $data as $key => $value) { if (is_object($value) || is_array($value)) { $clone[$key] = $this->cloneData($value); } else { $clone[$key] = $value; } } return $isObject ? (object) $clone : $clone; } /** * @param array $items */ protected function cleanLayout(array $items) { foreach ($items as $item) { if (!empty($item->inherit->include)) { $include = $item->inherit->include; foreach ($include as $part) { switch ($part) { case 'attributes': $item->attributes = new \stdClass(); break; case 'block': break; case 'children': $item->children = []; break; } } } if (!empty($item->children)) { $this->cleanLayout($item->children); } } } protected function initInheritance() { $index = null; if ($this->name) { $index = static::loadIndexFile($this->name); } $inheriting = $this->inherit(); if (GANTRY_DEBUGGER && $inheriting) { \Gantry\Debugger::addMessage(sprintf("Layout from outline %s inherits %s", $this->name, implode(", ", array_keys($inheriting)))); } foreach ($inheriting as $outlineId => $list) { try { $outline = $this->instance($outlineId); } catch (\Exception $e) { // Outline must have been deleted. GANTRY_DEBUGGER && \Gantry\Debugger::addMessage("Outline {$outlineId} is missing / deleted", 'error'); $outline = null; } foreach ($list as $id => $inheritId) { $item = $this->find($id); $inheritId = !empty($item->inherit->particle) ? $item->inherit->particle : $id; $inherited = $outline ? $outline->find($inheritId) : null; $include = !empty($item->inherit->include) ? (array) $item->inherit->include : []; foreach ($include as $part) { switch ($part) { case 'attributes': // Deep clone attributes. $item->attributes = isset($inherited->attributes) ? $this->cloneData($inherited->attributes) : new \stdClass(); break; case 'block': $block = $this->block($id); if (isset($block->attributes)) { $inheritBlock = $outline ? $this->cloneData($outline->block($inheritId)) : null; $blockAttributes = $inheritBlock ? array_diff_key((array)$inheritBlock->attributes, ['fixed' => 1, 'size' => 1]) : []; $block->attributes = (object)($blockAttributes + (array)$block->attributes); } break; case 'children': if (!empty($inherited->children)) { // Deep clone children. $item->children = $this->cloneData($inherited->children); $this->initReferences($item->children, $this->getParentId($id), null, ['outline' => $outlineId, 'include' => ['attributes', 'block']], $index); } else { $item->children = []; } break; } } if (!$outline || !isset($inherited->attributes)) { // Remove inheritance information if outline doesn't exist. $item->inherit = new \stdClass; unset($this->inherit[$item->id]); } } } } /** * @param array $items * @param object $parent * @param object $block * @param string $inherit * @param array $index */ protected function initReferences(array $items = null, $parent = null, $block = null, $inherit = null, array $index = null) { if ($items === null) { $items = $this->items; $this->references = []; $this->types = []; $this->inherit = []; } foreach ($items as $item) { if (is_object($item)) { $type = $item->type; $subtype = !empty($item->subtype) ? $item->subtype : $type; if ($block) { $this->parents[$item->id] = $parent; } if ($block) { $this->blocks[$item->id] = $block; } if ($inherit && !$this->isLayoutType($type)) { $item->inherit = (object) $inherit; $item->inherit->particle = $item->id; if (isset($index['inherit'][$item->inherit->outline]) && ($newId = array_search($item->id, $index['inherit'][$item->inherit->outline], true))) { $item->id = $newId; } else { $item->id = $this->id($type, $subtype); } } if (isset($item->id)) { if (isset($this->references[$item->id])) { if ($type === 'block' || $type === 'grid') { $item->id = $this->id($type, $subtype); } // elseif (null === $inherit) { // throw new \RuntimeException('Layout reference conflict on #' . $item->id); // } } $this->references[$item->id] = $item; $this->types[$type][$subtype][$item->id] = $item; if (!empty($item->inherit->outline)) { $this->inherit[$item->id] = $item; } } else { $this->types[$type][$subtype][] = $item; } if (isset($item->children) && is_array($item->children)) { $this->initReferences($item->children, $type === 'section' ? $item : $parent, $type === 'block' ? $item : null, $inherit, $index); } } } } /** * @param string $type * @param string $subtype * @param string $id * @return string */ protected function id($type, $subtype = null, $id = null) { $result = []; if ($type !== 'particle') { $result[] = $type; } if ($subtype && ($subtype !== $type || $subtype === 'position')) { $result[] = $subtype; } $key = implode('-', $result); $key_id = $key . '-'. $id; if (!$id || isset($this->references[$key_id])) { while ($id = rand(1000, 9999)) { $key_id = $key . '-'. $id; if (!isset($this->references[$key_id])) { break; } } } return $key_id; } /** * Prepare block width sizes. * * @return $this */ public function prepareWidths() { $this->init(); $this->calcWidths($this->items); return $this; } /** * Recalculate block widths. * * @param array $items * @internal */ protected function calcWidths(array &$items) { foreach ($items as $i => $item) { if (empty($item->children)) { continue; } $this->calcWidths($item->children); $dynamicSize = 0; $fixedSize = 0; $childrenCount = 0; foreach ($item->children as $child) { if ($child->type !== 'block') { continue; } $childrenCount++; if (!isset($child->attributes->size)) { $child->attributes->size = 100 / count($item->children); } if (empty($child->attributes->fixed)) { $dynamicSize += $child->attributes->size; } else { $fixedSize += $child->attributes->size; } } if (!$childrenCount) { continue; } $roundSize = round($dynamicSize, 1); $equalized = isset($this->equalized[$childrenCount]) ? $this->equalized[$childrenCount] : 0; // force-casting string for testing comparison due to weird PHP behavior that returns wrong result if ($roundSize !== 100 && (string) $roundSize !== (string) ($equalized * $childrenCount)) { $fraction = 0; $multiplier = (100 - $fixedSize) / ($dynamicSize ?: 1); foreach ($item->children as $child) { if ($child->type !== 'block') { continue; } if (!empty($child->attributes->fixed)) { continue; } // Calculate size for the next item by taking account the rounding error from the last item. // This will allow us to approximate cumulating error and fix it when rounding error grows // over the rounding treshold. $size = ($child->attributes->size * $multiplier) + $fraction; $newSize = round($size); $fraction = $size - $newSize; $child->attributes->size = $newSize; } } } } /** * @param string $name * @param string $preset * @return static */ public static function load($name, $preset = null) { if (!$name) { throw new \BadMethodCallException('Layout needs to have a name'); } $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $layout = null; $filename = $locator("gantry-config://{$name}/layout.yaml"); // If layout file doesn't exists, figure out what preset was used. if (!$filename) { // Attempt to load the index file. $indexFile = $locator("gantry-config://{$name}/index.yaml"); if ($indexFile || !$preset) { $index = static::loadIndex($name, true); $preset = $index['preset']['name']; } try { $layout = static::preset($preset); } catch (\Exception $e) { // Layout doesn't exist, do nothing. } } else { $layout = LayoutReader::read($filename); } return new static($name, $layout); } protected static function loadIndexFile($name) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; // Attempt to load the index file. $indexFile = $locator("gantry-config://{$name}/index.yaml"); if ($indexFile) { $file = CompiledYamlFile::instance($indexFile); $index = (array)$file->content(); $file->free(); } else { $index = []; } return $index; } /** * @param string $name * @param bool $autoSave * @return array */ public static function loadIndex($name, $autoSave = false) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $index = static::loadIndexFile($name); // Find out the currently used layout file. $layoutFile = $locator("gantry-config://{$name}/layout.yaml"); if (!$layoutFile) { /** @var Outlines $outlines */ $outlines = $gantry['outlines']; $preset = isset($index['preset']['name']) ? $index['preset']['name'] : $outlines->preset($name); } // Get timestamp for the layout file. $timestamp = $layoutFile ? filemtime($layoutFile) : 0; // If layout index file doesn't exist or is not up to date, rebuild it. if (empty($index['timestamp']) || $index['timestamp'] != $timestamp || !isset($index['version']) || $index['version'] != static::VERSION) { $layout = isset($preset) ? new static($name, static::preset($preset)) : static::instance($name); $layout->timestamp = $timestamp; if ($autoSave) { if (!$layout->timestamp) { $layout->save(); } $index = $layout->buildIndex(); $layout->saveIndex($index); } else { $index = $layout->buildIndex(); } } $index += [ 'name' => $name, 'timestamp' => $timestamp, 'preset' => [ 'name' => '', 'image' => 'gantry-admin://images/layouts/default.png' ], 'positions' => [], 'sections' => [], 'inherit' => [] ]; return $index; } public function check(array $children = null) { if ($children === null) { $children = $this->items; } foreach ($children as $item) { if (!$item instanceof \stdClass) { throw new \RuntimeException('Invalid layout element'); } if (!isset($item->type)) { throw new \RuntimeException('Type missing'); } if (!isset($item->subtype)) { throw new \RuntimeException('Subtype missing'); } if (!isset($item->attributes)) { throw new \RuntimeException('Attributes missing'); } if (!is_object($item->attributes)) { throw new \RuntimeException('Attributes not object'); } if (isset($item->children)) { if (!is_array($item->children)) { throw new \RuntimeException('Children not array'); } $this->check($item->children); } } } } classes/Gantry/Component/System/Messages.php 0000604 00000001175 15075035624 0015162 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Component\System; class Messages { protected $messages = []; public function add($message, $type = 'warning') { $this->messages[] = ['type' => $type, 'message' => $message]; return $this; } public function get() { return $this->messages; } public function clean() { $this->messages = []; return $this; } } classes/Gantry/Component/Config/CompiledBlueprints.php 0000604 00000004104 15075035624 0017133 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; /** * The Compiled Blueprints class. */ class CompiledBlueprints extends CompiledBase { /** * @var int Version number for the compiled file. */ public $version = 3; /** * @var BlueprintSchema Blueprints object. */ protected $object; /** * Create configuration object. * * @param array $data */ protected function createObject(array $data = []) { $this->object = new BlueprintSchema($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 array $files Files to be loaded. */ protected function loadFile($name, $files) { // Load blueprint file. $blueprint = new BlueprintForm($files); $this->object->embed($name, $blueprint->load()->toArray(), '/', true); } /** * Load and join all configuration files. * * @return bool * @internal */ protected function loadFiles() { $this->createObject(); // Convert file list into parent list. $list = []; foreach ($this->files as $files) { foreach ($files as $name => $item) { $list[$name][] = $this->path . $item['file']; } } // Load files. foreach ($list as $name => $files) { $this->loadFile($name, $files); } $this->finalizeObject(); return true; } protected function getState() { return $this->object->getState(); } } classes/Gantry/Component/Config/CompiledBase.php 0000604 00000014215 15075035624 0015662 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; use Gantry\Framework\Gantry; 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 = GANTRY5_ROOT) { 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) { $gantry = Gantry::instance(); /** @var Config $global */ $global = $gantry['global']; if (!$global->get('compile_yaml', 1)) { return false; } 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']); $this->finalizeObject(); return true; } /** * Save compiled file. * * @param string $filename * @throws \RuntimeException * @internal */ protected function saveCompiledFile($filename) { $gantry = Gantry::instance(); /** @var Config $global */ $global = $gantry['global']; if (!$global->get('compile_yaml', 1)) { return; } $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->getState() ]; $file->save($cache); $file->unlock(); $file->free(); $this->modified(); } protected function getState() { return $this->object->toArray(); } } classes/Gantry/Component/Config/Validation.php 0000604 00000053013 15075035624 0015424 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Yaml; /** * Data validation. * * @author RocketTheme * @license MIT */ class Validation { /** * Validate value against a blueprint field definition. * * @param $value * @param array $field * @return array */ public static function validate($value, array $field) { $messages = []; $validate = isset($field['validate']) ? (array) $field['validate'] : []; // If value isn't required, we will stop validation if empty value is given. if (empty($validate['required']) && ($value === null || $value === '')) { return $messages; } if (!isset($field['type'])) { $field['type'] = 'input.text'; } // Special case for files, value is never empty and errors with code 4 instead. if (empty($validate['required']) && $field['type'] === 'input.file' && isset($value['error']) && ($value['error'] === UPLOAD_ERR_NO_FILE || \in_array(UPLOAD_ERR_NO_FILE, $value['error'], true))) { return $messages; } // Validate type with fallback type text. $type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type']; $method = 'type_'.strtr($type, '-.', '__'); if (!method_exists(__CLASS__, $method)) { $method = 'type_Input_Text'; } $name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']); // TODO: translate $message = (string) isset($field['validate']['message']) ? sprintf($field['validate']['message']) : sprintf('Invalid input in field: ') . ' "' . $name . '"'; $success = self::$method($value, $validate, $field); if (!$success) { $messages[$field['name']][] = $message; } // Check individual rules. foreach ($validate as $rule => $params) { $method = 'validate_' . ucfirst(strtr($rule, '-.', '__')); if (method_exists(__CLASS__, $method)) { $success = self::$method($value, $params); if (!$success) { $messages[$field['name']][] = $message; } } } return $messages; } /** * Filter value against a blueprint field definition. * * @param mixed $value * @param array $field * @return mixed Filtered value. */ public static function filter($value, array $field) { $validate = isset($field['validate']) ? (array) $field['validate'] : []; // If value isn't required, we will return null if empty value is given. if (($value === null || $value === '') && empty($validate['required'])) { return null; } if (!isset($field['type'])) { $field['type'] = 'input.text'; } // Special case for files, value is never empty and errors with code 4 instead. if (empty($validate['required']) && $field['type'] === 'input.file' && isset($value['error']) && ($value['error'] === UPLOAD_ERR_NO_FILE || \in_array(UPLOAD_ERR_NO_FILE, $value['error'], true))) { return null; } // Validate type with fallback type text. $type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type']; $method = 'filter_' . ucfirst(str_replace('-', '_', $type)); if (!method_exists(__CLASS__, $method)) { $method = 'filter_Input_Text'; } return self::$method($value, $validate, $field); } /** * HTML5 input: text * * @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 type_Input_Text($value, array $params, array $field) { if (!\is_string($value) && !is_numeric($value)) { return false; } $value = (string)$value; if (isset($params['min']) && \strlen($value) < $params['min']) { return false; } if (isset($params['max']) && \strlen($value) > $params['max']) { return false; } $min = isset($params['min']) ? $params['min'] : 0; if (isset($params['step']) && (strlen($value) - $min) % $params['step'] === 0) { return false; } if ((!isset($params['multiline']) || !$params['multiline']) && preg_match('/\R/um', $value)) { return false; } return true; } protected static function filter_Input_Text($value, array $params, array $field) { return (string) $value; } protected static function filter_Input_CommaList($value, array $params, array $field) { return \is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY); } protected static function type_Input_CommaList($value, array $params, array $field) { return \is_array($value) ? true : self::type_Input_Text($value, $params, $field); } /** * HTML5 input: textarea * * @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 type_Textarea_Textarea($value, array $params, array $field) { if (!isset($params['multiline'])) { $params['multiline'] = true; } return self::type_Input_Text($value, $params, $field); } /** * HTML5 input: password * * @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 type_Input_Password($value, array $params, array $field) { return self::type_Input_Text($value, $params, $field); } /** * HTML5 input: hidden * * @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 type_Input_Hidden($value, array $params, array $field) { return self::type_Input_Text($value, $params, $field); } /** * Custom input: checkbox list * * @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 type_Checkboxes_Checkboxes($value, array $params, array $field) { // Set multiple: true so checkboxes can easily use min/max counts to control number of options required $field['multiple'] = true; return self::typeArray((array) $value, $params, $field); } protected static function filter_Checkboxes_Checkboxes($value, array $params, array $field) { return self::filterArray($value, $params, $field); } /** * HTML5 input: checkbox * * @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 type_Input_Checkbox($value, array $params, array $field) { $value = (string) $value; if (!isset($field['value'])) { $field['value'] = 1; } if ($value && $value != $field['value']) { return false; } return true; } /** * HTML5 input: radio * * @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 type_Input_Radio($value, array $params, array $field) { return self::typeArray((array) $value, $params, $field); } /** * Custom input: toggle * * @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 type_Toggle_Toggle($value, array $params, array $field) { 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 type_Input_File($value, array $params, array $field) { return self::typeArray((array) $value, $params, $field); } protected static function filter_Input_File($value, array $params, array $field) { if (isset($field['multiple']) && $field['multiple'] === true) { return (array) $value; } if (\is_array($value)) { return reset($value); } return $value; } /** * HTML5 input: select * * @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 type_Select_Select($value, array $params, array $field) { return self::typeArray((array) $value, $params, $field); } /** * HTML5 input: number * * @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 type_Input_Number($value, array $params, array $field) { if (!is_numeric($value)) { return false; } if (isset($params['min']) && $value < $params['min']) { return false; } if (isset($params['max']) && $value > $params['max']) { return false; } $min = isset($params['min']) ? $params['min'] : 0; return !(isset($params['step']) && fmod($value - $min, $params['step']) === 0); } protected static function filter_Input_Number($value, array $params, array $field) { return (string)(int)$value !== (string)(float)$value ? (float) $value : (int) $value; } protected static function filter_Input_DateTime($value, array $params, array $field) { $converted = new \DateTime($value); return $converted->format('Y-m-d H:i:s'); } /** * HTML5 input: range * * @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 type_Input_Range($value, array $params, array $field) { return self::type_Input_Number($value, $params, $field); } protected static function filter_Input_Range($value, array $params, array $field) { return self::filter_Input_Number($value, $params, $field); } /** * HTML5 input: color * * @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 type_Input_Color($value, array $params, array $field) { return preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', $value); } /** * HTML5 input: email * * @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 type_Input_Email($value, array $params, array $field) { return self::type_Input_Text($value, $params, $field) && filter_var($value, FILTER_VALIDATE_EMAIL); } /** * HTML5 input: url * * @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 type_Input_Url($value, array $params, array $field) { return self::type_Input_Text($value, $params, $field) && filter_var($value, FILTER_VALIDATE_URL); } /** * HTML5 input: datetime * * @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 type_Input_Datetime($value, array $params, array $field) { if ($value instanceof \DateTime) { return true; } if (!\is_string($value)) { return false; } if (!isset($params['format'])) { return false !== strtotime($value); } $dateFromFormat = \DateTime::createFromFormat($params['format'], $value); return $dateFromFormat && $value === date($params['format'], $dateFromFormat->getTimestamp()); } /** * HTML5 input: datetime-local * * @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 type_Input_DatetimeLocal($value, array $params, array $field) { return self::type_Input_Datetime($value, $params, $field); } /** * HTML5 input: date * * @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 type_Input_Date($value, array $params, array $field) { if (!isset($params['format'])) { $params['format'] = 'Y-m-d'; } return self::type_Input_Datetime($value, $params, $field); } /** * HTML5 input: time * * @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 type_Input_Time($value, array $params, array $field) { if (!isset($params['format'])) { $params['format'] = 'H:i'; } return self::type_Input_Datetime($value, $params, $field); } /** * HTML5 input: month * * @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 type_Input_Month($value, array $params, array $field) { if (!isset($params['format'])) { $params['format'] = 'Y-m'; } return self::type_Input_Datetime($value, $params, $field); } /** * HTML5 input: week * * @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 type_Input_Week($value, array $params, array $field) { if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', $value)) { return false; } return self::type_Input_Datetime($value, $params, $field); } /** * Custom input: array * * @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 typeArray($value, array $params, array $field) { if (!\is_array($value)) { return false; } if (isset($field['multiple'])) { if (isset($params['min']) && \count($value) < $params['min']) { return false; } if (isset($params['max']) && \count($value) > $params['max']) { return false; } $min = isset($params['min']) ? $params['min'] : 0; if (isset($params['step']) && (\count($value) - $min) % $params['step'] === 0) { return false; } } $options = isset($field['options']) ? array_keys($field['options']) : []; $values = isset($field['use']) && $field['use'] === 'keys' ? array_keys($value) : $value; return !($options && array_diff($values, $options)); } protected static function filterArray($value, $params, $field) { $values = (array) $value; $options = isset($field['options']) ? array_keys($field['options']) : []; $multi = isset($field['multiple']) ? $field['multiple'] : false; if (\count($values) === 1 && isset($values[0]) && $values[0] === '') { return null; } if ($options) { $useKey = isset($field['use']) && $field['use'] === 'keys'; foreach ($values as $key => $val) { $values[$key] = $useKey ? (bool) $val : $val; } } if ($multi) { foreach ($values as $key => $val) { if (\is_array($val)) { $val = implode(',', $val); } $values[$key] = array_map('trim', explode(',', $val)); } } return $values; } public static function type_Input_Yaml($value, $params) { try { Yaml::parse($value); return true; } catch (ParseException $e) { return false; } } public static function filter_Input_Yaml($value, $params) { try { return (array) Yaml::parse($value); } catch (ParseException $e) { return null; } } /** * Custom input: ignore (will not validate) * * @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 type_Novalidate($value, array $params, array $field) { return true; } public static function filter_Novalidate($value, array $params, array $field) { return $value; } // HTML5 attributes (min, max and range are handled inside the types) public static function validate_Required($value, $params) { if (is_scalar($value)) { return (bool) $params !== true || $value !== ''; } return (bool) $params !== true || !empty($value); } public static function validate_Pattern($value, $params) { return (bool) preg_match("`^{$params}$`u", $value); } // Internal types public static function validate_Alpha($value, $params) { return ctype_alpha($value); } public static function validate_Alnum($value, $params) { return ctype_alnum($value); } public static function type_Bool($value, $params) { return \is_bool($value) || $value == 1 || $value == 0; } public static function validate_Bool($value, $params) { return \is_bool($value) || $value == 1 || $value == 0; } protected static function filter_Bool($value, $params) { return (bool) $value; } public static function validate_Digit($value, $params) { return ctype_digit($value); } public static function validate_Float($value, $params) { return \is_float(filter_var($value, FILTER_VALIDATE_FLOAT)); } protected static function filter_Float($value, $params) { return (float) $value; } public static function validate_Hex($value, $params) { return ctype_xdigit($value); } public static function validate_Int($value, $params) { return is_numeric($value) && (int) $value == $value; } protected static function filter_Int($value, $params) { return (int) $value; } public static function validate_Array($value, $params) { return \is_array($value) || ($value instanceof \ArrayAccess && $value instanceof \Traversable && $value instanceof \Countable); } public static function validate_Json($value, $params) { return (bool) (@json_decode($value)); } } classes/Gantry/Component/Config/ValidationException.php 0000604 00000002002 15075035624 0017273 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; class ValidationException extends \RuntimeException { protected $messages = []; public function setMessages(array $messages = []) { $this->messages = $messages; // TODO: add translation. $this->message = sprintf('Form validation failed:') . ' ' . $this->message; foreach ($messages as $variable => &$list) { $list = array_unique($list); foreach ($list as $message) { $this->message .= "<br/>$message"; } } return $this; } public function getMessages() { return $this->messages; } } classes/Gantry/Component/Config/BlueprintForm.php 0000604 00000022071 15075035624 0016122 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; use Gantry\Component\File\CompiledYamlFile; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\Blueprints\BlueprintForm as BaseBlueprintForm; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * The Config class contains configuration information. * * @author RocketTheme */ class BlueprintForm extends BaseBlueprintForm { /** * @var string */ protected $context = 'gantry-blueprints://'; /** * @var BlueprintSchema */ protected $schema; /** * @param string $filename * @param string $context * @return BlueprintForm */ public static function instance($filename, $context = null) { /** @var BlueprintForm $instance */ $instance = new static($filename); if ($context) { $instance->setContext($context); } return $instance->load()->init(); } /** * 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->schema()->getDefaults(); } /** * Merge two arrays by using blueprints. * * @param array $data1 * @param array $data2 * @param string $name Optional * @param string $separator Optional * @return array */ public function mergeData(array $data1, array $data2, $name = null, $separator = '.') { return $this->schema()->mergeData($data1, $data2, $name, $separator); } /** * Return data fields that do not exist in blueprints. * * @param array $data * @param string $prefix * @return array */ public function extra(array $data, $prefix = '') { return $this->schema()->extra($data, $prefix); } /** * Validate data against blueprints. * * @param array $data * @throws \RuntimeException */ public function validate(array $data) { $this->schema()->validate($data); } /** * Filter data by using blueprints. * * @param array $data * @return array */ public function filter(array $data) { return $this->schema()->filter($data); } /** * @return BlueprintSchema */ public function schema() { if (!isset($this->schema)) { $this->schema = new BlueprintSchema; $this->schema->embed('', $this->items); $this->schema->init(); } return $this->schema; } /** * @param string $filename * @return string */ protected function loadFile($filename) { $file = CompiledYamlFile::instance($filename); $content = $file->content(); $file->free(); return $content; } /** * @param string|array $path * @param string $context * @return array */ protected function getFiles($path, $context = null) { if (is_string($path) && !strpos($path, '://')) { // Resolve filename. if (isset($this->overrides[$path])) { $path = $this->overrides[$path]; } else { if ($context === null) { $context = $this->context; } if ($context && $context[strlen($context)-1] !== '/') { $context .= '/'; } $path = $context . $path; if (!preg_match('/\.yaml$/', $path)) { $path .= '.yaml'; } } } if (is_string($path) && strpos($path, '://')) { /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; $files = $locator->findResources($path); } else { $files = (array) $path; } return $files; } /** * @param array $field * @param string $property * @param array $call */ protected function dynamicData(array &$field, $property, array &$call) { $params = $call['params']; if (is_array($params)) { $function = array_shift($params); } else { $function = $params; $params = []; } list($o, $f) = preg_split('/::/', $function, 2); if (!$f) { if (function_exists($o)) { $data = call_user_func_array($o, $params); } } else { if (method_exists($o, $f)) { $data = call_user_func_array(array($o, $f), $params); } } // 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; } } } /** * @param array $field * @param string $property * @param array $call */ protected function dynamicConfig(array &$field, $property, array &$call) { $value = $call['params']; $default = isset($field[$property]) ? $field[$property] : null; $config = Gantry::instance()['config']->get($value, $default); if (!is_null($config)) { $field[$property] = $config; } } /** * Get blueprints by using slash notation for nested arrays/objects. * * @param array $path * @param string $separator * @return array */ public function resolve(array $path, $separator = '/') { $fields = false; $parts = []; $current = $this['form/fields']; $result = [null, null, null]; $prefix = ''; while (($field = current($path)) !== false) { if (!$fields && isset($current['fields'])) { if (!empty($current['array'])) { $result = [$current, $parts, $path ? implode($separator, $path) : null]; // Skip item offset. $parts[] = array_shift($path); } $current = $current['fields']; $prefix = ''; $fields = true; } elseif (isset($current[$prefix . $field])) { $parts[] = array_shift($path); $current = $current[$prefix . $field]; $prefix = ''; $fields = false; } elseif (isset($current['.' . $prefix . $field])) { $parts[] = array_shift($path); $current = $current['.' . $prefix . $field]; $prefix = ''; $fields = false; } elseif ($field && $this->fieldExists($prefix . $field, $current)) { $parts[] = array_shift($path); $prefix = "{$prefix}{$field}."; $fields = false; } else { // Check if there's a container with the field. $current = $this->resolveContainer($current, $prefix, $field); // No containers with the field found. if (!$current) { break; } $prefix = ''; $fields = false; } } if (!$fields && !empty($current['array'])) { $result = [$current, $parts, $path ? implode($separator, $path) : null]; } return $result; } protected function resolveContainer($current, $prefix, $fieldName) { foreach ($current as $field) { $type = isset($field['type']) ? $field['type'] : 'container._implicit'; $container = (0 === strpos($type, 'container.')); if (!$container || !isset($field['fields'])) { continue; } $current_fields = $field['fields']; if (isset($current_fields[$prefix . $fieldName]) || isset($current_fields['.' . $prefix . $fieldName]) || $this->fieldExists($prefix . $fieldName, $current_fields)) { return $current_fields; } $current_fields = $this->resolveContainer($current_fields, $prefix, $fieldName); if ($current_fields !== null) { return $current_fields; } } return null; } protected function fieldExists($prefix, $list) { foreach ($list as $field => $data) { $pos = strpos($field, $prefix); if ($pos === 0 || ($pos === 1 && $field[0] === '.')) { return true; } } return false; } } classes/Gantry/Component/Config/Config.php 0000604 00000016544 15075035624 0014547 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\ExportInterface; use RocketTheme\Toolbox\ArrayTraits\Iterator; use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters; /** * The Config class contains configuration information. * * @author RocketTheme */ class Config implements \ArrayAccess, \Countable, \Iterator, ExportInterface { use NestedArrayAccessWithGetters, Iterator, Export; /** * @var array */ protected $items; /** * @var BlueprintSchema|BlueprintForm|callable */ protected $blueprint; /** * Constructor to initialize array. * * @param array $items Initial items inside the iterator. * @param callable $blueprints Function to load Blueprints for the configuration. */ public function __construct(array $items, callable $blueprint = null) { $this->items = $items; $this->blueprint = $blueprint; } /** * 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) { if (!is_array($old)) { throw new \RuntimeException("Value is not array in {$name}: " . print_r($old, true)); } if (is_object($value)) { $value = (array) $value; } elseif (!is_array($value)) { throw new \RuntimeException("Value is not array in {$name}: " . print_r($value, true)); } $value = $this->blueprint()->mergeData($old, $value, $name, $separator); } $this->set($name, $value, $separator); return $this; } /** * 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->blueprint()->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) { $value = $this->blueprint()->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 is not array in '{$name}': " . print_r($value, true)); } $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 is not array in '{$name}': " . print_r($value, true)); } // Return joined data. return $this->blueprint()->mergeData($old, $value, $name, $separator); } /** * Merge two configurations together. * * @param array $data * @return $this */ public function merge(array $data) { $this->items = $this->blueprint()->mergeData($this->items, $data); return $this; } /** * Set default values to the configuration if variables were not set. * * @param array $data * @return $this */ public function setDefaults(array $data) { $this->items = $this->blueprint()->mergeData($data, $this->items); return $this; } /** * Make a flat list from the configuration. * * @param string $name Dot separated path to the requested value. * @param string $separator Separator, defaults to '.' * @param string $prefix Name prefix. * @return array */ public function flatten($name = null, $separator = '.', $prefix = '') { $element = $name ? $this->offsetGet($name) : $this->items; if (!is_array($element)) { return [$name, $element]; } if (strlen($separator) == 2 && in_array($separator, ['][', ')(', '}{'])) { $separator = [$separator[1], $separator[0]]; } return $this->flattenNested('', $element, $separator, $prefix); } /** * @param string $name * @param array $element * @param string $separator * @param string $prefix * @return array * @internal */ protected function flattenNested($name, &$element, $separator, $prefix) { $list = []; foreach ($element as $key => $value) { $new = $name ? $name : $prefix; if (is_array($separator)) { $new .= $separator[0] . $key . $separator[1]; } else { $new .= ($new ? $separator : '') . $key; } if (!is_array($value) || empty($value)) { $list[$new] = $value; } else { $list += $this->flattenNested($new, $value, $separator, $prefix); } } return $list; } /** * Return blueprint. * * @return BlueprintSchema|BlueprintForm * @since 5.4.7 */ public function blueprint() { if (!$this->blueprint){ $this->blueprint = new BlueprintSchema; } elseif (is_callable($this->blueprint)) { // Lazy load blueprints. $blueprint = $this->blueprint; $this->blueprint = $blueprint(); } return $this->blueprint; } /** * Return blueprints. * * @return BlueprintSchema * @deprecated 5.4.7 */ public function blueprints() { return $this->blueprint(); } /** * Count items in nested array. * * @param string $path * @param string $separator * @return int */ public function count($path = null, $separator = '.') { $items = $path ? $this->get($path, null, $separator) : $this->items; return is_array($items) ? count($items) : 0; } } classes/Gantry/Component/Config/CompiledConfig.php 0000604 00000005024 15075035624 0016213 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; use Gantry\Component\File\CompiledYamlFile; /** * The Compiled Configuration class. */ class CompiledConfig extends CompiledBase { /** * @var int Version number for the compiled file. */ public $version = 2; /** * @var Config Configuration object. */ protected $object; /** * @var callable Blueprints loader. */ protected $callable; /** * @var bool */ protected $withDefaults; /** * 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)) . (int) $this->withDefaults); } return $this; } /** * 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() { } /** * 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(); } } classes/Gantry/Component/Config/BlueprintSchema.php 0000604 00000015361 15075035624 0016423 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\Blueprints\BlueprintSchema as BlueprintSchemaBase; /** * Blueprint schema handles the internal logic of blueprints. * * @author RocketTheme * @license MIT */ class BlueprintSchema extends BlueprintSchemaBase { protected $configuration; protected $ignoreFormKeys = [ 'title' => true, 'help' => true, 'placeholder' => true, 'fields' => true ]; protected $types = [ 'container.set' => [ 'input@' => false ], 'container.tabs' => [ 'input@' => false ], 'separator.note' => [ 'input@' => false ], 'separator.separator' => [ 'input@' => false ], 'key' => [ 'input@' => false ], 'collection.list' => [ 'array' => true ] ]; /** * Constructor. * * @param array $serialized Serialized content if available. */ public function __construct($serialized = null) { parent::__construct($serialized); $this->configuration = new Config(isset($serialized['configuration']) ? $serialized['configuration'] : []); } /** * Convert object into an array. * * @return array */ public function getState() { return parent::getState() + ['configuration' => $this->configuration->toArray()]; } /** * 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 array_merge_recursive($this->configuration->toArray(), $this->buildDefaults($this->nested)); } /** * Embed an array to the blueprint. * * @param $name * @param array $value * @param string $separator * @param bool $merge Merge fields instead replacing them. * @return $this */ public function embed($name, array $value, $separator = '.', $merge = false) { parent::embed($name, $value, $separator, $merge); if (isset($value['configuration'])) { $this->configuration->set($name, $value['configuration'], $separator); } return $this; } /** * Validate data against blueprints. * * @param array $data * @throws \RuntimeException */ public function validate(array $data) { try { $messages = $this->validateArray($data, $this->nested); } catch (\RuntimeException $e) { throw (new ValidationException($e->getMessage(), $e->getCode(), $e))->setMessages(); } if (!empty($messages)) { throw (new ValidationException())->setMessages($messages); } } /** * Filter data by using blueprints. * * @param array $data * @return array */ public function filter(array $data) { return $this->filterArray($data, $this->nested); } /** * @param array $data * @param array $rules * @returns array * @throws \RuntimeException * @internal */ protected function validateArray(array $data, array $rules) { $messages = $this->checkRequired($data, $rules); foreach ($data as $key => $field) { $val = isset($rules[$key]) ? $rules[$key] : (isset($rules['*']) ? $rules['*'] : null); $rule = is_string($val) ? $this->items[$val] : null; if ($rule) { // Item has been defined in blueprints. $messages += Validation::validate($field, $rule); } elseif (is_array($field) && is_array($val)) { // Array has been defined in blueprints. $messages += $this->validateArray($field, $val); } elseif (isset($rules['validation']) && $rules['validation'] == 'strict') { // Undefined/extra item. throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key)); } } return $messages; } /** * @param array $data * @param array $rules * @return array * @internal */ protected function filterArray(array $data, array $rules) { $results = array(); foreach ($data as $key => $field) { $val = isset($rules[$key]) ? $rules[$key] : (isset($rules['*']) ? $rules['*'] : null); $rule = is_string($val) ? $this->items[$val] : null; if ($rule) { // Item has been defined in blueprints. $field = Validation::filter($field, $rule); } elseif (is_array($field) && is_array($val)) { // Array has been defined in blueprints. $field = $this->filterArray($field, $val); } elseif (isset($rules['validation']) && $rules['validation'] == 'strict') { $field = null; } if (isset($field) && (!is_array($field) || !empty($field))) { $results[$key] = $field; } } return $results; } /** * @param array $data * @param array $fields * @return array */ protected function checkRequired(array $data, array $fields) { $messages = []; foreach ($fields as $name => $field) { if (!is_string($field)) { continue; } $field = $this->items[$field]; if (isset($field['validate']['required']) && $field['validate']['required'] === true && !isset($data[$name])) { $value = isset($field['label']) ? $field['label'] : $field['name']; // TODO: translate $message = sprintf("Please fill up required field '%s'.", $value); $messages[$field['name']][] = $message; } } return $messages; } /** * @param array $field * @param string $property * @param array $call */ protected function dynamicConfig(array &$field, $property, array &$call) { $value = $call['params']; $default = isset($field[$property]) ? $field[$property] : null; $config = Gantry::instance()['config']->get($value, $default); if (!is_null($config)) { $field[$property] = $config; } } } classes/Gantry/Component/Config/ConfigFileFinder.php 0000604 00000020534 15075035624 0016471 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Config; use Gantry\Component\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; } } classes/Gantry/Component/Controller/HtmlController.php 0000604 00000002060 15075035624 0017214 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Controller; use Gantry\Component\Response\HtmlResponse; use Gantry\Component\Response\Response; abstract class HtmlController extends BaseController { /** * Execute controller and returns Response object, defaulting to HtmlResponse. * * @param string $method * @param array $path * @param array $params * @return mixed * @throws \RuntimeException */ public function execute($method, array $path, array $params) { $response = parent::execute($method, $path, $params); if (!$response instanceof Response) { $response = new HtmlResponse($response); } return $response; } } classes/Gantry/Component/Controller/JsonController.php 0000604 00000001764 15075035624 0017233 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Controller; use Gantry\Component\Response\JsonResponse; abstract class JsonController extends BaseController { /** * Execute controller and returns JsonResponse object. * * @param string $method * @param array $path * @param array $params * @return mixed * @throws \RuntimeException */ public function execute($method, array $path, array $params) { $response = parent::execute($method, $path, $params); if (!$response instanceof JsonResponse) { $response = new JsonResponse($response); } return $response; } } classes/Gantry/Component/Controller/BaseController.php 0000604 00000014771 15075035624 0017176 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Controller; use Gantry\Framework\Request; use RocketTheme\Toolbox\DI\Container; use RuntimeException; abstract class BaseController implements RestfulControllerInterface { /** * @var string Default HTTP method. */ protected $method = 'GET'; /** * @var Request */ protected $request; /** * @var array List of HTTP verbs and their actions. */ protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/create' => 'create', '/*' => 'display', '/*/edit' => 'edit' ], 'POST' => [ '/' => 'store' ], 'PUT' => [ '/*' => 'replace' ], 'PATCH' => [ '/*' => 'update' ], 'DELETE' => [ '/*' => 'destroy' ] ]; /** * @var array Parameters from router. */ protected $params = []; /** * @var Container */ protected $container; public function __construct(Container $container) { $this->container = $container; $this->request = $container['request']; } /** * Execute controller. * * @param string $method * @param array $path * @param array $params * @return mixed * @throws \RuntimeException */ public function execute($method, array $path, array $params) { $this->method = $method; $this->setParams($params); list($action, $path) = $this->resolveHttpVerb($method, $path); if (!method_exists($this, $action)) { $action = 'undefined'; } return call_user_func_array([$this, $action], $path); } /** * Set router parameters. Replaces the old parameters. * * @param array $params * @return $this */ public function setParams(array $params) { $this->params = $params; return $this; } /** * @example GET /resources * * @return mixed */ public function index() { return $this->undefined(); } /** * @example GET /resources/:id * * @param string $id * @return mixed */ public function display($id) { return $this->undefined(); } /** * Special sub-resource to create a new resource (returns a form). * * @example GET /resources/create * * @return mixed */ public function create() { return $this->undefined(); } /** * Special sub-resource to edit existing resource (returns a form). * * @example GET /resources/:id/edit * * @param string $id * @return mixed */ public function edit($id) { return $this->undefined(); } /** * @example POST /resources * * @return mixed */ public function store() { return $this->undefined(); } /** * @example PUT /resources/:id * * @param string $id * @return mixed */ public function replace($id) { return $this->undefined(); } /** * @example PATCH /resources/:id * * @param string $id * @return mixed */ public function update($id) { return $this->undefined(); } /** * @example DELETE /resources/:id * * @param string $id * @return mixed */ public function destroy($id) { return $this->undefined(); } /** * Catch all action for all undefined actions. * * @return mixed * @throws RuntimeException */ public function undefined() { if (in_array($this->method, ['HEAD', 'GET'])) { throw new RuntimeException('Page Not Found', 404); } throw new RuntimeException('Invalid Action', 405); } /** * Catch all action for forbidden actions. * * @return mixed * @throws RuntimeException */ public function forbidden() { throw new RuntimeException('Forbidden', 403); } /** * Load resource. * * Function throws an exception if resource does not exist. * * @param string|int $id * @throws \RuntimeException */ protected function loadResource($id) { throw new RuntimeException('Resource Not Found', 404); } /** * Resolve HTTP verb. * * @param string $method * @param array $items * @return array [function, parameters] */ protected function resolveHttpVerb($method, array $items) { // HEAD has identical behavior to GET. $method = ($method == 'HEAD') ? 'GET' : $method; if (!isset($this->httpVerbs[$method])) { // HTTP method is not defined. return ['undefined', $items]; } $path = ''; $remaining = $items; $variables = []; $actions = $this->httpVerbs[$method]; // Build path for the verb and fetch all the variables. while (($current = array_shift($remaining)) !== null) { $test = "{$path}/{$current}"; if (!isset($actions[$test])) { // Specific path not found, check if we have a variable. $test = "{$path}/*"; if (isset($actions[$test])) { // Variable found, save the value and move on. $variables[] = $current; } elseif (isset($actions[$test . '*'])) { // Wildcard found, pass through rest of the variables. $path = $test . '*'; $variables = array_merge($variables, [$current], $remaining); break; } else { // No matches; we are done here. return ['undefined', $items]; } } // Path was found. $path = $test; } // No matching path; check if we have verb for the root. if (!$path && isset($actions['/'])) { $path = '/'; } // Get the action. $action = $path ? $actions[$path] : 'undefined'; return [$action, $variables]; } } classes/Gantry/Component/Controller/RestfulControllerInterface.php 0000604 00000003141 15075035624 0021556 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Controller; interface RestfulControllerInterface { /** * @example GET /resources * * @return mixed */ public function index(); /** * @example GET /resources/:id * * @param string $id * @return mixed */ public function display($id); /** * Special sub-resource to create a new resource (returns a form). * * @example GET /resources/create * * @return mixed */ public function create(); /** * Special sub-resource to edit existing resource (returns a form). * * @example GET /resources/:id/edit * * @param string $id * @return mixed */ public function edit($id); /** * @example POST /resources * * @return mixed */ public function store(); /** * @example PUT /resources/:id * * @param string $id * @return mixed */ public function replace($id); /** * @example PATCH /resources/:id * * @param string $id * @return mixed */ public function update($id); /** * @example DELETE /resources/:id * * @param string $id * @return mixed */ public function destroy($id); } classes/Gantry/Component/Gettext/Gettext.php 0000604 00000006016 15075035624 0015176 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Gettext; /** * Class Gettext * @package Gantry\Component\Gettext * * Examples on translating gettext in twig: * * {% trans string_var %} * http://twig.sensiolabs.org/doc/extensions/i18n.html * * {% trans %}Hello {{ author.name }}{% endtrans %} * http://symfony.com/doc/current/book/translation.html * * {{ 'Hello %name%'|trans({'%name%': name}) }} * {{ trans('Hello %name%', {'%name%': name}) }} */ class Gettext { public $pos = 0; public $str; public $len; public $endian = 'V'; public function parse($string) { $this->str = $string; $this->len = strlen($string); $magic = self::readInt() & 0xffffffff; if ($magic === 0x950412de) { // Low endian. $this->endian = 'V'; } elseif ($magic === 0xde120495) { // Big endian. $this->endian = 'N'; } else { throw new \Exception('Not a Gettext file (.mo)'); } // Skip revision number. self::readInt(); // Total count. $total = self::readInt(); // Offset of original table. $originals = self::readInt(); // Offset of translation table. $translations = self::readInt(); $this->seek($originals); $table_originals = self::readIntArray($total * 2); $this->seek($translations); $table_translations = self::readIntArray($total * 2); $items = []; for ($i = 0; $i < $total; $i++) { $this->seek($table_originals[$i * 2 + 2]); $original = $this->read($table_originals[$i * 2 + 1]); if ($original) { $this->seek($table_translations[$i * 2 + 2]); $items[$original] = $this->read($table_translations[$i * 2 + 1]); } } return $items; } /** * @return int */ protected function readInt() { $read = $this->read(4); if ($read === false) { return false; } $read = unpack($this->endian, $read); return array_shift($read); } /** * @param $count * @return array */ protected function readIntArray($count) { return unpack($this->endian . $count, $this->read(4 * $count)); } /** * @param $bytes * @return string */ private function read($bytes) { $data = substr($this->str, $this->pos, $bytes); $this->seek($this->pos + $bytes); return $data; } /** * @param $pos * @return mixed */ private function seek($pos) { $this->pos = max($this->len, $pos); return $this->pos; } } classes/Gantry/Component/Request/Request.php 0000604 00000002740 15075035624 0015206 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Request; class Request { /** * @var string */ protected $method; /** * @var Input */ public $get; /** * @var Input */ public $post; /** * @var Input */ public $cookie; /** * @var Input */ public $server; /** * @var Input */ public $request; public function __construct() { $this->init(); } public function getMethod() { if (!$this->method) { $method = $this->server['REQUEST_METHOD'] ?: 'GET'; if ('POST' === $method) { $method = $this->server['X-HTTP-METHOD-OVERRIDE'] ?: $method; $method = $this->post['METHOD'] ?: $method; } $this->method = strtoupper($method); } return $this->method; } protected function init() { $this->get = new Input($_GET); $this->post = new Input($_POST); $this->cookie = new Input($_COOKIE); $this->server = new Input($_SERVER); $this->request = new Input($_REQUEST); } } classes/Gantry/Component/Request/Input.php 0000604 00000007016 15075035624 0014656 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Request; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\ExportInterface; use RocketTheme\Toolbox\ArrayTraits\Iterator; use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters; class Input implements \ArrayAccess, \Iterator, ExportInterface { use NestedArrayAccessWithGetters, Iterator, Export; /** * @var array */ protected $items; /** * Constructor to initialize array. * * @param array $items Initial items inside the iterator. */ public function __construct(array &$items = []) { $this->items = &$items; } /** * Returns input array. If there are any JSON encoded fields (key: _json), those will be decoded as well. * * @param string $path Dot separated path to the requested value. * @param mixed $default Default value (or null). * @param string $separator Separator, defaults to '.' * @return array */ public function getArray($path = null, $default = null, $separator = '.') { $data = $path ? $this->get($path, $default, $separator) : $this->items; return (array) $this->getChildren($data); } /** * Returns JSON decoded input array. * * @param string $path Dot separated path to the requested value. * @param mixed $default Default value (or null). * @param string $separator Separator, defaults to '.' * @return array */ public function getJsonArray($path = null, $default = null, $separator = '.') { return (array) $this->getJson($path, $default, $separator, true); } /** * Returns JSON decoded input. Accosiative arrays become objects. * * @param string|null $path Dot separated path to the requested value. * @param mixed $default Default value (or null). * @param string $separator Separator, defaults to '.' * @param bool $assoc True to return associative arrays instead of objects. * @return mixed */ public function getJson($path = null, $default = null, $separator = '.', $assoc = false) { $data = $this->get($path, null, $separator); if (!isset($data)) { return $default; } if (!is_string($data)) { throw new \RuntimeException(sprintf('%s::%s(%s) expects input to be JSON encoded string', __CLASS__, __FUNCTION__, $path)); } $data = json_decode($data, $assoc); if (!isset($data)) { throw new \RuntimeException(sprintf('%s::%s(): %s', __CLASS__, __FUNCTION__, json_last_error_msg())); } return $data; } /** * @param $current * @return array|mixed * @internal */ protected function getChildren(&$current) { if (!is_array($current)) { return $current; } $array = []; foreach ($current as $key => &$value) { if ($key === '_json') { $array += json_decode($value, true); } else { $array[$key] = $this->getChildren($value); } } return $array; } } classes/Gantry/Component/Menu/AbstractMenu.php 0000604 00000026431 15075035624 0015425 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Menu; use Gantry\Component\Config\Config; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Gantry\GantryTrait; use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters; use RocketTheme\Toolbox\ArrayTraits\Countable; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\Iterator; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; abstract class AbstractMenu implements \ArrayAccess, \Iterator, \Countable { use GantryTrait, ArrayAccessWithGetters, Iterator, Export, Countable; protected $default; protected $base; protected $active; protected $params; protected $override = false; protected $config; /** * @var array|Item[] */ protected $items; /** * @var Config|null */ protected $pathMap; protected $defaults = [ 'menu' => '', 'base' => '/', 'startLevel' => 1, 'maxLevels' => 0, 'showAllChildren' => true, 'highlightAlias' => true, 'highlightParentAlias' => true ]; abstract public function __construct(); /** * Return list of menus. * * @return array */ abstract public function getMenus(); /** * Return default menu. * * @return string */ public function getDefaultMenuName() { return null; } /** * Returns true if the platform implements a Default menu. * * @return boolean */ public function hasDefaultMenu() { return false; } /** * Return active menu. * * @return string */ public function getActiveMenuName() { return null; } /** * Returns true if the platform implements an Active menu. * * @return boolean */ public function hasActiveMenu() { return false; } /** * @param array $params * @param Config $menu * @return AbstractMenu */ public function instance(array $params = [], Config $menu = null) { $params = $params + $this->defaults; $menus = $this->getMenus(); if (!$menus) { throw new \RuntimeException('Site does not have menus', 404); } if (empty($params['menu'])) { $params['menu'] = $this->getDefaultMenuName(); if (!$params['menu'] && !empty($params['admin'])) { // In admin just select the first menu if there isn't default menu to be selected. $params['menu'] = reset($menus); }; } elseif ($params['menu'] == '-active-') { $params['menu'] = $this->getActiveMenuName(); } if (!$params['menu']) { throw new \RuntimeException('No menu selected', 404); } if (!in_array($params['menu'], $menus)) { throw new \RuntimeException('Menu not found', 404); } $instance = clone $this; $instance->params = $params; if ($menu) { $instance->override = true; $instance->config = $menu; } else { $instance->config = null; } $config = $instance->config(); $items = isset($config['items']) ? $config['items'] : []; // Create menu structure. $instance->init($params); // Get menu items from the system (if not specified otherwise). if ($config->get('settings.type') !== 'custom') { $instance->getList($params, $items); } // Add custom menu items. $instance->addCustom($params, $items); // Sort menu items. $instance->sortAll(); return $instance; } /** * Get menu configuration. * * @return Config */ public function config() { if (!$this->config) { $gantry = static::gantry(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $menu = $this->params['menu']; $file = CompiledYamlFile::instance($locator("gantry-config://menu/{$menu}.yaml")); $this->config = new Config($file->content()); $this->config->def('settings.title', ucfirst($menu)); $file->free(); } return $this->config; } public function name() { return $this->params['menu']; } public function root() { return $this->offsetGet(''); } public function ordering() { $list = []; foreach ($this->items as $name => $item) { $groups = $item->groups(); if (count($groups) == 1 && empty($groups[0])) { continue; } $list[$name] = []; foreach ($groups as $col => $children) { $list[$name][$col] = []; foreach ($children as $child) { $list[$name][$col][] = $child->path; } } } return $list; } public function items($withdefaults = true) { $list = []; foreach ($this->items as $key => $item) { if ($key !== '') { $list[$item->path] = $item->toArray($withdefaults); } } return $list; } public function settings() { return (array) $this->config()->get('settings'); } /** * @return object */ public function getBase() { return $this->offsetGet($this->base); } /** * @return object */ public function getDefault() { return $this->offsetGet($this->default); } /** * @return object */ public function getActive() { return $this->offsetGet($this->active); } /** * @return string|null */ public function getCacheId() { return $this->active ?: '-inactive-'; } public function isActive($item) { $active = $this->getActive(); if ($active && $item && ($active->path === $item->path || strpos($active->path, $item->path . '/') === 0)) { return true; } return false; } public function isCurrent($item) { $active = $this->getActive(); return $item && $active && $item->path === $active->path; } public function init(&$params) { $this->items = ['' => new Item($this, '', ['layout' => 'horizontal'])]; } public function add(Item $item) { $this->items[$item->path] = $item; // If parent exists, assign menu item to its parent; otherwise ignore menu item. if (isset($this->items[$item->parent_id])) { $this->items[$item->parent_id]->addChild($item); } elseif (!$this->items['']->count()) { $this->items[$item->parent_id] = $this->items['']; $this->items[$item->parent_id]->addChild($item); } return $this; } /** * Get menu items from the platform. * * @param int $levels * @return array */ abstract protected function getItemsFromPlatform($levels); /** * Get base menu item. * * If itemid is not specified or does not exist, return active menu item. * If there is no active menu item, fall back to home page for the current language. * If there is no home page, return null. * * @param string $path * * @return string */ abstract protected function calcBase($path); /** * Get a list of the menu items. * * @param array $params * @param array $items */ abstract public function getList(array $params, array $items); /** * Add custom menu items. * * @param array $params * @param array $items */ public function addCustom(array $params, array $items) { $start = $params['startLevel']; $max = $params['maxLevels']; $end = $max ? $start + $max - 1 : 0; $config = $this->config(); $type = $config->get('settings.type'); // Add custom menu elements. foreach ($items as $route => $item) { if ($type !== 'custom' && (!isset($item['type']) || $item['type'] !== 'particle')) { continue; } $tree = explode('/', $route); $parentTree = $tree; array_pop($parentTree); // Enabled state should equal particle setting. $item['enabled'] = !isset($item['options']['particle']['enabled']) || !empty($item['options']['particle']['enabled']); $item['level'] = $level = count($tree); $item['parent_id'] = implode('/', $parentTree); if (($start && $start > $level) || ($end && $level > $end) // TODO: Improve. In the mean time Item::add() handles this part. // || ($start > 1 && !in_array($tree[$start - 2], $tree)) ) { continue; } $item = new Item($this, $route, $item); $this->add($item); } } /** * @param array $ordering * @param string $path * @param array $map */ public function sortAll(array $ordering = null, $path = '', $map = null) { if ($ordering === null) { $config = $this->config(); $ordering = $config['ordering'] ? $config['ordering'] : []; } if (!isset($this->items[$path]) || !$this->items[$path]->hasChildren()) { return; } if ($map === null) { $map = $this->pathMap ? $this->pathMap->toArray() : []; } $order = []; $newMap = []; $item = $this->items[$path]; if ($this->isAssoc($ordering)) { foreach ($ordering as $key => $value) { if ($map) { $newMap = isset($map[$key]['children']) ? $map[$key]['children'] : []; $key = isset($map[$key]['path']) ? basename($map[$key]['path']) : $key; $order[$key] = $value; } if (is_array($value)) { $this->sortAll($value, $path ? $path . '/' . $key : $key, $newMap); } } $item->sortChildren($order ?: $ordering); } else { foreach ($ordering as $i => $group) { foreach ($group as $key => $value) { if ($map) { $newMap = isset($map[$key]['children']) ? $map[$key]['children'] : []; $key = isset($map[$key]['path']) ? basename($map[$key]['path']) : $key; $order[$i][$key] = $value; } if (is_array($value)) { $this->sortAll($value, $path ? $path . '/' . $key : $key, $newMap); } } } $item->groupChildren($order ?: $ordering); } } protected function isAssoc(array $array) { return (array_values($array) !== $array); } } classes/Gantry/Component/Menu/Item.php 0000604 00000023274 15075035624 0013735 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Menu; use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters; use RocketTheme\Toolbox\ArrayTraits\Export; /** * @property string $id * @property string $type * @property string $path * @property string $alias * @property string $title * @property string $link * @property string $parent_id * @property string $layout * @property int $browserNav * @property bool $menu_text * @property bool $visible * @property int $group * @property int $level */ class Item implements \ArrayAccess, \Iterator, \Serializable, \Countable { use ArrayAccessWithGetters, Export; const VERSION = 1; protected $items; protected $menu; protected $groups = []; protected $children = []; protected $url; protected static $defaults = [ 'id' => 0, 'type' => 'link', 'path' => null, 'alias' => null, 'title' => null, 'link' => null, 'parent_id' => null, 'layout' => 'list', 'target' => '_self', 'dropdown' => '', 'icon' => '', 'image' => '', 'subtitle' => '', 'hash' => '', 'class' => '', 'icon_only' => false, 'enabled' => true, 'visible' => true, 'group' => 0, 'columns' => [], 'level' => 0, 'link_title' => '', 'anchor_class' => '' ]; public function __construct(AbstractMenu $menu, $name, array $item = []) { $this->menu = $menu; $tree = explode('/', $name); $alias = array_pop($tree); $parent = implode('/', $tree); // As we always calculate parent (it can change), prevent old one from being inserted. unset($item['parent_id']); $this->items = $item + [ 'id' => preg_replace('|[^a-z0-9]|i', '-', $name) ?: 'root', 'path' => $name, 'alias' => $alias, 'title' => ucfirst($alias), 'link' => $name, 'parent_id' => $parent != '.' ? $parent : '', ] + static::$defaults; } public function getDropdown() { if (!$this->items['dropdown']) { return count($this->groups()) > 1 ? 'fullwidth' : 'standard'; } return $this->items['dropdown']; } public function serialize() { // FIXME: need to create collection class to gather the sibling data. return serialize([ 'version' => static::VERSION, 'items' => $this->items, 'groups' => $this->groups, 'children' => $this->children, 'url' => $this->url ]); } public function unserialize($serialized) { // FIXME: need to create collection class to gather the sibling data. $data = unserialize($serialized); if (!isset($data['version']) && $data['version'] === static::VERSION) { throw new \UnexpectedValueException('Serialized data is not valid'); } $this->items = $data['items']; $this->groups = $data['groups']; $this->children = $data['children']; $this->url = $data['url']; } /** * @param string|null|bool $url * @return string */ public function url($url = false) { if ($url !== false) { $this->url = $url; } return $this->url; } /** * @return AbstractMenu * @deprecated Need to break relationship to the menu and use a collection instead. */ protected function menu() { return $this->menu; } /** * @return Item */ public function parent() { return $this->menu()[$this->items['parent_id']]; } public function columnWidth($column) { if (isset($this->items['columns'][$column])) { return $this->items['columns'][$column]; } return 100 / count($this->groups()); } public function groups() { if ($this->groups) { $list = []; foreach ($this->groups as $i => $group) { $list[$i] = []; foreach ($group as $path) { $list[$i][] = $this->menu()[$path]; } } return $list; } return [$this->children()]; } public function children() { $list = []; foreach ($this as $child) { $list[] = $child; } return $list; } public function hasChildren() { return !empty($this->children); } public function getGroup($i) { $groups = $this->groups(); $i = (int) $i; return isset($groups[$i]) ? $groups[$i] : []; } public function update(array $data) { $this->items = array_replace($this->items, $data); return $this; } public function addChild(Item $child) { $child->level = $this->level + 1; $child->parent_id = $this->path; $this->children[$child->alias] = $child->path; return $this; } public function removeChild(Item $child) { unset($this->children[$child->alias]); return $this; } public function sortChildren($ordering) { // Array with keys that point to the items. $children =& $this->children; if ($children) { if (is_array($ordering)) { // Remove extra items from ordering and reorder. $children = array_replace(array_intersect_key($ordering, $children), $children); } else { switch ((string) $ordering) { case 'abc': // Alphabetical ordering. ksort($children, SORT_NATURAL); break; case 'cba': // Reversed alphabetical ordering. krsort($children, SORT_NATURAL); break; } } } return $this; } public function reverse() { array_reverse($this->children, true); array_reverse($this->groups, true); return $this; } public function groupChildren(array $groups) { // Array with keys that point to the items. $children =& $this->children; if ($children) { $menu = $this->menu(); $ordered = []; // Create empty groups. $this->groups = array_fill(0, max(1, count($this->items['columns'])), []); foreach ($groups as $i => $ordering) { if (!is_array($ordering)) { continue; } // Get the items for this group with proper ordering. $group = array_replace( array_intersect_key($ordering, $children), array_intersect_key($children, $ordering) ); // Assign each menu items to the group. $group = array_map( function($value) use ($i, $menu) { $item = $menu[$value]; $item->group = $i; return $value; }, $group ); // Update remaining children. $children = array_diff_key($children, $ordering); // Build child ordering. $ordered += $group; // Add items to the current group. $this->groups[$i] = $group; } if ($children) { // Add leftover children to the ordered list and to the first group. $ordered += $children; $this->groups[0] += $children; } // Reorder children by their groups. $children = $ordered; } return $this; } // Implements \Iterator /** * Returns the current child. * * @return Item */ public function current() { return $this->menu()[current($this->children)]; } /** * Returns the key of the current child. * * @return mixed Returns scalar on success, or NULL on failure. */ public function key() { return key($this->children); } /** * Moves the current position to the next child. * * @return void */ public function next() { next($this->children); } /** * Rewinds back to the first child. * * @return void */ public function rewind() { reset($this->children); } /** * Count number of children. * * @return int */ public function count() { return count($this->children); } /** * This method is called after Iterator::rewind() and Iterator::next() to check if the current position is valid. * * @return bool Returns TRUE on success or FALSE on failure. */ public function valid() { return key($this->children) !== null; } /** * Convert object into an array. * * @return array */ public function toArray($withDefaults = true) { $items = $this->items; if (!$withDefaults) { foreach (static::$defaults as $key => $value) { if ($items[$key] === $value) { unset($items[$key]); } } } return $items; } } classes/Gantry/Component/Admin/HtmlController.php 0000604 00000001745 15075035624 0016132 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Admin; use Gantry\Component\Controller\HtmlController as BaseController; abstract class HtmlController extends BaseController { /** * @param string|array $file * @param array $context * @return string */ public function render($file, array $context = []) { return $this->container['admin.theme']->render($file, $context); } /** * @param string $action * @param string $id * @return boolean */ public function authorize($action, $id = null) { return $this->container['platform']->authorize($action, $id); } } classes/Gantry/Component/Admin/JsonController.php 0000604 00000001745 15075035624 0016137 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Admin; use Gantry\Component\Controller\JsonController as BaseController; abstract class JsonController extends BaseController { /** * @param string|array $file * @param array $context * @return string */ public function render($file, array $context = []) { return $this->container['admin.theme']->render($file, $context); } /** * @param string $action * @param string $id * @return boolean */ public function authorize($action, $id = null) { return $this->container['platform']->authorize($action, $id); } } classes/Gantry/Component/Content/Document/HtmlDocument.php 0000604 00000052570 15075035624 0017727 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Content\Document; use Gantry\Component\Content\Block\ContentBlock; use Gantry\Component\Content\Block\HtmlBlock; use Gantry\Component\Gantry\GantryTrait; use Gantry\Component\Url\Url; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class HtmlDocument { use GantryTrait; public static $timestamp_age = 604800; public static $urlFilterParams; /** * @var array|HtmlBlock[] */ protected static $stack; protected static $frameworks = []; protected static $scripts = []; protected static $styles = []; protected static $availableFrameworks = [ 'jquery' => 'registerJquery', 'jquery.framework' => 'registerJquery', 'jquery.ui.core' => 'registerJqueryUiSortable', 'jquery.ui.sortable' => 'registerJqueryUiSortable', 'bootstrap.2' => 'registerBootstrap2', 'bootstrap.3' => 'registerBootstrap3', 'mootools' => 'registerMootools', 'mootools.framework' => 'registerMootools', 'mootools.core' => 'registerMootools', 'mootools.more' => 'registerMootoolsMore', 'lightcase' => 'registerLightcase', 'lightcase.init' => 'registerLightcaseInit', ]; public function __construct() { static::$stack = []; static::push(); } /** * Create new local instance of document allowing asset caching. */ public static function push() { array_unshift(static::$stack, new HtmlBlock()); } /** * Return local instance of document allowing it to be cached. * * @return HtmlBlock */ public static function pop() { return array_shift(static::$stack); } /** * @param ContentBlock $block * @return $this */ public function addBlock(ContentBlock $block) { static::$stack[0]->addBlock($block); return $this; } /** * @param string $framework * @return bool */ public static function addFramework($framework) { if (!isset(static::$availableFrameworks[$framework])) { return false; } static::getObject(); static::$stack[0]->addFramework($framework); return true; } /** * @param string|array $element * @param int $priority * @param string $location * @return bool */ public static function addStyle($element, $priority = 0, $location = 'head') { static::getObject(); return static::$stack[0]->addStyle($element, $priority, $location); } /** * @param string|array $element * @param int $priority * @param string $location * @return bool */ public static function addInlineStyle($element, $priority = 0, $location = 'head') { static::getObject(); return static::$stack[0]->addInlineStyle($element, $priority, $location); } /** * @param string|array $element * @param int $priority * @param string $location * @return bool */ public static function addScript($element, $priority = 0, $location = 'head') { static::getObject(); return static::$stack[0]->addScript($element, $priority, $location); } /** * @param string|array $element * @param int $priority * @param string $location * @return bool */ public static function addInlineScript($element, $priority = 0, $location = 'head') { static::getObject(); return static::$stack[0]->addInlineScript($element, $priority, $location); } /** * @param string $html * @param int $priority * @param string $location * @return bool */ public static function addHtml($html, $priority = 0, $location = 'bottom') { static::getObject(); return static::$stack[0]->addHtml($html, $priority, $location); } /** * @param array $element * @param string $location * @param int $priority * @return bool */ public static function addHeaderTag(array $element, $location = 'head', $priority = 0) { $success = false; switch ($element['tag']) { case 'link': if (!empty($element['rel']) && $element['rel'] === 'stylesheet') { $success = static::addStyle($element, $priority, $location); } break; case 'style': $success = static::addInlineStyle($element, $priority, $location); break; case 'script': if (!empty($element['src'])) { $success = static::addScript($element, $priority, $location); } elseif (!empty($element['content'])) { $success = static::addInlineScript($element, $priority, $location); } break; } return $success; } public static function getStyles($location = 'head') { static::getObject(); $styles = static::$stack[0]->getStyles($location); $output = []; foreach ($styles as $style) { switch ($style[':type']) { case 'file': $attribs = ''; if ($style['media']) { $attribs .= ' media="' . static::escape($style['media']) . '"'; } $output[] = sprintf( '<link rel="stylesheet" href="%s" type="%s"%s />', static::escape($style['href']), static::escape($style['type']), $attribs ); break; case 'inline': $attribs = ''; if ($style['type'] !== 'text/css') { $attribs .= ' type="' . static::escape($style['type']) . '"'; } $output[] = sprintf( '<style%s>%s</style>', $attribs, $style['content'] ); break; } } return $output; } public static function getScripts($location = 'head') { static::getObject(); $scripts = static::$stack[0]->getScripts($location); $output = []; foreach ($scripts as $script) { switch ($script[':type']) { case 'file': $attribs = ''; if ($script['async']) { $attribs .= ' async="async"'; } if ($script['defer']) { $attribs .= ' defer="defer"'; } $output[] = sprintf( '<script type="%s"%s src="%s"></script>', static::escape($script['type']), $attribs, static::escape($script['src']) ); break; case 'inline': $output[] = sprintf( '<script type="%s">%s</script>', static::escape($script['type']), $script['content'] ); break; } } return $output; } public static function getHtml($location = 'bottom') { static::getObject(); $htmls = static::$stack[0]->getHtml($location); $output = []; foreach ($htmls as $html) { $output[] = $html['html']; } return $output; } /** * Escape string (emulates twig filter). * * @param string $string * @return string */ public static function escape($string, $strategy = 'html') { if (!is_string($string)) { if (is_object($string) && method_exists($string, '__toString')) { $string = (string) $string; } elseif (in_array($strategy, array('html', 'js', 'css', 'html_attr', 'url'))) { return $string; } } switch ($strategy) { case 'html': return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); case 'js': if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { throw new \RuntimeException('The string to escape is not a valid UTF-8 string.'); } $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string); return $string; case 'css': if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { throw new \RuntimeException('The string to escape is not a valid UTF-8 string.'); } $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string); return $string; case 'html_attr': if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { throw new \RuntimeException('The string to escape is not a valid UTF-8 string.'); } $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string); return $string; case 'url': return rawurlencode($string); default: throw new \RuntimeException(sprintf('Invalid escaping strategy "%s" (valid ones: html, js, css, html_attr, url).', $strategy)); } } /** * @param $framework * @return bool * @deprecated 5.3 */ public static function load($framework) { return static::addFramework($framework); } /** * Register assets. */ public static function registerAssets() { static::registerFrameworks(); } public static function siteUrl() { return static::rootUri(); } /** * NOTE: In PHP this function can be called either from Gantry DI container or statically. * * @return string */ public static function rootUri() { return ''; } /** * NOTE: In PHP this function can be called either from Gantry DI container or statically. * * @param bool $addDomain * @return string */ public static function domain($addDomain = false) { return ''; } /** * Return URL to the resource. * * @example {{ url('gantry-theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4') }} * * NOTE: In PHP this function can be called either from Gantry DI container or statically. * * @param string $url Resource to be located. * @param bool $domain True to include domain name. * @param int $timestamp_age Append timestamp to files that are less than x seconds old. Defaults to a week. * Use value <= 0 to disable the feature. * @param bool $allowNull True if non-existing files should return null. * @return string|null Returns url to the resource or null if resource was not found. */ public static function url($url, $domain = false, $timestamp_age = null, $allowNull = true) { if (!is_string($url) || $url === '') { // Return null on invalid input. return null; } if ($url[0] === '#' || $url[0] === '?') { // Handle urls with query string or fragment only. return str_replace(' ', '%20', $url); } $parts = Url::parse($url); if (!is_array($parts)) { // URL could not be parsed. return $allowNull ? null : str_replace(' ', '%20', $url); } // Make sure we always have scheme, host, port and path. $scheme = isset($parts['scheme']) ? $parts['scheme'] : ''; $host = isset($parts['host']) ? $parts['host'] : ''; $port = isset($parts['port']) ? $parts['port'] : ''; $path = isset($parts['path']) ? $parts['path'] : ''; if ($scheme && !$port) { // If URL has a scheme, we need to check if it's one of Gantry streams. $gantry = static::gantry(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; if (!$locator->schemeExists($scheme)) { // If scheme does not exists as a stream, assume it's external. return str_replace(' ', '%20', $url); } // Attempt to find the resource (because of parse_url() we need to put host back to path). $newPath = $locator->findResource("{$scheme}://{$host}{$path}", false); if ($newPath === false) { if ($allowNull) { return null; } // Return location where the file would be if it was saved. $path = $locator->findResource("{$scheme}://{$host}{$path}", false, true); } else { $path = $newPath; } } elseif ($host || $port) { // If URL doesn't have scheme but has host or port, it is external. return str_replace(' ', '%20', $url); } // At this point URL is either relative or absolute path; let us find if it is relative and not . or .. if ($path && '/' !== $path[0] && '.' !== $path[0]) { if ($timestamp_age === null) { $timestamp_age = static::$timestamp_age; } if ($timestamp_age > 0) { // We want to add timestamp to the URI: do it only for existing files. $realPath = @realpath(GANTRY5_ROOT . '/' . $path); if ($realPath && is_file($realPath)) { $time = filemtime($realPath); // Only append timestamp for files that are less than the maximum age. if ($time > time() - $timestamp_age) { $parts['query'] = (!empty($parts['query']) ? "{$parts['query']}&" : '') . sprintf('%x', $time); } } } // We need absolute URI instead of relative. $path = rtrim(static::rootUri(), '/') . '/' . $path; } // Set absolute URI. $uri = $path; // Add query string back. if (!empty($parts['query'])) { if (!$uri) $uri = static::rootUri(); $uri .= '?' . $parts['query']; } // Add fragment back. if (!empty($parts['fragment'])) { if (!$uri) $uri = static::rootUri(); $uri .= '#' . $parts['fragment']; } return static::domain($domain) . str_replace(' ', '%20', $uri); } /** * Filter stream URLs from HTML. * * @param string $html HTML input to be filtered. * @param bool $domain True to include domain name. * @param int $timestamp_age Append timestamp to files that are less than x seconds old. Defaults to a week. * Use value <= 0 to disable the feature. * @param bool $streamOnly Only touch streams. * @return string Returns modified HTML. */ public static function urlFilter($html, $domain = false, $timestamp_age = null, $streamOnly = false) { static::$urlFilterParams = [$domain, $timestamp_age, $streamOnly]; // Tokenize all PRE, CODE and SCRIPT tags to avoid modifying any src|href|url in them $tokens = []; $html = preg_replace_callback('#<(pre|code|script)(\s[^>]+)?>.*?</\\1>#ius', function($matches) use (&$tokens) { // Unfortunately uniqid() doesn't quite work in Windows, so we need to work it around by adding some randomness. $token = '@@'. uniqid(mt_rand(), true) . '@@'; $match = $matches[0]; $tokens[$token] = $match; return $token; }, $html); if ($streamOnly) { $gantry = static::gantry(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $schemes = $locator->getSchemes(); $list = []; foreach ($schemes as $scheme) { if (strpos($scheme, 'gantry-') === 0) { $list[] = substr($scheme, 7); } } if (empty($list)) { return $html; } $match = '(gantry-(' . implode('|', $list). ')://.*?)'; } else { $match = '(.*?)'; } $html = preg_replace_callback('^(\s)(src|href)="' . $match . '"^u', 'static::linkHandler', $html); $html = preg_replace_callback('^(\s)url\(' . $match . '\)^u', 'static::urlHandler', $html); $html = static::replaceTokens($tokens, $html); return $html; } /** * @param array $matches * @return string * @internal */ public static function linkHandler(array $matches) { list($domain, $timestamp_age) = static::$urlFilterParams; $url = trim($matches[3]); $url = static::url($url, $domain, $timestamp_age, false); return "{$matches[1]}{$matches[2]}=\"{$url}\""; } /** * @param array $matches * @return string * @internal */ public static function urlHandler(array $matches) { list($domain, $timestamp_age) = static::$urlFilterParams; $url = trim($matches[2], '"\''); $url = static::url($url, $domain, $timestamp_age, false); return "{$matches[1]}url({$url})"; } /** * Replace tokens with strings. * * @param array $tokens * @param $html * @return string|NUll */ protected static function replaceTokens(array $tokens, $html) { foreach ($tokens as $token => $replacement) { // We need to use callbacks to turn off backreferences ($1, \\1) in the replacement string. $callback = function() use ($replacement) { return $replacement; }; $html = preg_replace_callback('#' . preg_quote($token, '#') . '#u', $callback, $html); } return $html; } /** * Register loaded frameworks. */ protected static function registerFrameworks() { foreach (static::$stack[0]->getFrameworks() as $framework) { if (isset(static::$availableFrameworks[$framework])) { call_user_func([get_called_class(), static::$availableFrameworks[$framework]]); } } } protected static function registerJquery() { static::addScript( [ 'src' => 'https://code.jquery.com/jquery-2.2.2.min.js', 'integrity' => 'sha256-36cp2Co+/62rEAAYHLmRCPIych47CvdM+uTBJwSzWjI=', 'crossorigin' => 'anonymous' ], 11 ); } protected static function registerJqueryUiSortable() { static::registerJquery(); static::addScript( [ 'src' => 'https://code.jquery.com/ui/1.11.4/jquery-ui.min.js', 'integrity' => 'sha256-xNjb53/rY+WmG+4L6tTl9m6PpqknWZvRt0rO1SRnJzw=', 'crossorigin' => 'anonymous' ], 11 ); } protected static function registerBootstrap2() { static::registerJquery(); static::addScript(['src' => 'https://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js'], 11); } protected static function registerBootstrap3() { static::registerJquery(); static::addScript(['src' => 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'], 11); } protected static function registerMootools() { static::addScript(['src' => 'https://cdnjs.cloudflare.com/ajax/libs/mootools/1.5.2/mootools-core-compat.min.js'], 11); } protected static function registerMootoolsMore() { static::registerMootools(); static::addScript(['src' => 'https://cdnjs.cloudflare.com/ajax/libs/mootools-more/1.5.2/mootools-more-compat-compressed.js'], 11); } protected static function registerLightcase() { static::registerJquery(); static::addScript(['src' => static::url('gantry-assets://js/lightcase.js', false, null, false)], 11, 'footer'); static::addStyle(['href' => static::url('gantry-assets://css/lightcase.css', false, null, false)], 11); } protected static function registerLightcaseInit() { static::registerLightcase(); static::addInlineScript(['content' => "jQuery(document).ready(function($) { jQuery('[data-rel^=lightcase]').lightcase({maxWidth: '100%', maxHeight: '100%', video: {width: '1280', height: '720'}}); });"], 0, 'footer'); } protected static function getObject() { static $object; if (!$object) { // We need to initialize document for backwards compatibility (RokSprocket/RokGallery in WP). $object = Gantry::instance()['document']; } return $object; } } classes/Gantry/Component/Content/Block/HtmlBlock.php 0000604 00000031255 15075035624 0016454 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Content\Block; use Gantry\Framework\Document; use Gantry\Framework\Gantry; use Gantry\Framework\Theme; /** * Class HtmlBlock * @package Gantry\Component\Content\Block * @since 5.4.3 */ class HtmlBlock extends ContentBlock implements HtmlBlockInterface { protected $version = 1; protected $frameworks = []; protected $styles = []; protected $scripts = []; protected $html = []; /** * @return array * @since 5.4.3 */ public function getAssets() { $assets = $this->getAssetsFast(); $this->sortAssets($assets['styles']); $this->sortAssets($assets['scripts']); $this->sortAssets($assets['html']); return $assets; } /** * @return array * @since 5.4.3 */ public function getFrameworks() { $assets = $this->getAssetsFast(); return array_keys($assets['frameworks']); } /** * @param string $location * @return array * @since 5.4.3 */ public function getStyles($location = 'head') { $styles = $this->getAssetsInLocation('styles', $location); if (!$styles) { return []; } $gantry = Gantry::instance(); /** @var Theme $theme */ $theme = isset($gantry['theme']) ? $gantry['theme'] : null; /** @var Document $document */ $document = $gantry['document']; foreach ($styles as $key => $style) { if (isset($style['href'])) { $url = $style['href']; if ($theme && preg_match('|\.scss$|', $url)) { // Compile SCSS files. $url = $theme->css(basename($url, '.scss')); } // Deal with streams and relative paths. $url = $document->url($url, false, null, false); $styles[$key]['href'] = $url; } } return $styles; } /** * @param string $location * @return array * @since 5.4.3 */ public function getScripts($location = 'head') { $scripts = $this->getAssetsInLocation('scripts', $location); if (!$scripts) { return []; } $gantry = Gantry::instance(); /** @var Document $document */ $document = $gantry['document']; foreach ($scripts as $key => $script) { if (isset($script['src'])) { // Deal with streams and relative paths. $scripts[$key]['src'] = $document->url($script['src'], false, null, false); } } return $scripts; } /** * @param string $location * @return array * @since 5.4.3 */ public function getHtml($location = 'bottom') { return $this->getAssetsInLocation('html', $location); } /** * @return array * @since 5.4.3 */ public function toArray() { $array = parent::toArray(); if ($this->frameworks) { $array['frameworks'] = $this->frameworks; } if ($this->styles) { $array['styles'] = $this->styles; } if ($this->scripts) { $array['scripts'] = $this->scripts; } if ($this->html) { $array['html'] = $this->html; } return $array; } /** * @param array $serialized * @since 5.4.3 */ public function build(array $serialized) { parent::build($serialized); $this->frameworks = isset($serialized['frameworks']) ? (array) $serialized['frameworks'] : []; $this->styles = isset($serialized['styles']) ? (array) $serialized['styles'] : []; $this->scripts = isset($serialized['scripts']) ? (array) $serialized['scripts'] : []; $this->html = isset($serialized['html']) ? (array) $serialized['html'] : []; } /** * @param string $framework * @return $this * @since 5.4.3 */ public function addFramework($framework) { $this->frameworks[$framework] = 1; return $this; } /** * @param string|array $element * @param int $priority * @param string $location * @return bool * * @example $block->addStyle('assets/js/my.js'); * @example $block->addStyle(['href' => 'assets/js/my.js', 'media' => 'screen']); * @since 5.4.3 */ public function addStyle($element, $priority = 0, $location = 'head') { if (!is_array($element)) { $element = ['href' => (string) $element]; } if (empty($element['href'])) { return false; } if (!isset($this->styles[$location])) { $this->styles[$location] = []; } $id = !empty($element['id']) ? ['id' => (string) $element['id']] : []; $href = $element['href']; $type = !empty($element['type']) ? (string) $element['type'] : 'text/css'; $media = !empty($element['media']) ? (string) $element['media'] : null; unset($element['tag'], $element['id'], $element['rel'], $element['content'], $element['href'], $element['type'], $element['media']); $this->styles[$location][md5($href) . sha1($href)] = [ ':type' => 'file', ':priority' => (int) $priority, 'href' => $href, 'type' => $type, 'media' => $media, 'element' => $element ] + $id; return true; } /** * @param string|array $element * @param int $priority * @param string $location * @return bool * @since 5.4.3 */ public function addInlineStyle($element, $priority = 0, $location = 'head') { if (!is_array($element)) { $element = ['content' => (string) $element]; } if (empty($element['content'])) { return false; } if (!isset($this->styles[$location])) { $this->styles[$location] = []; } $content = (string) $element['content']; $type = !empty($element['type']) ? (string) $element['type'] : 'text/css'; $this->styles[$location][md5($content) . sha1($content)] = [ ':type' => 'inline', ':priority' => (int) $priority, 'content' => $content, 'type' => $type ]; return true; } /** * @param string|array $element * @param int $priority * @param string $location * @return bool * @since 5.4.3 */ public function addScript($element, $priority = 0, $location = 'head') { if (!is_array($element)) { $element = ['src' => (string) $element]; } if (empty($element['src'])) { return false; } if (!isset($this->scripts[$location])) { $this->scripts[$location] = []; } $src = $element['src']; $type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript'; $defer = isset($element['defer']) ? true : false; $async = isset($element['async']) ? true : false; $handle = !empty($element['handle']) ? (string) $element['handle'] : ''; $this->scripts[$location][md5($src) . sha1($src)] = [ ':type' => 'file', ':priority' => (int) $priority, 'src' => $src, 'type' => $type, 'defer' => $defer, 'async' => $async, 'handle' => $handle ]; return true; } /** * @param string|array $element * @param int $priority * @param string $location * @return bool * @since 5.4.3 */ public function addInlineScript($element, $priority = 0, $location = 'head') { if (!is_array($element)) { $element = ['content' => (string) $element]; } if (empty($element['content'])) { return false; } if (!isset($this->scripts[$location])) { $this->scripts[$location] = []; } $content = (string) $element['content']; $type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript'; $this->scripts[$location][md5($content) . sha1($content)] = [ ':type' => 'inline', ':priority' => (int) $priority, 'content' => $content, 'type' => $type ]; return true; } /** * @param string $html * @param int $priority * @param string $location * @return bool * @since 5.4.3 */ public function addHtml($html, $priority = 0, $location = 'bottom') { if (empty($html) || !is_string($html)) { return false; } if (!isset($this->html[$location])) { $this->html[$location] = []; } $this->html[$location][md5($html) . sha1($html)] = [ ':priority' => (int) $priority, 'html' => $html ]; return true; } /** * @param string $location * @deprecated Temporarily needed in WP * @since 5.4.3 */ public function clearStyles($location = 'head') { foreach ($this->blocks as $block) { if (method_exists($block, 'clearStyles')) { $block->clearStyles($location); } } unset($this->styles[$location]); } /** * @param string $location * @deprecated Temporarily needed in WP * @since 5.4.3 */ public function clearScripts($location = 'head') { foreach ($this->blocks as $block) { if (method_exists($block, 'clearScripts')) { $block->clearScripts($location); } } unset($this->scripts[$location]); } /** * @return array * @since 5.4.3 */ protected function getAssetsFast() { $assets = [ 'frameworks' => $this->frameworks, 'styles' => $this->styles, 'scripts' => $this->scripts, 'html' => $this->html ]; foreach ($this->blocks as $block) { if ($block instanceof HtmlBlock) { $blockAssets = $block->getAssetsFast(); $assets['frameworks'] += $blockAssets['frameworks']; foreach ($blockAssets['styles'] as $location => $styles) { if (!isset($assets['styles'][$location])) { $assets['styles'][$location] = $styles; } elseif ($styles) { $assets['styles'][$location] += $styles; } } foreach ($blockAssets['scripts'] as $location => $scripts) { if (!isset($assets['scripts'][$location])) { $assets['scripts'][$location] = $scripts; } elseif ($scripts) { $assets['scripts'][$location] += $scripts; } } foreach ($blockAssets['html'] as $location => $htmls) { if (!isset($assets['html'][$location])) { $assets['html'][$location] = $htmls; } elseif ($htmls) { $assets['html'][$location] += $htmls; } } } } return $assets; } /** * @param string $type * @param string $location * @return array * @since 5.4.3 */ protected function getAssetsInLocation($type, $location) { $assets = $this->getAssetsFast(); if (empty($assets[$type][$location])) { return []; } $styles = $assets[$type][$location]; $this->sortAssetsInLocation($styles); return $styles; } /** * @param array $items * @since 5.4.3 */ protected function sortAssetsInLocation(array &$items) { $count = 0; foreach ($items as &$item) { $item[':order'] = ++$count; } uasort( $items, function ($a, $b) { return ($a[':priority'] == $b[':priority']) ? $a[':order'] - $b[':order'] : $b[':priority'] - $a[':priority']; } ); } /** * @param array $array * @since 5.4.3 */ protected function sortAssets(array &$array) { foreach ($array as $location => &$items) { $this->sortAssetsInLocation($items); } } } classes/Gantry/Component/Content/Block/ContentBlockInterface.php 0000604 00000001570 15075035624 0021000 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Content\Block; /** * @since 5.4.3 */ interface ContentBlockInterface extends \Serializable { public static function create($id = null); public static function fromArray(array $serialized); public function __construct($id = null); public function getId(); public function getToken(); public function toArray(); public function build(array $serialized); public function setContent($content); public function addBlock(ContentBlockInterface $block); } classes/Gantry/Component/Content/Block/ContentBlock.php 0000604 00000013323 15075035624 0017156 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Content\Block; /** * Class to create nested blocks of content. * * $innerBlock = ContentBlock::create(); * $innerBlock->setContent('my inner content'); * $outerBlock = ContentBlock::create(); * $outerBlock->setContent(sprintf('Inside my outer block I have %s.', $innerBlock->getToken())); * $outerBlock->addBlock($innerBlock); * echo $outerBlock; * * @package Gantry\Component\Content\Block * @since 5.4.3 */ class ContentBlock implements ContentBlockInterface { protected $version = 1; protected $id; protected $tokenTemplate = '@@BLOCK-%s@@'; protected $content = ''; protected $blocks = []; /** * @param string $id * @return static * @since 5.4.3 */ public static function create($id = null) { return new static($id); } /** * @param array $serialized * @return ContentBlockInterface * @since 5.4.3 */ public static function fromArray(array $serialized) { try { $type = isset($serialized['_type']) ? $serialized['_type'] : null; $id = isset($serialized['id']) ? $serialized['id'] : null; if (!$type || !$id || !is_a($type, 'Gantry\Component\Content\Block\ContentBlockInterface', true)) { throw new \RuntimeException('Bad data'); } /** @var ContentBlockInterface $instance */ $instance = new $type($id); $instance->build($serialized); } catch (\Exception $e) { throw new \RuntimeException(sprintf('Cannot unserialize Block: %s', $e->getMessage()), $e->getCode(), $e); } return $instance; } /** * Block constructor. * * @param string $id * @since 5.4.3 */ public function __construct($id = null) { $this->id = $id ? (string) $id : $this->generateId(); } /** * @return string * @since 5.4.3 */ public function getId() { return $this->id; } /** * @return string * @since 5.4.3 */ public function getToken() { return sprintf($this->tokenTemplate, $this->getId()); } /** * @return array * @since 5.4.3 */ public function toArray() { $blocks = []; /** * @var string $id * @var ContentBlockInterface $block */ foreach ($this->blocks as $block) { $blocks[$block->getId()] = $block->toArray(); } $array = [ '_type' => get_class($this), '_version' => $this->version, 'id' => $this->id, ]; if ($this->content) { $array['content'] = $this->content; } if ($blocks) { $array['blocks'] = $blocks; } return $array; } /** * @return string * @since 5.4.3 */ public function toString() { if (!$this->blocks) { return (string) $this->content; } $tokens = []; $replacements = []; foreach ($this->blocks as $block) { $tokens[] = $block->getToken(); $replacements[] = $block->toString(); } return str_replace($tokens, $replacements, (string) $this->content); } /** * @return string * @since 5.4.3 */ public function __toString() { try { return $this->toString(); } catch (\Exception $e) { return sprintf('Error while rendering block: %s', $e->getMessage()); } } /** * @param array $serialized * @since 5.4.3 */ public function build(array $serialized) { $this->checkVersion($serialized); $this->id = isset($serialized['id']) ? $serialized['id'] : $this->generateId(); if (isset($serialized['content'])) { $this->setContent($serialized['content']); } $blocks = isset($serialized['blocks']) ? (array) $serialized['blocks'] : []; foreach ($blocks as $block) { $this->addBlock(self::fromArray($block)); } } /** * @param string $content * @return $this * @since 5.4.3 */ public function setContent($content) { $this->content = $content; return $this; } /** * @param ContentBlockInterface $block * @return $this * @since 5.4.3 */ public function addBlock(ContentBlockInterface $block) { $this->blocks[$block->getId()] = $block; return $this; } /** * @return string * @since 5.4.3 */ public function serialize() { return serialize($this->toArray()); } /** * @param string $serialized * @since 5.4.3 */ public function unserialize($serialized) { $array = unserialize($serialized); $this->build($array); } /** * @return string * @since 5.4.3 */ protected function generateId() { return uniqid('', true); } /** * @param array $serialized * @throws \RuntimeException * @since 5.4.3 */ protected function checkVersion(array $serialized) { $version = isset($serialized['_version']) ? (string) $serialized['_version'] : 1; if ($version != $this->version) { throw new \RuntimeException(sprintf('Unsupported version %s', $version)); } } } classes/Gantry/Component/Content/Block/HtmlBlockInterface.php 0000604 00000001710 15075035624 0020266 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Content\Block; /** * @since 5.4.3 */ interface HtmlBlockInterface extends ContentBlockInterface { public function getAssets(); public function addFramework($framework); public function addStyle($element, $priority = 0, $location = 'head'); public function addInlineStyle($element, $priority = 0, $location = 'head'); public function addScript($element, $priority = 0, $location = 'head'); public function addInlineScript($element, $priority = 0, $location = 'head'); public function addHtml($html, $priority = 0, $location = 'bottom'); } classes/Gantry/Component/Translator/TranslatorInterface.php 0000604 00000001507 15075035624 0020231 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Translator; interface TranslatorInterface { /** * @param string $string * @return string */ public function translate($string); /** * Set new active language if given and return previous active language. * * @param string $language Language code. If not given, current language is kept. * @return string Previously active language. */ public function active($language = null); } classes/Gantry/Component/Translator/Translator.php 0000604 00000006704 15075035624 0016414 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Translator; use Gantry\Component\File\CompiledYamlFile; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Translator implements TranslatorInterface { protected $default = 'en'; protected $active = 'en'; protected $sections = []; protected $translations = []; protected $untranslated = []; public function translate($string) { if (preg_match('|^GANTRY5(_[A-Z0-9]+){2,}$|', $string)) { list(, $section, $code) = explode('_', $string, 3); $string = ($this->find($this->active, $section, $string) ?: $this->find($this->default, $section, $string)) ?: $string; } if (func_num_args() === 1) { return $string; } $args = func_get_args(); $args[0] = $string; return call_user_func_array('sprintf', $args); } /** * Set new active language if given and return previous active language. * * @param string $language Language code. If not given, current language is kept. * @return string Previously active language. */ public function active($language = null) { $previous = $this->active; if ($language) { $this->active = $language; } return $previous; } public function untranslated() { return $this->untranslated; } protected function find($language, $section, $string) { if (!isset($this->sections[$language][$section])) { $translations = $this->load($language, $section); if (isset($this->translations[$language])) { $this->translations[$language] += $translations; } else { $this->translations[$language] = $translations; } $this->sections[$language][$section] = !empty($translations); } if (!isset($this->translations[$language][$string])) { $this->untranslated[$language][$section][$string] = null; return null; } return $this->translations[$language][$string]; } protected function load($language, $section) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $section = strtolower($section); if ($section === 'engine') { // TODO: add support for other engines than nucleus. $section = 'nucleus'; } $filename = 'gantry-admin://translations/' . $language . '/' . $section . '.yaml'; $file = CompiledYamlFile::instance($filename); if (!$file->exists() && ($pos = strpos($language, '-')) > 0) { $filename = 'gantry-admin://translations/' . substr($language, 0, $pos) . '/' . $section . '.yaml'; $file = CompiledYamlFile::instance($filename); } $cachePath = $locator->findResource('gantry-cache://translations', true, true); $translations = (array) $file->setCachePath($cachePath)->content(); $file->free(); return $translations; } } classes/Gantry/Component/Outline/OutlineCollection.php 0000604 00000046107 15075035624 0017205 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Outline; use FilesystemIterator; use Gantry\Component\Collection\Collection; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Layout\Layout; use Gantry\Framework\Atoms; use RocketTheme\Toolbox\DI\Container; use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class OutlineCollection extends Collection { /** * @var Container */ protected $container; /** * @var string */ protected $path; /** * @param Container $container * @param array $items */ public function __construct(Container $container, $items = []) { $this->container = $container; $this->items = $items; } /** * @param string $id * @return string|null */ public function name($id) { return isset($this->items[$id]) ? $this->items[$id] : null; } /** * @param string $id * @return string */ public function title($id) { return isset($this->items[$id]) ? $this->items[$id] : $id; } public function all() { return $this; } public function system() { foreach ($this->items as $key => $item) { if (substr($key, 0, 1) !== '_') { unset($this->items[$key]); } } return $this; } public function user() { foreach ($this->items as $key => $item) { if (substr($key, 0, 1) === '_' || $key == 'default') { unset($this->items[$key]); } } return $this; } public function filter(array $include = null) { if ($include !== null) { foreach ($this->items as $key => $item) { if (!in_array($key, $include)) { unset($this->items[$key]); } } } return $this; } /** * Returns list of all positions defined in all outlines. * * @return array */ public function positions() { $list = []; foreach ($this->items as $name => $title) { try { $index = Layout::index($name); $list += $index['positions']; } catch (\Exception $e) { // Layout cannot be read. We will just skip it instead of throwing an exception. } } return $list; } /** * @param string $section * @param bool $includeInherited * @return array */ public function getOutlinesWithSection($section, $includeInherited = true) { $list = []; foreach ($this->items as $name => $title) { try { $index = Layout::index($name); } catch (\Exception $e) { // Layout cannot be read. We will just skip it instead of throwing an exception. continue; } if (isset($index['sections'][$section])) { if (!$includeInherited) { foreach ($index['inherit'] as $outline => $items) { if (is_array($items) && in_array($section, $items)) { continue 2; } } } $list[$name] = $title; } } return $list; } /** * @param string $particle * @param bool $includeInherited * @return array */ public function getOutlinesWithParticle($particle, $includeInherited = true) { $list = []; foreach ($this->items as $name => $title) { try { $index = Layout::index($name); } catch (\Exception $e) { // Layout cannot be read. We will just skip it instead of throwing an exception. continue; } if (isset($index['particles'][$particle])) { $ids = $index['particles'][$particle]; if (!$includeInherited && !empty($index['inherit'])) { foreach ($index['inherit'] as $items) { foreach ((array) $items as $id => $inheritId) { unset($ids[$id]); } } } if ($ids) { $list[$name] = $title; } } } return $list; } /** * @param string $type * @param bool $includeInherited * @return array */ public function getOutlinesWithAtom($type, $includeInherited = true) { $list = []; foreach ($this->items as $name => $title) { $file = CompiledYamlFile::instance("gantry-theme://config/{$name}/page/head.yaml"); $index = $file->content(); $file->free(); if (isset($index['atoms'])) { foreach ($index['atoms'] as $atom) { if (!empty($atom['id']) && $atom['type'] === $type && ($includeInherited || empty($atom['inherit']))) { $list[$name] = $title; } } } } return $list; } /** * @param string $particle * @param bool $includeInherited * @return array */ public function getAllParticleInstances($particle, $includeInherited = true) { $list = []; foreach ($this->items as $name => $title) { $list += $this->getParticleInstances($name, $particle, $includeInherited); } return $list; } /** * @param string $outline * @param string $particle * @param bool $includeInherited * @return array */ public function getParticleInstances($outline, $particle, $includeInherited = true) { $list = []; $index = Layout::index($outline); if (isset($index['particles'][$particle])) { $list = $index['particles'][$particle]; if (!$includeInherited && !empty($index['inherit'])) { foreach ($index['inherit'] as $items) { foreach ((array) $items as $id => $inheritId) { unset($list[$id]); } } } } $layout = Layout::instance($outline); foreach ($list as $id => $title) { $item = clone $layout->find($id); $block = $layout->block($id); $item->block = isset($block->attributes) ? $block->attributes : new \stdClass(); $list[$id] = $item; } return $list; } /** * @param string $outline * @param string $type * @param bool $includeInherited * @return array */ public function getAtomInstances($outline, $type, $includeInherited = true) { $list = []; $file = CompiledYamlFile::instance("gantry-theme://config/{$outline}/page/head.yaml"); $head = $file->content(); $file->free(); if (isset($head['atoms'])) { foreach ($head['atoms'] as $atom) { if (!empty($atom['id']) && $atom['type'] === $type && ($includeInherited || empty($atom['inherit']['outline']))) { $list[$atom['id']] = (object) $atom; } } } return $list; } /** * Return list of outlines which are inheriting the specified atom. * * @param string $outline * @param string $id * @return array */ public function getInheritingOutlinesWithAtom($outline, $id = null) { $list = []; foreach ($this->items as $name => $title) { $file = CompiledYamlFile::instance("gantry-theme://config/{$name}/page/head.yaml"); $head = $file->content(); $file->free(); if (isset($head['atoms'])) { foreach ($head['atoms'] as $atom) { if (!empty($atom['inherit']['outline']) && $atom['inherit']['outline'] == $outline && (!$id || $atom['inherit']['atom'] == $id)) { $list[$name] = $title; } } } } return $list; } /** * Return list of outlines which are inheriting the specified outline. * * You can additionally pass section or particle id to filter the results for only that type. * * @param string $outline * @param string|array $id * @return array */ public function getInheritingOutlines($outline, $id = null) { $list = []; foreach ($this->items as $name => $title) { try { $index = Layout::index($name); } catch (\Exception $e) { // Layout cannot be read. We will just skip it instead of throwing an exception. continue; } if (!empty($index['inherit'][$outline]) && (!$id || array_intersect((array) $id, $index['inherit'][$outline]))) { $list[$name] = $title; } } return $list; } /** * Return list of outlines inherited by the specified outline. * * You can additionally pass section or particle id to filter the results for only that type. * * @param string $outline * @param string $id * @return array */ public function getInheritedOutlines($outline, $id = null) { try { $index = Layout::index($outline); } catch (\Exception $e) { // Layout cannot be read. We will just return nothing instead of throwing an exception. return []; } $list = []; foreach ($index['inherit'] as $name => $inherited) { if (!$id || array_intersect_key((array) $id, $inherited[$id])) { $list[$name] = isset($this->items[$name]) ? $this->items[$name] : $name; } } return $list; } /** * @param int|string $id * @return int|string */ public function preset($id) { return $id; } /** * @param int|string $id * @return Layout */ public function layout($id) { return Layout::load($id); } /** * @param int|string $id * @return array */ public function layoutPreset($id) { $layout = Layout::load($id); $preset = $layout->preset; unset($layout); return $preset; } /** * @param string $path * @return $this * @throws \RuntimeException */ public function load($path = 'gantry-config://') { $this->path = $path; $iterator = $this->getFilesystemIterator($path); $files = []; /** @var FilesystemIterator $info */ foreach ($iterator as $name => $info) { if (!$info->isDir() || $name[0] == '.' || !is_file($info->getPathname() . '/index.yaml')) { continue; } $files[$name] = ucwords(trim(preg_replace(['|_|', '|/|'], [' ', ' / '], $name))); } unset($files['default']); unset($files['menu']); asort($files); $this->items = $this->addDefaults($files); return $this; } /** * @param string|null $id * @param string $title * @param string|array $preset * @return string * @throws \RuntimeException */ public function create($id, $title = null, $preset = null) { $title = $title ?: 'Untitled'; $name = ltrim(strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $id ?: $title)), '_'); if (!$name) { throw new \RuntimeException("Outline needs a name", 400); } if ($name === 'default') { throw new \RuntimeException("Outline cannot use reserved name '{$name}'", 400); } $name = $this->findFreeName($name); if (!$id) { $title = ucwords(trim(preg_replace(['|_|', '|/|'], [' ', ' / '], $name))); } if (!is_array($preset)) { // Load preset. $preset = Layout::preset($preset ?: 'default'); } // Create layout and index for the new layout. $layout = new Layout($name, $preset); $layout->save()->saveIndex(); $this->items[$name] = $title; return $name; } /** * @param string $id * @param string $title * @param bool $inherit * @return string * @throws \RuntimeException */ public function duplicate($id, $title = null, $inherit = false) { if (!$this->canDuplicate($id)) { throw new \RuntimeException("Outline '$id' cannot be duplicated", 400); } $layout = Layout::load($id); if ($inherit) { $layout->inheritAll()->clean(); } $new = $this->create(null, $title, $layout->toArray() + ['preset' => $layout->preset]); if ($id === 'default') { // For Base Outline we're done. return $new; } /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $path = $locator->findResource("{$this->path}/{$id}"); if (!$path) { // Nothing to copy. return $new; } $newPath = $locator->findResource("{$this->path}/{$new}", true, true); try { // Copy everything over except index, layout and assignments. Folder::copy($path, $newPath, '/^(index|layout|assignments)\..*$/'); } catch (\Exception $e) { throw new \RuntimeException(sprintf('Duplicating Outline failed: ', $e->getMessage()), 500, $e); } return $new; } /** * @param string $id * @param string $title * @return string * @throws \RuntimeException */ public function rename($id, $title) { if (!$this->canDelete($id)) { throw new \RuntimeException("Outline '$id' cannot be renamed", 400); } $gantry = $this->container; /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $path = $locator->findResource("{$this->path}/{$id}", true, true); if (!$path || !is_dir($path)) { throw new \RuntimeException('Outline not found', 404); } $folder = strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $title)); if ($folder === 'default' || $folder[0] === '_') { throw new \RuntimeException("Outline cannot use reserved name '{$folder}'", 400); } $newPath = $locator->findResource("{$this->path}/{$folder}", true, true); if (is_dir($newPath)) { throw new \RuntimeException("Outline '$id' already exists.", 400); } try { foreach ($this->getInheritingOutlines($id) as $outline => $title) { $this->layout($outline)->updateInheritance($id, $folder)->save()->saveIndex(); } foreach ($this->getInheritingOutlinesWithAtom($id) as $outline => $title) { Atoms::instance($outline)->updateInheritance($id, $folder)->save(); } Folder::move($path, $newPath); } catch (\Exception $e) { throw new \RuntimeException(sprintf('Renaming Outline failed: %s', $e->getMessage()), 500, $e); } $this->items[$id] = $title; return $folder; } /** * @param string $id * @throws \RuntimeException */ public function delete($id) { if (!$this->canDelete($id)) { throw new \RuntimeException("Outline '$id' cannot be deleted", 400); } $gantry = $this->container; /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $path = $locator->findResource("{$this->path}/{$id}", true, true); if (!is_dir($path)) { throw new \RuntimeException('Outline not found', 404); } foreach ($this->getInheritingOutlines($id) as $outline => $title) { $this->layout($outline)->updateInheritance($id)->save()->saveIndex(); } foreach ($this->getInheritingOutlinesWithAtom($id) as $outline => $title) { Atoms::instance($outline)->updateInheritance($id)->save(); } if (file_exists($path)) { Folder::delete($path); } unset($this->items[$id]); } /** * @param string $id * @return boolean */ public function canDuplicate($id) { if (!isset($this->items[$id])) { return false; } return true; } /** * @param string $id * @return boolean */ public function canDelete($id) { if (!$id || $id[0] === '_' || $id === 'default') { return false; } return true; } /** * @param string $id * @return boolean */ public function isDefault($id) { return $id === 'default'; } /** * @param array $outlines * @return array */ protected function addDefaults(array $outlines) { return [ 'default' => 'Base Outline', '_body_only' => 'Body Only', '_error' => 'Error', '_offline' => 'Offline' ] + $outlines; } /** * Find unused name with number appended to it when duplicating an outline. * * @param string $id * @return string */ protected function findFreeName($id) { if (!isset($this->items[$id])) { return $id; } $name = $id; $count = 0; if (preg_match('|^(?:_)?(.*?)(?:_(\d+))?$|ui', $id, $matches)) { $matches += ['', '', '']; list (, $name, $count) = $matches; } $count = max(1, $count); do { $count++; } while (isset($this->items["{$name}_{$count}"])); return "{$name}_{$count}"; } protected function getFilesystemIterator($path) { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $custom = $locator->findResource($path, true, true); if (is_dir($custom)) { /** @var FilesystemIterator $iterator */ $iterator = new FilesystemIterator( $custom, FilesystemIterator::CURRENT_AS_SELF | FilesystemIterator::KEY_AS_FILENAME | FilesystemIterator::UNIX_PATHS | FilesystemIterator::SKIP_DOTS ); } else { /** @var UniformResourceIterator $iterator */ $iterator = $locator->getIterator( $path, UniformResourceIterator::CURRENT_AS_SELF | UniformResourceIterator::KEY_AS_FILENAME | UniformResourceIterator::UNIX_PATHS | UniformResourceIterator::SKIP_DOTS ); } return $iterator; } } classes/Gantry/Component/Gantry/GantryTrait.php 0000604 00000001527 15075035624 0015644 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Gantry; use Gantry\Framework\Gantry; trait GantryTrait { /** * @var Gantry */ private static $gantry; /** * Get global Gantry instance. * * @return Gantry */ public static function gantry() { // We cannot set variable directly for the trait as it doesn't work in HHVM. if (!self::$gantry) { self::$gantry = Gantry::instance(); } return self::$gantry; } } classes/Gantry/Component/Router/RouterInterface.php 0000604 00000000725 15075035624 0016510 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Router; interface RouterInterface { public function dispatch(); } classes/Gantry/Component/Router/Router.php 0000604 00000012471 15075035624 0014670 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Router; use Gantry\Admin\EventListener; use Gantry\Admin\Theme; use Gantry\Component\Controller\BaseController; use Gantry\Component\Response\HtmlResponse; use Gantry\Component\Response\Response; use Gantry\Component\Response\JsonResponse; use Gantry\Framework\Services\ErrorServiceProvider; use RocketTheme\Toolbox\DI\Container; use RocketTheme\Toolbox\Event\EventDispatcher; use Whoops\Exception\ErrorException; abstract class Router implements RouterInterface { /** * @var Container */ protected $container; protected $format; protected $resource; protected $method; protected $path; protected $params; public function __construct(Container $container) { $this->container = $container; } public function dispatch() { $this->boot(); $this->load(); // Render the page or execute the task. try { $response = static::execute($this->resource, $this->method, $this->path, $this->params, $this->format); } catch (ErrorException $e) { throw $e; } catch (\Exception $e) { // Handle errors. if ($this->container->debug()) { throw $e; } $response = $this->getErrorResponse($e, $this->format == 'json'); } return $this->send($response); } public function execute($resource, $method = 'GET', $path, $params = [], $format = 'html') { $class = '\\Gantry\\Admin\\Controller\\' . ucfirst($format) . '\\' . strtr(ucwords(strtr($resource, '/', ' ')), ' ', '\\'); // Protect against CSRF Attacks. if (!in_array($method, ['GET', 'HEAD'], true) && !$this->checkSecurityToken()) { throw new \RuntimeException('Invalid security token; please reload the page and try again.', 403); } if (!class_exists($class)) { if ($format === 'json') { // Special case: All HTML requests can be returned also as JSON. $response = $this->execute($resource, $method, $path, $params, 'html'); return $response instanceof JsonResponse ? $response : new JsonResponse($response); } throw new \RuntimeException('Page Not Found', 404); } /** @var BaseController $controller */ $controller = new $class($this->container); // Execute action. $response = $controller->execute($method, $path, $params); if (!$response instanceof Response) { $response = new HtmlResponse($response); } return $response; } /** * @return $this */ abstract protected function boot(); abstract protected function checkSecurityToken(); /** * @return $this */ public function load() { static $loaded = false; if ($loaded) { return $this; } $loaded = true; if (isset($this->container['theme.path']) && file_exists($this->container['theme.path'] . '/includes/gantry.php')) { include $this->container['theme.path'] . '/includes/gantry.php'; } if (isset($this->container['theme'])) { // Initialize current theme if it is set. $this->container['theme']; } else { // Otherwise initialize streams and error handler manually. $this->container['streams']->register(); $this->container->register(new ErrorServiceProvider); } $this->container['admin.theme'] = function () { return new Theme(GANTRYADMIN_PATH); }; // Add event listener. if (class_exists('Gantry\\Admin\\EventListener')) { $listener = new EventListener; /** @var EventDispatcher $events */ $events = $this->container['events']; $events->addSubscriber($listener); } // Boot the service. $this->container['admin.theme']; return $this; } protected function getErrorResponse(\Exception $e, $json = false) { $response = new HtmlResponse; $response->setStatusCode($e->getCode()); $params = [ 'ajax' => $json, 'title' => $response->getStatus(), 'error' => $e, ]; $response->setContent($this->container['admin.theme']->render('@gantry-admin/error.html.twig', $params)); if ($json) { return new JsonResponse([$e, $response]); } return $response; } protected function send(Response $response) { // Output HTTP header. header("HTTP/1.1 {$response->getStatus()}", true, $response->getStatusCode()); header("Content-Type: {$response->mimeType}; charset={$response->charset}"); foreach ($response->getHeaders() as $key => $values) { foreach ($values as $value) { header("{$key}: {$value}"); } } echo $response; return true; } } classes/Gantry/Component/Whoops/SystemFacade.php 0000604 00000011101 15075035624 0015744 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Whoops; class SystemFacade extends \Whoops\Util\SystemFacade { protected $registeredPatterns; protected $whoopsErrorHandler; protected $whoopsExceptionHandler; protected $whoopsShutdownHandler; protected $platformExceptionHandler; /** * @param array|string $patterns List or a single regex pattern to match for silencing errors in particular files. */ public function __construct($patterns = []) { $this->registeredPatterns = array_map( function ($pattern) { return["pattern" => $pattern]; }, (array) $patterns ); } /** * @param callable $handler * @param int|string $types * * @return callable|null */ public function setErrorHandler(callable $handler, $types = 'use-php-defaults') { // Workaround for PHP 5.5 if ($types === 'use-php-defaults') { $types = E_ALL | E_STRICT; } $this->whoopsErrorHandler = $handler; return parent::setErrorHandler([$this, 'handleError'], $types); } /** * @param callable $function * * @return void */ public function registerShutdownFunction(callable $function) { $this->whoopsShutdownHandler = $function; register_shutdown_function([$this, 'handleShutdown']); } /** * @param callable $handler * * @return callable|null */ public function setExceptionHandler(callable $handler) { $this->whoopsExceptionHandler = $handler; $this->platformExceptionHandler = parent::setExceptionHandler([$this, 'handleException']); return $this->platformExceptionHandler; } /** * Converts generic PHP errors to \ErrorException instances, before passing them off to be handled. * * This method MUST be compatible with set_error_handler. * * @param int $level * @param string $message * @param string $file * @param int $line * * @return bool * @throws \ErrorException */ public function handleError($level, $message, $file = null, $line = null) { $handler = $this->whoopsErrorHandler; if (!$this->registeredPatterns) { // Just forward to parent function is there aren't no registered patterns. return $handler($level, $message, $file, $line); } // If there are registered patterns, only handle errors if error matches one of the patterns. if ($level & error_reporting()) { foreach ($this->registeredPatterns as $entry) { $pathMatches = $file && preg_match($entry["pattern"], $file); if ($pathMatches) { return $handler($level, $message, $file, $line); } } } // Propagate error to the next handler, allows error_get_last() to work on silenced errors. return false; } /** * Handles an exception, ultimately generating a Whoops error page. * * @param \Throwable $exception * @return void */ public function handleException($exception) { $handler = $this->whoopsExceptionHandler; // If there are registered patterns, only handle errors if error matches one of the patterns. if ($this->registeredPatterns) { foreach ($this->registeredPatterns as $entry) { $file = $exception->getFile(); $pathMatches = $file && preg_match($entry["pattern"], $file); if ($pathMatches) { $handler($exception); return; } } } // Propagate error to the next handler. if ($this->platformExceptionHandler) { call_user_func_array($this->platformExceptionHandler, [&$exception]); } } /** * Special case to deal with Fatal errors and the like. */ public function handleShutdown() { $handler = $this->whoopsShutdownHandler; $error = $this->getLastError(); // Ignore core warnings and errors. if ($error && !($error['type'] & (E_CORE_WARNING | E_CORE_ERROR))) { $handler(); } } } classes/Gantry/Component/Collection/Collection.php 0000604 00000002471 15075035624 0016315 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Collection; use RocketTheme\Toolbox\ArrayTraits\ArrayAccess; use RocketTheme\Toolbox\ArrayTraits\Countable; use RocketTheme\Toolbox\ArrayTraits\Export; class Collection implements CollectionInterface { use ArrayAccess, Countable, Export; /** * @var array */ protected $items = []; public static function __set_state($variables) { $instance = new static(); $instance->items = $variables['items']; return $instance; } /** * * Create a copy of this collection. * * @return static */ public function copy() { return clone $this; } /** * @param $item * @return $this */ public function add($item) { $this->items[] = $item; return $this; } /** * @return \ArrayIterator */ public function getIterator() { return new \ArrayIterator($this->items); } } classes/Gantry/Component/Collection/CollectionInterface.php 0000604 00000002176 15075035624 0020140 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Collection; interface CollectionInterface extends \IteratorAggregate, \ArrayAccess, \Countable { public function toArray(); /** * @param $item */ public function add($item); /** * @return \ArrayIterator */ public function getIterator(); /** * @param $offset * * @return bool */ public function offsetExists($offset); /** * @param $offset * @param $value */ public function offsetSet($offset, $value); /** * @param $offset * * @return mixed */ public function offsetGet($offset); /** * @param $offset */ public function offsetUnset($offset); /** * @return int */ public function count(); } classes/Gantry/Component/Filesystem/Folder.php 0000604 00000025621 15075035624 0015470 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Filesystem; /** * Folder helper class. * * @author RocketTheme * @license MIT */ abstract class Folder { /** * Recursively find the last modified time under given path. * * @param string $path * @return int */ public static function lastModifiedFolder($path) { $last_modified = 0; $directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS); $iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST); /** @var \RecursiveDirectoryIterator $file */ foreach ($iterator as $file) { $dir_modified = $file->getMTime(); if ($dir_modified > $last_modified) { $last_modified = $dir_modified; } } return $last_modified; } /** * 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 getRelativePath($path, $base = GANTRY5_ROOT) { $base = preg_replace('![\\\/]+!', '/', $base); $path = preg_replace('![\\\/]+!', '/', $path); if (strpos($path, $base) === 0) { $path = ltrim(substr($path, strlen($base)), '/'); } 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. * * @param string $path * @return string */ public static function shift(&$path) { $parts = explode('/', trim($path, '/'), 2); $result = array_shift($parts); $path = array_shift($parts); return $result ?: null; } /** * Return recursive list of all files and directories under given path. * * @param string $path * @param array $params * @return array * @throws \RuntimeException */ public static function all($path, array $params = array()) { if ($path === false) { throw new \RuntimeException("Path to {$path} doesn't exist."); } $compare = isset($params['compare']) ? 'get' . $params['compare'] : null; $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); } $results = array(); /** @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; } $fileKey = $key ? $file->{$key}() : null; $filePath = $file->{$value}(); if ($filters) { if (isset($filters['key'])) { $filter = $filters['key']; $pre = !empty($filters['pre-key']) ? $filters['pre-key'] : ''; if (is_callable($filter)) { $fileKey = $pre . call_user_func($filter, $fileKey); } else { $fileKey = $pre . preg_replace($filter, '', $fileKey); } } if (isset($filters['value'])) { $filter = $filters['value']; if (is_callable($filter)) { $filePath = call_user_func($filter, $file); } else { $filePath = preg_replace($filter, '', $filePath); } } } if ($fileKey !== null) { $results[$fileKey] = $filePath; } else { $results[] = $filePath; } } return $results; } /** * Recursively copy directory in filesystem. * * @param string $source * @param string $target * @param string $ignore Ignore files matching pattern (regular expression). * @throws \RuntimeException */ public static function copy($source, $target, $ignore = null) { $source = rtrim($source, '\\/'); $target = rtrim($target, '\\/'); if (!is_dir($source)) { throw new \RuntimeException('Cannot copy non-existing folder.'); } // Make sure that path to the target exists before copying. 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 (if it doesn't exist). if (!is_dir($dst)) { $success &= @mkdir($dst, 0777, true); } } else { // Or copy current file. $success &= @copy($src, $dst); } } if (!$success) { $error = error_get_last(); throw new \RuntimeException($error['message']); } // Make sure that the change will be detected when caching. @touch(dirname($target)); } /** * Move directory in filesystem. * * @param string $source * @param string $target * @throws \RuntimeException */ public static function move($source, $target) { if (!is_dir($source)) { throw new \RuntimeException('Cannot move non-existing folder.'); } // Make sure that path to the target exists before moving. self::create(dirname($target)); // Just rename the directory. $success = @rename($source, $target); if (!$success) { $error = error_get_last(); throw new \RuntimeException($error['message']); } // Make sure that the change will be detected when caching. @touch(dirname($source)); @touch(dirname($target)); } /** * Recursively delete directory from filesystem. * * @param string $target * @param bool $include_target * @throws \RuntimeException */ public static function delete($target, $include_target = true) { if (!$target) { return; } if (!is_dir($target)) { throw new \RuntimeException('Cannot delete non-existing folder.'); } $success = self::doDelete($target, $include_target); if (!$success) { $error = error_get_last(); throw new \RuntimeException($error['message']); } // Make sure that the change will be detected when caching. if ($include_target) { @touch(dirname($target)); } else { @touch($target); } } /** * @param string $folder * @throws \RuntimeException */ public static function create($folder) { if (is_dir($folder)) { return; } $success = @mkdir($folder, 0777, true); if (!$success) { // Take yet another look, make sure that the folder doesn't exist. clearstatcache(true, $folder); if (is_dir($folder)) { return; } $error = error_get_last(); throw new \RuntimeException($error['message']); } } /** * @param string $folder * @param bool $include_target * @return bool * @internal */ protected static function doDelete($folder, $include_target = true) { // Special case for symbolic links. if ($include_target && 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); } return $include_target ? @rmdir($folder) : true; } } classes/Gantry/Component/Filesystem/Streams.php 0000604 00000005415 15075035624 0015672 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Filesystem; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RocketTheme\Toolbox\StreamWrapper\ReadOnlyStream; use RocketTheme\Toolbox\StreamWrapper\Stream; class Streams { /** * @var array */ protected $schemes = []; /** * @var array */ protected $registered; /** * @var UniformResourceLocator */ protected $locator; public function __construct(UniformResourceLocator $locator = null) { if ($locator) { $this->setLocator($locator); } } /** * @param UniformResourceLocator $locator */ public function setLocator(UniformResourceLocator $locator) { $this->locator = $locator; // Set locator to both streams. Stream::setLocator($locator); ReadOnlyStream::setLocator($locator); } /** * @return UniformResourceLocator */ public function getLocator() { return $this->locator; } public function add(array $schemes) { foreach ($schemes as $scheme => $config) { $force = !empty($config['force']); if (isset($config['paths'])) { $this->locator->addPath($scheme, '', $config['paths'], false, $force); } if (isset($config['prefixes'])) { foreach ($config['prefixes'] as $prefix => $paths) { $this->locator->addPath($scheme, $prefix, $paths, false, $force); } } $type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream'; if ($type[0] != '\\') { $type = '\\Rockettheme\\Toolbox\\StreamWrapper\\' . $type; } $this->schemes[$scheme] = $type; if (isset($this->registered)) { $this->doRegister($scheme, $type); } } } public function register() { $this->registered = stream_get_wrappers(); foreach ($this->schemes as $scheme => $type) { $this->doRegister($scheme, $type); } } protected function doRegister($scheme, $type) { if (in_array($scheme, $this->registered)) { stream_wrapper_unregister($scheme); } if (!stream_wrapper_register($scheme, $type)) { throw new \InvalidArgumentException("Stream '{$type}' could not be initialized."); } } } classes/Gantry/Component/Stylesheet/ScssCompiler.php 0000604 00000014766 15075035624 0016700 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Stylesheet; use Gantry\Component\Stylesheet\Scss\Compiler; use Gantry\Framework\Document; use Gantry\Framework\Gantry; use Leafo\ScssPhp\Exception\CompilerException; use RocketTheme\Toolbox\File\File; use RocketTheme\Toolbox\File\JsonFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class ScssCompiler extends CssCompiler { /** * @var string */ public $type = 'scss'; /** * @var string */ public $name = 'SCSS'; /** * @var Compiler */ protected $compiler; /** * Constructor. */ public function __construct() { parent::__construct(); $this->compiler = new Compiler(); if ($this->production) { $this->compiler->setFormatter('Leafo\ScssPhp\Formatter\Crunched'); } else { $this->compiler->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); // Work around bugs in SCSS compiler. // TODO: Pass our own SourceMapGenerator instance instead. $this->compiler->setSourceMap(Compiler::SOURCE_MAP_INLINE); $this->compiler->setSourceMapOptions([ 'sourceMapBasepath' => '/', 'sourceRoot' => '/', ]); $this->compiler->setLineNumberStyle(Compiler::LINE_COMMENTS); } } public function compile($in) { return $this->compiler->compile($in); } public function resetCache() { } /** * @param string $in Filename without path or extension. * @return bool True if the output file was saved. * @throws \RuntimeException */ public function compileFile($in) { // Buy some extra time as compilation may take a lot of time in shared environments. @set_time_limit(30); @set_time_limit(60); @set_time_limit(90); @set_time_limit(120); ob_start(); $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $out = $this->getCssUrl($in); $path = $locator->findResource($out, true, true); $file = File::instance($path); // 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, lets avoid compiling the same file twice. return false; } // Set the lookup paths. $this->compiler->setBasePath($path); $this->compiler->setImportPaths([[$this, 'findImport']]); // Run the compiler. $this->compiler->setVariables($this->getVariables()); $scss = '@import "' . $in . '.scss"'; try { $css = $this->compiler->compile($scss); } catch (CompilerException $e) { throw new \RuntimeException("CSS Compilation on file '{$in}.scss' failed on error: {$e->getMessage()}", 500, $e); } if (strpos($css, $scss) === 0) { $css = '/* ' . $scss . ' */'; } // Extract map from css and save it as separate file. if ($pos = strrpos($css, '/*# sourceMappingURL=')) { $map = json_decode(urldecode(substr($css, $pos + 43, -3)), true); /** @var Document $document */ $document = $gantry['document']; foreach ($map['sources'] as &$source) { $source = $document->url($source, null, -1); } unset($source); $mapFile = JsonFile::instance($path . '.map'); $mapFile->save($map); $mapFile->free(); $css = substr($css, 0, $pos) . '/*# sourceMappingURL=' . basename($out) . '.map */'; } $warnings = trim(ob_get_clean()); if ($warnings) { $this->warnings[$in] = explode("\n", $warnings); } if (!$this->production) { $warning = <<<WARN /* GANTRY5 DEVELOPMENT MODE ENABLED. WARNING: This file is automatically generated by Gantry5. Any modifications to this file will be lost! For more information on modifying CSS, please read: http://docs.gantry.org/gantry5/configure/styles http://docs.gantry.org/gantry5/tutorials/adding-a-custom-style-sheet */ WARN; $css = $warning . "\n\n" . $css; } else { $css = "{$this->checksum()}\n{$css}"; } $file->save($css); $file->unlock(); $file->free(); $this->createMeta($out, md5($css)); $this->compiler->cleanParsedFiles(); return true; } /** * @param string $name Name of function to register to the compiler. * @param callable $callback Function to run when called by the compiler. * @return $this */ public function registerFunction($name, callable $callback) { $this->compiler->registerFunction($name, $callback); return $this; } /** * @param string $name Name of function to unregister. * @return $this */ public function unregisterFunction($name) { $this->compiler->unregisterFunction($name); return $this; } /** * @param string $url * @return null|string * @internal */ public function findImport($url) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; // Ignore vanilla css and external requests. if (preg_match('/\.css$|^https?:\/\//', $url)) { return null; } // Try both normal and the _partial filename. $files = array($url, preg_replace('/[^\/]+$/', '_\0', $url)); foreach ($this->paths as $base) { foreach ($files as $file) { if (!preg_match('|\.scss$|', $file)) { $file .= '.scss'; } if ($locator->findResource($base . '/' . $file)) { return $base . '/' . $file; } } } return null; } } classes/Gantry/Component/Stylesheet/Scss/Compiler.php 0000604 00000026204 15075035624 0016745 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Stylesheet\Scss; use Gantry\Component\Filesystem\Folder; use Gantry\Framework\Document; use Gantry\Framework\Gantry; use Leafo\ScssPhp\Compiler as BaseCompiler; use Leafo\ScssPhp\Formatter\OutputBlock; use Leafo\ScssPhp\Parser; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Compiler extends BaseCompiler { protected $basePath; protected $fonts; protected $usedFonts; protected $streamNames; protected $parsedFiles = []; public function __construct() { parent::__construct(); $this->registerFunction('get-font-url', [$this, 'userGetFontUrl']); $this->registerFunction('get-font-family', [$this, 'userGetFontFamily']); $this->registerFunction('get-local-fonts', [$this, 'userGetLocalFonts']); $this->registerFunction('get-local-font-weights', [$this, 'userGetLocalFontWeights']); $this->registerFunction('get-local-font-url', [$this, 'userGetLocalFontUrl']); } /** * @param $basePath */ public function setBasePath($basePath) { /** @var Document $document */ $document = Gantry::instance()['document']; $this->basePath = rtrim($document->rootUri(), '/') . '/' . Folder::getRelativePath($basePath); } /** * @param array $fonts */ public function setFonts(array $fonts) { $this->fonts = $fonts; } /** * @param $args * @return mixed */ public function compileArgs($args) { foreach ($args as &$arg) { $arg = $this->compileValue($arg); } return $args; } /** * Get variable * * @api * * @param string $name * @param boolean $shouldThrow * @param BaseCompiler\Environment $env * @param bool $unreduced * * @return mixed */ public function get($name, $shouldThrow = true, BaseCompiler\Environment $env = null, $unreduced = false) { try { return parent::get($name, $shouldThrow, $env, $unreduced); } catch (\Exception $e) { echo $e->getMessage() . "\n"; return ['string', '', ['']]; } } /** * @param array $args * @return string * @throws \Leafo\ScssPhp\Exception\CompilerException */ public function libUrl(array $args) { // Function has a single parameter. $parsed = reset($args); if (!$parsed) { $this->throwError('url() is missing parameter'); } // Compile parsed value to string. $url = trim($this->compileValue($parsed), '\'"'); // Handle ../ inside CSS files (points to current theme). if (strpos($url, '../') === 0 && strpos($url, '../', 3) === false) { $url = 'gantry-theme://' . substr($url, 3); } // Generate URL, failed streams will be transformed to 404 URLs. $url = Gantry::instance()['document']->url($url, null, null, false); // Changes absolute URIs to relative to make the path to work even if the site gets moved. if ($url && $url[0] === '/' && $this->basePath) { $url = Folder::getRelativePathDotDot($url, $this->basePath); } // Make sure that all the URLs inside CSS are https compatible by replacing http:// protocol with //. if (strpos($url, 'http://') === 0) { $url = str_replace('http://', '//', $url); } // Return valid CSS. return "url('{$url}')"; } /** * get-font-url($my-font-variable); * * @param array $args * @return string */ public function userGetFontUrl($args) { $value = trim($this->compileValue(reset($args)), '\'"'); // It's a google font if (0 === strpos($value, 'family=')) { $fonts = $this->decodeFonts($value); $font = reset($fonts); // Only return url once per font. if ($font && !isset($this->usedFonts[$font])) { $this->usedFonts[$font] = true; return "url('//fonts.googleapis.com/css?{$value}')"; } } return false; } /** * font-family: get-font-family($my-font-variable); * * @param array $args * @return string */ public function userGetFontFamily($args) { $value = trim($this->compileValue(reset($args)), '\'"'); return $this->encodeFonts($this->decodeFonts($value)); } /** * get-local-fonts($my-font-variable, $my-font-variable2, ...); * * @param array $args * @return array */ public function userGetLocalFonts($args) { $args = $this->compileArgs($args); $fonts = []; foreach ($args as $value) { // It's a local font, we need to load any of the mapped fonts from the theme $fonts = array_merge($fonts, $this->decodeFonts($value, true)); } $fonts = $this->getLocalFonts($fonts); // Create a basic list of strings so that SCSS parser can parse the list. $list = []; foreach ($fonts as $font => $data) { $list[] = ['string', '"', [$font]]; } return ['list', ',', $list]; } /** * get-local-font-weights(roboto); * * @param array $args * @return array */ public function userGetLocalFontWeights($args) { $name = trim($this->compileValue(reset($args)), '\'"'); $weights = isset($this->fonts[$name]) ? array_keys($this->fonts[$name]) : []; // Create a list of numbers so that SCSS parser can parse the list. $list = []; foreach ($weights as $weight) { $list[] = ['string', '', [(int) $weight]]; } return ['list', ',', $list]; } /** * get-local-font-url(roboto, 400); * * @param array $args * @return string */ public function userGetLocalFontUrl($args) { $args = $this->compileArgs($args); $name = isset($args[0]) ? trim($args[0], '\'"') : ''; $weight = isset($args[1]) ? $args[1] : 400; // Only return url once per font. $weightName = $name . '-' . $weight; if (isset($this->fonts[$name][$weight]) && !isset($this->usedFonts[$weightName])) { $this->usedFonts[$weightName] = true; return $this->fonts[$name][$weight]; } return false; } /** * Get local font data. * * @param array $fonts * @return array */ protected function getLocalFonts(array $fonts) { $list = []; foreach ($fonts as $family) { $family = strtolower($family); if (isset($this->fonts[$family])) { $list[$family] = $this->fonts[$family]; } } return $list; } /** * Convert array of fonts into a CSS parameter string. * * @param array $fonts * @return string */ protected function encodeFonts(array $fonts) { array_walk($fonts, function(&$val) { // Check if font family is one of the 4 default ones, otherwise add quotes. if (!\in_array($val, ['cursive', 'serif', 'sans-serif', 'monospace'], true)) { $val = '"' . $val . '"'; } }); return implode(', ', $fonts); } /** * Convert string into array of fonts. * * @param string $string * @param bool $localOnly * @return array */ protected function decodeFonts($string, $localOnly = false) { if (0 === strpos($string, 'family=')) { if ($localOnly) { // Do not return external fonts. return []; } // Matches google font family name preg_match('/^family=([^&:]+).*$/ui', $string, $matches); return [urldecode($matches[1])]; } // Filter list of fonts and quote them. $list = (array) explode(',', $string); array_walk($list, function(&$val) { $val = trim($val, "'\" \t\n\r\0\x0B"); }); array_filter($list); return $list; } public function reset() { $this->usedFonts = []; return $this; } /** * Instantiate parser * * @param string $path * * @return \Leafo\ScssPhp\Parser */ protected function parserFactory($path) { $parser = new Parser($path, count($this->sourceNames), $this->encoding); /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; $this->sourceNames[] = $locator->isStream($path) ? $locator->findResource($path, false) : $path; $this->streamNames[] = $path; $this->addParsedFile($path); return $parser; } /** * Adds to list of parsed files * * @api * * @param string $path */ public function addParsedFile($path) { if ($path && file_exists($path)) { $this->parsedFiles[$path] = filemtime($path); } } /** * Returns list of parsed files * * @api * * @return array */ public function getParsedFiles() { return $this->parsedFiles; } /** * Clean parset files. * * @api */ public function cleanParsedFiles() { $this->parsedFiles = []; } /** * Handle import loop * * @param string $name * * @throws \Exception */ protected function handleImportLoop($name) { for ($env = $this->env; $env; $env = $env->parent) { $file = $this->streamNames[$env->block->sourceIndex]; if (realpath($file) === $name) { $this->throwError('An @import loop has been found: %s imports %s', $file, basename($file)); break; } } } /** * Override function to improve the logic. * * @param string $path * @param OutputBlock $out * * @throws \Exception */ protected function importFile($path, OutputBlock $out) { $this->addParsedFile($path); /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; // see if tree is cached $realPath = $locator($path); if (isset($this->importCache[$realPath])) { $this->handleImportLoop($realPath); $tree = $this->importCache[$realPath]; } else { $code = file_get_contents($realPath); $parser = $this->parserFactory($path); $tree = $parser->parse($code); $this->importCache[$realPath] = $tree; } $dirname = dirname($path); array_unshift($this->importPaths, $dirname); $this->compileChildrenNoReturn($tree->children, $out); array_shift($this->importPaths); } } classes/Gantry/Component/Stylesheet/CssCompilerInterface.php 0000604 00000003324 15075035624 0020322 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Stylesheet; interface CssCompilerInterface { /** * @return array */ public function getWarnings(); /** * @return string */ public function getTarget(); /** * @param string $target * @return $this */ public function setTarget($target = null); /** * @param string $configuration * @return $this */ public function setConfiguration($configuration = null); /** * @param array $paths * @return $this */ public function setPaths(array $paths = null); /** * @param array $files * @return $this */ public function setFiles(array $files = null); /** * @param array $fonts * @return $this */ public function setFonts(array $fonts); /** * @param string $name * @return string */ public function getCssUrl($name); public function getVariables(); public function setVariables(array $variables); public function registerFunction($name, callable $callback); public function unregisterFunction($name); public function needsCompile($in, $variables); public function compileFile($in); /** * @return $this */ public function reset(); /** * @return $this */ public function compileAll(); public function resetCache(); } classes/Gantry/Component/Stylesheet/CssCompiler.php 0000604 00000023161 15075035624 0016502 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Stylesheet; use Gantry\Component\Config\Config; use Gantry\Component\Gantry\GantryTrait; use Gantry\Framework\Gantry; use Leafo\ScssPhp\Colors; use RocketTheme\Toolbox\File\PhpFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; abstract class CssCompiler implements CssCompilerInterface { use GantryTrait; protected $type; protected $name; protected $debug = false; protected $warnings = []; /** * @var array */ protected $fonts; /** * @var array */ protected $variables; /** * @var string */ protected $target = 'gantry-theme://css-compiled'; /** * @var string */ protected $configuration = 'default'; /** * @var array */ protected $paths; /** * @var array */ protected $files; /** * @var mixed */ protected $compiler; /** * @var bool */ protected $production; public function __construct() { $gantry = static::gantry(); /** @var Config $global */ $global = $gantry['global']; // In production mode we do not need to do any other checks. $this->production = (bool) $global->get('production'); } public function getWarnings() { return $this->warnings; } /** * @return string */ public function getTarget() { return $this->target; } /** * @param string $target * @return $this */ public function setTarget($target = null) { if ($target !== null) { $this->target = (string) $target; } return $this; } /** * @param string $configuration * @return $this */ public function setConfiguration($configuration = null) { if ($configuration !== null) { $this->configuration = $configuration; } return $this; } /** * @param array $fonts * @return $this */ public function setFonts(array $fonts = null) { if ($fonts !== null) { // Normalize font data. $list = []; foreach ($fonts as $family => $data) { $family = strtolower($family); if (is_array($data)) { // font: [400: url1, 500: url2, 700: url3] $list[$family] = $data; } else { // font: url $list[$family] = [400 => (string) $data]; } } $this->compiler->setFonts($list); } return $this; } /** * @param array $paths * @return $this */ public function setPaths(array $paths = null) { if ($paths !== null) { $this->paths = $paths; } return $this; } /** * @param array $files * @return $this */ public function setFiles(array $files = null) { if ($files !== null) { $this->files = $files; } return $this; } /** * @param string $name * @return string */ public function getCssUrl($name) { $out = $name . ($this->configuration !== 'default' ? '_'. $this->configuration : ''); return "{$this->target}/{$out}.css"; } /** * @return $this */ public function compileAll() { foreach ($this->files as $file) { $this->compileFile($file); } return $this; } public function needsCompile($in, $variables) { $gantry = static::gantry(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $out = $this->getCssUrl($in); $path = $locator->findResource($out); // Check if CSS file exists at all. if (!$path) { $this->setVariables($variables()); return true; } if ($this->production) { // Open the file to see if it contains development comment in the beginning of the file. $handle = fopen($path, 'rb'); $contents = fread($handle, 36); fclose($handle); if ($contents === '/* GANTRY5 DEVELOPMENT MODE ENABLED.') { $this->setVariables($variables()); return true; } // Compare checksum comment in the file. if ($contents !== $this->checksum()) { $this->setVariables($variables()); return true; } // In production mode we do not need to do any other checks. return false; } $uri = basename($out); $metaFile = PhpFile::instance($locator->findResource("gantry-cache://theme/scss/{$uri}.php", true, true)); // Check if meta file exists. if (!$metaFile->exists()) { $this->setVariables($variables()); return true; } $content = $metaFile->content(); $metaFile->free(); // Check if filename in meta file matches. if (empty($content['file']) || $content['file'] !== $out) { $this->setVariables($variables()); return true; } // Check if meta timestamp matches to CSS file. if (filemtime($path) !== $content['timestamp']) { $this->setVariables($variables()); return true; } $this->setVariables($variables()); // Check if variables have been changed. $oldVariables = isset($content['variables']) ? $content['variables'] : []; if ($oldVariables != $this->getVariables()) { return true; } // Preload all CSS files to locator cache. foreach ($this->paths as $path) { $locator->fillCache($path); } // Check if any of the imported files have been changed. $imports = isset($content['imports']) ? $content['imports'] : []; if (!$imports) { return $this->findImport($in) !== null; } foreach ($imports as $resource => $timestamp) { $import = $locator->isStream($resource) ? $locator->findResource($resource) : realpath($resource); if (!$import || filemtime($import) !== $timestamp) { return true; } } return false; } public function setVariables(array $variables) { $this->variables = array_filter($variables); foreach($this->variables as &$value) { // Check variable against colors and units. /* Test regex against these: * Should only match the ones marked as + * - family=Aguafina+Script * - #zzzzzz * - #fff * + #ffaaff * + 33em * + 0.5px * - 50 rem * - rgba(323,323,2323) * + rgba(125,200,100,0.3) * - rgb(120,12,12) */ if (preg_match('/(^(#([a-fA-F0-9]{6})|(rgba\(\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*((0.[0-9]+)|[01])\s*\)))|(\d+(\.\d+){0,1}(rem|em|ex|ch|vw|vh|vmin|vmax|%|px|cm|mm|in|pt|pc))$)/i', $value)) { continue; } // Check variable against predefined color names (we use Leafo SCSS Color class to do that). if (isset(Colors::$cssColors[strtolower($value)])) { continue; } // All the unknown values need to be quoted. $value = "'{$value}'"; } return $this; } public function getVariables() { return $this->variables; } public function reset() { $this->compiler->reset(); return $this; } /** * @param string $url * @return null|string */ abstract public function findImport($url); protected function checksum($len = 36) { static $checksum; if (!$checksum) { $checksum = md5(GANTRY5_VERSION . ' ' . Gantry::instance()['theme']->version); } return '/*' . substr($checksum, 0, $len - 4) . '*/'; } protected function createMeta($out, $md5) { $gantry = Gantry::instance(); if ($this->production) { return; } /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $uri = basename($out); $metaFile = PhpFile::instance($locator->findResource("gantry-cache://theme/scss/{$uri}.php", true, true)); $data = [ 'file' => $out, 'timestamp' => filemtime($locator->findResource($out)), 'md5' => $md5, 'variables' => $this->getVariables(), 'imports' => $this->compiler->getParsedFiles() ]; // Attempt to lock the file for writing. try { $metaFile->lock(false); } catch (\Exception $e) { // Another process has locked the file; we will check this in a bit. } // If meta file wasn't already locked by another process, save it. if ($metaFile->locked() !== false) { $metaFile->save($data); $metaFile->unlock(); } $metaFile->free(); } } classes/Gantry/Component/File/CompiledYamlFile.php 0000604 00000001502 15075035624 0016157 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\File; use RocketTheme\Toolbox\File\YamlFile; class CompiledYamlFile extends YamlFile { use CompiledFile; static public $defaultCachePath; static public $defaultCaching = true; protected function __construct() { parent::__construct(); $this->caching(static::$defaultCaching); if (static::$defaultCachePath) { $this->setCachePath(static::$defaultCachePath); } } } classes/Gantry/Component/File/CompiledFile.php 0000604 00000007774 15075035624 0015355 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\File; use RocketTheme\Toolbox\File\PhpFile; /** * Class CompiledFile * @package Grav\Common\File * * @property string $filename * @property string $extension * @property string $raw * @property array|string $content */ trait CompiledFile { protected $cachePath; protected $caching = true; /** * @param string $path * @return $this */ public function setCachePath($path) { $this->cachePath = $path; return $this; } public function caching($enabled = null) { if (null !== $enabled) { $this->caching = (bool) $enabled; } return $this->caching; } /** * Get/set parsed file contents. * * @param mixed $var * @return string * @throws \BadMethodCallException */ public function content($var = null) { if (!$this->cachePath) { throw new \BadMethodCallException("Cache path not defined for compiled file ({$this->filename})!"); } try { // If nothing has been loaded, attempt to get pre-compiled version of the file first. if ($var === null && $this->raw === null && $this->content === null) { $modified = $this->modified(); if (!$modified || !$this->caching) { return $this->decode($this->raw()); } $key = md5($this->filename); $file = PhpFile::instance($this->cachePath . "/{$key}{$this->extension}.php"); $class = get_class($this); $cache = $file->exists() ? $file->content() : null; // Load real file if cache isn't up to date (or is invalid). if (!isset($cache['@class']) || $cache['@class'] != $class || $cache['modified'] != $modified || $cache['filename'] != $this->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. } // Decode RAW file into compiled array. $data = $this->decode($this->raw()); $cache = [ '@class' => $class, 'filename' => $this->filename, 'modified' => $modified, 'data' => $data ]; // If compiled file wasn't already locked by another process, save it. if ($file->locked() !== false) { $file->save($cache); $file->unlock(); // Compile cached file into bytecode cache if (function_exists('opcache_invalidate')) { // Silence error in case if `opcache.restrict_api` directive is set. @opcache_invalidate($file->filename(), true); } elseif (function_exists('apc_compile_file')) { // PHP 5.4 @apc_compile_file($file->filename()); } } } $file->free(); $this->content = $cache['data']; } } catch (\Exception $e) { throw new \RuntimeException(sprintf('Failed to read %s: %s', basename($this->filename), $e->getMessage()), 500, $e); } return parent::content($var); } } classes/Gantry/Component/Position/Module.php 0000604 00000010215 15075035624 0015153 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Position; use Gantry\Component\File\CompiledYamlFile; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Module implements \ArrayAccess { use NestedArrayAccessWithGetters, Export; public $name; public $position; public $assigned; protected $items; /** * Module constructor. * * @param string $name * @param string $position * @param array $data */ public function __construct($name, $position = null, array $data = null) { $this->name = $name; $this->position = $position; if ($data) { $this->init($data); } else { $this->load(); } } public function update(array $data) { $this->init($data); return $this; } /** * Save module. * * @param string $position * @param string $name * @return $this */ public function save($name = null, $position = null) { $this->name = $name ?: $this->name; $this->position = $position ?: $this->position; $items = $this->toArray(); unset($items['position'], $items['id']); $file = $this->file(true); $file->save($items); return $this; } /** * Delete module. * * @return $this */ public function delete() { $file = $this->file(true); if ($file->exists()) { $file->delete(); } return $this; } /** * Return true if module exists. * * @return bool */ public function exists() { return $this->name ? $this->file()->exists() : false; } public function toArray() { return ['position' => $this->position, 'id' => $this->name] + $this->items; } protected function load() { $file = $this->file(); $this->init($file->content()); $file->free(); } protected function init($data) { unset($data['id'], $data['position']); $this->items = $data; if (isset($this->items['assignments'])) { $assignments = $this->items['assignments']; if (is_array($assignments)) { $this->assigned = 'some'; } elseif ($assignments !== 'all') { $this->assigned = 'none'; } else { $this->assigned = 'all'; } } else { $this->assigned = 'all'; } } protected function file($save = false) { $position = $this->position ?: '_unassigned_'; $this->name = $this->name ?: ($save ? $this->findFreeName() : null); $name = $this->name ?: '_untitled_'; /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; return CompiledYamlFile::instance($locator->findResource("gantry-positions://{$position}/{$name}.yaml", true, $save)); } /** * Find unused name with number appended. */ protected function findFreeName() { $position = $this->position ?: '_unassigned_'; $name = $this->get('type'); $name = $name == 'particle' ? $this->get('options.type') : $name; /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; if (!file_exists($locator->findResource("gantry-positions://{$position}/{$name}.yaml", true, true))) { return $name; } $count = 1; do { $count++; } while (file_exists($locator->findResource("gantry-positions://{$position}/{$name}_{$count}.yaml", true, true))); return "{$name}_{$count}"; } } classes/Gantry/Component/Position/Position.php 0000604 00000021451 15075035624 0015536 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Position; use Gantry\Component\Collection\Collection; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Filesystem\Folder; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use Symfony\Component\Yaml\Yaml; class Position extends Collection { public $name; public $title; protected $modules = []; /** * Position constructor. * * @param string $name * @param array $items */ public function __construct($name, array $items = null) { $this->name = $name; $this->load($items); } /** * Save position. * * @return $this */ public function save() { $file = $this->file(true); $file->save($this->toArray()); return $this; } /** * Clone position together with its modules. Returns new position. * * @param string $name * @return Position */ public function duplicate($name) { $new = clone $this; $new->name = $name; $new->save(); foreach ($this as $module) { $clone = clone $module; $clone->position = $name; $clone->save(); } return $new; } /** * Raname module key * * @param string $name * @return static */ public function rename($name) { $new = $this->duplicate($name); $this->delete(); return $new; } /** * Delete position. * * @return $this */ public function delete() { $file = $this->file(true); if ($file->exists()) { $file->delete(); } $folder = $this->folder(true); if (is_dir($folder)) { Folder::delete($folder); } return $this; } /** * Update modules in the position. * * @param array $items * @return $this */ public function update(array $items) { $list = []; foreach ($items as $item) { $name = ($item instanceof Module) ? $item->name : $item; $list[] = $name; if (!in_array($name, $this->items)) { $this->add($item); } } $remove = array_diff($this->items, $list); foreach ($remove as $item) { $module = $this->get($item); if ($module->position === $this->name) { $module->delete(); } } $this->items = $list; return $this; } /** * @param Module|string $item * @param string $name Temporary name for the module. * @return $this */ public function add($item, $name = null) { if ($item instanceof Module) { $this->modules[$name ?: $item->name] = $item; $item = $name ?: $item->name; } $this->items[] = $item; return $this; } public function remove($item) { if ($item instanceof Module) { $item = $item->name; } unset($this->modules[$item]); $this->items = array_diff($this->items, $item); return $this; } /** * @param $name * @return Module */ public function get($name) { if (!isset($this->modules[$name])) { $this->modules[$name] = $this->loadModule($name); } return $this->modules[$name]; } /** * Returns the value at specified offset. * * @param string $offset The offset to retrieve. * @return Module */ public function offsetGet($offset) { if (!isset($this->items[$offset])) { return null; } $name = $this->items[$offset]; if (!isset($this->modules[$name])) { $this->modules[$name] = $this->loadModule($name); } return $this->modules[$name]; } /** * Assigns a value to the specified offset. * * @param mixed $offset The offset to assign the value to. * @param mixed $value The value to set. */ public function offsetSet($offset, $value) { if (!$value instanceof Position) { throw new \InvalidArgumentException('Value has to be instance of Position'); } if (is_null($offset)) { $this->items[] = $value->name; $this->modules[$value->name] = $value; } else { $this->items[$offset] = $value->name; $this->modules[$value->name] = $value; } } /** * Unsets an offset. * * @param mixed $offset The offset to unset. */ public function offsetUnset($offset) { parent::offsetUnset($offset); if (!isset($this->items[$offset])) { return; } $name = $this->items[$offset]; if (isset($this->modules[$name])) { unset($this->modules[$name]); } } /** * @return \ArrayIterator */ public function getIterator() { $items = []; foreach ($this->items as $key => $name) { $items[] = $this->offsetGet($key); } return new \ArrayIterator($items); } /** * @return array */ public function toArray($includeModules = false) { $array = [ 'name' => $this->name, 'title' => $this->title, ]; if (!$includeModules) { $array['ordering'] = $this->items; } else { $list = []; foreach ($this->getIterator() as $key => $module) { $list[$key] = $module->toArray(); } $array['modules'] = $list; } return $array; } /** * @param int $inline * @param int $indent * @param bool $includeModules * @return string */ public function toYaml($inline = 3, $indent = 2, $includeModules = false) { return Yaml::dump($this->toArray($includeModules), $inline, $indent, true, false); } /** * @param bool $includeModules * @return string */ public function toJson($includeModules = false) { return json_encode($this->toArray($includeModules)); } /** * @return array */ public function listModules() { $list = []; foreach ($this->items as $name) { $list[] = "{$this->name}/{$name}"; } return $list; } /** * @param bool $save * @return string */ public function folder($save = false) { return $this->locator()->findResource($this->path(), true, $save); } /** * @param $data */ protected function load($data) { if ($data === null) { $file = $this->file(); $data = $file->content(); $file->free(); } $this->title = isset($data['title']) ? $data['title'] : $this->name; if (isset($data['modules'])) { foreach ($data['modules'] as $array) { $this->add(new Module($array['id'], $this->name, $array), $array['id'] ?: rand()); } return; } // Sort modules by ordering, if items are not listed in ordering, use alphabetical order. $ordering = isset($data['ordering']) ? array_flip($data['ordering']) : []; $path = $this->locator()->findResource($this->path()); $files = $path ? Folder::all( $path, [ 'compare' => 'Filename', 'pattern' => '|\.yaml$|', 'folders' => false, 'recursive' => false, 'key' => 'Filename', 'filters' => ['key' => '|\.yaml$|'] ] ) : []; ksort($files); $this->items = array_keys($ordering + $files); } /** * @param string $name * @return $this */ protected function loadModule($name) { return new Module($name, $this->name); } /** * @param bool $save * @return CompiledYamlFile */ protected function file($save = false) { return CompiledYamlFile::instance($this->locator()->findResource($this->path() . '.yaml', true, $save)); } /** * @return UniformResourceLocator */ protected function locator() { return Gantry::instance()['locator']; } /** * @return string */ protected function path() { return "gantry-positions://{$this->name}"; } } classes/Gantry/Component/Position/Positions.php 0000604 00000014277 15075035624 0015731 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Position; use Gantry\Component\Collection\Collection; use Gantry\Component\File\CompiledYamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RocketTheme\Toolbox\DI\Container; class Positions extends Collection { /** * @var array|Position[] */ protected $items; /** * @var string */ protected $path; /** * @var Container */ protected $container; public function __construct(Container $container) { $this->container = $container; } /** * @param string $path * * @return $this * @throws \RuntimeException */ public function load($path = 'gantry-positions://') { $this->path = $path; $positions = []; /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; /** @var UniformResourceIterator $iterator */ $iterator = $locator->getIterator($path); /** @var UniformResourceIterator $info */ foreach ($iterator as $info) { if (!$info->isFile() || $info->getExtension() != 'yaml') { continue; } $name = $info->getBasename('.yaml'); $position = CompiledYamlFile::instance($info->getPathname())->content(); // Only use filesystem position if it it is properly set up. if ($position) { $positions[$name] = new Position($name, $position); } } // Add empty positions from the layouts. foreach ($this->container['outlines']->positions() as $name => $title) { if (!isset($positions[$name])) { $positions[$name] = new Position($name, ['title' => $title]); } } ksort($positions); $this->items = $positions; return $this; } /** * Updates all positions with their modules from an array and saves them. * * @param array $data * @return $this */ public function import(array $data) { foreach ($data as $pos) { $list = []; $position = $pos['name']; foreach ($pos['modules'] as $item) { $name = !empty($item['id']) ? $item['id'] : ''; if ($name && !empty($item['position'])) { $module = $this[$item['position']]->get($name); if ($position !== $item['position']) { $module->delete(); } } else { $module = new Module($name, $position); } $module->update($item)->save($name, $position); $list[] = $module; } $this[$pos['name']]->update($list)->save(); } return $this; } /** * @param Position $item * @return $this */ public function add($item) { if ($item instanceof Position) { $this->items[$item->name] = $item; } return $this; } /** * @param string $title * @param string $id * * @return string * @throws \RuntimeException */ public function create($title = 'Untitled', $id = null) { $name = strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $id ?: $title)); if (!$name) { throw new \RuntimeException("Position needs a name", 400); } $name = $this->findFreeName($name); $position = new Position($name, ['title' => $title]); $position->save(); return $name; } /** * @param string $id * @param string $new * * @return string * @throws \RuntimeException */ public function duplicate($id, $new = null) { if (!isset($this->items[$id])) { throw new \RuntimeException(sprintf("Duplicating Position failed: '%s' not found.", $id), 400); } $new = $this->findFreeName($new ? strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $new)) : $id); $position = $this->items[$id]; $new = $position->duplicate($new); return $new->name; } /** * @param string $id * @param string $new * * @return string * @throws \RuntimeException */ public function rename($id, $new) { if (!isset($this->items[$id])) { throw new \RuntimeException(sprintf("Renaming Position failed: '%s' not found.", $id), 400); } $newId = strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $new)); if (isset($this->items[$newId])) { throw new \RuntimeException(sprintf("Renaming Position failed: '%s' already exists.", $newId), 400); } $position = $this->items[$id]; $position->rename($new); return $position->name; } /** * @param string $id * * @throws \RuntimeException */ public function delete($id) { if (!isset($this->items[$id])) { throw new \RuntimeException(sprintf("Deleting Position failed: '%s' not found.", $id), 400); } $position = $this->items[$id]; $position->delete(); } /** * Find unused name with number appended to it when duplicating an position. * * @param string $id * * @return string */ protected function findFreeName($id) { if (!isset($this->items[$id])) { return $id; } $name = $id; $count = 0; if (preg_match('|^(?:_)?(.*?)(?:_(\d+))?$|ui', $id, $matches)) { $matches += ['', '', '']; list (, $name, $count) = $matches; } $count = max(1, $count); do { $count++; } while (isset($this->items["{$name}_{$count}"])); return "{$name}_{$count}"; } } classes/Gantry/Component/Theme/ThemeDetails.php 0000604 00000013737 15075035624 0015550 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Theme; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Filesystem\Streams; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Class ThemeDetails * @package Gantry\Component\Theme */ class ThemeDetails implements \ArrayAccess { use NestedArrayAccessWithGetters, Export; protected $items; protected $parent; /** * Create new theme details. * * @param string $theme */ public function __construct($theme) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $filename = $locator->findResource("gantry-themes://{$theme}/gantry/theme.yaml"); if (!$filename) { throw new \RuntimeException(sprintf('Theme %s not found', $theme), 404); } $cache = $locator->findResource("gantry-cache://{$theme}/compiled/yaml", true, true); $file = CompiledYamlFile::instance($filename); $this->items = $file->setCachePath($cache)->content(); $file->free(); $this->offsetSet('name', $theme); $parent = (string) $this->get('configuration.theme.parent', $theme); $parent = $parent != $theme ? $parent : null; $this->offsetSet('parent', $parent); } /** * @return string */ public function addStreams() { $gantry = Gantry::instance(); // Initialize theme stream. $streamName = $this->addStream($this->offsetGet('name'), $this->getPaths()); // Initialize parent theme streams. $loaded = [$this->offsetGet('name')]; $details = $this; while ($details = $details->parent()) { if (in_array($details->name, $loaded)) { break; } $this->addStream($details->name, $details->getPaths(false)); $loaded[] = $details->name; } /** @var Streams $streams */ $streams = $gantry['streams']; $streams->register(); return $streamName; } /** * Get parent theme details if theme has a parent. * * @return ThemeDetails|null * @throws \RuntimeException */ public function parent() { $parent = $this->offsetGet('parent'); if (!$this->parent && $parent) { try { $this->parent = new ThemeDetails($parent); } catch (\RuntimeException $e) { throw new \RuntimeException(sprintf('Parent theme %s not found', $parent), 404); } } return $this->parent; } /** * Get all possible paths to the theme. * * @return array */ public function getPaths($overrides = true) { $paths = array_merge( $overrides ? (array) $this->get('configuration.theme.overrides', 'gantry-theme://custom') : [], ['gantry-theme://'], (array) $this->get('configuration.theme.base', 'gantry-theme://common') ); $parent = $this->offsetGet('parent'); if ($parent) { // Stream needs to be valid URL. $streamName = 'gantry-themes-' . preg_replace('|[^a-z\d+.-]|ui', '-', $parent); $paths[] = "{$streamName}://"; } return $this->parsePaths($paths); } /** * Convert theme path into stream URI. * * @param string $path * @return string */ public function getUrl($path) { $uri = (string) $this->offsetGet($path); if (strpos($uri, 'gantry-theme://') === 0) { list (, $uri) = explode('://', $uri, 2); } if (!strpos($uri, '://')) { $name = $this->offsetGet('name'); // Stream needs to be valid URL. $streamName = 'gantry-themes-' . preg_replace('|[^a-z\d+.-]|ui', '-', $name); $uri = "{$streamName}://{$uri}"; } return $uri; } /** * Turn list of theme paths to be universal, so they can be used outside of the theme. * * @param array $items * @return array */ public function parsePaths(array $items) { foreach ($items as &$item) { $item = $this->parsePath($item); } return $items; } /** * Convert theme paths to be universal, so they can be used outside of the theme. * * @param string $path * @return string */ public function parsePath($path) { if (strpos($path, 'gantry-theme://') === 0) { list (, $path) = explode('://', $path, 2); } if (!strpos($path, '://')) { $name = $this->offsetGet('name'); $path = "gantry-themes://{$name}/{$path}"; } return $path; } /** * @return string|null * @deprecated 5.1.5 */ public function getParent() { return $this->offsetGet('parent'); } /** * @param string $name * @param array $paths * @return string|null */ protected function addStream($name, $paths) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; /** @var Streams $streams */ $streams = $gantry['streams']; // Add theme stream. $streamName = 'gantry-themes-' . preg_replace('|[^a-z\d+.-]|ui', '-', $name); if (!$locator->schemeExists($streamName)) { $streams->add([$streamName => ['paths' => $paths]]); } return $streamName; } } classes/Gantry/Component/Theme/ThemeInterface.php 0000604 00000007372 15075035624 0016061 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Theme; use Gantry\Component\Config\Config; use Gantry\Component\Layout\Layout; use Gantry\Component\Stylesheet\CssCompilerInterface; /** * Class ThemeTrait * @package Gantry\Framework\Base * * @property string $path * @property string $layout */ interface ThemeInterface { // AbstractTheme class /** * Get context for render(). * * @param array $context * @return array */ public function getContext(array $context); /** * Define twig environment. * * @param \Twig_Environment $twig * @param \Twig_LoaderInterface $loader * @return \Twig_Environment */ public function extendTwig(\Twig_Environment $twig, \Twig_LoaderInterface $loader = null); /** * Returns renderer. * * @return \Twig_Environment */ public function renderer(); /** * Render a template file. * * @param string $file * @param array $context * @return string */ public function render($file, array $context = array()); // ThemeTrait class /** * Update all CSS files in the theme. * * @param array $outlines * @return array List of CSS warnings. */ public function updateCss(array $outlines = null); /** * Set current layout. * * @param string $name * @param bool $force * @return $this */ public function setLayout($name = null, $force = false); /** * Get current preset. * * @param bool $forced If true, return only forced preset or null. * @return string|null $preset */ public function preset($forced = false); /** * Set preset to be used. * * @param string $name * @return $this */ public function setPreset($name = null); /** * Return CSS compiler used in the theme. * * @return CssCompilerInterface * @throws \RuntimeException */ public function compiler(); /** * Returns URL to CSS file. * * If file does not exist, it will be created by using CSS compiler. * * @param string $name * @return string */ public function css($name); /** * Return all CSS variables. * * @return array */ public function getCssVariables(); /** * Returns style presets for the theme. * * @return Config */ public function presets(); /** * Return name of the used layout preset. * * @return string * @throws \RuntimeException */ public function type(); /** * Load current layout and its configuration. * * @param string $name * @return Layout * @throws \LogicException */ public function loadLayout($name = null); /** * Check whether layout has content bock. * * @return bool */ public function hasContent(); /** * Returns all non-empty segments from the layout. * * @return array */ public function segments(); /** * Returns details of the theme. * * @return ThemeDetails */ public function details(); /** * Returns configuration of the theme. * * @return array */ public function configuration(); /** * Function to convert block sizes into CSS classes. * * @param $text * @return string */ public function toGrid($text); } classes/Gantry/Component/Theme/AbstractTheme.php 0000604 00000016062 15075035624 0015720 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Theme; use Gantry\Component\Config\Config; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Gantry\GantryTrait; use Gantry\Component\Twig\TwigCacheFilesystem; use Gantry\Component\Twig\TwigExtension; use Gantry\Framework\Platform; use Gantry\Framework\Services\ErrorServiceProvider; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Class AbstractTheme * @package Gantry\Component * * @property string $path * @property string $layout */ abstract class AbstractTheme { use GantryTrait; /** * @var string */ public $name; /** * @var string */ public $path; /** * @var \Twig_Environment */ protected $renderer; /** * Construct theme object. * * @param string $path * @param string $name */ public function __construct($path, $name = null) { if (!is_dir($path)) { throw new \LogicException('Theme not found!'); } $this->name = $name ? $name : basename($path); $this->path = $path; $this->init(); } /** * Get context for render(). * * @param array $context * @return array */ public function getContext(array $context) { $context['theme'] = $this; return $context; } /** * Define twig environment. * * @param \Twig_Environment $twig * @param \Twig_LoaderInterface $loader * @return \Twig_Environment */ public function extendTwig(\Twig_Environment $twig, \Twig_LoaderInterface $loader = null) { if ($twig->hasExtension('Gantry\Component\Twig\TwigExtension')) { return $twig; } if (!$loader) { $loader = $twig->getLoader(); } $this->setTwigLoaderPaths($loader); $twig->addExtension(new TwigExtension); if (method_exists($this, 'toGrid')) { $filter = new \Twig_SimpleFilter('toGrid', [$this, 'toGrid']); $twig->addFilter($filter); } return $twig; } /** * Return renderer. * * @return \Twig_Environment */ public function renderer() { if (!$this->renderer) { $gantry = static::gantry(); /** @var Config $global */ $global = $gantry['global']; $cachePath = $global->get('compile_twig', 1) ? $this->getCachePath('twig') : null; $cache = $cachePath ? new TwigCacheFilesystem($cachePath, \Twig_Cache_Filesystem::FORCE_BYTECODE_INVALIDATION) : null; $debug = $gantry->debug(); $production = (bool) $global->get('production', 1); $loader = new \Twig_Loader_Filesystem(); $params = [ 'cache' => $cache, 'debug' => $debug, 'auto_reload' => !$production, 'autoescape' => 'html' ]; $twig = new \Twig_Environment($loader, $params); $this->setTwigLoaderPaths($loader); if ($debug) { $twig->addExtension(new \Twig_Extension_Debug()); } $this->renderer = $this->extendTwig($twig, $loader); } return $this->renderer; } /** * Render a template file by using given context. * * @param string $file * @param array $context * @return string */ public function render($file, array $context = []) { // Include Gantry specific things to the context. $context = $this->getContext($context); return $this->renderer()->render($file, $context); } /** * Compile and render twig string. * * @param string $string * @param array $context * @return string */ public function compile($string, array $context = []) { $renderer = $this->renderer(); $template = $renderer->createTemplate($string); // Include Gantry specific things to the context. $context = $this->getContext($context); return $template->render($context); } /** * Initialize theme. */ protected function init() { $gantry = static::gantry(); $gantry['streams']->register(); // Only add error service if development or debug mode has been enabled or user is admin. if (!$gantry['global']->get('production', 0) || $gantry->debug() || $gantry->admin()) { $gantry->register(new ErrorServiceProvider); } // Initialize theme cache stream. $cachePath = $this->getCachePath(); Folder::create($cachePath); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $locator->addPath('gantry-cache', 'theme', [$cachePath], true, true); CompiledYamlFile::$defaultCachePath = $locator->findResource('gantry-cache://theme/compiled/yaml', true, true); CompiledYamlFile::$defaultCaching = $gantry['global']->get('compile_yaml', 1); } /** * Set twig lookup paths to the loader. * * @param \Twig_LoaderInterface $loader * @return \Twig_Loader_Filesystem|null * @internal */ protected function setTwigLoaderPaths(\Twig_LoaderInterface $loader) { if ($loader instanceof \Twig_Loader_Chain) { $new = new \Twig_Loader_Filesystem(); $loader->addLoader($new); $loader = $new; } elseif (!($loader instanceof \Twig_Loader_Filesystem)) { return null; } $gantry = static::gantry(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $loader->setPaths($locator->findResources('gantry-engine://templates'), 'nucleus'); $loader->setPaths($locator->findResources('gantry-particles://'), 'particles'); return $loader; } /** * Get path to Twig cache. * * @param string $path * @return string */ protected function getCachePath($path = '') { $gantry = static::gantry(); /** @var Platform $patform */ $patform = $gantry['platform']; // Initialize theme cache stream. return $patform->getCachePath() . '/' . $this->name . ($path ? '/' . $path : ''); } /** * @deprecated 5.0.2 */ public function debug() { return static::gantry()->debug(); } /** * @deprecated 5.1.5 */ public function add_to_context(array $context) { return $this->getContext($context); } /** * @deprecated 5.1.5 */ public function add_to_twig(\Twig_Environment $twig, \Twig_LoaderInterface $loader = null) { return $this->extendTwig($twig, $loader); } } classes/Gantry/Component/Theme/ThemeInstaller.php 0000604 00000022755 15075035624 0016120 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Theme; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Layout\Layout; use Gantry\Framework\Gantry; use Gantry\Framework\Platform; use Gantry\Framework\Services\ErrorServiceProvider; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; abstract class ThemeInstaller { /** * Set to true if in Gantry. * * @var bool */ public $initialized = false; public $actions = []; protected $name; protected $outlines; protected $script; public function __construct($extension = null) { if ($extension) { $this->name = $extension; } } abstract public function getPath(); /** * Get list of available outlines. * * @param array $filter * @return array */ public function getOutlines(array $filter = null) { if (!isset($this->outlines)) { $this->outlines = []; $path = $this->getPath(); // If no outlines are given, try loading outlines.yaml file. $file = YamlFile::instance($path . '/install/outlines.yaml'); if ($file->exists()) { // Load the list from the yaml file. $this->outlines = (array) $file->content(); $file->free(); } elseif (is_dir($path . '/install/outlines')) { // Build the list from the install folder. // recurse = false, full=true $folders = Folder::all($path . '/install/outlines', ['folders' => true, 'recursive' => false]); foreach ($folders as $folder) { $this->outlines[basename($folder)] = []; } } // Always include system outlines. $this->outlines += ['default' => [], '_body_only' => [], '_error' => [], '_offline' => []]; } return is_array($filter) ? array_intersect_key($this->outlines, array_flip($filter)) : $this->outlines; } public function getOutline($name) { $list = $this->getOutlines([$name]); return reset($list); } public function installDefaults() { $installerScript = $this->getInstallerScript(); if ($installerScript && method_exists($installerScript, 'installDefaults')) { $installerScript->installDefaults($this); } else { $this->createDefaults(); } } public function installSampleData() { $installerScript = $this->getInstallerScript(); if ($installerScript && method_exists($installerScript, 'installSampleData')) { $installerScript->installSampleData($this); } else { $this->createSampleData(); } } public function createDefaults() { $this->createOutlines(); } public function createSampleData() { } public function render($template, $context = []) { try { $loader = new \Twig_Loader_Filesystem(); $loader->setPaths([$this->getPath() . '/install/templates']); $params = [ 'cache' => null, 'debug' => false, 'autoescape' => 'html' ]; $twig = new \Twig_Environment($loader, $params); $name = $this->name; $context += [ 'name' => $this->translate($name), 'actions' => $this->actions ]; return $twig->render($template, $context); } catch (\Exception $e) { return ''; } } /** * Set available outlines. * * @param array $outlines If parameter isn't provided, outlines list get reloaded from the disk. * @return $this */ public function setOutlines(array $outlines = null) { $this->outlines = $outlines; return $this; } /** * @param array $filter */ public function createOutlines(array $filter = null) { $outlines = $this->getOutlines($filter); foreach ($outlines as $folder => $params) { $this->createOutline($folder, $params); } } /** * @param string $folder * @param array $params * @return string|bool */ public function createOutline($folder, array $params = []) { if (!$folder) { throw new \RuntimeException('Cannot create outline without folder name'); } $this->initialize(); $created = false; $params += [ 'preset' => null, 'title' => null ]; $title = $params['title'] ?: ucwords(trim(strtr($folder, ['_' => ' ']))); $preset = $params['preset'] ?: 'default'; // Copy configuration for the new layout. if (($this->copyCustom($folder, $folder) || $created)) { // Update layout and save it. $layout = Layout::load($folder, $preset); $layout->save()->saveIndex(); if ($created) { $this->actions[] = ['action' => 'outline_created', 'text' => $this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_CREATED', $title)]; } else { $this->actions[] = ['action' => 'outline_updated', 'text' => $this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_UPDATED', $title)]; } } return $folder; } public function initialize() { if ($this->initialized) { return; } $name = $this->name; $path = $this->getPath(); // Remove compiled CSS files if they exist. $cssPath = $path . '/custom/css-compiled'; if (is_dir($cssPath)) { Folder::delete($cssPath); } elseif (is_file($cssPath)) { @unlink($cssPath); } // Remove wrongly named file if it exists. $md5path = $path . '/MD5SUM'; if (is_file($md5path)) { @unlink($md5path); } // Restart Gantry and initialize it. $gantry = Gantry::restart(); $gantry['theme.name'] = $name; $gantry['streams']->register(); // Only add error service if debug mode has been enabled. if ($gantry->debug()) { $gantry->register(new ErrorServiceProvider); } /** @var Platform $patform */ $patform = $gantry['platform']; /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; // Initialize theme stream. $details = new ThemeDetails($name); $locator->addPath('gantry-theme', '', $details->getPaths(), false, true); // Initialize theme cache stream and clear theme cache. $cachePath = $patform->getCachePath() . '/' . $name; if (is_dir($cachePath)) { Folder::delete($cachePath); } Folder::create($cachePath); $locator->addPath('gantry-cache', 'theme', [$cachePath], true, true); CompiledYamlFile::$defaultCachePath = $locator->findResource('gantry-cache://theme/compiled/yaml', true, true); CompiledYamlFile::$defaultCaching = $gantry['global']->get('compile_yaml', 1); $this->initialized = true; } public function finalize() { // Copy standard outlines if they haven't been copied already. $this->copyCustom('default', 'default'); $this->copyCustom('_body_only', '_body_only'); $this->copyCustom('_error', '_error'); $this->copyCustom('_offline', '_offline'); $this->initialize(); } /** * @param string $layout * @param string $id * @return bool True if files were copied over. */ protected function copyCustom($layout, $id) { $path = $this->getPath(); // Only copy files if the target id doesn't exist. $dst = $path . '/custom/config/' . $id; if (!$layout || !$id || is_dir($dst)) { return false; } // New location for G5.3.2+ $src = $path . '/install/outlines/' . $layout; if (!is_dir($src)) { // Old and deprecated location. $src = $path . '/install/layouts/' . $layout; } try { is_dir($src) ? Folder::copy($src, $dst) : Folder::create($dst); } catch (\Exception $e) { throw new \RuntimeException("Creating configuration for outline '{$layout}' failed: {$e->getMessage()}", 500, $e); } return true; } protected function translate($text) { $translator = Gantry::instance()['translator']; $args = func_get_args(); return call_user_func_array([$translator, 'translate'], $args); } protected function getInstallerScript() { if (!$this->script) { $className = ucfirst($this->name) . 'InstallerScript'; if (!class_exists($className)) { $path = "{$this->getPath()}/install.php"; if (is_file($path)) { require_once $path; } } if (class_exists($className)) { $this->script = new $className; } } return $this->script; } } classes/Gantry/Component/Theme/ThemeTrait.php 0000604 00000055171 15075035624 0015244 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Theme; use Gantry\Component\Config\Config; use Gantry\Component\Content\Block\ContentBlock; use Gantry\Component\Content\Block\HtmlBlock; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Gantry\GantryTrait; use Gantry\Component\Layout\Layout; use Gantry\Component\Stylesheet\CssCompilerInterface; use Gantry\Framework\Document; use Gantry\Framework\Menu; use Gantry\Framework\Services\ConfigServiceProvider; use RocketTheme\Toolbox\File\PhpFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Class ThemeTrait * @package Gantry\Component * * @property string $path * @property string $layout */ trait ThemeTrait { use GantryTrait; protected $layoutObject; protected $atoms; protected $segments; protected $preset; protected $cssCache; /** * @var CssCompilerInterface */ protected $compiler; protected $equalized = [3 => 33.3, 6 => 16.7, 7 => 14.3, 8 => 12.5, 9 => 11.1, 11 => 9.1, 12 => 8.3]; /** * @var ThemeDetails */ protected $details; /** * Register Theme stream. * * @param string $savePath */ public function registerStream($savePath = null) { $streamName = $this->details()->addStreams(); /** @var UniformResourceLocator $locator */ $locator = self::gantry()['locator']; $locator->addPath('gantry-theme', '', array_merge((array) $savePath, [[$streamName, '']])); } /** * Update all CSS files in the theme. * * @param array $outlines * @return array List of CSS warnings. */ public function updateCss(array $outlines = null) { $gantry = static::gantry(); $compiler = $this->compiler(); if (is_null($outlines)) { /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $path = $locator->findResource($compiler->getTarget(), true, true); // Make sure that all the CSS files get deleted. if (is_dir($path)) { Folder::delete($path, false); } $outlines = $gantry['outlines']; } // Make sure that PHP has the latest data of the files. clearstatcache(); $warnings = []; foreach ($outlines as $outline => $title) { $config = ConfigServiceProvider::load($gantry, $outline); $compiler->reset()->setConfiguration($outline)->setVariables($config->flatten('styles', '-')); $results = $compiler->compileAll()->getWarnings(); if ($results) { $warnings[$outline] = $results; } } return $warnings; } /** * Set layout to be used. * * @param string $name * @param bool $force * @return $this */ public function setLayout($name = null, $force = false) { $gantry = static::gantry(); // Force new layout to be set. if ($force) { unset($gantry['configuration']); } // Set default name only if configuration has not been set before. if ($name === null && !isset($gantry['configuration'])) { $name = 'default'; } $outline = isset($gantry['configuration']) ? $gantry['configuration'] : null; // Set configuration if given. if ($name && $name != $outline) { GANTRY_DEBUGGER && \Gantry\Debugger::addMessage("Using Gantry outline {$name}"); $gantry['configuration'] = $name; } return $this; } /** * Get current preset. * * @param bool $forced If true, return only forced preset or null. * @return string|null $preset */ public function preset($forced = false) { $presets = $this->presets()->toArray(); $preset = $this->preset; if (!$preset && !$forced) { $preset = static::gantry()['config']->get('styles.preset', '-undefined-'); } if ($preset && !isset($presets[$preset])) { $preset = null; } return $preset; } /** * Set preset to be used. * * @param string $name * @return $this */ public function setPreset($name = null) { // Set preset if given. if ($name) { $this->preset = $name; } return $this; } /** * Return CSS compiler used in the theme. * * @return CssCompilerInterface * @throws \RuntimeException */ public function compiler() { if (!$this->compiler) { $compilerClass = (string) $this->details()->get('configuration.css.compiler', '\Gantry\Component\Stylesheet\ScssCompiler'); if (!class_exists($compilerClass)) { throw new \RuntimeException('CSS compiler used by the theme not found'); } $details = $this->details(); /** @var CssCompilerInterface $compiler */ $this->compiler = new $compilerClass(); $this->compiler ->setTarget($details->get('configuration.css.target')) ->setPaths($details->get('configuration.css.paths')) ->setFiles($details->get('configuration.css.files')) ->setFonts($details->get('configuration.fonts')); } $preset = $this->preset(true); if ($preset) { $this->compiler->setConfiguration($preset); } else { $gantry = static::gantry(); $this->compiler->setConfiguration(isset($gantry['configuration']) ? $gantry['configuration'] : 'default'); } return $this->compiler->reset(); } /** * Returns URL to CSS file. * * If file does not exist, it will be created by using CSS compiler. * * @param string $name * @return string */ public function css($name) { if (!isset($this->cssCache[$name])) { $compiler = $this->compiler(); if ($compiler->needsCompile($name, [$this, 'getCssVariables'])) { GANTRY_DEBUGGER && \Gantry\Debugger::startTimer("css-{$name}", "Compiling CSS: {$name}") && \Gantry\Debugger::addMessage("Compiling CSS: {$name}"); $compiler->compileFile($name); GANTRY_DEBUGGER && \Gantry\Debugger::stopTimer("css-{$name}"); } $this->cssCache[$name] = $compiler->getCssUrl($name); } return $this->cssCache[$name]; } public function getCssVariables() { if ($this->preset) { $variables = $this->presets()->flatten($this->preset . '.styles', '-'); } else { $gantry = self::gantry(); $variables = $gantry['config']->flatten('styles', '-'); } return $variables; } /** * Returns style presets for the theme. * * @return Config */ public function presets() { static $presets; if (!$presets) { $gantry = static::gantry(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $filename = $locator->findResource("gantry-theme://gantry/presets.yaml"); $file = CompiledYamlFile::instance($filename); $presets = new Config($file->content()); $file->free(); } return $presets; } /** * Return name of the used layout preset. * * @return string * @throws \RuntimeException */ public function type() { if (!$this->layoutObject) { throw new \RuntimeException('Function called too early'); } $name = isset($this->layoutObject->preset['name']) ? $this->layoutObject->preset['name'] : 'unknown'; return $name; } /** * Load current layout and its configuration. * * @param string $name * @return Layout * @throws \LogicException */ public function loadLayout($name = null) { if (!$name) { try { $name = static::gantry()['configuration']; } catch (\Exception $e) { throw new \LogicException('Gantry: Outline has not been defined yet', 500); } } if (!isset($this->layoutObject) || $this->layoutObject->name != $name) { $layout = Layout::instance($name); if (!$layout->exists()) { $layout = Layout::instance('default'); } // TODO: Optimize $this->layoutObject = $layout->init(); } return $this->layoutObject; } /** * Check whether layout has content bock. * * @return bool */ public function hasContent() { $layout = $this->loadLayout(); $content = $layout->referencesByType('system', 'content'); return !empty($content); } /** * Load atoms and assets from the page settings. * * @since 5.4.9 */ public function loadAtoms() { if (!isset($this->atoms)) { $this->atoms = true; GANTRY_DEBUGGER && \Gantry\Debugger::startTimer('atoms', "Preparing atoms"); $gantry = static::gantry(); /** @var Config $config */ $config = $gantry['config']; /** @var \Gantry\Framework\Document $document */ $document = $gantry['document']; $atoms = (array) $config->get('page.head.atoms'); foreach ($atoms as $data) { $atom = [ 'type' => 'atom', 'subtype' => $data['type'], ] + $data; try { $block = $this->getContent($atom); $document->addBlock($block); } catch (\Exception $e) { if ($gantry->debug()) { throw new \RuntimeException("Rendering Atom '{$atom['subtype']}' failed on error: {$e->getMessage()}", 500, $e); } } } $assets = (array) $config->get('page.assets'); if ($assets) { $atom = [ 'id' => 'page-assets', 'title' => 'Page Assets', 'type' => 'atom', 'subtype' => 'assets', 'attributes' => $assets + ['enabled' => 1] ]; try { $block = $this->getContent($atom); $document->addBlock($block); } catch (\Exception $e) { if ($gantry->debug()) { throw new \RuntimeException("Rendering CSS/JS Assets failed on error: {$e->getMessage()}", 500, $e); } } } GANTRY_DEBUGGER && \Gantry\Debugger::stopTimer('atoms'); } } /** * Returns all non-empty segments from the layout. * * @return array */ public function segments() { if (!isset($this->segments)) { $this->segments = $this->loadLayout()->toArray(); GANTRY_DEBUGGER && \Gantry\Debugger::startTimer('segments', "Preparing layout"); $this->prepareLayout($this->segments); GANTRY_DEBUGGER && \Gantry\Debugger::stopTimer('segments'); } return $this->segments; } /** * Prepare layout for rendering. Initializes all CSS/JS in particles. */ public function prepare() { $this->segments(); } /** * Returns details of the theme. * * @return ThemeDetails */ public function details() { if (!$this->details) { $this->details = new ThemeDetails($this->name); } return $this->details; } /** * Returns configuration of the theme. * * @return array */ public function configuration() { return (array) $this->details()['configuration']; } /** * Function to convert block sizes into CSS classes. * * @param $text * @return string */ public function toGrid($text) { if (!$text) { return ''; } $number = round($text, 1); $number = max(5, $number); $number = (string) ($number == 100 ? 100 : min(95, $number)); static $sizes = array( '33.3' => 'size-33-3', '16.7' => 'size-16-7', '14.3' => 'size-14-3', '12.5' => 'size-12-5', '11.1' => 'size-11-1', '9.1' => 'size-9-1', '8.3' => 'size-8-3' ); return isset($sizes[$number]) ? ' ' . $sizes[$number] : 'size-' . (int) $number; } /** * Magic setter method * * @param mixed $offset Asset name value * @param mixed $value Asset value */ public function __set($offset, $value) { if ($offset == 'title') { $offset = 'name'; } $this->details()->offsetSet('details.' . $offset, $value); } /** * Magic getter method * * @param mixed $offset Asset name value * @return mixed Asset value */ public function __get($offset) { if ($offset == 'title') { $offset = 'name'; } $value = $this->details()->offsetGet('details.' . $offset); if ($offset == 'version' && is_int($value)) { $value .= '.0'; } return $value; } /** * Magic method to determine if the attribute is set * * @param mixed $offset Asset name value * @return boolean True if the value is set */ public function __isset($offset) { if ($offset == 'title') { $offset = 'name'; } return $this->details()->offsetExists('details.' . $offset); } /** * Magic method to unset the attribute * * @param mixed $offset The name value to unset */ public function __unset($offset) { if ($offset == 'title') { $offset = 'name'; } $this->details()->offsetUnset('details.' . $offset); } /** * Prepare layout by loading all the positions and particles. * * Action is needed before displaying the layout as it recalculates block widths based on the visible content. * * @param array $items * @param bool $temporary * @param bool $sticky * @internal */ protected function prepareLayout(array &$items, $temporary = false, $sticky = false) { foreach ($items as $i => &$item) { // Non-numeric items are meta-data which should be ignored. if (((string)(int) $i !== (string) $i) || !is_object($item)) { continue; } if (!empty($item->children)) { $fixed = true; foreach ($item->children as $child) { $fixed &= !empty($child->attributes->fixed); } $this->prepareLayout($item->children, $fixed, $temporary); } // TODO: remove hard coded types. switch ($item->type) { case 'system': break; case 'atom': case 'particle': case 'position': case 'spacer': GANTRY_DEBUGGER && \Gantry\Debugger::startTimer($item->id, "Rendering {$item->id}"); $item->content = $this->renderContent($item, ['prepare_layout' => true]); // Note that content can also be null (postpone rendering). if ($item->content === '') { unset($items[$i]); } GANTRY_DEBUGGER && \Gantry\Debugger::stopTimer($item->id); break; default: if ($sticky) { $item->attributes->sticky = 1; break; } if (empty($item->children)) { unset($items[$i]); break; } $dynamicSize = 0; $fixedSize = 0; $childrenCount = count($item->children); foreach ($item->children as $child) { if (!isset($child->attributes->size)) { $child->attributes->size = 100 / count($item->children); } if (empty($child->attributes->fixed)) { $dynamicSize += $child->attributes->size; } else { $fixedSize += $child->attributes->size; } } $roundSize = round($dynamicSize, 1); $equalized = isset($this->equalized[$childrenCount]) ? $this->equalized[$childrenCount] : 0; // force-casting string for testing comparison due to weird PHP behavior that returns wrong result if ($roundSize != 100 && (string) $roundSize != (string) ($equalized * $childrenCount)) { $fraction = 0; $multiplier = (100 - $fixedSize) / ($dynamicSize ?: 1); foreach ($item->children as $child) { if (!empty($child->attributes->fixed)) { continue; } // Calculate size for the next item by taking account the rounding error from the last item. // This will allow us to approximate cumulating error and fix it when rounding error grows // over the rounding treshold. $size = ($child->attributes->size * $multiplier) + $fraction; $newSize = round($size); $fraction = $size - $newSize; $child->attributes->size = $newSize; } } } } } /** * Renders individual content block, like particle or position. * * Function is used to pre-render content. * * @param object|array $item * @param array $options * @return string|null */ public function renderContent($item, $options = []) { $gantry = static::gantry(); $content = $this->getContent($item, $options); /** @var Document $document */ $document = $gantry['document']; $document->addBlock($content); $html = $content->toString(); return !strstr($html, '@@DEFERRED@@') ? $html : null; } /** * Renders individual content block, like particle or position. * * Function is used to pre-render content. * * @param object|array $item * @param array $options * @return ContentBlock * @since 5.4.3 */ public function getContent($item, $options = []) { if (is_array($item)) { $item = (object) $item; } $gantry = static::gantry(); /** @var Config $global */ $global = $gantry['global']; $production = (bool) $global->get('production'); $subtype = $item->subtype; $enabled = $gantry['config']->get("particles.{$subtype}.enabled", 1); if (!$enabled) { return new HtmlBlock; } $attributes = isset($item->attributes) ? $item->attributes : []; $particle = $gantry['config']->getJoined("particles.{$subtype}", $attributes); $cached = false; $cacheKey = []; // Enable particle caching only in production mode. if ($production && isset($particle['caching'])) { $caching = $particle['caching'] + ['type' => 'dynamic']; switch ($caching['type']) { case 'static': $cached = true; break; case 'config_matches': if (isset($particle['caching']['values'])) { $values = (array) $particle['caching']['values']; $compare = array_intersect_key($particle, $values); $cached = ($values === $compare); } break; case 'menu': /** @var Menu $menu */ $menu = $gantry['menu']; $cacheId = $menu->getCacheId(); // FIXME: menu caching needs to handle dynamic modules inside menu: turning it off for now. if (false && $cacheId !== null) { $cached = true; $cacheKey['menu_cache_key'] = $cacheId; } break; } } if ($cached) { $cacheKey['language'] = $gantry['page']->language; $cacheKey['attributes'] = $particle; $cacheKey += (array) $item; /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $key = md5(json_encode($cacheKey)); $filename = $locator->findResource("gantry-cache://theme/html/{$key}.php", true, true); $file = PhpFile::instance($filename); if ($file->exists()) { try { return ContentBlock::fromArray((array) $file->content()); } catch (\Exception $e) { // Invalid cache, continue to rendering. GANTRY_DEBUGGER && \Gantry\Debugger::addMessage(sprintf('Failed to load %s %s cache', $item->type, $item->id), 'debug'); } } } // Create new document context for assets. $context = $this->getContext(['segment' => $item, 'enabled' => 1, 'particle' => $particle] + $options); /** @var Document $document */ $document = $gantry['document']; $document->push(); $html = trim($this->render("@nucleus/content/{$item->type}.html.twig", $context)); $content = $document->pop()->setContent($html); if (isset($file)) { // Save HTML and assets into the cache. GANTRY_DEBUGGER && \Gantry\Debugger::addMessage(sprintf('Caching %s %s', $item->type, $item->id), 'debug'); $file->save($content->toArray()); } return $content; } } classes/Gantry/Component/Remote/Response.php 0000604 00000015615 15075035624 0015164 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Remote; class Response { /** * The callback for the progress * * @var callable Either a function or callback in array notation */ public static $callback = null; /** * Which method to use for HTTP calls, can be 'curl', 'fopen' or 'auto'. Auto is default and fopen is the preferred method * * @var string */ private static $method = 'auto'; /** * Default parameters for `curl` and `fopen` * * @var array */ private static $defaults = [ 'curl' => [ CURLOPT_REFERER => 'Gantry5 Response', CURLOPT_USERAGENT => 'Gantry5 Response', CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_TIMEOUT => 15, CURLOPT_HEADER => false, /** * Example of callback parameters from within your own class */ //CURLOPT_NOPROGRESS => false, //CURLOPT_PROGRESSFUNCTION => [$this, 'progress'] ], 'fopen' => [ 'method' => 'GET', 'user_agent' => 'Gantry5 Response', 'max_redirects' => 5, 'follow_location' => 1, 'timeout' => 15, /** * Example of callback parameters from within your own class */ //'notification' => [$this, 'progress'] ] ]; /** * Sets the preferred method to use for making HTTP calls. * * @param string $method Default is `auto` * * @return Response */ public static function setMethod($method = 'auto') { if (!in_array($method, ['auto', 'curl', 'fopen'])) { $method = 'auto'; } self::$method = $method; return new self(); } /** * Makes a request to the URL by using the preferred method * * @param string $uri URL to call * @param array $options An array of parameters for both `curl` and `fopen` * @param callable $callback * * @return string The response of the request */ public static function get($uri = '', $options = [], $callback = null) { if (!self::isCurlAvailable() && !self::isFopenAvailable()) { throw new \RuntimeException('Could not start an HTTP request. `allow_url_open` is disabled and `cURL` is not available'); } $options = array_replace_recursive(self::$defaults, $options); $method = 'get' . ucfirst(strtolower(self::$method)); self::$callback = $callback; return static::$method($uri, $options, $callback); } /** * Checks if cURL is available * * @return boolean */ public static function isCurlAvailable() { return function_exists('curl_version'); } /** * Checks if the remote fopen request is enabled in PHP * * @return boolean */ public static function isFopenAvailable() { return preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen')); } /** * Progress normalized for cURL and fopen * * @return array Normalized array with useful data. * Format: ['code' => int|false, 'filesize' => bytes, 'transferred' => bytes, 'percent' => int] */ public static function progress() { static $filesize = null; $args = func_get_args(); $isCurlResource = is_resource($args[0]) && get_resource_type($args[0]) == 'curl'; $notification_code = !$isCurlResource ? $args[0] : false; $bytes_transferred = $isCurlResource ? $args[2] : $args[4]; if ($isCurlResource) { $filesize = $args[1]; } elseif ($notification_code == STREAM_NOTIFY_FILE_SIZE_IS) { $filesize = $args[5]; } if ($bytes_transferred > 0) { if ($notification_code == STREAM_NOTIFY_PROGRESS | STREAM_NOTIFY_COMPLETED || $isCurlResource) { $progress = [ 'code' => $notification_code, 'filesize' => $filesize, 'transferred' => $bytes_transferred, 'percent' => $filesize <= 0 ? '-' : round(($bytes_transferred * 100) / $filesize, 1) ]; if (self::$callback !== null) { call_user_func_array(self::$callback, [$progress]); } } } } /** * Automatically picks the preferred method * * @return string The response of the request */ private static function getAuto() { if (self::isFopenAvailable()) { return self::getFopen(func_get_args()); } if (self::isCurlAvailable()) { return self::getCurl(func_get_args()); } return ''; } /** * Starts a HTTP request via fopen * * @return string The response of the request */ private static function getFopen() { if (count($args = func_get_args()) == 1) { $args = $args[0]; } $uri = $args[0]; $options = $args[1]; $callback = $args[2]; if ($callback) { $options['fopen']['notification'] = ['self', 'progress']; } $stream = stream_context_create(['http' => $options['fopen']], $options['fopen']); $content = @file_get_contents($uri, false, $stream); if ($content === false) { throw new \RuntimeException("Error while trying to download '$uri'"); } return $content; } /** * Starts a HTTP request via cURL * * @return string The response of the request */ private static function getCurl() { $args = func_get_args(); $args = count($args) > 1 ? $args : array_shift($args); $uri = $args[0]; $options = $args[1]; $callback = $args[2]; $ch = curl_init($uri); curl_setopt_array($ch, $options['curl']); if ($callback) { curl_setopt_array( $ch, [ CURLOPT_NOPROGRESS => false, CURLOPT_PROGRESSFUNCTION => ['self', 'progress'] ] ); } $response = curl_exec($ch); if ($errno = curl_errno($ch)) { $error_message = curl_strerror($errno); throw new \RuntimeException("cURL error ({$errno}):\n {$error_message}"); } curl_close($ch); return $response; } } classes/Gantry/Component/Response/JsonResponse.php 0000604 00000007147 15075035624 0016362 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Response; class JsonResponse extends Response { public $mimeType = 'application/json'; protected $success = true; protected $message; protected $exceptions = []; protected $messages = []; protected $content = []; /** * @param string $content * @param bool $success * @return $this */ public function setContent($content, $success = true) { $this->success = (bool) $success; if (is_array($content)) { foreach ($content as $key => $value) { $this->parseValue($key, $value); } } else { $this->parseValue(null, $content); } return $this; } /** * @return string */ public function __toString() { // Empty output buffer to make sure that the response is clean and valid. while (($output = ob_get_clean()) !== false) { // In debug mode send also output buffers (debug dumps, PHP notices and warnings). if ($output && (GANTRY5_DEBUG || headers_sent())) { $this->messages['php'][] = $output; } } $json = [ 'code' => $this->code, 'success' => $this->success ]; if ($this->messages) { $json['messages'] = $this->messages; } if ($this->exceptions) { $json['exceptions'] = $this->exceptions; } if (GANTRY5_DEBUG) { $json['memory'] = ['peak' => memory_get_peak_usage(), 'current' => memory_get_usage()]; } $json += $this->content; return (string) json_encode($json); } protected function parseValue($key, $value) { if ($value instanceof \Exception) { // Prepare the error response if we are dealing with an error. $this->success = false; $this->exceptions = $this->parseException($value); } elseif ($value instanceof HtmlResponse) { // Add HTML response (numeric keys are always integers). $key = !$key || is_int($key) ? 'html' : $key; $this->content[$key] = trim((string) $value); } elseif (is_null($key)) { // If the returned value was not an array, put the contents into data variable. $this->content['data'] = $value; } elseif (is_int($key)) { // If the key was an integer, also put the contents into data variable. $this->content['data'][$key] = $value; } else { $this->content[$key] = $value; } } protected function parseException(\Exception $e) { $this->code = $e->getCode(); // Build data from exceptions. $exceptions = []; do { $exception = [ 'code' => $e->getCode(), 'message' => $e->getMessage() ]; if (GANTRY5_DEBUG) { $exception += [ 'type' => get_class($e), 'file' => $e->getFile(), 'line' => $e->getLine() ]; } $exceptions[] = $exception; $e = $e->getPrevious(); } while (GANTRY5_DEBUG && $e); return $exceptions; } } classes/Gantry/Component/Response/HtmlResponse.php 0000604 00000000701 15075035624 0016342 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Response; class HtmlResponse extends Response { } classes/Gantry/Component/Response/Response.php 0000604 00000010313 15075035624 0015515 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Response; class Response { public $charset = 'utf-8'; public $mimeType = 'text/html'; protected $code = 200; protected $message = 'OK'; protected $lifetime = 0; protected $etag; /** * @var array Response headers. */ protected $headers = []; /** * @var string Response body. */ protected $content; protected $responseCodes = [ 200 => 'OK', 400 => 'Bad Request', 401 => 'Unauthorized', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 410 => 'Gone', 500 => 'Internal Server Error', 501 => 'Not Implemented', 503 => 'Service Temporarily Unavailable' ]; public function __construct($content = '', $status = 200) { if ($content) { $this->setContent($content); } if ($status != 200) { $this->setStatusCode($status); } } /** * @param int $seconds * @return $this */ public function setLifetime($seconds) { $this->lifetime = $seconds; return $this; } /** * @param mixed $key * @return $this */ public function setKey($key) { $this->etag = md5(json_encode($key)); return $this; } /** * @return int */ public function getStatusCode() { return $this->code; } /** * @param int $code * @param string $message * @return $this */ public function setStatusCode($code, $message = null) { if ($message) { $this->code = $code; $this->message = $message; } else { $this->code = isset($this->responseCodes[$code]) ? (int) $code : 500; $this->message = $this->responseCodes[$this->code]; } return $this; } /** * @return string */ public function getStatus() { $code = $this->getStatusCode(); return $code . ' ' . (isset($this->responseCodes[$code]) ? $this->responseCodes[$code] : 'Unknown error'); } /** * @return array */ public function getHeaders() { return $this->headers; } /** * @param array $headers * @param bool $replace * @return $this */ public function setHeaders(array $headers, $replace = false) { foreach ($headers as $key => $values) { $act = $replace; foreach ((array) $values as $value) { $this->setHeader($key, $value, $act); $act = false; } } return $this; } /** * @return $this */ public function clearHeaders() { $this->headers = []; return $this; } /** * @param $name * @param $value * @param bool $replace * @return $this */ public function setHeader($name, $value, $replace = false) { if ($replace) { $this->headers[$name] = [$value]; } else { $this->headers[$name][] = $value; } return $this; } /** * @return string */ public function getContent() { return (string) $this->content; } /** * @param string $content * @return Response * @throws \UnexpectedValueException */ public function setContent($content) { if ($content !== null && !is_string($content) && !is_numeric($content) && !is_callable([$content, '__toString'])) { throw new \UnexpectedValueException( sprintf('Content must be a string or object implementing __toString()') ); } $this->content = $content; return $this; } /** * @return string */ public function __toString() { return (string) $this->content; } } classes/Gantry/Component/Response/RedirectResponse.php 0000604 00000001467 15075035624 0017211 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Response; class RedirectResponse extends Response { public function __construct($content = '', $status = 303) { parent::__construct('', $status); $this->setHeader('Location', $content); } public function getContent() { return (string) $this->getHeaders()['Location']; } public function setContent($content) { $this->setHeader('Location', $content); } } classes/Gantry/Component/Twig/TwigCacheFilesystem.php 0000604 00000005435 15075035624 0016747 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig; /** * Class TwigCacheFilesystem * @package Gantry\Component\Twig * * Replaces \Twig_Cache_Filesystem, needed for being able to change PHP versions on fly. */ class TwigCacheFilesystem implements \Twig_CacheInterface { const FORCE_BYTECODE_INVALIDATION = 1; private $directory; private $options; /** * @param $directory string The root cache directory * @param $options int A set of options */ public function __construct($directory, $options = 0) { $this->directory = rtrim($directory, '\/').'/'; $this->options = $options; } /** * {@inheritdoc} */ public function generateKey($name, $className) { $hash = hash('sha256', $className . '-' . PHP_VERSION); return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php'; } /** * {@inheritdoc} */ public function load($key) { @include_once $key; } /** * {@inheritdoc} */ public function write($key, $content) { $dir = dirname($key); if (!is_dir($dir)) { if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { throw new \RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir)); } } elseif (!is_writable($dir)) { throw new \RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir)); } $tmpFile = tempnam($dir, basename($key)); if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) { @chmod($key, 0666 & ~umask()); if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) { // Compile cached file into bytecode cache if (function_exists('opcache_invalidate')) { // Silence error in case if `opcache.restrict_api` directive is set. @opcache_invalidate($key, true); } elseif (function_exists('apc_compile_file')) { @apc_compile_file($key); } } return; } throw new \RuntimeException(sprintf('Failed to write cache file "%s".', $key)); } /** * {@inheritdoc} */ public function getTimestamp($key) { if (!file_exists($key)) { return 0; } return (int) @filemtime($key); } } classes/Gantry/Component/Twig/Node/TwigNodeAssets.php 0000604 00000004267 15075035624 0016636 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodeAssets extends \Twig_Node implements \Twig_NodeCaptureInterface { protected $tagName = 'assets'; public function __construct(\Twig_Node $body = null, \Twig_Node_Expression $location = null, \Twig_Node_Expression $variables = null, $lineno = 0, $tag = null) { parent::__construct(['body' => $body, 'location' => $location, 'variables' => $variables], [], $lineno, $tag); } /** * Compiles the node to PHP. * * @param \Twig_Compiler $compiler A Twig_Compiler instance */ public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this) ->write("\$assetFunction = \$this->env->getFunction('parse_assets')->getCallable();\n") ->write('$assetVariables = ') ->subcompile($this->getNode('variables')) ->raw(";\n") ->write("if (\$assetVariables && !is_array(\$assetVariables)) {\n") ->indent() ->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');\n") ->outdent() ->write("}\n") ->write('$location = ') ->subcompile($this->getNode('location')) ->raw(";\n") ->write("if (\$location && !is_string(\$location)) {\n") ->indent() ->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');\n") ->outdent() ->write("}\n") ->write("\$priority = isset(\$assetVariables['priority']) ? \$assetVariables['priority'] : 0;\n") ->write("ob_start();\n") ->subcompile($this->getNode('body')) ->write("\$content = ob_get_clean();\n") ->write("\$assetFunction(\$content, \$location, \$priority);\n"); } } classes/Gantry/Component/Twig/Node/TwigNodeTryCatch.php 0000604 00000003233 15075035624 0017105 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodeTryCatch extends \Twig_Node { public function __construct(\Twig_Node $try, \Twig_Node $catch = null, $lineno = 0, $tag = null) { parent::__construct(array('try' => $try, 'catch' => $catch), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param \Twig_Compiler $compiler A Twig_Compiler instance */ public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this); $compiler ->write('try {') ; $compiler ->indent() ->subcompile($this->getNode('try')) ; if ($this->hasNode('catch') && null !== $this->getNode('catch')) { $compiler ->outdent() ->write('} catch (\Exception $e) {' . "\n") ->indent() ->write('if ($context[\'gantry\']->debug()) throw $e;' . "\n") ->write('GANTRY_DEBUGGER && method_exists(\'Gantry\\Debugger\', \'addException\') && \Gantry\Debugger::addException($e);' . "\n") ->write('$context[\'e\'] = $e;' . "\n") ->subcompile($this->getNode('catch')) ; } $compiler ->outdent() ->write("}\n"); } } classes/Gantry/Component/Twig/Node/TwigNodePageblock.php 0000604 00000004226 15075035624 0017256 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodePageblock extends \Twig_Node implements \Twig_NodeCaptureInterface { protected $tagName = 'pageblock'; public function __construct(\Twig_Node $body = null, \Twig_Node_Expression $location = null, \Twig_Node_Expression $variables = null, $lineno = 0, $tag = null) { parent::__construct(['body' => $body, 'location' => $location, 'variables' => $variables], [], $lineno, $tag); } /** * Compiles the node to PHP. * * @param \Twig_Compiler $compiler A Twig_Compiler instance */ public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this) ->write('$pageblockVariables = ') ->subcompile($this->getNode('variables')) ->raw(";\n") ->write("if (\$pageblockVariables && !is_array(\$pageblockVariables)) {\n") ->indent() ->write("throw new UnexpectedValueException('{% {$this->tagName} with x %}: x is not an array');\n") ->outdent() ->write("}\n") ->write('$location = ') ->subcompile($this->getNode('location')) ->raw(";\n") ->write("if (\$location && !is_string(\$location)) {\n") ->indent() ->write("throw new UnexpectedValueException('{% {$this->tagName} in x %}: x is not a string');\n") ->outdent() ->write("}\n") ->write("\$priority = isset(\$pageblockVariables['priority']) ? \$pageblockVariables['priority'] : 0;\n") ->write("ob_start();\n") ->subcompile($this->getNode('body')) ->write("\$content = ob_get_clean();\n") ->write("Gantry\Framework\Gantry::instance()['document']->addHtml(\$content, \$priority, \$location);\n"); } } classes/Gantry/Component/Twig/Node/TwigNodeMarkdown.php 0000604 00000002701 15075035624 0017145 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodeMarkdown extends \Twig_Node implements \Twig_NodeOutputInterface { public function __construct(\Twig_Node $body, $lineno, $tag = 'markdown') { parent::__construct(['body' => $body], [], $lineno, $tag); } /** * Compiles the node to PHP. * * @param \Twig_Compiler A Twig_Compiler instance */ public function compile(\Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write('ob_start();' . PHP_EOL) ->subcompile($this->getNode('body')) ->write('$content = ob_get_clean();' . PHP_EOL) ->write('preg_match("/^\s*/", $content, $matches);' . PHP_EOL) ->write('$lines = explode("\n", $content);' . PHP_EOL) ->write('$content = preg_replace(\'/^\' . $matches[0]. \'/\', "", $lines);' . PHP_EOL) ->write('$content = join("\n", $content);' . PHP_EOL) ->write('echo $this->env->getExtension(\'Gantry\Component\Twig\TwigExtension\')->markdownFunction($content);' . PHP_EOL); } } classes/Gantry/Component/Twig/Node/TwigNodeScripts.php 0000604 00000000757 15075035624 0017023 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodeScripts extends TwigNodeAssets { protected $tagName = 'scripts'; } classes/Gantry/Component/Twig/Node/TwigNodeThrow.php 0000604 00000002221 15075035624 0016463 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodeThrow extends \Twig_Node { public function __construct( $code, \Twig_Node $message, $lineno = 0, $tag = null ) { parent::__construct(['message' => $message], ['code' => $code], $lineno, $tag); } /** * Compiles the node to PHP. * * @param \Twig_Compiler $compiler A Twig_Compiler instance * @throws \LogicException */ public function compile(\Twig_Compiler $compiler) { $compiler->addDebugInfo($this); $compiler ->write('throw new \RuntimeException(') ->subcompile($this->getNode('message')) ->write(', ') ->write($this->getAttribute('code') ?: 500) ->write(");\n"); } } classes/Gantry/Component/Twig/Node/TwigNodeStyles.php 0000604 00000000756 15075035624 0016656 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodeStyles extends TwigNodeScripts { protected $tagName = 'styles'; } classes/Gantry/Component/Twig/Node/TwigNodeSwitch.php 0000604 00000004011 15075035624 0016620 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\Node; class TwigNodeSwitch extends \Twig_Node { public function __construct(\Twig_Node $value, \Twig_Node $cases, \Twig_Node $default = null, $lineno = 0, $tag = null) { parent::__construct(array('value' => $value, 'cases' => $cases, 'default' => $default), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param \Twig_Compiler A Twig_Compiler instance */ public function compile(\Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write('switch (') ->subcompile($this->getNode('value')) ->raw(") {\n") ->indent(); foreach ($this->getNode('cases') as $case) { if (!$case->hasNode('body')) { continue; } foreach ($case->getNode('values') as $value) { $compiler ->write('case ') ->subcompile($value) ->raw(":\n"); } $compiler ->write("{\n") ->indent() ->subcompile($case->getNode('body')) ->write("break;\n") ->outdent() ->write("}\n"); } if ($this->hasNode('default') && $this->getNode('default') !== null) { $compiler ->write("default:\n") ->write("{\n") ->indent() ->subcompile($this->getNode('default')) ->outdent() ->write("}\n"); } $compiler ->outdent() ->write("}\n"); } } classes/Gantry/Component/Twig/TwigExtension.php 0000604 00000050657 15075035625 0015662 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig; use Gantry\Component\Content\Document\HtmlDocument; use Gantry\Component\Gantry\GantryTrait; use Gantry\Component\Translator\TranslatorInterface; use Gantry\Component\Twig\TokenParser\TokenParserPageblock; use Gantry\Component\Twig\TokenParser\TokenParserAssets; use Gantry\Component\Twig\TokenParser\TokenParserScripts; use Gantry\Component\Twig\TokenParser\TokenParserStyles; use Gantry\Component\Twig\TokenParser\TokenParserTryCatch; use Gantry\Component\Twig\TokenParser\TokenParserMarkdown; use Gantry\Component\Twig\TokenParser\TokenParserSwitch; use Gantry\Component\Twig\TokenParser\TokenParserThrow; use Gantry\Framework\Gantry; use Gantry\Framework\Markdown\Parsedown; use Gantry\Framework\Markdown\ParsedownExtra; use Gantry\Framework\Request; use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess; class TwigExtension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface { use GantryTrait; /** * Register some standard globals * * @return array */ public function getGlobals() { return [ 'gantry' => static::gantry(), ]; } /** * Return a list of all filters. * * @return array */ public function getFilters() { $filters = [ new \Twig_SimpleFilter('html', [$this, 'htmlFilter']), new \Twig_SimpleFilter('url', [$this, 'urlFunc']), new \Twig_SimpleFilter('trans_key', [$this, 'transKeyFilter']), new \Twig_SimpleFilter('trans', [$this, 'transFilter']), new \Twig_SimpleFilter('repeat', [$this, 'repeatFilter']), new \Twig_SimpleFilter('values', [$this, 'valuesFilter']), new \Twig_SimpleFilter('base64', 'base64_encode'), new \Twig_SimpleFilter('imagesize', [$this, 'imageSize']), new \Twig_SimpleFilter('truncate_text', [$this, 'truncateText']), new \Twig_SimpleFilter('attribute_array', [$this, 'attributeArrayFilter'], ['is_safe' => ['html']]), ]; if (1 || GANTRY5_PLATFORM !== 'grav') { $filters = array_merge($filters, [ new \Twig_SimpleFilter('fieldName', [$this, 'fieldNameFilter']), new \Twig_SimpleFilter('json_decode', [$this, 'jsonDecodeFilter']), new \Twig_SimpleFilter('truncate_html', [$this, 'truncateHtml']), new \Twig_SimpleFilter('markdown', [$this, 'markdownFunction'], ['is_safe' => ['html']]), new \Twig_SimpleFilter('nicetime', [$this, 'nicetimeFilter']), // Casting values new \Twig_SimpleFilter('string', [$this, 'stringFilter']), new \Twig_SimpleFilter('int', [$this, 'intFilter'], ['is_safe' => ['all']]), new \Twig_SimpleFilter('bool', [$this, 'boolFilter']), new \Twig_SimpleFilter('float', [$this, 'floatFilter'], ['is_safe' => ['all']]), new \Twig_SimpleFilter('array', [$this, 'arrayFilter']), ]); } return $filters; } /** * Return a list of all functions. * * @return array */ public function getFunctions() { $functions = [ new \Twig_SimpleFunction('nested', [$this, 'nestedFunc']), new \Twig_SimpleFunction('parse_assets', [$this, 'parseAssetsFunc']), new \Twig_SimpleFunction('colorContrast', [$this, 'colorContrastFunc']), new \Twig_SimpleFunction('get_cookie', [$this, 'getCookie']), new \Twig_SimpleFunction('preg_match', [$this, 'pregMatch']), new \Twig_SimpleFunction('imagesize', [$this, 'imageSize']), new \Twig_SimpleFunction('is_selected', [$this, 'is_selectedFunc']), new \Twig_SimpleFunction('url', [$this, 'urlFunc']), ]; if (1 || GANTRY5_PLATFORM !== 'grav') { $functions = array_merge($functions, [ new \Twig_SimpleFunction('array', [$this, 'arrayFilter']), new \Twig_SimpleFunction('json_decode', [$this, 'jsonDecodeFilter']), ]); } return $functions; } /** * @return array */ public function getTokenParsers() { return [ new TokenParserPageblock(), new TokenParserAssets(), new TokenParserScripts(), new TokenParserStyles(), new TokenParserThrow(), new TokenParserTryCatch(), new TokenParserMarkdown(), new TokenParserSwitch() ]; } /** * Filters field name by changing dot notation into array notation. * * @param string $str * @return string */ public function fieldNameFilter($str) { $path = explode('.', $str); return array_shift($path) . ($path ? '[' . implode('][', $path) . ']' : ''); } /** * Translate by using key, default on original string. * * @param $str * @return string */ public function transKeyFilter($str) { $params = \func_get_args(); array_shift($params); $key = preg_replace('|[^A-Z0-9]+|', '_', strtoupper(implode('_', $params))); $translation = $this->transFilter($key); return $translation === $key ? $str : $translation; } /** * Translate string. * * @param string $str * @return string */ public function transFilter($str) { /** @var TranslatorInterface $translator */ static $translator; $params = \func_get_args(); if (!$translator) { $translator = self::gantry()['translator']; } return \call_user_func_array([$translator, 'translate'], $params); } /** * Repeat string x times. * * @param string $str * @param int $count * @return string */ public function repeatFilter($str, $count) { return str_repeat($str, max(0, (int) $count)); } /** * Decodes string from JSON. * * @param string $str * @param bool $assoc * @param int $depth * @param int $options * @return array */ public function jsonDecodeFilter($str, $assoc = false, $depth = 512, $options = 0) { return json_decode(html_entity_decode($str), $assoc, $depth, $options); } public function imageSize($src, $attrib = true, $remote = false) { // TODO: need to better handle absolute and relative paths //$url = Gantry::instance()['document']->url(trim((string) $src), false, false); $width = $height = null; $sizes = ['width' => $width, 'height' => $height]; $attr = ''; if (@is_file($src) || $remote) { try { list($width, $height,, $attr) = @getimagesize($src); } catch (\Exception $e) {} $sizes['width'] = $width; $sizes['height'] = $height; } return $attrib ? $attr : $sizes; } /** * Reindexes values in array. * * @param array $array * @return array */ public function valuesFilter(array $array) { return array_values($array); } /** * Casts input to string. * * @param mixed $input * @return string */ public function stringFilter($input) { return (string) $input; } /** * Casts input to int. * * @param mixed $input * @return int */ public function intFilter($input) { return (int) $input; } /** * Casts input to bool. * * @param mixed $input * @return bool */ public function boolFilter($input) { return (bool) $input; } /** * Casts input to float. * * @param mixed $input * @return float */ public function floatFilter($input) { return (float) $input; } /** * Casts input to array. * * @param mixed $input * @return array */ public function arrayFilter($input) { return (array) $input; } /** * Takes array of attribute keys and values and converts it to properly escaped HTML attributes. * * @example ['data-id' => 'id', 'data-key' => 'key'] => ' data-id="id" data-key="key"' * @example [['data-id' => 'id'], ['data-key' => 'key']] => ' data-id="id" data-key="key"' * * @param string|string[] $input * @return string */ public function attributeArrayFilter($input) { if (\is_string($input)) { return $input; } $array = []; foreach ((array) $input as $key => $value) { if (\is_array($value)) { foreach ((array) $value as $key2 => $value2) { $array[] = HtmlDocument::escape($key2) . '="' . HtmlDocument::escape($value2, 'html_attr') . '"'; } } elseif ($key) { $array[] = HtmlDocument::escape($key) . '="' . HtmlDocument::escape($value, 'html_attr') . '"'; } } return $array ? ' ' . implode(' ', $array) : ''; } public function is_selectedFunc($a, $b) { $b = (array) $b; array_walk( $b, function (&$item) { if (\is_bool($item)) { $item = (int) $item; } $item = (string) $item; } ); return \in_array((string) $a, $b, true); } /** * Truncate text by number of characters but can cut off words. Removes html tags. * * @param string $string * @param int $limit Max number of characters. * * @return string */ public function truncateText($string, $limit = 150) { $platform = Gantry::instance()['platform']; return $platform->truncate($string, (int) $limit, false); } /** * Truncate text by number of characters but can cut off words. * * @param string $string * @param int $limit Max number of characters. * * @return string */ public function truncateHtml($string, $limit = 150) { $platform = Gantry::instance()['platform']; return $platform->truncate($string, (int) $limit, true); } /** * @param string $string * @param bool $block Block or Line processing * @param array $settings * @return mixed|string */ public function markdownFunction($string, $block = true, array $settings = null) { // Initialize the preferred variant of Parsedown if ($settings['extra']) { $parsedown = new ParsedownExtra($settings); } else { $parsedown = new Parsedown($settings); } if ($block) { $string = $parsedown->text($string); } else { $string = $parsedown->line($string); } return $string; } /** * Get value by using dot notation for nested arrays/objects. * * @example {{ nested(array, 'this.is.my.nested.variable')|json_encode }} * * @param array $items Array of items. * @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 nestedFunc($items, $name, $default = null, $separator = '.') { if ($items instanceof NestedArrayAccess) { return $items->get($name, $default, $separator); } $path = explode($separator, $name); $current = $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; } /** * Return URL to the resource. * * @example {{ url('theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4') }} * * @param string $input Resource to be located. * @param bool $domain True to include domain name. * @param int $timestamp_age Append timestamp to files that are less than x seconds old. Defaults to a week. * Use value <= 0 to disable the feature. * @return string|null Returns url to the resource or null if resource was not found. */ public function urlFunc($input, $domain = false, $timestamp_age = null) { $gantry = Gantry::instance(); return $gantry['document']->url(trim((string) $input), $domain, $timestamp_age); } /** * Filter stream URLs from HTML input. * * @param string $str HTML input to be filtered. * @param bool $domain True to include domain name. * @param int $timestamp_age Append timestamp to files that are less than x seconds old. Defaults to a week. * Use value <= 0 to disable the feature. * @return string Returns modified HTML. */ public function htmlFilter($str, $domain = false, $timestamp_age = null) { $gantry = Gantry::instance(); return $gantry['document']->urlFilter($str, $domain, $timestamp_age); } /** * @param \libXMLError $error * @param string $input * @throws \RuntimeException */ protected function dealXmlError(\libXMLError $error, $input) { switch ($error->level) { case LIBXML_ERR_WARNING: $level = 1; $message = "DOM Warning {$error->code}: "; break; case LIBXML_ERR_ERROR: $level = 2; $message = "DOM Error {$error->code}: "; break; case LIBXML_ERR_FATAL: $level = 3; $message = "Fatal DOM Error {$error->code}: "; break; default: $level = 3; $message = "Unknown DOM Error {$error->code}: "; } $message .= "{$error->message} while parsing:\n{$input}\n"; if ($level <= 2 && !Gantry::instance()->debug()) { return; } throw new \RuntimeException($message, 500); } /** * Move supported document head elements into platform document object, return all * unsupported tags in a string. * * @param string $input * @param string $location * @param int $priority * @return string */ public function parseAssetsFunc($input, $location = 'head', $priority = 0) { if ($location === 'head') { $scope = 'head'; $html = "<!doctype html>\n<html><head>{$input}</head><body></body></html>"; } else { $scope = 'body'; $html = "<!doctype html>\n<html><head></head><body>{$input}</body></html>"; } libxml_clear_errors(); $internal = libxml_use_internal_errors(true); $doc = new \DOMDocument(); $doc->loadHTML($html); foreach (libxml_get_errors() as $error) { $this->dealXmlError($error, $html); } libxml_clear_errors(); libxml_use_internal_errors($internal); $raw = []; /** @var \DomElement $element */ foreach ($doc->getElementsByTagName($scope)->item(0)->childNodes as $element) { if (empty($element->tagName)) { continue; } $result = ['tag' => $element->tagName, 'content' => $element->textContent]; foreach ($element->attributes as $attribute) { $result[$attribute->name] = $attribute->value; } $success = Gantry::instance()['document']->addHeaderTag($result, $location, (int) $priority); if (!$success) { $raw[] = $doc->saveHTML($element); } } return implode("\n", $raw); } public function colorContrastFunc($value) { $value = str_replace(' ', '', $value); $rgb = new \stdClass; $opacity = 1; if (0 !== strpos($value, 'rgb')) { $value = str_replace('#', '', $value); if (\strlen($value) === 3) { $h0 = str_repeat(substr($value, 0, 1), 2); $h1 = str_repeat(substr($value, 1, 1), 2); $h2 = str_repeat(substr($value, 2, 1), 2); $value = $h0 . $h1 . $h2; } $rgb->r = hexdec(substr($value, 0, 2)); $rgb->g = hexdec(substr($value, 2, 2)); $rgb->b = hexdec(substr($value, 4, 2)); } else { preg_match("/(\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(1\\.|0?\\.?[0-9]?+))?/uim", $value, $matches); $rgb->r = $matches[1]; $rgb->g = $matches[2]; $rgb->b = $matches[3]; $opacity = isset($matches[4]) ? $matches[4] : 1; $opacity = substr($opacity, 0, 1) === '.' ? '0' . $opacity : $opacity; } $yiq = ((($rgb->r * 299) + ($rgb->g * 587) + ($rgb->b * 114)) / 1000) >= 128; $contrast = $yiq || (!$opacity || (float) $opacity < 0.35); return $contrast; } /** * Displays a facebook style 'time ago' formatted date/time. * * @param string|int $date * @param bool $long_strings * * @return string */ public function nicetimeFilter($date, $long_strings = true) { static $lengths = [60, 60, 24, 7, 4.35, 12, 10]; static $periods_long = [ 'GANTRY5_ENGINE_NICETIME_SECOND', 'GANTRY5_ENGINE_NICETIME_MINUTE', 'GANTRY5_ENGINE_NICETIME_HOUR', 'GANTRY5_ENGINE_NICETIME_DAY', 'GANTRY5_ENGINE_NICETIME_WEEK', 'GANTRY5_ENGINE_NICETIME_MONTH', 'GANTRY5_ENGINE_NICETIME_YEAR', 'GANTRY5_ENGINE_NICETIME_DECADE' ]; static $periods_short = [ 'GANTRY5_ENGINE_NICETIME_SEC', 'GANTRY5_ENGINE_NICETIME_MIN', 'GANTRY5_ENGINE_NICETIME_HR', 'GANTRY5_ENGINE_NICETIME_DAY', 'GANTRY5_ENGINE_NICETIME_WK', 'GANTRY5_ENGINE_NICETIME_MO', 'GANTRY5_ENGINE_NICETIME_YR', 'GANTRY5_ENGINE_NICETIME_DEC' ]; if (empty($date)) { return $this->transFilter('GANTRY5_ENGINE_NICETIME_NO_DATE_PROVIDED'); } $periods = $long_strings ? $periods_long : $periods_short; $now = time(); // check if unix timestamp if ((string)(int)$date === (string)$date) { $unix_date = (int)$date; } else { $unix_date = strtotime($date); } // check validity of date if (!$unix_date) { return $this->transFilter('GANTRY5_ENGINE_NICETIME_BAD_DATE'); } // is it future date or past date if ($now > $unix_date) { $difference = $now - $unix_date; $tense = $this->transFilter('GANTRY5_ENGINE_NICETIME_AGO'); } else if ($now === $unix_date) { $difference = $now - $unix_date; $tense = $this->transFilter('GANTRY5_ENGINE_NICETIME_JUST_NOW'); } else { $difference = $unix_date - $now; $tense = $this->transFilter('GANTRY5_ENGINE_NICETIME_FROM_NOW'); } for ($j = 0; $difference >= $lengths[$j] && $j < \count($lengths) - 1; $j++) { $difference /= $lengths[$j]; } $period = $periods[$j]; $difference = round($difference); if ($difference !== 1) { $period .= '_PLURAL'; } $period = $this->transFilter($period); if ($now === $unix_date) { return $tense; } return "{$difference} {$period} {$tense}"; } public function getCookie($name) { $gantry = Gantry::instance(); /** @var Request $request */ $request = $gantry['request']; return $request->cookie[$name]; } public function pregMatch($pattern, $subject, &$matches = []) { preg_match($pattern, $subject, $matches); return $matches ?: false; } } classes/Gantry/Component/Twig/TokenParser/TokenParserTryCatch.php 0000604 00000003514 15075035625 0021175 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; use Gantry\Component\Twig\Node\TwigNodeTryCatch; /** * Handles try/catch in template file. * * <pre> * {% try %} * <li>{{ user.get('name') }}</li> * {% catch %} * {{ e.message }} * {% endcatch %} * </pre> */ class TokenParserTryCatch extends \Twig_TokenParser { /** * Parses a token and returns a node. * * @param \Twig_Token $token A Twig_Token instance * * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); $try = $this->parser->subparse([$this, 'decideCatch']); $stream->next(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); $catch = $this->parser->subparse([$this, 'decideEnd']); $stream->next(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); return new TwigNodeTryCatch($try, $catch, $lineno, $this->getTag()); } public function decideCatch(\Twig_Token $token) { return $token->test(array('catch')); } public function decideEnd(\Twig_Token $token) { return $token->test(array('endtry')) || $token->test(array('endcatch')); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'try'; } } classes/Gantry/Component/Twig/TokenParser/TokenParserMarkdown.php 0000604 00000002767 15075035625 0021247 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; use Gantry\Component\Twig\Node\TwigNodeMarkdown; /** * Adds ability to inline markdown between tags. * * {% markdown %} * This is **bold** and this _underlined_ * * 1. This is a bullet list * 2. This is another item in that same list * {% endmarkdown %} */ class TokenParserMarkdown extends \Twig_TokenParser { /** * {@inheritdoc} */ public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideMarkdownEnd'), true); $this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE); return new TwigNodeMarkdown($body, $lineno, $this->getTag()); } /** * Decide if current token marks end of Markdown block. * * @param \Twig_Token $token * @return bool */ public function decideMarkdownEnd(\Twig_Token $token) { return $token->test('endmarkdown'); } /** * {@inheritdoc} */ public function getTag() { return 'markdown'; } } classes/Gantry/Component/Twig/TokenParser/TokenParserThrow.php 0000604 00000002564 15075035625 0020563 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; use Gantry\Component\Twig\Node\TwigNodeThrow; /** * Handles try/catch in template file. * * <pre> * {% throw 404 'Not Found' %} * </pre> */ class TokenParserThrow extends \Twig_TokenParser { /** * Parses a token and returns a node. * * @param \Twig_Token $token A Twig_Token instance * * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $code = $stream->expect(\Twig_Token::NUMBER_TYPE)->getValue(); $message = $this->parser->getExpressionParser()->parseExpression(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); return new TwigNodeThrow($code, $message, $lineno, $this->getTag()); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'throw'; } } classes/Gantry/Component/Twig/TokenParser/TokenParserPageblock.php 0000604 00000004534 15075035625 0021346 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; use Gantry\Component\Twig\Node\TwigNodePageblock; /** * Adds javascript / style assets to head/footer/custom location. * * {% pageblock in 'bottom' with { priority: 0 } %} * <div>Bottom HTML</div> * {% endpageblock -%} */ class TokenParserPageblock extends \Twig_TokenParser { /** * Parses a token and returns a node. * * @param \Twig_Token $token A Twig_Token instance * * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); list($location, $variables) = $this->parseArguments($token); $content = $this->parser->subparse([$this, 'decideBlockEnd'], true); $stream->expect(\Twig_Token::BLOCK_END_TYPE); return new TwigNodePageblock($content, $location, $variables, $lineno, $this->getTag()); } /** * @param \Twig_Token $token * @return array */ protected function parseArguments(\Twig_Token $token) { $stream = $this->parser->getStream(); $lineno = $token->getLine(); $location = new \Twig_Node_Expression_Constant($stream->expect(\Twig_Token::NAME_TYPE)->getValue(), $lineno); if ($stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) { $variables = $this->parser->getExpressionParser()->parseExpression(); } else { $lineno = $token->getLine(); $variables = new \Twig_Node_Expression_Array([], $lineno); $variables->setAttribute('priority', 0); } $stream->expect(\Twig_Token::BLOCK_END_TYPE); return [$location, $variables]; } public function decideBlockEnd(\Twig_Token $token) { return $token->test('endpageblock'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'pageblock'; } } classes/Gantry/Component/Twig/TokenParser/TokenParserSwitch.php 0000604 00000007354 15075035625 0020723 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; use Gantry\Component\Twig\Node\TwigNodeSwitch; /** * Adds ability use elegant switch instead of ungainly if statements * * {% switch type %} * {% case 'foo' %} * {{ my_data.foo }} * {% case 'bar' %} * {{ my_data.bar }} * {% default %} * {{ my_data.default }} * {% endswitch %} */ class TokenParserSwitch extends \Twig_TokenParser { /** * {@inheritdoc} */ public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $name = $this->parser->getExpressionParser()->parseExpression(); $stream->expect(\Twig_Token::BLOCK_END_TYPE); // There can be some whitespace between the {% switch %} and first {% case %} tag. while ($stream->getCurrent()->getType() === \Twig_Token::TEXT_TYPE && trim($stream->getCurrent()->getValue()) === '') { $stream->next(); } $stream->expect(\Twig_Token::BLOCK_START_TYPE); $expressionParser = $this->parser->getExpressionParser(); $default = null; $cases = []; $end = false; while (!$end) { $next = $stream->next(); switch ($next->getValue()) { case 'case': $values = []; while (true) { $values[] = $expressionParser->parsePrimaryExpression(); // Multiple allowed values? if ($stream->test(\Twig_Token::OPERATOR_TYPE, 'or')) { $stream->next(); } else { break; } } $stream->expect(\Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideIfFork')); $cases[] = new \Twig_Node([ 'values' => new \Twig_Node($values), 'body' => $body ]); break; case 'default': $stream->expect(\Twig_Token::BLOCK_END_TYPE); $default = $this->parser->subparse(array($this, 'decideIfEnd')); break; case 'endswitch': $end = true; break; default: throw new \Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "case", "default", or "endswitch" to close the "switch" block started at line %d)', $lineno), -1); } } $stream->expect(\Twig_Token::BLOCK_END_TYPE); return new TwigNodeSwitch($name, new \Twig_Node($cases), $default, $lineno, $this->getTag()); } /** * Decide if current token marks switch logic. * * @param \Twig_Token $token * @return bool */ public function decideIfFork(\Twig_Token $token) { return $token->test(array('case', 'default', 'endswitch')); } /** * Decide if current token marks end of swtich block. * * @param \Twig_Token $token * @return bool */ public function decideIfEnd(\Twig_Token $token) { return $token->test(array('endswitch')); } /** * {@inheritdoc} */ public function getTag() { return 'switch'; } } classes/Gantry/Component/Twig/TokenParser/TokenParserScripts.php 0000604 00000001731 15075035625 0021102 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; /** * Adds scripts to head/footer/custom location. * * {% scripts in 'head' with { priority: 2 } %} * <script type="text/javascript" src="{{ url('gantry-theme://js/my.js') }}"></script> * {% endscripts -%} */ class TokenParserScripts extends TokenParserAssets { public function decideBlockEnd(\Twig_Token $token) { return $token->test('endscripts'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'scripts'; } } classes/Gantry/Component/Twig/TokenParser/TokenParserStyles.php 0000604 00000001715 15075035625 0020740 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; /** * Adds stylesheets to document. * * {% styles with { priority: 2 } %} * <link rel="stylesheet" href="{{ url('gantry-assets://css/font-awesome.min.css') }}" type="text/css"/> * {% endstyles -%} */ class TokenParserStyles extends TokenParserAssets { public function decideBlockEnd(\Twig_Token $token) { return $token->test('endstyles'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'styles'; } } classes/Gantry/Component/Twig/TokenParser/TokenParserAssets.php 0000604 00000005221 15075035625 0020713 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Twig\TokenParser; use Gantry\Component\Twig\Node\TwigNodeScripts; /** * Adds javascript / style assets to head/footer/custom location. * * {% assets in 'head' with { priority: 2 } %} * <script type="text/javascript" src="{{ url('gantry-theme://js/my.js') }}"></script> * <link rel="stylesheet" href="{{ url('gantry-assets://css/font-awesome.min.css') }}" type="text/css"/> * {% endassets -%} */ class TokenParserAssets extends \Twig_TokenParser { /** * Parses a token and returns a node. * * @param \Twig_Token $token A Twig_Token instance * * @return \Twig_Node A Twig_Node instance */ public function parse(\Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); list($location, $variables) = $this->parseArguments($token); $content = $this->parser->subparse([$this, 'decideBlockEnd'], true); $stream->expect(\Twig_Token::BLOCK_END_TYPE); return new TwigNodeScripts($content, $location, $variables, $lineno, $this->getTag()); } /** * @param \Twig_Token $token * @return array */ protected function parseArguments(\Twig_Token $token) { $stream = $this->parser->getStream(); $location = null; if ($stream->nextIf(\Twig_Token::OPERATOR_TYPE, 'in')) { $location = $this->parser->getExpressionParser()->parseExpression(); } else { $lineno = $token->getLine(); $location = new \Twig_Node_Expression_Constant('head', $lineno); } if ($stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) { $variables = $this->parser->getExpressionParser()->parseExpression(); } else { $lineno = $token->getLine(); $variables = new \Twig_Node_Expression_Array([], $lineno); $variables->setAttribute('priority', 0); } $stream->expect(\Twig_Token::BLOCK_END_TYPE); return [$location, $variables]; } public function decideBlockEnd(\Twig_Token $token) { return $token->test('endassets'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'assets'; } } classes/Gantry/Component/Url/Url.php 0000604 00000007731 15075035625 0013440 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Component\Url; class Url { /** * UTF8 aware parse_url(). * * @param string $url * @param bool $queryArray * @return array|bool */ public static function parse($url, $queryArray = false) { $encodedUrl = preg_replace_callback( '%[^:/@?&=#]+%usD', function ($matches) { return rawurlencode($matches[0]); }, $url ); // PHP versions below 5.4.7 have troubles with URLs without scheme, so lets help by fixing that. // TODO: This is not needed in PHP >= 5.4.7, but for now we need to test if the function works. if ('/' === $encodedUrl[0] && false !== strpos($encodedUrl, '://')) { $schemeless = true; // Fix the path so that parse_url() will not return false. $parts = parse_url('fake://fake.com' . $encodedUrl); // Remove the fake values. unset($parts['scheme'], $parts['host']); } else { $parts = parse_url($encodedUrl); } if (!$parts) { return false; } // PHP versions below 5.4.7 do not understand schemeless URLs starting with // either. if (isset($schemeless) && !isset($parts['host']) && 0 === strpos($encodedUrl, '//')) { // Path is stored in format: //[host]/[path], so let's fix it. list($parts['host'], $path) = explode('/', substr($parts['path'], 2), 2); $parts['path'] = "/{$path}"; } foreach($parts as $name => $value) { $parts[$name] = rawurldecode($value); } // Return query string also as an array if requested. if ($queryArray) { $parts['vars'] = isset($parts['query']) ? static::parseQuery($parts['query']) : []; } return $parts; } /** * Parse query string and return array. * * @param $query * @return mixed */ public static function parseQuery($query) { parse_str($query, $vars); return $vars; } /** * Build parsed URL array. * * @param array $parsed_url * @return string */ public static function build(array $parsed_url) { // Build query string from variables if they are set. if (isset($parsed_url['vars'])) { $parsed_url['query'] = static::buildQuery($parsed_url['vars']); } // Build individual parts of the url. $scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : ''; $host = isset($parsed_url['host']) ? $parsed_url['host'] : ''; $port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''; $user = isset($parsed_url['user']) ? $parsed_url['user'] : ''; $pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : ''; $pass = ($user || $pass) ? "{$pass}@" : ''; $path = isset($parsed_url['path']) ? $parsed_url['path'] : ''; $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : ''; $fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : ''; $scheme = $host && !$scheme ? '//' : $scheme; return "{$scheme}{$user}{$pass}{$host}{$port}{$path}{$query}{$fragment}"; } /** * Build query string from variables. * * @param array $vars * @return null|string */ public static function buildQuery(array $vars) { $list = []; foreach ($vars as $key => $var) { $list[] = $key . '=' . rawurlencode($var); } return $list ? implode('&', $list) : null; } } classes/Gantry/Framework/Configurations.php 0000604 00000000727 15075035625 0015117 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework; /** * @deprecated 5.1.1 */ class Configurations extends Outlines { } classes/Gantry/Framework/Platform.php 0000604 00000041205 15075035625 0013705 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Admin\ThemeList; use Gantry\Component\Filesystem\Folder; use Gantry\Framework\Base\Platform as BasePlatform; use Gantry\Joomla\Category\CategoryFinder; use Gantry\Joomla\Content\Content; use Gantry\Joomla\Content\ContentFinder; /** * The Platform Configuration class contains configuration information. * * @author RocketTheme * @license MIT */ class Platform extends BasePlatform { public $no_base_layout = false; public $module_wrapper = '<div class="platform-content">%s</div>'; public $component_wrapper = '<div class="platform-content row-fluid"><div class="span12">%s</div></div>'; protected $name = 'joomla'; protected $features = ['modules' => true]; protected $settings_key = 'return'; protected $modules; public function setModuleWrapper($html) { $this->module_wrapper = $html; } public function setComponentWrapper($html) { $this->component_wrapper = $html; } public function init() { // Support linked sample data. $theme = isset($this->container['theme.name']) ? $this->container['theme.name'] : null; if ($theme && is_dir(JPATH_ROOT . "/media/gantry5/themes/{$theme}/media-shared")) { $custom = JPATH_ROOT . "/media/gantry5/themes/{$theme}/custom"; if (!is_dir($custom)) { // First run -- copy configuration into a single location. $shared = JPATH_ROOT . "/media/gantry5/themes/{$theme}/template-shared"; $demo = JPATH_ROOT . "/media/gantry5/themes/{$theme}/template-demo"; try { Folder::create($custom); } catch (\Exception $e) { throw new \RuntimeException(sprintf("Failed to create folder '%s'.", $custom), 500, $e); } if (is_dir("{$shared}/custom/config")) { Folder::copy("{$shared}/custom/config", "{$custom}/config"); } if (is_dir("{$demo}/custom/config")) { Folder::copy("{$demo}/custom/config", "{$custom}/config"); } } array_unshift($this->items['streams']['gantry-theme']['prefixes'][''], "media/gantry5/themes/{$theme}/template-shared"); array_unshift($this->items['streams']['gantry-theme']['prefixes'][''], "media/gantry5/themes/{$theme}/template-demo"); array_unshift($this->items['streams']['gantry-theme']['prefixes'][''], "media/gantry5/themes/{$theme}/custom"); } return parent::init(); } public function getCachePath() { $path = \JFactory::getConfig()->get('cache_path', JPATH_SITE . '/cache'); if (!is_dir($path)) { throw new \RuntimeException('Joomla cache path does not exist!'); } return $path . '/gantry5'; } public function getThemesPaths() { return ['' => ['templates']]; } public function getMediaPaths() { $paths = ['images']; // Support linked sample data. $theme = isset($this->container['theme.name']) ? $this->container['theme.name'] : null; if ($theme && is_dir(JPATH_ROOT . "/media/gantry5/themes/{$theme}/media-shared")) { array_unshift($paths, "media/gantry5/themes/{$theme}/media-shared"); array_unshift($paths, "media/gantry5/themes/{$theme}/media-demo"); } if ($this->container['global']->get('use_media_folder', false)) { array_push($paths, 'gantry-theme://images'); } else { array_unshift($paths, 'gantry-theme://images'); } return ['' => $paths]; } public function getEnginesPaths() { if (is_link(GANTRY5_ROOT . '/media/gantry5/engines')) { // Development environment. return ['' => ["media/gantry5/engines/{$this->name}", 'media/gantry5/engines/common']]; } return ['' => ['media/gantry5/engines']]; } public function getAssetsPaths() { if (is_link(GANTRY5_ROOT . '/media/gantry5/assets')) { // Development environment. return ['' => ['gantry-theme://', "media/gantry5/assets/{$this->name}", 'media/gantry5/assets/common']]; } return ['' => ['gantry-theme://', 'media/gantry5/assets']]; } /** * Get preview url for individual theme. * * @param string $theme * @return string */ public function getThemePreviewUrl($theme) { return (string)(int) $theme === (string) $theme ? \JUri::root(false) . 'index.php?templateStyle=' . $theme : null; } /** * Get administrator url for individual theme. * * @param string $theme * @return string */ public function getThemeAdminUrl($theme) { $token = \JSession::getFormToken(); return \JRoute::_("index.php?option=com_gantry5&view=configurations/default/styles&theme={$theme}&{$token}=1" , false); } public function filter($text) { \JPluginHelper::importPlugin('content'); return \JHtml::_('content.prepare', $text, '', 'mod_custom.content'); } public function countModules($position) { $document = \JFactory::getDocument(); return ($document instanceof \JDocumentHTML) ? $document->countModules($position) : 0; } public function getModules($position) { // TODO: return []; } public function displayModule($id, $attribs = []) { $document = \JFactory::getDocument(); if (!$document instanceof \JDocumentHTML) { return ''; } $module = is_object($id) ? $id : $this->getModule($id); // Make sure that module really exists. if (!is_object($module)) { return ''; } $isGantry = \strpos($module->module, 'gantry5') !== false; $content = isset($module->content) ? $module->content : null; $renderer = $document->loadRenderer('module'); $html = trim($renderer->render($module, $attribs)); // Add frontend editing feature as it has only been defined for module positions. $app = \JFactory::getApplication(); $user = \JFactory::getUser(); $frontEditing = ($app->isSite() && $app->get('frontediting', 1) && !$user->guest); $menusEditing = ($app->get('frontediting', 1) == 2) && $user->authorise('core.edit', 'com_menus'); if (!$isGantry && $frontEditing && $html && $user->authorise('module.edit.frontend', 'com_modules.module.' . $module->id)) { $displayData = [ 'moduleHtml' => &$html, 'module' => $module, 'position' => isset($attribs['position']) ? $attribs['position'] : $module->position, 'menusediting' => $menusEditing ]; \JLayoutHelper::render('joomla.edit.frontediting_modules', $displayData); } // Work around Joomla "issue" which corrupts content of custom html module (last checked J! 3.6.5). $module->content = $content; if ($html && !$isGantry) { $this->container['theme']->joomla(true); return sprintf($this->module_wrapper, $html); } return $html; } public function displayModules($position, $attribs = []) { $document = \JFactory::getDocument(); if (!$document instanceof \JDocumentHTML) { return ''; } $html = ''; foreach (\JModuleHelper::getModules($position) as $module) { $html .= $this->displayModule($module, $attribs); } return $html; } public function displaySystemMessages($params = []) { // We cannot use JDocument renderer here as it fires too early to display any messages. return '<jdoc:include type="message" />'; } public function displayContent($content, $params = []) { $document = \JFactory::getDocument(); if (!$document instanceof \JDocumentHTML) { return $content; } $renderer = $document->loadRenderer('component'); $html = trim($renderer->render(null, $params, $content ?: $document->getBuffer('component'))); $isGantry = \strpos(\JFactory::getApplication()->input->getCmd('option'), 'gantry5') !== false; if ($html && !$isGantry) { $this->container['theme']->joomla(true); return sprintf($this->component_wrapper, $html); } return $html; } public function getModule($id) { $modules = $this->getModuleList(); return $id && isset($modules[$id]) ? $modules[$id] : null; } protected function &getModuleList() { if ($this->modules === null) { $modules = \JModuleHelper::getModuleList(); $this->modules = []; foreach ($modules as $module) { $this->modules[$module->id] = $module; } } return $this->modules; } public function listModules() { $db = \JFactory::getDbo(); $query = $db->getQuery(true); $query->select('a.id, a.title, a.position, a.module, a.published AS enabled') ->from('#__modules AS a'); // Join on the asset groups table. $query->select('ag.title AS access') ->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access') ->where('a.published >= 0') ->where('a.client_id = 0') ->order('a.position, a.module, a.ordering'); $db->setQuery($query); try { $result = $db->loadObjectList(); } catch (\RuntimeException $e) { return false; } return $result; } public function getEditor($name, $content = '', $width = null, $height = null) { $conf = \JFactory::getConfig(); $editor = \JEditor::getInstance($conf->get('editor')); if (!$height) { $height = 250; } return $editor->display($name, $content, $width, $height, 50, 8, false, null, null, null, ['html_height' => $height]); } public function errorHandlerPaths() { return ['|gantry5|']; } public function settings() { if (!$this->authorize('platform.settings.manage')) { return ''; } return \JRoute::_('index.php?option=com_config&view=component&component=com_gantry5', false); } public function update() { return \JRoute::_('index.php?option=com_installer&view=update', false); } public function updates() { if (!$this->authorize('updates.manage')) { return []; } $styles = ThemeList::getThemes(); $extension_ids = array_unique(array_map( function($item) { return (int) $item->extension_id; }, $styles)); $extension_ids = $extension_ids ? implode(',', $extension_ids) : '-1'; $db = \JFactory::getDbo(); $query = $db->getQuery(true); $query ->select('*') ->from('#__updates') ->where("element='pkg_gantry5' OR extension_id IN ($extension_ids)"); $db->setQuery($query); $updates = $db->loadObjectList(); $list = []; foreach ($updates as $update) { if ($update->element === 'pkg_gantry5') { // Rename Gantry 5 package. $update->name = 'Gantry'; // Ignore git and CI installs and if the Gantry version is the same or higher than in the updates. if (version_compare(GANTRY5_VERSION, 0) < 0 || version_compare($update->version, GANTRY5_VERSION) <= 0) { continue; } } else { // Check if templates need to be updated. $version = isset($styles[$update->element]) ? $styles[$update->element]->get('details.version') : null; if (version_compare($version, 0) < 0 || version_compare($update->version, $version) <= 0) { continue; } } $list[] = $update->name . ' ' . $update->version; } return $list; } public function factory() { $args = func_get_args(); $method = ['JFactory', 'get'. ucfirst((string) array_shift($args))]; return method_exists($method[0], $method[1]) ? call_user_func_array($method, $args) : null; } public function instance() { $args = func_get_args(); $class = ucfirst((string) array_shift($args)); if (!$class) { return null; } if (class_exists('J'. $class)) { $class = 'J'. $class; } $method = [$class, 'getInstance']; return method_exists($method[0], $method[1]) ? call_user_func_array($method, $args) : null; } public function route() { return call_user_func_array(['JRoute', '_'], func_get_args()); } public function html() { $args = func_get_args(); if (isset($args[0]) && method_exists('JHtml', $args[0])) { return call_user_func_array(['JHtml', array_shift($args)], $args); } return call_user_func_array(['JHtml', '_'], $args); } public function article($keys) { return Content::getInstance($keys); } public function finder($domain, $options = null) { $options = (array) $options; switch ($domain) { case 'article': case 'articles': case 'content': $finder = new ContentFinder($options); return \JFactory::getApplication()->isSite() ? $finder->authorised() : $finder; case 'category': case 'categories': $finder = (new CategoryFinder($options))->extension('content'); return \JFactory::getApplication()->isSite() ? $finder->authorised() : $finder; } return null; } public function truncate($text, $length, $html = false) { return \JHtml::_('string.truncate', $text, $length, true, $html); } public function authorize($action, $id = null) { $user = \JFactory::getUser(); switch ($action) { case 'platform.settings.manage': return $user->authorise('core.admin', 'com_templates') || $user->authorise('core.admin', 'com_gantry5'); case 'menu.manage': return $user->authorise('core.manage', 'com_menus') && $user->authorise('core.edit', 'com_menus'); case 'menu.edit': if ($id) { $db = \JFactory::getDbo(); $userId = \JFactory::getUser()->id; // Verify that no items are checked out. $query = $db->getQuery(true) ->select('id') ->from('#__menu') ->where('menutype=' . $db->quote($id)) ->where('checked_out !=' . (int) $userId) ->where('checked_out !=0'); $db->setQuery($query); if ($db->loadRowList()) { return false; } // Verify that no module for this menu are checked out. $query->clear() ->select('id') ->from('#__modules') ->where('module=' . $db->quote('mod_menu')) ->where('params LIKE ' . $db->quote('%"menutype":' . json_encode($id) . '%')) ->where('checked_out !=' . (int) $userId) ->where('checked_out !=0'); $db->setQuery($query); if ($db->loadRowList()) { return false; } } return $user->authorise('core.edit', 'com_menus'); case 'updates.manage': return $user->authorise('core.manage', 'com_installer'); case 'outline.create': return $user->authorise('core.create', 'com_templates'); case 'outline.delete': return $user->authorise('core.delete', 'com_templates'); case 'outline.rename': return $user->authorise('core.edit', 'com_templates'); case 'outline.assign': return $user->authorise('core.edit.state', 'com_templates') && $user->authorise('core.edit', 'com_menu'); case 'outline.edit': return true; } return true; } } classes/Gantry/Framework/Exporter.php 0000604 00000025761 15075035625 0013742 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Component\Layout\Layout; use Gantry\Framework\Services\ConfigServiceProvider; use Gantry\Joomla\Category\CategoryFinder; use Gantry\Joomla\Content\ContentFinder; use Gantry\Joomla\Module\ModuleFinder; use Gantry\Joomla\StyleHelper; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Exporter { protected $files = []; public function all() { $theme = Gantry::instance()['theme']->details(); return [ 'export' => [ 'gantry' => [ 'version' => GANTRY5_VERSION !== '@version@' ? GANTRY5_VERSION : 'GIT', 'format' => 1 ], 'platform' => [ 'name' => 'joomla', 'version' => JVERSION ], 'theme' => [ 'name' => $theme->get('name'), 'title' => $theme->get('details.name'), 'version' => $theme->get('details.version'), 'date' => $theme->get('details.date'), 'author' => $theme->get('details.author'), 'copyright' => $theme->get('details.copyright'), 'license' => $theme->get('details.license'), ] ], 'outlines' => $this->outlines(), 'positions' => $this->positions(), 'menus' => $this->menus(), 'content' => $this->articles(), 'categories' => $this->categories(), 'files' => $this->files, ]; } public function outlines() { $gantry = Gantry::instance(); $styles = StyleHelper::loadStyles($gantry['theme.name']); $list = [ 'default' => ['title' => 'Default'], '_error' => ['title' => 'Error'], '_offline' => ['title' => 'Offline'], '_body_only' => ['title' => 'Body Only'], ]; $inheritance = []; foreach ($styles as $style) { $name = $base = strtolower(trim(preg_replace('|[^a-z\d_-]+|ui', '_', $style->title), '_')); $i = 0; while (isset($list[$name])) { $i++; $name = "{$base}-{$i}"; }; $inheritance[$style->id] = $name; $list[$name] = [ 'id' => (int) $style->id, 'title' => $style->title, 'home' => $style->home, ]; if (!$style->home) { unset($list[$name]['home']); } } foreach ($list as $name => &$style) { $id = isset($style['id']) ? $style['id'] : $name; $config = ConfigServiceProvider::load($gantry, $id, false, false); // Update layout inheritance. $layout = Layout::instance($id); $layout->name = $name; foreach ($inheritance as $from => $to) { $layout->updateInheritance($from, $to); } $style['preset'] = $layout->preset['name']; $config['index'] = $layout->buildIndex(); $config['layout'] = $layout->export(); // Update atom inheritance. $atoms = $config->get('page.head.atoms'); if (is_array($atoms)) { $atoms = new Atoms($atoms); foreach ($inheritance as $from => $to) { $atoms->updateInheritance($from, $to); } $config->set('page.head.atoms', $atoms->update()->toArray()); } // Add assignments. if (is_numeric($id)) { $assignments = $this->getOutlineAssignments($id); if ($assignments) { $config->set('assignments', $this->getOutlineAssignments($id)); } } $style['config'] = $config->toArray(); } return $list; } public function positions($all = true) { $gantry = Gantry::instance(); $positions = $gantry['outlines']->positions(); $positions['debug'] = 'Debug'; $finder = new ModuleFinder(); if (!$all) { $finder->particle(); } $modules = $finder->find()->export(); $list = []; foreach ($modules as $position => &$items) { if (!isset($positions[$position])) { continue; } foreach ($items as &$item) { $func = 'module' . $item['options']['type']; if (method_exists($this, $func)) { $item = $this->{$func}($item); } } $list[$position] = [ 'title' => $positions[$position], 'items' => $items, ]; } return $list; } public function menus() { $gantry = Gantry::instance(); $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->select('id, menutype, title, description') ->from('#__menu_types'); $db->setQuery($query); $menus = $db->loadObjectList('id'); $list = []; foreach ($menus as $menu) { $items = $gantry['menu']->instance(['menu' => $menu->menutype])->items(false); array_walk( $items, function (&$item) { $item['id'] = (int) $item['id']; if (in_array($item['type'], ['component', 'alias'])) { $item['type'] = "joomla.{$item['type']}"; } unset($item['alias'], $item['path'], $item['parent_id'], $item['level']); } ); $list[$menu->menutype] = [ 'id' => (int) $menu->id, 'title' => $menu->title, 'description' => $menu->description, 'items' => $items ]; } return $list; } public function articles() { $finder = new ContentFinder(); $articles = $finder->limit(0)->find(); $list = []; foreach ($articles as $article) { $exported = $article->toArray(); // Convert images to use streams. $exported['introtext'] = $this->urlFilter($exported['introtext']); $exported['fulltext'] = $this->urlFilter($exported['fulltext']); $list[$article->id . '-' . $article->alias] = $exported; } return $list; } public function categories() { $finder = new CategoryFinder(); $categories = $finder->limit(0)->find(); $list = []; foreach ($categories as $category) { $list[$category->id] = $category->toArray(); } return $list; } /** * List all the rules available. * * @param string $configuration * @return array */ public function getOutlineAssignments($configuration) { require_once JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php'; $app = \JApplicationCms::getInstance('site'); $menu = $app->getMenu(); $data = \MenusHelper::getMenuLinks(); $items = []; foreach ($data as $item) { foreach ($item->links as $link) { if ($link->template_style_id == $configuration) { $items[$menu->getItem($link->value)->route] = 1; } } } if ($items) { return ['page' => [$items]]; } return []; } /** * Filter stream URLs from HTML. * * @param string $html HTML input to be filtered. * @return string Returns modified HTML. */ public function urlFilter($html) { // Tokenize all PRE and CODE tags to avoid modifying any src|href|url in them $tokens = []; $html = preg_replace_callback('#<(pre|code).*?>.*?<\\/\\1>#is', function($matches) use (&$tokens) { $token = uniqid('__g5_token'); $tokens['#' . $token . '#'] = $matches[0]; return $token; }, $html); $html = preg_replace_callback('^(\s)(src|href)="(.*?)"^', [$this, 'linkHandler'], $html); $html = preg_replace_callback('^(\s)url\((.*?)\)^', [$this, 'urlHandler'], $html); $html = preg_replace(array_keys($tokens), array_values($tokens), $html); // restore tokens return $html; } public function url($url) { // Only process local urls. if ($url === '' || $url[0] === '/' || $url[0] === '#') { return $url; } /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; // Handle URIs. if (strpos($url, '://')) { if ($locator->isStream($url)) { // File is a stream, include it to files list. list ($stream, $path) = explode('://', $url); $this->files[$stream][$path] = $url; } return $url; } // Try to convert local paths to streams. $paths = $locator->getPaths(); $found = false; $stream = $path = ''; foreach ($paths as $stream => $prefixes) { foreach ($prefixes as $prefix => $paths) { foreach ($paths as $path) { if (is_string($path) && strpos($url, $path) === 0) { $path = ($prefix ? "{$prefix}/" : '') . substr($url, strlen($path) + 1); $found = true; break 3; } } } } if ($found) { $url = "{$stream}://{$path}"; $this->files[$stream][$path] = $url; } return $url; } /** * @param array $matches * @return string * @internal */ public function linkHandler(array $matches) { $url = $this->url(trim($matches[3])); return "{$matches[1]}{$matches[2]}=\"{$url}\""; } /** * @param array $matches * @return string * @internal */ public function urlHandler(array $matches) { $url = $this->url(trim($matches[2], '"\'')); return "{$matches[1]}url({$url})"; } protected function moduleMod_Custom(array $data) { // Convert to particle... $data['type'] = 'particle'; $data['joomla'] = $data['options']; $data['options'] = [ 'type' => 'custom', 'attributes' => [ 'enabled' => $data['joomla']['published'], 'html' => $this->urlFilter($data['joomla']['content']), 'filter' => $data['joomla']['params']['prepare_content'] ] ]; unset($data['joomla']['content'], $data['joomla']['params']['prepare_content']); return $data; } } classes/Gantry/Framework/Positions.php 0000604 00000000765 15075035625 0014116 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework; use Gantry\Component\Position\Positions as BasePositions; class Positions extends BasePositions { } classes/Gantry/Framework/Assignments.php 0000604 00000013503 15075035625 0014414 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Component\Assignments\AbstractAssignments; use Gantry\Joomla\CacheHelper; use Gantry\Joomla\StyleHelper; use Joomla\Utilities\ArrayHelper; class Assignments extends AbstractAssignments { protected $platform = 'Joomla'; /** * Load all assignments. * * @return array */ public function loadAssignments() { $app = \JFactory::getApplication(); if (!$app->isSite()) { return []; } // Get current template, style id and rules. $template = $app->getTemplate(); $active = $app->getMenu()->getActive(); if ($active) { $style = (int) $active->template_style_id; $rules = [$active->menutype => [$active->id => true]]; } else { $style = 0; $rules = []; } // Load saved assignments. $assignments = parent::loadAssignments(); // Add missing template styles from Joomla. $styles = StyleHelper::loadStyles($template); $assignments += array_fill_keys(array_keys($styles), []); foreach ($assignments as $id => &$assignment) { // Add current menu item if it has been assigned to the style. $assignment['menu'] = $style === $id ? $rules : []; // Always add the current template style. $assignment['style'] = ['id' => [$id => true]]; } return $assignments; } /** * Save assignments for the configuration. * * @param array $data */ public function save(array $data) { $data += ['assignment' => 0, 'menu' => []]; // Joomla stores language and menu assignments by its own. $this->saveAssignment($data['assignment']); $this->saveMenu($data['menu']); unset($data['assignment'], $data['menu'], $data['style']); // Continue saving rest of the assignments. parent::save($data); } public function types() { return ['menu', 'style']; } public function saveMenu($data) { $active = []; foreach ($data as $menutype => $items) { $active += array_filter($items, function($value) {return $value > 0; }); } $active = array_keys($active); // Detect disabled template. $extension = \JTable::getInstance('Extension'); $template = Gantry::instance()['theme.name']; if ($extension->load(array('enabled' => 0, 'type' => 'template', 'element' => $template, 'client_id' => 0))) { throw new \RuntimeException(\JText::_('COM_TEMPLATES_ERROR_SAVE_DISABLED_TEMPLATE')); } \JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_templates/tables'); $style = \JTable::getInstance('Style', 'TemplatesTable'); if (!$style->load($this->configuration) || $style->client_id != 0) { throw new \RuntimeException('Template style does not exist'); } $user = \JFactory::getUser(); $n = 0; if ($user->authorise('core.edit', 'com_menus')) { $db = \JFactory::getDbo(); $user = \JFactory::getUser(); if (!empty($active)) { ArrayHelper::toInteger($active); // Update the mapping for menu items that this style IS assigned to. $query = $db->getQuery(true) ->update('#__menu') ->set('template_style_id = ' . (int) $style->id) ->where('id IN (' . implode(',', $active) . ')') ->where('template_style_id != ' . (int) $style->id) ->where('checked_out IN (0,' . (int) $user->id . ')'); $db->setQuery($query); $db->execute(); $n += $db->getAffectedRows(); } // Remove style mappings for menu items this style is NOT assigned to. // If unassigned then all existing maps will be removed. $query = $db->getQuery(true) ->update('#__menu') ->set('template_style_id = 0'); if (!empty($active)) { $query->where('id NOT IN (' . implode(',', $active) . ')'); } $query->where('template_style_id = ' . (int) $style->id) ->where('checked_out IN (0,' . (int) $user->id . ')'); $db->setQuery($query); $db->execute(); $n += $db->getAffectedRows(); } // Clean the cache. CacheHelper::cleanTemplates(); return ($n > 0); } public function getAssignment() { $style = StyleHelper::getStyle($this->configuration); return $style->home; } public function saveAssignment($value) { $options = $this->assignmentOptions(); if (!isset($options[$value])) { throw new \RuntimeException('Invalid value for default assignment!', 400); } $style = StyleHelper::getStyle($this->configuration); $style->home = $value; if (!$style->check() || !$style->store()) { throw new \RuntimeException($style->getError()); } // Clean the cache. CacheHelper::cleanTemplates(); } public function assignmentOptions() { if ((string)(int) $this->configuration !== (string) $this->configuration) { return []; } $languages = \JHtml::_('contentlanguage.existing'); $options = ['- Make Default -', 'All Languages']; foreach ($languages as $language) { $options[$language->value] = $language->text; } return $options; } } classes/Gantry/Framework/ThemeInstaller.php 0000604 00000042612 15075035625 0015044 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Component\Layout\Layout; use Gantry\Component\Theme\ThemeInstaller as AbstractInstaller; use Gantry\Joomla\Manifest; use RocketTheme\Toolbox\File\YamlFile; class ThemeInstaller extends AbstractInstaller { protected $extension; protected $manifest; public function __construct($extension = null) { parent::__construct(); jimport('joomla.filesystem.folder'); \JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_templates/tables'); if ($extension instanceof \JInstallerAdapterTemplate) { $this->setInstaller($extension); } elseif ($extension) { $this->loadExtension($extension); } } public function setInstaller(\JInstallerAdapterTemplate $install) { // We need access to a protected variable $install->extension. $reflectionClass = new \ReflectionClass($install); $property = $reflectionClass->getProperty('extension'); $property->setAccessible(true); $this->extension = $property->getValue($install); $this->name = $this->extension->name; $this->manifest = new Manifest($this->extension->name, $install->getManifest()); return $this; } public function loadExtension($id) { if ((string) intval($id) !== (string) $id) { $id = ['type' => 'template', 'element' => (string) $id, 'client_id' => 0]; } $this->extension = \JTable::getInstance('extension'); $this->extension->load($id); $this->name = $this->extension->name; } public function getPath() { return JPATH_SITE . '/templates/' . $this->extension->name; } public function getStyleName($title) { return \JText::sprintf($title, \JText::_($this->extension->name)); } public function getStyle($name = null) { if (is_numeric($name)) { $field = 'id'; } else { $field = 'title'; $name = $this->getStyleName($name); } $style = $this->createStyle(); $style->load([ 'template' => $this->extension->element, 'client_id' => $this->extension->client_id, $field => $name ]); return $style; } public function getDefaultStyle() { $style = \JTable::getInstance('Style', 'TemplatesTable'); $style->load(['home' => 1, 'client_id' => 0]); return $style; } /** * @param string $type * @return \JTableMenu */ public function getMenu($type) { /** @var \JTableMenuType $table */ $table = \JTable::getInstance('MenuType'); $table->load(['menutype' => $type]); return $table; } public function createSampleData() { $this->updateStyle('JLIB_INSTALLER_DEFAULT_STYLE', [], 1); $this->installMenus(); } public function render($template, $context = []) { $token = \JSession::getFormToken(); $manifest = $this->getManifest(); $context += [ 'description' => $this->translate((string) $manifest->get('description')), 'version' => (string) $manifest->get('version'), 'date' => (string) $manifest->get('creationDate'), 'author' => [ 'name' => (string) $manifest->get('author'), 'email' => (string) $manifest->get('authorEmail'), 'url' => (string) $manifest->get('authorUrl') ], 'copyright' => (string) $manifest->get('copyright'), 'license' => (string) $manifest->get('license'), 'install_url' => \JRoute::_("index.php?option=com_gantry5&view=install&theme={$this->name}&{$token}=1", false), 'edit_url' => \JRoute::_("index.php?option=com_gantry5&view=configurations/default/styles&theme={$this->name}&{$token}=1", false), ]; return parent::render($template, $context); } public function createStyle() { $style = \JTable::getInstance('Style', 'TemplatesTable'); $style->reset(); $style->template = $this->extension->element; $style->client_id = $this->extension->client_id; return $style; } public function addStyle($title, array $configuration = [], $home = 0) { // Make sure language debug is turned off. $lang = \JFactory::getLanguage(); $debug = $lang->setDebug(false); // Translate title. $title = $this->getStyleName($title); // Turn language debug back on. $lang->setDebug($debug); $data = [ 'home' => (int) $home, 'title' => $title, 'params' => json_encode($configuration), ]; $style = $this->createStyle(); $style->save($data); if ($home) { $this->actions[] = ['action' => 'default_style_assigned', 'text' => \JText::sprintf('GANTRY5_INSTALLER_ACTION_DEFAULT_STYLE_ASSIGNED', $title)]; } return $style; } public function updateStyle($name, array $configuration, $home = null) { $style = $this->getStyle($name); if ($style->id) { $home = ($home !== null ? $home : $style->home); $params = (array) json_decode($style->params, true); $data = [ 'params' => json_encode($configuration + $params), 'home' => $home ]; if ($home && !$style->home) { $this->actions[] = ['action' => 'default_style_assigned', 'text' => \JText::sprintf('GANTRY5_INSTALLER_ACTION_DEFAULT_STYLE_ASSIGNED', $style->title)]; } $style->save($data); } return $style; } public function assignHomeStyle($style) { // Update the mapping for menu items that this style IS assigned to. $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->update('#__menu') ->set('template_style_id=' . (int) $style->id) ->where('home=1') ->where('client_id=0'); $db->setQuery($query); $db->execute(); if ($db->getAffectedRows()) { $this->actions[] = ['action' => 'home_style_assigned', 'text' => \JText::sprintf('GANTRY5_INSTALLER_ACTION_HOME_STYLE_ASSIGNED', $style->title)]; } } /** * @param string $folder * @param array $params * @return string|bool */ public function createOutline($folder, array $params = []) { if (!$folder) { throw new \RuntimeException('Cannot create outline without folder name'); } $this->initialize(); $created = false; $params += [ 'preset' => null, 'title' => null ]; $title = $params['title'] ?: ucwords(trim(strtr($folder, ['_' => ' ']))); $preset = $params['preset'] ?: 'default'; if ($folder[0] !== '_') { $title = $this->getStyleName($title !== 'Default' ? "%s - {$title}" : 'JLIB_INSTALLER_DEFAULT_STYLE'); $style = $this->getStyle($title); if (!$style->id) { // Only add style if it doesn't exist. $style = $this->addStyle($title, ['preset' => $preset]); $created = true; } $id = $style->id; } else { $id = $folder; } $target = $folder !== 'default' ? $id : $folder; // Copy configuration for the new layout. if (($this->copyCustom($folder, $target) || $created) && isset($style)) { // Update layout and save it. $layout = Layout::load($target, $preset); $layout->save()->saveIndex(); if ($id !== $target) { // Default outline: Inherit everything from the base. $layout->inheritAll()->name = $id; $layout->save()->saveIndex(); $this->actions[] = ['action' => 'base_outline_created', 'text' => $this->translate('GANTRY5_INSTALLER_ACTION_BASE_OUTLINE_CREATED', $title)]; } if ($created) { $this->actions[] = ['action' => 'outline_created', 'text' => $this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_CREATED', $title)]; } else { $this->actions[] = ['action' => 'outline_updated', 'text' => $this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_UPDATED', $title)]; } // Update preset in Joomla table. $this->updateStyle($title, ['preset' => $layout['preset']['name']]); } return $id; } /** * @param array $item [menutype, title, alias, link, template_style_id, params] * @param int $parent_id Parent menu id. * @param bool $load True if updating existing items. * @return int * @throws \Exception */ public function addMenuItem(array $item, $parent_id = 1, $load = false) { $component_id = $this->getComponent(); $table = \JTable::getInstance('menu'); $date = new \JDate(); $update = false; // Defaults for the item. $item += [ 'menutype' => 'mainmenu', 'title' => 'Home', 'alias' => 'gantry5', 'note' => '', 'link' => 'index.php?option=com_gantry5&view=custom', 'type' => 'component', 'published' => 1, 'parent_id' => $parent_id, 'component_id' => $component_id, 'checked_out' => 0, 'checked_out_time' => $date->toSql(), 'browserNav' => 0, 'access' => 1, 'img' => '', 'template_style_id' => 0, 'params' => '{}', 'home' => 0, 'language' => '*', 'client_id' => 0 ]; if (in_array($item['type'], ['separator', 'heading'])) { $item['link'] = ''; } if ($item['type'] !== 'component') { $item['component_id'] = 0; } if ($load) { $update = $table->load([ 'menutype' => $item['menutype'], 'alias' => $item['alias'], 'parent_id' => $item['parent_id'] ]); } $table->setLocation($parent_id, 'last-child'); if (!$table->bind($item) || !$table->check() || !$table->store()) { throw new \Exception($table->getError()); } /** @var \JCache|\JCacheController $cache */ $cache = \JFactory::getCache(); $cache->clean('mod_menu'); $menu = \JTable::getInstance('menuType'); $menu->load(['menutype' => $item['menutype']]); if (!isset($this->actions["menu_{$item['menutype']}_created"])) { $postfix = $item['home'] ? '_HOME' : ''; if ($update) { $this->actions[] = ['action' => 'menu_item_updated', 'text' => \JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_ITEM_UPDATED' . $postfix, $table->title, $table->path, $menu->title)]; } else { $this->actions[] = ['action' => 'menu_item_created', 'text' => \JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_ITEM_CREATED' . $postfix, $table->title, $table->path, $menu->title)]; } } elseif ($item['home']) { $this->actions[] = ['action' => 'menu_item_updated', 'text' => \JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_ITEM_HOME', $table->title, $table->path, $menu->title)]; } return $table->id; } public function installMenus(array $menus = null, $parent = 1) { if ($menus === null) { $path = $this->getPath(); $file = YamlFile::instance($path . '/install/menus.yaml'); $menus = (array) $file->content(); $file->free(); } foreach ($menus as $menutype => $menu) { $title = !empty($menu['title']) ? $menu['title'] : ucfirst($menutype); $description = !empty($menu['description']) ? $menu['description'] : ''; $exists = $this->getMenu($menutype)->id; // If $parent = 0, do dry run. if ((int) $parent && !$exists) { $this->deleteMenu($menutype, true); $this->createMenu($menutype, $title, $description); } if (!empty($menu['items'])) { $this->addMenuItems($menutype, $menu['items'], (int) $parent); } } } /** * @param string $type * @param string $title * @param string $description * @throws \Exception */ public function createMenu($type, $title, $description) { /** @var \JTableMenuType $table */ $table = \JTable::getInstance('MenuType'); $data = array( 'menutype' => $type, 'title' => $title, 'description' => $description ); if (!$table->bind($data) || !$table->check()) { // Menu already exists, do nothing return; } if (!$table->store()) { throw new \Exception($table->getError()); } $this->actions["menu_{$type}_created"] = ['action' => 'menu_created', 'text' => \JText::sprintf('GANTRY5_INSTALLER_ACTION_MENU_CREATED', $title)]; } /** * @param string $type * @param bool $force */ public function deleteMenu($type, $force = false) { if ($force) { $this->unsetHome($type); } $table = \JTable::getInstance('MenuType'); $table->load(array('menutype' => $type)); if ($table->id) { $success = $table->delete(); if (!$success) { \JFactory::getApplication()->enqueueMessage($table->getError(), 'error'); } else { $this->actions["menu_{$type}_deleted"] = ['action' => 'menu_delete', 'text' => \JText::_('GANTRY5_INSTALLER_ACTION_MENU_DELETED', $table->title)]; } } /** @var \JCache|\JCacheController $cache */ $cache = \JFactory::getCache(); $cache->clean('mod_menu'); } public function unsetHome($type) { // Update the mapping for menu items that this style IS assigned to. $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->update('#__menu') ->set('home=0') ->where('menutype=' . $db->quote($type)) ->where('client_id=0'); $db->setQuery($query); $db->execute(); } /** * @deprecated 5.3.2 */ public function cleanup() { $this->initialize(); $this->finalize(); } public function finalize() { parent::finalize(); $gantry = Gantry::instance(); /** @var Outlines $outlines */ $outlines = $gantry['outlines']; $name = $this->extension->name; // Update positions in manifest file. $positions = $outlines->positions(); $manifest = new Manifest($name); $manifest->setPositions(array_keys($positions)); $manifest->save(); } protected function addMenuItems($menutype, array $items, $parent) { foreach ($items as $alias => $item) { $item = (array) $item; $item += [ 'menutype' => $menutype, 'title' => ucfirst($alias), 'alias' => $alias ]; $outline = isset($item['outline']) ? $item['outline'] : (isset($item['layout']) ? $item['layout'] : null); $params = $this->getOutline($outline); if (!is_array($params)) { $params = [ 'preset' => isset($item['preset']) ? $item['preset'] : (isset($item['layout']) ? $item['layout'] : null), 'title' => isset($item['style']) ? $item['style'] : null ]; } $id = $outline ? $this->createOutline($outline, $params) : 0; $item['template_style_id'] = (string)(int) $id === (string) $id ? $id : 0; // If $parent = 0, do dry run. $itemId = $parent ? $this->addMenuItem($item, $parent, true) : 0; if (!empty($item['items'])) { $this->addMenuItems($menutype, $item['items'], $itemId); } } } protected function getInstallerScript() { if (!$this->script) { $className = $this->extension->name . 'InstallerScript'; if (!class_exists($className)) { $manifest = new Manifest($this->extension->name); $file = $manifest->getScriptFile(); $path = "{$this->getPath()}/{$file}"; if ($file && is_file($path)) { require_once $path; } } if (class_exists($className)) { $this->script = new $className; } } return $this->script; } protected function getManifest() { if (!$this->manifest) { $this->manifest = new Manifest($this->extension->name); } return $this->manifest; } protected function getComponent() { static $component_id; if (!$component_id) { // Get Gantry component id. $component_id = \JComponentHelper::getComponent('com_gantry5')->id; } return $component_id; } } classes/Gantry/Framework/Outlines.php 0000604 00000020730 15075035625 0013723 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Admin\ThemeList; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Outline\OutlineCollection; use Gantry\Joomla\StyleHelper; use Gantry\Joomla\TemplateInstaller; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Outlines extends OutlineCollection { protected $createId; public function preset($id) { if (is_numeric($id)) { $style = StyleHelper::getStyle($id); $params = json_decode($style->params, true); $id = isset($params['preset']) ? $params['preset'] : 'default'; } return $id; } public function current($template = null) { if (!is_object($template)) { // Get the template style. $template = \JFactory::getApplication()->getTemplate(true); } $preset = $template->params->get('preset', 'default'); $outline = $template->params->get('configuration', !empty($template->id) ? $template->id : null); GANTRY_DEBUGGER && \Gantry\Debugger::addMessage('Template Style:') && \Gantry\Debugger::addMessage($template); if (JDEBUG && !$outline) { static $shown = false; if (!$shown) { $shown = true; \JFactory::getApplication()->enqueueMessage('[DEBUG] JApplicationSite::getTemplate() was overridden with no specified Gantry 5 outline.', 'notice'); } } /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; return ($outline && is_dir($locator("{$this->path}/{$outline}"))) ? $outline : $preset; } /** * @param string $path * @return $this */ public function load($path = 'gantry-config://') { $this->path = $path; $gantry = $this->container; $theme = isset($gantry['theme.name']) ? $gantry['theme.name'] : null; $styles = ThemeList::getStyles($theme); $installer = new TemplateInstaller($this->container['theme.name']); $title = $installer->getStyleName('%s - '); $outlines = []; foreach ($styles as $style) { $preset = isset($style->params['preset']) ? $style->params['preset'] : null; $outline = isset($style->params['configuration']) ? $style->params['configuration'] : $preset; if ($outline && $outline != $style->id) { // New style generated by Joomla. StyleHelper::copy($style, $outline, $style->id); } $outlines[$style->id] = preg_replace('|^' . preg_quote($title) . '|', '', $style->style); } asort($outlines); $this->items = $this->addDefaults($outlines); return $this; } /** * @param string|null $id * @param string $title * @param string|array $preset * @return string * @throws \RuntimeException */ public function create($id, $title = null, $preset = null) { if ($this->createId) { // Workaround Joomla wanting to use different logic for style duplication. $new = parent::create($this->createId, $title, $preset); $this->createId = null; return $new; } $title = $title ? "%s - {$title}" : '%s - Untitled'; $installer = new TemplateInstaller($this->container['theme.name']); $title = $installer->getStyleName($title); $style = $installer->addStyle($title); $error = $style->getError(); if ($error) { throw new \RuntimeException($error, 400); } $presetId = (string) (isset($preset['preset']['name']) ? $preset['preset']['name'] : ($preset ?: 'default')); StyleHelper::update($style->id, $presetId); // Create configuration folder. $id = parent::create($style->id, $title, $preset); if ($id != $style->id) { throw new \RuntimeException(sprintf("Creating outline: folder '%s' already exists!", $style->id)); } return $style->id; } public function duplicate($id, $title = null, $inherit = false) { if (!$this->canDuplicate($id)) { throw new \RuntimeException("Outline '$id' cannot be duplicated", 400); } // Handle special case of duplicating system outlines. if ((string)(int) $id !== (string) $id) { return parent::duplicate($id, $title, $inherit); } // Use Joomla logic to duplicate the style. $model = StyleHelper::loadModel(); $pks = [$id]; if (!$model->duplicate($pks)) { throw new \RuntimeException($model->getError(), 400); } // Seek the newly generated style ID since Joomla doesn't return one on duplication. $theme = $this->container['theme.name']; $styles = ThemeList::getStyles($theme, true); $style = end($styles); if ($title) { // Change the title. $installer = new TemplateInstaller($theme); $title = $installer->getStyleName("%s - {$title}"); $this->rename($style->id, $title); } else { $title = $style->style; } $this->createId = $style->id; return parent::duplicate($id, $title, $inherit); } public function rename($id, $title) { $model = StyleHelper::loadModel(); $item = $model->getTable(); $item->load($id); if (!$item->id) { throw new \RuntimeException('Outline not found', 404); } $theme = $this->container['theme.name']; $installer = new TemplateInstaller($theme); $title = $title ? "%s - {$title}" : '%s - Untitled'; $title = $installer->getStyleName($title); $item->title = $title; if (!$item->check()) { throw new \RuntimeException($item->getError(), 400); } if (!$item->store()) { throw new \RuntimeException($item->getError(), 500); } if (isset($this->items[$id])) { $this->items[$id] = $title; } return $id; } public function delete($id, $deleteModel = true) { if (!$this->canDelete($id)) { throw new \RuntimeException("Outline '$id' cannot be deleted", 400); } $model = StyleHelper::loadModel(); $item = $model->getTable(); $item->load($id); try { foreach ($this->getInheritingOutlines($id) as $outline => $title) { $this->layout($outline)->updateInheritance($id)->save()->saveIndex(); } foreach ($this->getInheritingOutlinesWithAtom($id) as $outline => $title) { Atoms::instance($outline)->updateInheritance($id)->save(); } if ($deleteModel && !$model->delete($id)) { $error = $model->getError(); // Well, Joomla can always send enqueue message instead! if (!$error) { $messages = \JFactory::getApplication()->getMessageQueue(); $message = reset($messages); $error = $message ? $message['message'] : 'Unknown error'; } throw new \RuntimeException($error); } } catch (\Exception $e) { throw new \RuntimeException('Deleting outline failed: ' . $e->getMessage(), 400, $e); } // Remove configuration directory. $gantry = $this->container; /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $path = $locator->findResource("{$this->path}/{$item->id}", true, true); if ($path) { if (file_exists($path)) { Folder::delete($path); } } unset($this->items[$item->id]); } /** * @param string $id * @return boolean */ public function canDelete($id) { $model = StyleHelper::loadModel(); $item = $model->getTable(); $item->load($id); return !$item->id || $item->home ? false : true; } /** * @param string $id * @return boolean */ public function isDefault($id) { $model = StyleHelper::loadModel(); $item = $model->getTable(); $item->load($id); return (bool) $item->home; } } classes/Gantry/Framework/Page.php 0000604 00000007214 15075035625 0012777 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; class Page extends Base\Page { public $home; public $outline; public $language; public $direction; // Joomla specific properties. public $theme; public $baseUrl; public $title; public $description; public function __construct($container) { parent::__construct($container); $app = \JFactory::getApplication(); $document = \JFactory::getDocument(); $input = $app->input; $this->tmpl = $input->getCmd('tmpl', ''); $this->option = $input->getCmd('option', ''); $this->view = $input->getCmd('view', ''); $this->layout = $input->getCmd('layout', ''); $this->task = $input->getCmd('task', ''); $this->itemid = $input->getInt('Itemid', 0); $this->printing = $input->getCmd('print', ''); $this->class = ''; if ($this->itemid) { $menuItem = $app->getMenu()->getActive(); if ($menuItem && $menuItem->id) { $this->home = (bool) $menuItem->home; $this->class = $menuItem->params->get('pageclass_sfx', ''); } } $templateParams = $app->getTemplate(true); $this->outline = Gantry::instance()['configuration']; $this->sitename = $app->get('sitename'); $this->theme = $templateParams->template; $this->baseUrl = \JUri::base(true); $this->title = $document->title; $this->description = $document->description; // Document has lower case language code, which causes issues with some JS scripts (Snipcart). Use tag instead. $code = explode('-', $document->getLanguage(), 2); $language = array_shift($code); $country = strtoupper(array_shift($code)); $this->language = $language . ($country ? '-' . $country : ''); $this->direction = $document->direction; } public function url(array $args = []) { $url = \JUri::getInstance(); foreach ($args as $key => $val) { $url->setVar($key, $val); } return $url->toString(); } public function htmlAttributes() { $attributes = [ 'lang' => $this->language, 'dir' => $this->direction ] + (array) $this->config->get('page.html', []); return $this->getAttributes($attributes); } public function bodyAttributes($attributes = []) { if ($this->tmpl == 'component') { $classes = ['contentpane', 'modal']; } else { $classes = ['site', $this->option, "view-{$this->view}"]; $classes[] = $this->layout ? 'layout-' . $this->layout : 'no-layout'; $classes[] = $this->task ? 'task-' . $this->task : 'no-task'; } $classes[] = 'dir-' . $this->direction; if ($this->class) $classes[] = $this->class; if ($this->printing) $classes[] = 'print-mode'; if ($this->itemid) $classes[] = 'itemid-' . $this->itemid; if ($this->outline) $classes[] = 'outline-' . $this->outline; $baseAttributes = (array) $this->config->get('page.body.attribs', []); if (!empty($baseAttributes['class'])) { $baseAttributes['class'] = array_merge((array) $baseAttributes['class'], $classes); } else { $baseAttributes['class'] = $classes; } return $this->getAttributes($baseAttributes, $attributes); } } classes/Gantry/Framework/Translator.php 0000604 00000001134 15075035625 0014247 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Component\Translator\Translator as BaseTranslator; class Translator extends BaseTranslator { public function translate($string) { if (\func_num_args() === 1) { return \JText::_($string); } $args = \func_get_args(); return \call_user_func_array(['JText', 'sprintf'], $args); } } classes/Gantry/Framework/Gantry.php 0000604 00000002733 15075035625 0013370 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; class Gantry extends Base\Gantry { /** * @return boolean */ public function debug() { return JDEBUG; } /** * @return boolean */ public function admin() { return \JFactory::getApplication()->isAdmin(); } /** * @param string $location * @param bool $force * @return array */ public function styles($location = 'head', $force = false) { // Do not display head, Joomla will take care of it (most of the time). return (!$force && $location == 'head') ? [] : parent::styles($location); } /** * @param string $location * @param bool $force * @return array */ public function scripts($location = 'head', $force = false) { // Do not display head, Joomla will take care of it (most of the time). return (!$force && $location == 'head') ? [] : parent::scripts($location); } /** * @return array */ protected function loadGlobal() { $global = null; // Trigger the event. $dispatcher = \JEventDispatcher::getInstance(); $dispatcher->trigger('onGantryGlobalConfig', ['global' => &$global]); return $global; } } classes/Gantry/Framework/Theme.php 0000604 00000014207 15075035625 0013165 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Component\Theme\AbstractTheme; use Gantry\Component\Theme\ThemeTrait; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Class Theme * @package Gantry\Framework */ class Theme extends AbstractTheme { use ThemeTrait; /** * @var bool */ protected $joomla = false; /** * If parameter is set to true, loads bootstrap. Returns true if bootstrap has been loaded. * * @param bool|null $enable * @return bool */ public function joomla($enable = null) { if ($enable && !$this->joomla) { $this->joomla = true; // Workaround for Joomla! not loading bootstrap when it needs it. $this->gantry()->load('bootstrap.2'); } return $this->joomla; } /** * @see AbstractTheme::extendTwig() * * @param \Twig_Environment $twig * @param \Twig_LoaderInterface $loader * @return \Twig_Environment */ public function extendTwig(\Twig_Environment $twig, \Twig_LoaderInterface $loader = null) { parent::extendTwig($twig, $loader); /** @var \Twig_Extension_Core $core */ $core = $twig->getExtension('Twig_Extension_Core'); // Get user timezone and if not set, use Joomla default. $timezone = \JFactory::getUser()->getParam('timezone', \JFactory::getConfig()->get('offset', 'UTC')); $core->setTimezone(new \DateTimeZone($timezone)); // Set locale for dates and numbers. $core->setDateFormat(\JText::_('DATE_FORMAT_LC2'), \JText::_('GANTRY5_X_DAYS')); $core->setNumberFormat(0, \JText::_('DECIMALS_SEPARATOR'), \JText::_('THOUSANDS_SEPARATOR')); $filter = new \Twig_SimpleFilter('date', [$this, 'twig_dateFilter'], array('needs_environment' => true)); $twig->addFilter($filter); return $twig; } /** * Converts a date to the given format. * * <pre> * {{ post.published_at|date("m/d/Y") }} * </pre> * * @param \Twig_Environment $env * @param \DateTime|\DateTimeInterface|\DateInterval|string $date A date * @param string|null $format The target format, null to use the default * @param \DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged * * @return string The formatted date */ public function twig_dateFilter(\Twig_Environment $env, $date, $format = null, $timezone = null) { if (null === $format) { $formats = $env->getExtension('Twig_Extension_Core')->getDateFormat(); $format = $date instanceof \DateInterval ? $formats[1] : $formats[0]; } if ($date instanceof \DateInterval) { return $date->format($format); } if (!($date instanceof \JDate)) { // Create localized JDate object. $twig_date = \twig_date_converter($env, $date, $timezone); $date = new \JDate($twig_date->getTimestamp()); $date->setTimezone($twig_date->getTimezone()); } elseif ($timezone) { $date->setTimezone($timezone); } return $date->format($format, true); } /** * @see AbstractTheme::getContext() * * @param array $context * @return array */ public function getContext(array $context) { $gantry = static::gantry(); $context = parent::getContext($context); $context['site'] = $gantry['site']; $context['joomla'] = $gantry['platform']; return $context; } /** * @see AbstractTheme::init() */ protected function init() { parent::init(); $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $lang = \JFactory::getLanguage(); // FIXME: Do not hardcode this file. $lang->load('files_gantry5_nucleus', JPATH_SITE); if (\JFactory::getApplication()->isSite()) { // Load our custom positions file as frontend requires the strings to be there. $filename = $locator("gantry-theme://language/en-GB/en-GB.tpl_{$this->name}_positions.ini"); if ($filename) { $lang->load("tpl_{$this->name}_positions", \dirname(\dirname(\dirname($filename))), 'en-GB'); } // Load template language files, including overrides. $paths = $locator->findResources('gantry-theme://language'); foreach (array_reverse($paths) as $path) { $lang->load("tpl_{$this->name}", \dirname($path)); } } $doc = \JFactory::getDocument(); if ($doc instanceof \JDocumentHtml) { $doc->setHtml5(true); } $this->language = $doc->language; $this->direction = $doc->direction; $this->url = \JUri::root(true) . '/templates/' . $this->name; \JPluginHelper::importPlugin('gantry5'); // Trigger the onGantryThemeInit event. $dispatcher = \JEventDispatcher::getInstance(); $dispatcher->trigger('onGantry5ThemeInit', ['theme' => $this]); } /** * Get list of twig paths. * * @return array */ public static function getTwigPaths() { /** @var UniformResourceLocator $locator */ $locator = static::gantry()['locator']; return $locator->mergeResources(['gantry-theme://twig', 'gantry-engine://twig']); } /** * @see AbstractTheme::setTwigLoaderPaths() * * @param \Twig_LoaderInterface $loader * @return \Twig_Loader_Filesystem */ protected function setTwigLoaderPaths(\Twig_LoaderInterface $loader) { $loader = parent::setTwigLoaderPaths($loader); if ($loader) { $loader->setPaths($this->getTwigPaths()); } return $loader; } } classes/Gantry/Framework/Atoms.php 0000604 00000022345 15075035625 0013210 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\Config; use Gantry\Component\File\CompiledYamlFile; use RocketTheme\Toolbox\ArrayTraits\ArrayAccess; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\ExportInterface; use RocketTheme\Toolbox\ArrayTraits\Iterator; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Atoms implements \ArrayAccess, \Iterator, ExportInterface { use ArrayAccess, Iterator, Export; /** * @var string */ protected $name; /** * @var array */ protected $items; /** * @var array */ protected $ids; /** * @var array|static[] */ protected static $instances; protected $inherit = false; /** * @param string $outline * @return static */ public static function instance($outline) { if (!isset(static::$instances[$outline])) { $file = CompiledYamlFile::instance("gantry-theme://config/{$outline}/page/head.yaml"); $head = $file->content(); static::$instances[$outline] = new static(isset($head['atoms']) ? $head['atoms'] : [], $outline); $file->free(); static::$instances[$outline]->init(); } return static::$instances[$outline]; } /** * Atoms constructor. * @param array $atoms * @param string $name */ public function __construct(array $atoms = [], $name = null) { $this->name = $name; $this->items = array_filter($atoms); $this->inherit = file_exists('gantry-admin://blueprints/layout/inheritance/atom.yaml'); foreach ($this->items as &$item) { if (!empty($item['id'])) { $this->ids[$item['id']] = $item; } } } public function init() { foreach ($this->items as &$item) { if (!empty($item['inherit']['outline']) && !empty($item['inherit']['atom'])) { $inherited = static::instance($item['inherit']['outline']); $test = $inherited->id($item['inherit']['atom']); if (isset($test['attributes'])) { $item['attributes'] = $test['attributes']; } else { unset($item['inherit']); } } } return $this; } /** * @return $this */ public function update() { foreach ($this->items as &$item) { if (empty($item['id'])) { $item['id'] = $this->createId($item); } if (!empty($item['inherit']['outline']) && !empty($item['inherit']['atom'])) { unset($item['attributes']); } else { unset($item['inherit']); } } return $this; } /** * @param string $outline * @return $this */ public function inheritAll($outline) { foreach ($this->items as &$item) { if (!empty($item['id'])) { $item['inherit'] = [ 'outline' => $outline, 'atom' => $item['id'], 'include' => ['attributes'] ]; } } return $this; } /** * @param string $old * @param string $new * @param array $ids * @return $this */ public function updateInheritance($old, $new = null, $ids = null) { $this->init(); foreach ($this->items as &$item) { if (!empty($item['inherit']['outline']) && $item['inherit']['outline'] == $old && isset($item['inherit']['atom'])) { if ($new && ($ids === null || isset($ids[$item['inherit']['atom']]))) { $item['inherit']['outline'] = $new; } else { unset($item['inherit']); } } } return $this; } public function save() { if ($this->name) { /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; $loadPath = $locator->findResource("gantry-theme://config/{$this->name}/page/head.yaml"); $savePath = $locator->findResource("gantry-theme://config/{$this->name}/page/head.yaml", true, true); if ($loadPath && $savePath) { $file = CompiledYamlFile::instance($loadPath); $head = $file->content(); $head['atoms'] = $this->update()->toArray(); $file->free(); $file = CompiledYamlFile::instance($savePath); $file->save($head); $file->free(); } } } /** * @param string $id * @return array */ public function id($id) { return isset($this->ids[$id]) ? $this->ids[$id] : []; } /** * @param string $type * @return array */ public function type($type) { $list = []; foreach ($this->items as $item) { if ($item['type'] === $type) { $list[] = $item; } } return $list; } /** * @param string $type * @param array $data * @return Config */ public function createAtom($type, array $data = []) { $self = $this; $callable = function () use ($self, $type) { return $self->getBlueprint($type); }; // Create configuration from the data. $item = new Config($data, $callable); $item->def('id', null); $item->def('type', $type); if (!isset($item['title'])) { $item->def('title', $item->blueprint()->get('name')); } $item->def('attributes', []); $item->def('inherit', []); return $item; } /** * @param string $type * @return BlueprintForm */ public function getBlueprint($type) { $blueprint = BlueprintForm::instance($type, 'gantry-blueprints://particles'); if ($this->inherit) { $blueprint->set('form/fields/_inherit', ['type' => 'gantry.inherit']); } return $blueprint; } /** * @param string $type * @param string $id * @param bool $force * @return BlueprintForm|null */ public function getInheritanceBlueprint($type, $id = null, $force = false) { if (!$this->inherit) { return null; } $inheriting = $id ? $this->getInheritingOutlines($id) : []; $list = $this->getOutlines($type, false); if ($force || (empty($inheriting) && $list)) { $inheritance = BlueprintForm::instance('layout/inheritance/atom.yaml', 'gantry-admin://blueprints'); $inheritance->set('form/fields/outline/filter', array_keys($list)); $inheritance->set('form/fields/atom/atom', $type); } elseif (!empty($inheriting)) { // Already inherited by other outlines. $inheritance = BlueprintForm::instance('layout/inheritance/messages/inherited.yaml', 'gantry-admin://blueprints'); $inheritance->set( 'form/fields/_note/content', sprintf($inheritance->get('form/fields/_note/content'), 'atom', ' <ul><li>' . implode('</li> <li>', $inheriting) . '</li></ul>') ); } elseif ($this->name === 'default') { // Base outline. $inheritance = BlueprintForm::instance('layout/inheritance/messages/default.yaml', 'gantry-admin://blueprints'); } else { // Nothing to inherit from. $inheritance = BlueprintForm::instance('layout/inheritance/messages/empty.yaml', 'gantry-admin://blueprints'); } return $inheritance; } /** * @param string $id * @return array */ public function getInheritingOutlines($id = null) { /** @var Outlines $outlines */ $outlines = Gantry::instance()['outlines']; return $outlines->getInheritingOutlinesWithAtom($this->name, $id); } /** * @param string $type * @param bool $includeInherited * @return array */ public function getOutlines($type, $includeInherited = true) { if ($this->name !== 'default') { /** @var Outlines $outlines */ $outlines = Gantry::instance()['outlines']; $list = $outlines->getOutlinesWithAtom($type, $includeInherited); unset($list[$this->name]); } else { $list = []; } return $list; } /** * @param array $item * @return string */ protected function createId(array &$item) { $type = $item['type']; while ($num = rand(1000, 9999)) { if (!isset($this->ids["{$type}-{$num}"])) { break; } } $id = "{$type}-{$num}"; $this->ids[$id] = $item; return $id; } } classes/Gantry/Framework/Services/StreamsServiceProvider.php 0000604 00000002464 15075035625 0020362 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Services; use Gantry\Component\Filesystem\Streams; use Pimple\Container; use RocketTheme\Toolbox\DI\ServiceProviderInterface; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class StreamsServiceProvider implements ServiceProviderInterface { public function register(Container $gantry) { $sp = $this; $gantry['locator'] = function() use ($sp) { return new UniformResourceLocator(GANTRY5_ROOT); }; $gantry['streams'] = function($c) use ($sp) { $schemes = (array) $c['platform']->init()->get('streams'); /** @var UniformResourceLocator $locator */ $locator = $c['locator']; $streams = new Streams($locator); $streams->add($schemes); GANTRY_DEBUGGER && method_exists('Gantry\Debugger', 'setLocator') && \Gantry\Debugger::setLocator($locator); return $streams; }; } } classes/Gantry/Framework/Services/ConfigServiceProvider.php 0000604 00000007551 15075035625 0020153 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Services; use Gantry\Component\Config\CompiledBlueprints; use Gantry\Component\Config\CompiledConfig; use Gantry\Component\Config\ConfigFileFinder; use Gantry\Framework\Atoms; use Pimple\Container; use Pimple\ServiceProviderInterface; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class ConfigServiceProvider implements ServiceProviderInterface { public function register(Container $gantry) { $gantry['blueprints'] = function($c) { GANTRY_DEBUGGER && \Gantry\Debugger::startTimer('blueprints', 'Loading blueprints'); $blueprints = static::blueprints($c); GANTRY_DEBUGGER && \Gantry\Debugger::stopTimer('blueprints'); return $blueprints; }; $gantry['config'] = function($c) { // Make sure configuration has been set. if (!isset($c['configuration'])) { throw new \LogicException('Gantry: Please set current configuration before using $gantry["config"]', 500); } GANTRY_DEBUGGER && \Gantry\Debugger::startTimer('config', 'Loading configuration'); // Get the current configuration and lock the value from modification. $outline = $c->lock('configuration'); $config = static::load($c, $outline); GANTRY_DEBUGGER && \Gantry\Debugger::setConfig($config)->stopTimer('config'); return $config; }; } public static function blueprints(Container $container) { /** @var UniformResourceLocator $locator */ $locator = $container['locator']; $cache = $locator->findResource('gantry-cache://theme/compiled/blueprints', true, true); $files = []; $paths = $locator->findResources('gantry-particles://'); $files += (new ConfigFileFinder)->setBase('particles')->locateFiles($paths); $paths = $locator->findResources('gantry-blueprints://'); $files += (new ConfigFileFinder)->locateFiles($paths); $config = new CompiledBlueprints($cache, $files, GANTRY5_ROOT); return $config->load(); } public static function load(Container $container, $name = 'default', $combine = true, $withDefaults = true) { /** @var UniformResourceLocator $locator */ $locator = $container['locator']; $combine = $combine && $name !== 'default'; // Merge current configuration with the default. $uris = $combine ? ["gantry-config://{$name}", 'gantry-config://default'] : ["gantry-config://{$name}"]; $paths = []; foreach ($uris as $uri) { $paths = array_merge($paths, $locator->findResources($uri)); } // Locate all configuration files to be compiled. $files = (new ConfigFileFinder)->locateFiles($paths); $cache = $locator->findResource('gantry-cache://theme/compiled/config', true, true); if (!$cache) { throw new \RuntimeException('Who just removed Gantry 5 cache folder? Try reloading the page if it fixes the issue'); } $compiled = new CompiledConfig($cache, $files, GANTRY5_ROOT); $compiled->setBlueprints(function() use ($container) { return $container['blueprints']; }); $config = $compiled->load($withDefaults); // Set atom inheritance. $atoms = $config->get('page.head.atoms'); if (is_array($atoms)) { $config->set('page.head.atoms', (new Atoms($atoms))->init()->toArray()); } return $config; } } classes/Gantry/Framework/Services/ErrorServiceProvider.php 0000604 00000004351 15075035625 0020032 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Services; use Gantry\Component\Whoops\SystemFacade; use Gantry\Framework\Platform; use Pimple\Container; use Pimple\ServiceProviderInterface; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use Whoops\Handler\JsonResponseHandler; use Whoops\Handler\PrettyPageHandler; use Whoops\Run; use Whoops\Util\Misc; class ErrorServiceProvider implements ServiceProviderInterface { protected $format; public function __construct($format = 'html') { $this->format = $format; } public function register(Container $container) { /** @var UniformResourceLocator $locator */ $locator = $container['locator']; /** @var Platform $platform */ $platform = $container['platform']; // Setup Whoops-based error handler $system = new SystemFacade($platform->errorHandlerPaths()); $errors = new Run($system); $error_page = new PrettyPageHandler; $error_page->setPageTitle('Crikey! There was an error...'); $error_page->setEditor('sublime'); foreach ($locator->findResources('gantry-assets://css/whoops.css') as $path) { $error_page->addResourcePath(dirname($path)); } $error_page->addCustomCss('whoops.css'); $errors->pushHandler($error_page); $jsonRequest = $this->format === 'json' || ($_SERVER && isset($_SERVER['HTTP_ACCEPT']) && $_SERVER['HTTP_ACCEPT'] == 'application/json'); if (Misc::isAjaxRequest() || $jsonRequest) { $json_handler = new JsonResponseHandler; //$json_handler->setJsonApi(true); $errors->pushHandler($json_handler); } $errors->register(); $container['errors'] = $errors; if (GANTRY_DEBUGGER && method_exists('Gantry\Debugger', 'setErrorHandler')) { \Gantry\Debugger::setErrorHandler(); } } } classes/Gantry/Framework/Site.php 0000604 00000001155 15075035625 0013025 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; class Site { public function __construct() { $document = \JFactory::getDocument(); if ($document instanceof \JDocumentHTML) { $this->theme = $document->template; $this->url = $document->baseurl; $this->title = $document->title; $this->description = $document->description; } } } classes/Gantry/Framework/Request.php 0000604 00000000753 15075035625 0013554 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework; use Gantry\Component\Request\Request as BaseRequest; class Request extends BaseRequest {} classes/Gantry/Framework/Base/Platform.php 0000604 00000014730 15075035625 0014562 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Base; use Gantry\Component\Filesystem\Folder; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess; use RocketTheme\Toolbox\DI\Container; /** * The Platform Configuration class contains configuration information. * * @author RocketTheme * @license MIT */ abstract class Platform { use NestedArrayAccess, Export; protected $name; protected $features = []; protected $settings_key; protected $items; protected $container; public function __construct(Container $container) { $this->container = $container; //Make sure that cache folder exists, otherwise it will be removed from the lookup. $cachePath = $this->getCachePath(); Folder::create($cachePath); $this->items = [ 'streams' => [ // Cached files. 'gantry-cache' => [ 'type' => 'Stream', 'force' => true, 'prefixes' => ['' => [$cachePath]] ], // Container for all frontend themes. 'gantry-themes' => [ 'type' => 'ReadOnlyStream', 'prefixes' => $this->getThemesPaths() ], // Selected frontend theme. 'gantry-theme' => [ 'type' => 'ReadOnlyStream', 'prefixes' => $this->getThemePaths() ], // System defined media files. 'gantry-assets' => [ 'type' => 'ReadOnlyStream', 'prefixes' => $this->getAssetsPaths() ], // User defined media files. 'gantry-media' => [ 'type' => 'ReadOnlyStream', 'prefixes' => $this->getMediaPaths() ], // Container for all Gantry engines. 'gantry-engines' => [ 'type' => 'ReadOnlyStream', 'prefixes' => $this->getEnginesPaths() ], // Gantry engine used to render the selected theme. 'gantry-engine' => [ 'type' => 'ReadOnlyStream', 'prefixes' => $this->getEnginePaths() ], // Layout definitions for the blueprints. 'gantry-layouts' => [ 'type' => 'ReadOnlyStream', 'prefixes' => ['' => ['gantry-theme://layouts', 'gantry-engine://layouts']] ], // Gantry particles. 'gantry-particles' => [ 'type' => 'ReadOnlyStream', 'prefixes' => ['' => ['gantry-theme://particles', 'gantry-engine://particles']] ], // Gantry administration. 'gantry-admin' => [ 'type' => 'ReadOnlyStream', 'prefixes' => [] ], // Blueprints for the configuration. 'gantry-blueprints' => [ 'type' => 'ReadOnlyStream', 'prefixes' => [ '' => ['gantry-theme://blueprints', 'gantry-engine://blueprints'], 'particles' => ['gantry-particles://'] ] ], // Configuration from the selected theme. 'gantry-config' => [ 'type' => 'ReadOnlyStream', 'prefixes' => ['' => ['gantry-theme://config']] ] ] ]; } abstract public function getCachePath(); abstract public function getThemesPaths(); abstract public function getAssetsPaths(); abstract public function getMediaPaths(); public function init() { return $this; } public function has($feature) { return !empty($this->features[$feature]); } public function getThemePaths() { return ['' => []]; } public function getEnginePaths($name = 'nucleus') { return ['' => ['gantry-theme://engine', "gantry-engines://{$name}"]]; } public function getEnginesPaths() { return ['' => []]; } public function errorHandlerPaths() { return []; } /** * Get preview url for individual theme. * * @param string $theme * @return string|null */ abstract public function getThemePreviewUrl($theme); /** * Get administrator url for individual theme. * * @param string $theme * @return string|null */ abstract public function getThemeAdminUrl($theme); public function settings() { return null; } public function settings_key() { return $this->settings_key; } public function listModules() { return false; } public function getName() { return $this->name; } public function getEditor($name, $content = '', $width = null, $height = null) { return null; } public function filter($text) { return $text; } public function finalize() { $gantry = Gantry::instance(); $gantry['document']->registerAssets(); } public function call() { $args = func_get_args(); $callable = array_shift($args); return is_callable($callable) ? call_user_func_array($callable, $args) : null; } public function authorize($action) { return true; } /** * @param array|string $dependencies * @return bool|null * @since 5.4.3 */ public function checkDependencies($dependencies) { if (is_string($dependencies) && $dependencies !== $this->name) { return false; } if (isset($dependencies['platform'])) { if (is_string($dependencies['platform']) && $dependencies['platform'] !== $this->name) { return false; } if (!isset($dependencies['platform'][$this->name])) { return false; } } return true; } } classes/Gantry/Framework/Base/Page.php 0000604 00000004115 15075035625 0013646 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Base; abstract class Page { protected $container; protected $config; public function __construct($container) { $this->container = $container; $this->config = $container['config']; } public function doctype() { return $this->config->get('page.doctype', 'html'); } abstract public function url(array $args = []); public function preset() { /** @var Theme $theme */ $theme = $this->container['theme']; return 'g-' . preg_replace('/[^a-z0-9-]/', '', $theme->type()); } public function htmlAttributes() { return $this->getAttributes($this->config->get('page.html')); } public function bodyAttributes($attributes = []) { return $this->getAttributes($this->config->get('page.body.attribs'), $attributes); } protected function getAttributes($params, $extra = []) { $params = array_merge_recursive($params, $extra); $list = []; foreach ($params as $param => $value) { if (!$value) { continue; } if (!is_array($value) || !count(array_filter($value, 'is_array'))) { $value = array_filter(array_unique((array) $value)); $list[] = $param . '="' . implode(' ', $value) . '"'; } else { $values = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($value)); foreach ($values as $iparam => $ivalue) { $ivalue = array_filter(array_unique((array) $ivalue)); $list[] = $iparam . '="' . implode(' ', $ivalue) . '"'; } } } return $list ? ' ' . implode(' ', $list) : ''; } } classes/Gantry/Framework/Base/Theme.php 0000604 00000001107 15075035625 0014032 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Base; use Gantry\Component\Theme\AbstractTheme; use Gantry\Component\Theme\ThemeTrait; /** * @deprecated 5.1.5 */ abstract class Theme extends AbstractTheme { use ThemeTrait; } classes/Gantry/Framework/Base/Site.php 0000604 00000000644 15075035625 0013701 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Base; class Site { } classes/Gantry/Framework/Base/Gantry.php 0000604 00000022206 15075035625 0014237 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Base; use Gantry\Component\Config\Config; use Gantry\Component\System\Messages; use Gantry\Framework\Document; use Gantry\Framework\Menu; use Gantry\Framework\Outlines; use Gantry\Framework\Page; use Gantry\Framework\Platform; use Gantry\Framework\Positions; use Gantry\Framework\Request; use Gantry\Framework\Services\ConfigServiceProvider; use Gantry\Framework\Services\StreamsServiceProvider; use Gantry\Framework\Site; use Gantry\Framework\Translator; use RocketTheme\Toolbox\DI\Container; use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\Event\EventDispatcher; abstract class Gantry extends Container { /** * @var static */ protected static $instance; protected $wrapper; public static function instance() { if (!self::$instance) { self::$instance = static::init(); if (!defined('GANTRY5_DEBUG')) { define('GANTRY5_DEBUG', self::$instance->debug()); } } return self::$instance; } public static function restart() { self::$instance = null; return static::instance(); } /** * Returns true if debug mode has been enabled. * * @return boolean */ public function debug() { return $this['global']->get('debug', false); } /** * Returns true if we are in administration. * * @return boolean */ public function admin() { return defined('GANTRYADMIN_PATH'); } /** * @return string */ public function siteUrl() { $gantry = Gantry::instance(); return $gantry['document']->siteUrl(); } /** * @param string $location * @return array */ public function styles($location = 'head') { return $this['document']->getStyles($location); } /** * @param string $location * @return array */ public function scripts($location = 'head') { return $this['document']->getScripts($location); } /** * Load Javascript framework / extension in platform independent way. * * @param string $framework * @return bool */ public function load($framework) { return $this['document']->addFramework($framework); } /** * Lock the variable against modification and return the value. * * @param string $id * @return mixed */ public function lock($id) { $value = $this[$id]; try { // Create a dummy service. $this[$id] = function () use ($value) { return $value; }; } catch (\RuntimeException $e) { // Services are already locked, so ignore the error. } // Lock the service and return value. return $this[$id]; } /** * Fires an event with optional parameters. * * @param string $eventName * @param Event $event * @return Event */ public function fireEvent($eventName, Event $event = null) { /** @var EventDispatcher $events */ $events = $this['events']; return $events->dispatch($eventName, $event); } public function route($path) { $routes = $this->offsetGet('routes'); $route = isset($routes[$path]) ? $routes[$path] : $routes[1]; if (!$route) { // TODO: need to implement back to root in Prime.. return $this->offsetGet('base_url'); } $path = implode('/', array_filter(func_get_args(), function($var) { return isset($var) && $var !== ''; })); // rawurlencode() the whole path, but keep the slashes. $path = preg_replace(['|%2F|', '|%25|'], ['/', '%'], rawurlencode($path)); return preg_replace('|/+|', '/', '/' . $this->offsetGet('base_url') . sprintf($route, $path)); } public function authorize($action, $id = null) { return $this['platform']->authorize($action, $id); } public function wrapper($value = null) { if ($value !== null ) { $this->wrapper = $value; } return $this->wrapper; } protected static function init() { /** @var Gantry $instance */ $instance = new static(); if (GANTRY_DEBUGGER) { $instance['debugger'] = \Gantry\Debugger::instance(); } $instance['loader'] = \Gantry5\Loader::get(); $instance->register(new ConfigServiceProvider); $instance->register(new StreamsServiceProvider); $instance['request'] = function () { return new Request; }; $instance['events'] = function () { return new EventDispatcher; }; $instance['platform'] = function ($c) { return new Platform($c); }; $instance['translator'] = function () { return new Translator; }; $instance['site'] = function () { return new Site; }; $instance['menu'] = function () { return new Menu; }; $instance['messages'] = function () { return new Messages; }; $instance['page'] = function ($c) { return new Page($c); }; $instance['document'] = function () { return new Document; }; // Make sure that nobody modifies the original collection by making it a factory. $instance['outlines'] = $instance->factory(function ($c) { static $collection; if (!$collection) { $collection = (new Outlines($c))->load(); } return $collection->copy(); }); // @deprecated 5.3 $instance['configurations'] = $instance->factory(function ($c) { GANTRY_DEBUGGER && \Gantry\Debugger::addMessage("Depredated call: gantry.configurations"); static $collection; if (!$collection) { $collection = (new Outlines($c))->load(); } return $collection->copy(); }); $instance['positions'] = $instance->factory(function ($c) { static $collection; if (!$collection) { $collection = (new Positions($c))->load(); } return $collection->copy(); }); $instance['global'] = function ($c) { $data = $c->loadGlobal() + [ 'debug' => false, 'production' => true, 'use_media_folder' => false, 'asset_timestamps' => true, 'asset_timestamps_period' => 7, 'compile_yaml' => true, 'compile_twig' => true ]; return new Config($data); }; return $instance; } /** * Check if Gantry is compatible with your theme / extension. * * This function can be used to make sure that user has installed Gantry version * that has been tested to work with your extension. All existing functions should * be backwards compatible, but each release can add some new functionality, which * you may want to use. * * <code> * if ($gantry->isCompatible('5.0.1')) { * // You can do it in the new way. * } else { * // Revert to the old way to display an error message. * } * </code> * * @param string $version Minimum required version. * * @return boolean Yes, if it is safe to use Gantry Framework. */ public function isCompatible($version) { // If requested version is smaller than 5.0-rc, it's not compatible. if (version_compare($version, '5.0-rc', '<')) { return false; } // Development version support. if ($version === '5.3' || static::isDev()) { return true; } // Check if future version is needed. if (version_compare($version, GANTRY5_VERSION, '>')) { return false; } return true; } /** * Check if Gantry is running from a Git repository or is a CI build. * * Developers tend to do their work directly in the Git repositories instead of * creating and installing new builds after every change. This function can be * used to check the condition and make sure we do not break users repository * by replacing files during upgrade. * * @return boolean True if Git repository or CI build is detected. */ public function isDev() { if ('@version@' == GANTRY5_VERSION) { return true; } if ('dev-' === substr(GANTRY5_VERSION, 0, 4)) { return true; } return false; } /** * @return array */ protected function loadGlobal() { return []; } } classes/Gantry/Framework/Exception.php 0000604 00000002030 15075035625 0014050 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework; class Exception extends \RuntimeException { protected $responseCodes = [ 200 => '200 OK', 400 => '400 Bad Request', 401 => '401 Unauthorized', 403 => '403 Forbidden', 404 => '404 Not Found', 410 => '410 Gone', 500 => '500 Internal Server Error', 501 => '501 Not Implemented', 503 => '503 Service Temporarily Unavailable' ]; public function getResponseCode() { return isset($this->responseCodes[$this->code]) ? (int) $this->code : 500; } public function getResponseStatus() { return $this->responseCodes[$this->getResponseCode()]; } } classes/Gantry/Framework/Document.php 0000604 00000016143 15075035625 0013702 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Component\Content\Document\HtmlDocument; class Document extends HtmlDocument { protected static $availableFrameworks = [ 'jquery' => 'registerJquery', 'jquery.framework' => 'registerJquery', 'jquery.ui.core' => 'registerJqueryUiCore', 'jquery.ui.sortable' => 'registerJqueryUiSortable', 'bootstrap.2' => 'registerBootstrap2', 'mootools' => 'registerMootools', 'mootools.framework' => 'registerMootools', 'mootools.core' => 'registerMootools', 'mootools.more' => 'registerMootoolsMore', 'lightcase' => 'registerLightcase', 'lightcase.init' => 'registerLightcaseInit', ]; public static function registerAssets() { static::registerFrameworks(); static::registerStyles(); static::registerScripts(); } /** * NOTE: In PHP this function can be called either from Gantry DI container or statically. * * @param bool $addDomain * @return string */ public static function domain($addDomain = false) { if (!$addDomain) { return ''; } $absolute = \JUri::root(false); $relative = \JUri::root(true); return substr($absolute, 0, -strlen($relative)); } public static function rootUri() { return rtrim(\JUri::root(true), '/') ?: '/'; } public static function errorPage($new = null) { static $error = false; if (isset($new)) { $error = (bool) $new; } return $error; } protected static function registerStyles() { if (static::errorPage()) { return; } $doc = \JFactory::getDocument(); $styles = static::$stack[0]->getStyles(); foreach ($styles as $style) { switch ($style[':type']) { case 'file': $doc->addStyleSheet($style['href'], $style['type'], $style['media'], $style['element']); break; case 'inline': $doc->addStyleDeclaration($style['content'], $style['type']); break; } } } protected static function registerScripts() { if (static::errorPage()) { return; } $doc = \JFactory::getDocument(); $scripts = static::$stack[0]->getScripts(); foreach ($scripts as $script) { switch ($script[':type']) { case 'file': $doc->addScript($script['src'], $script['type'], $script['defer'], $script['async']); break; case 'inline': $doc->addScriptDeclaration($script['content'], $script['type']); break; } } } protected static function registerJquery() { if (!static::errorPage()) { \JHtml::_('jquery.framework'); return; } // Workaround for error document type. static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/jui/js/jquery.min.js' ], 'head', 100 ); static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/jui/js/jquery-noconflict.js' ], 'head', 100 ); static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/jui/js/jquery-migrate.min.js' ], 'head', 100 ); } protected static function registerJqueryUiCore() { if (!static::errorPage()) { \JHtml::_('jquery.ui', ['core']); return; } // Workaround for error document type. static::registerJquery(); static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/jui/js/jquery.ui.core.min.js' ], 'head', 100 ); } protected static function registerJqueryUiSortable() { if (!static::errorPage()) { \JHtml::_('jquery.ui', ['sortable']); return; } // Workaround for error document type. static::registerJqueryUiCore(); static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/jui/js/jquery.ui.sortable.min.js' ], 'head', 100 ); } protected static function registerBootstrap2() { Gantry::instance()['theme']->joomla(true); if (!static::errorPage()) { \JHtml::_('bootstrap.framework'); return; } // Workaround for error document type. static::registerJquery(); static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/jui/js/bootstrap.min.js' ], 'head', 100 ); } protected static function registerMootools() { if (!static::errorPage()) { \JHtml::_('behavior.framework'); return; } // Workaround for error document type. static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/system/js/mootools-core.js' ], 'head', 99 ); static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/system/js/core.js' ], 'head', 99 ); } protected static function registerMootoolsMore() { if (!static::errorPage()) { \JHtml::_('behavior.framework', true); return; } // Workaround for error document type. static::registerMootools(); static::addHeaderTag( [ 'tag' => 'script', 'src' => \JUri::getInstance()->base(true) . '/media/system/js/mootools-more.js' ], 'head', 99 ); } /** * Override to support index.php?Itemid=xxx. * * @param array $matches * @return string * @internal */ public static function linkHandler(array $matches) { $url = trim($matches[3]); if (strpos($url, 'index.php?') !== 0) { list($domain, $timestamp_age) = static::$urlFilterParams; $url = static::url(trim($matches[3]), $domain, $timestamp_age); } return "{$matches[1]}{$matches[2]}=\"{$url}\""; } } classes/Gantry/Framework/Markdown/Parsedown.php 0000604 00000001227 15075035625 0015645 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Markdown; class Parsedown extends \Parsedown { use ParsedownTrait; /** * Parsedown constructor. * * @param array $defaults */ public function __construct(array $defaults = null) { $this->init($defaults ?: []); } } classes/Gantry/Framework/Markdown/ParsedownExtra.php 0000604 00000001337 15075035625 0016653 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Markdown; class ParsedownExtra extends \ParsedownExtra { use ParsedownTrait; /** * ParsedownExtra constructor. * * @param array $defaults * @throws \Exception */ public function __construct(array $defaults = null) { parent::__construct(); $this->init($defaults ?: []); } } classes/Gantry/Framework/Markdown/ParsedownTrait.php 0000604 00000010342 15075035625 0016647 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Framework\Markdown; use Gantry\Framework\Gantry; trait ParsedownTrait { protected $special_chars; protected $twig_link_regex = '/\!*\[(?:.*)\]\((\{([\{%#])\s*(.*?)\s*(?:\2|\})\})\)/'; /** * Initialization function to setup key variables needed by the MarkdownGravLinkTrait * * @param $defaults */ protected function init(array $defaults) { $defaults += [ 'auto_line_breaks' => false, 'auto_url_links' => false, 'escape_markup' => false, 'special_chars' => false ]; $this->BlockTypes['{'][] = 'TwigTag'; $this->special_chars = ['>' => 'gt', '<' => 'lt', '"' => 'quot']; $this->setBreaksEnabled($defaults['auto_line_breaks']); $this->setUrlsLinked($defaults['auto_url_links']); $this->setMarkupEscaped($defaults['escape_markup']); $this->setSpecialChars($defaults['special_chars']); } /** * Setter for special chars * * @param $special_chars * * @return $this */ public function setSpecialChars($special_chars) { $this->special_chars = $special_chars; return $this; } /** * Ensure Twig tags are treated as block level items with no <p></p> tags * * @param array $line * @return array|null */ protected function blockTwigTag($line) { if (preg_match('/(?:{{|{%|{#)(.*)(?:}}|%}|#})/', $line['body'], $matches)) { return ['markup' => $line['body']]; } return null; } protected function inlineSpecialCharacter($excerpt) { if ($excerpt['text'][0] === '&' && !preg_match('/^&#?\w+;/', $excerpt['text'])) { return [ 'markup' => '&', 'extent' => 1, ]; } if (isset($this->special_chars[$excerpt['text'][0]])) { return [ 'markup' => '&' . $this->special_chars[$excerpt['text'][0]] . ';', 'extent' => 1, ]; } return null; } protected function inlineImage($excerpt) { if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) { $excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']); $excerpt = parent::inlineImage($excerpt); $excerpt['element']['attributes']['src'] = $matches[1]; $excerpt['extent'] = $excerpt['extent'] + \strlen($matches[1]) - 1; return $excerpt; } $excerpt['type'] = 'image'; $excerpt = parent::inlineImage($excerpt); // if this is an image process it if (isset($excerpt['element']['attributes']['src'])) { $gantry = Gantry::instance(); $excerpt['element']['attributes']['src'] = $gantry['document']->url($excerpt['element']['attributes']['src']); } return $excerpt; } protected function inlineLink($excerpt) { if (!isset($excerpt['type'])) { $excerpt['type'] = 'link'; } // do some trickery to get around Parsedown requirement for valid URL if its Twig in there if (preg_match($this->twig_link_regex, $excerpt['text'], $matches)) { $excerpt['text'] = str_replace($matches[1], '/', $excerpt['text']); $excerpt = parent::inlineLink($excerpt); $excerpt['element']['attributes']['href'] = $matches[1]; $excerpt['extent'] = $excerpt['extent'] + \strlen($matches[1]) - 1; return $excerpt; } $excerpt = parent::inlineLink($excerpt); // if this is a link if (isset($excerpt['element']['attributes']['href'])) { $gantry = Gantry::instance(); $excerpt['element']['attributes']['href'] = $gantry['document']->url($excerpt['element']['attributes']['href']); } return $excerpt; } } classes/Gantry/Framework/Menu.php 0000604 00000031100 15075035625 0013016 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Framework; use Gantry\Component\Config\Config; use Gantry\Component\Gantry\GantryTrait; use Gantry\Component\Menu\AbstractMenu; use Gantry\Component\Menu\Item; class Menu extends AbstractMenu { use GantryTrait; /** * @var \JApplicationCms */ protected $app; /** * @var \JMenu */ protected $menu; public function __construct() { $this->app = \JApplicationCms::getInstance('site'); $lang = \JFactory::getLanguage(); $tag = \JLanguageMultilang::isEnabled() ? $lang->getTag() : '*'; $this->menu = $this->app->getMenu(); $this->default = $this->menu->getDefault($tag); $this->active = $this->menu->getActive(); } public function init(&$params) { parent::init($params); if (!empty($params['admin'])) { /** @var \JTableMenuType $table */ $menuType = \JTable::getInstance('MenuType'); $menuType->load(['menutype' => $params['menu']]); $config = $this->config(); $config->set('settings.title', $menuType->title); $config->set('settings.description', $menuType->description); } } /** * Return list of menus. * * @return array * @throws \RuntimeException */ public function getMenus() { static $items; if ($items === null) { require_once JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php'; $items = (array) \MenusHelper::getMenuTypes(); } return $items; } public function getGroupedItems() { $groups = array(); // Get the menu items. $items = \MenusHelper::getMenuLinks(); // Build the groups arrays. foreach ($items as $item) { // Initialize the group. $groups[$item->menutype] = []; // Build the options array. foreach ($item->links as $link) { $groups[$item->menutype][$link->value] = [ 'spacing' => str_repeat(' ', max(0, $link->level-1)), 'label' => $link->text ]; } } return $groups; } /** * Return default menu. * * @return string|null */ public function getDefaultMenuName() { return $this->default ? $this->default->menutype : null; } /** * Returns true if the platform implements a Default menu. * * @return boolean */ public function hasDefaultMenu() { return true; } /** * Return active menu. * * @return string|null */ public function getActiveMenuName() { return $this->active ? $this->active->menutype : null; } /** * Returns true if the platform implements an Active menu. * * @return boolean */ public function hasActiveMenu() { return true; } /** * @return string|null */ public function getCacheId() { if (!\JFactory::getUser()->guest) { return null; } return $this->active ? $this->active->id : 0; } public function isActive($item) { $tree = $this->base->tree; if (in_array($item->id, $tree)) { return true; } elseif ($item->type == 'alias') { $aliasToId = $item->link_id; if (count($tree) > 0 && $aliasToId == $tree[count($tree) - 1]) { return (bool) $this->params['highlightAlias']; } elseif (in_array($aliasToId, $tree)) { return (bool) $this->params['highlightParentAlias']; } } return false; } public function isCurrent($item) { return $item->id == $this->active->id || ($item->type == 'alias' && $item->params->get('aliasoptions') == $this->active->id); } /** * Get menu items from the platform. * * @param array $params * @return array List of routes to the pages. */ protected function getItemsFromPlatform($params) { $attributes = ['menutype']; $values = [$params['menu']]; // Items are already filtered by access and language, in admin we need to work around that. if (\JFactory::getApplication()->isAdmin()) { $attributes[] = 'access'; $values[] = null; $attributes[] = 'language'; $values[] = null; } return $this->menu->getItems($attributes, $values); } /** * Get base menu item. * * If itemid is not specified or does not exist, return active menu item. * If there is no active menu item, fall back to home page for the current language. * If there is no home page, return null. * * @param int $itemid * * @return object|null */ protected function calcBase($itemid = null) { $menu = $this->app->getMenu(); // Get base menu item. $base = $itemid ? $menu->getItem($itemid) : null; if (!$base) { // Use active menu item or fall back to default menu item. $base = $this->active ?: $this->default; } // Return base menu item. return $base; } /** * Get a list of the menu items. * * Logic was originally copied from Joomla 3.4 mod_menu/helper.php (joomla-cms/staging, 2014-11-12). * We should keep the contents of the function similar to Joomla in order to review it against any changes. * * @param array $params * @param array $items */ public function getList(array $params, array $items) { // Get base menu item for this menu (defaults to active menu item). $this->base = $this->calcBase($params['base']); // Make sure that the menu item exists. if (!$this->base && !\JFactory::getApplication()->isAdmin()) { return; } $levels = \JFactory::getUser()->getAuthorisedViewLevels(); asort($levels); // FIXME: need to create collection class to gather the sibling data, otherwise caching cannot work. //$key = 'gantry_menu_items.' . json_encode($params) . '.' . json_encode($levels) . '.' . $this->base->id; //$cache = \JFactory::getCache('mod_menu', ''); //try { // $this->items = $cache->get($key); //} catch (\Exception $e) { // $this->items = false; //} if (1) { $tree = isset($this->base->tree) ? $this->base->tree : []; $start = $params['startLevel']; $max = $params['maxLevels']; $end = $max ? $start + $max - 1 : 0; $menuItems = $this->getItemsFromPlatform($params); $itemMap = []; foreach ($items as $path => &$itemRef) { if (isset($itemRef['id']) && is_numeric($itemRef['id'])) { $itemRef['path'] = $path; $itemMap[$itemRef['id']] = &$itemRef; } } foreach ($menuItems as $menuItem) { if (($start && $start > $menuItem->level) || ($end && $menuItem->level > $end) || ($start > 1 && !in_array($menuItem->tree[$start - 2], $tree))) { continue; } // These params always come from Joomla and cannot be overridden. $itemParams = [ 'id' => $menuItem->id, 'type' => $menuItem->type, 'alias' => $menuItem->alias, 'path' => $menuItem->route, 'link' => $menuItem->link, 'link_title' => $menuItem->params->get('menu-anchor_title', ''), 'rel' => $menuItem->params->get('menu-anchor_rel', ''), 'enabled' => (bool) $menuItem->params->get('menu_show', 1), ]; // Rest of the items will come from saved configuration. if (isset($itemMap[$menuItem->id])) { // ID found, use it. $itemParams += $itemMap[$menuItem->id]; // Store new path for the menu item into path map. if ($itemParams['path'] !== $itemMap[$menuItem->id]['path']) { if (!$this->pathMap) { $this->pathMap = new Config([]); } $this->pathMap->set(preg_replace('|/|u', '/children/', $itemMap[$menuItem->id]['path']) . '/path', $itemParams['path'], '/'); } } elseif (isset($items[$menuItem->route])) { // ID not found, try to use route. $itemParams += $items[$menuItem->route]; } // Get default target from Joomla. switch ($menuItem->browserNav) { default: case 0: // Target window: Parent. $target = '_self'; break; case 1: case 2: // Target window: New with navigation. $target = '_blank'; break; } // And if not available in configuration, default to Joomla. $itemParams += [ 'title' => $menuItem->title, 'anchor_class' => $menuItem->params->get('menu-anchor_css', ''), 'image' => $menuItem->params->get('menu_image', ''), 'icon_only' => !$menuItem->params->get('menu_text', 1), 'target' => $target ]; $item = new Item($this, $menuItem->route, $itemParams); $this->add($item); $link = $item->link; switch ($item->type) { case 'separator': case 'heading': // These types have no link. $link = null; break; case 'url': if ((strpos($item->link, 'index.php?') === 0) && (strpos($item->link, 'Itemid=') === false)) { // If this is an internal Joomla link, ensure the Itemid is set. $link = $item->link . '&Itemid=' . $item->id; } break; case 'alias': // If this is an alias use the item id stored in the parameters to make the link. $link = 'index.php?Itemid=' . $menuItem->params->get('aliasoptions', 0); break; default: $app = $this->app; $router = $app::getRouter(); if ($router->getMode() == JROUTER_MODE_SEF) { $link = 'index.php?Itemid=' . $item->id; if (isset($menuItem->query['format']) && $app->get('sef_suffix')) { $link .= '&format=' . $menuItem->query['format']; } } else { $link .= '&Itemid=' . $item->id; } break; } if (!$link) { $item->url(false); } elseif (strcasecmp(substr($link, 0, 4), 'http') && (strpos($link, 'index.php?') !== false)) { $item->url(\JRoute::_($link, false, $menuItem->params->get('secure'))); } else { $item->url(\JRoute::_($link, false)); } if ($item->type == 'url') { // Moved from modules/mod_menu/tmpl/default_url.php, not sure why Joomla had application logic in there. // Keep compatibility to Joomla menu module, but we need non-encoded version of the url. $item->url( htmlspecialchars_decode(\JFilterOutput::ampReplace(htmlspecialchars($item->link, ENT_COMPAT|ENT_SUBSTITUTE, 'UTF-8'))) ); } } // FIXME: need to create collection class to gather the sibling data, otherwise caching cannot work. // $cache->store($this->items, $key); } } } classes/Gantry/Joomla/Object/AbstractObject.php 0000604 00000031372 15075035625 0015511 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Object; /** * Abstract base class for database objects. * * */ abstract class AbstractObject extends \JObject { /** * If you don't have global instance ids, override this in extending class. * @var array */ static protected $instances = []; /** * Override table class in your own class. * @var string */ static protected $table; /** * JTable class prefix, override if needed. * @var string */ static protected $tablePrefix = 'JTable'; /** * Override table in your own class. * @var string */ static protected $order; /** * @var int */ public $id; /** * Is object stored into database? * @var boolean */ protected $_exists = false; /** * Readonly object. * @var bool */ protected $_readonly = false; /** * @var bool */ protected $_initialized = false; /** * Class constructor, overridden in descendant classes. * * @param int $identifier Identifier. */ public function __construct($identifier = null) { parent::__construct(); if ($identifier) { $this->load($identifier); } } /** * Override this function if you need to initialize object right after creating it. * * Can be used for example if the database fields need to be converted to array or JRegistry. * * @return bool True if initialization was done, false if object was already initialized. */ public function initialize() { $initialized = $this->_initialized; $this->_initialized = true; return !$initialized; } /** * Make instance as read only object. */ public function readonly() { $this->_readonly = true; } /** * Returns the global instance to the object. * * Note that using array of fields will always make a query to the database, but it's very useful feature if you want to search * one item by using arbitrary set of matching fields. If there are more than one matching object, first one gets returned. * * @param int|array $keys An optional primary key value to load the object by, or an array of fields to match. * @param boolean $reload Force object reload from the database. * * @return Object */ static public function getInstance($keys = null, $reload = false) { // If we are creating or loading a new item or we load instance by alternative keys, // we need to create a new object. if (!$keys || is_array($keys) || !isset(static::$instances[(int) $keys])) { $c = get_called_class(); $instance = new $c($keys); /** @var Object $instance */ if (!$instance->exists()) return $instance; // Instance exists: make sure that we return the global instance. $keys = $instance->id; } // Return global instance from the identifier, possibly reloading it first. $instance = static::$instances[(int) $keys]; if ($reload) $instance->load($keys); return $instance; } /** * Removes all or selected instances from the object cache. * * @param null|int|array $ids */ static public function freeInstances($ids = null) { if ($ids === null) { $ids = array_keys(static::$instances); } $ids = (array) $ids; foreach ($ids as $id) { unset(static::$instances[$id]); } } /** * Returns true if the object exists in the database. * * @param boolean $exists Internal parameter to change state. * * @return boolean True if object exists in database. */ public function exists($exists = null) { $return = $this->_exists; if ($exists !== null) $this->_exists = (bool) $exists; return $return; } /** * Tests if dynamically defined property has been defined. * * @param string $property * @param bool $defined * @return bool */ public function defined($property, $defined = true) { $property = '_' . $property; return $defined ? isset($this->{$property}) : !isset($this->{$property}); } /** * Returns an associative array of object properties. * * @param boolean $public If true, returns only the public properties. * * @return array */ public function getProperties($public = true) { if ($public) { $getProperties = function($obj) { return get_object_vars($obj); }; return $getProperties($this); } return get_object_vars($this); } /** * Method to bind an associative array to the instance. * * This method optionally takes an array of properties to ignore or allow when binding. * * @param array $src An associative array or object to bind to the JTable instance. * @param array $fields An optional array list of properties to ignore / include only while binding. * @param boolean $include True to include only listed fields, false to ignore listed fields. * * @return boolean True on success. */ public function bind(array $src = null, array $fields = null, $include = false) { if (empty($src)) return false; if (!empty($fields)) { $src = $include ? array_intersect_key($src, array_flip($fields)) : array_diff_key($src, array_flip($fields)); } $this->setProperties ( $src ); return true; } /** * Method to load object from the database. * * @param mixed $keys An optional primary key value to load the object by, or an array of fields to match. If not * set the instance key value is used. * * @return boolean True on success, false if the object doesn't exist. */ public function load($keys = null) { if ($keys !== null && !is_array($keys)) { $keys = array('id'=>(int) $keys); } // Create the table object. $table = static::getTable (); // Make sure we set the given keys to the object even if it is not loaded. $table->reset(); if ($keys !== null) $table->bind($keys); // Load the object based on the keys. $this->_exists = $table->load($keys, false); // Work around Joomla 3.1.1 bug on load() returning true if keys didn't exist. if ($table->id == 0) $this->_exists = false; // Assuming all is well at this point lets bind the data. $this->setProperties($table->getProperties()); if ($this->id) { if (!isset(static::$instances[$this->id])) { static::$instances[$this->id] = $this; } } $this->initialize(); return $this->_exists; } /** * Method to save the object to the database. * * Before saving the object, this method checks if object can be safely saved. * It will also trigger onContentBeforeSave and onContentAfterSave events. * * @return boolean True on success. */ public function save() { // Check the object. if ($this->_readonly || !$this->check()) { return false; } $isNew = !$this->_exists; // Initialize table object. $table = static::getTable (); $table->bind($this->getProperties()); // Check the table object. if (!$table->check()) { $this->setError($table->getError()); return false; } // Include the content plugins for the on save events. $dispatcher = \JEventDispatcher::getInstance(); \JPluginHelper::importPlugin('content'); // Trigger the onContentBeforeSave event. $result = $dispatcher->trigger('onContentBeforeSave', array("com_gantry5.".get_called_class(), $table, $isNew)); if (in_array(false, $result, true)) { $this->setError($table->getError()); return false; } // Store the data. if (!$table->store()) { $this->setError($table->getError()); return false; } // If item was created, load the object. if ($isNew) { $this->load($table->id); if (!isset(static::$instances[$this->id])) { static::$instances[$this->id] = $this; } } // Trigger the onContentAfterSave event. $dispatcher->trigger('onContentAfterSave', array("com_gantry5.".get_called_class(), $table, $isNew)); return true; } /** * Method to delete the object from the database. * * @return boolean True on success. */ public function delete() { if ($this->_readonly) { return false; } if (!$this->_exists) { return true; } // Initialize table object. $table = static::getTable(); $table->bind($this->getProperties()); // Include the content plugins for the on save events. $dispatcher = \JEventDispatcher::getInstance(); \JPluginHelper::importPlugin('content'); // Trigger the onContentBeforeDelete event. $result = $dispatcher->trigger('onContentBeforeDelete', array("com_gantry5.".get_called_class(), $table)); if (in_array(false, $result, true)) { $this->setError($table->getError()); return false; } if (!$table->delete()) { $this->setError($table->getError()); return false; } $this->_exists = false; // Trigger the onContentAfterDelete event. $dispatcher->trigger('onContentAfterDelete', array("com_gantry5.".get_called_class(), $table)); return true; } /** * Method to perform sanity checks on the instance properties to ensure * they are safe to store in the database. * * Child classes should override this method to make sure the data they are storing in * the database is safe and as expected before storage. * * @return boolean True if the instance is sane and able to be stored in the database. */ public function check() { return true; } static public function getAvailableInstances() { return static::collection(static::$instances); } static public function getInstances(array $ids, $readonly = true) { if (!$ids) { return array(); } $results = array(); $list = array(); foreach ($ids as $id) { if (!isset(static::$instances[$id])) { $list[] = $id; } } if ($list) { $query = static::getQuery(); $query->where('id IN (' . implode(',', $list) . ')'); static::loadInstances($query); } foreach ($ids as $id) { if (isset(static::$instances[$id])) { if ($readonly) { $results[$id] = clone static::$instances[$id]; } else { $results[$id] = static::$instances[$id]; } } } return static::collection($results); } // Internal functions static protected function collection($items) { return new Collection($items); } /** * Method to get the table object. * * @return \JTable The table object. */ static protected function getTable() { return \JTable::getInstance(static::$table, static::$tablePrefix); } /** * @return \JDatabaseQuery */ static protected function getQuery() { $table = static::getTable(); $db = \JFactory::getDbo(); $query = $db->getQuery(true); $query->select('a.*')->from($table->getTableName().' AS a')->order(static::$order); return $query; } /** * @param \JDatabaseQuery|string $query */ static protected function loadInstances($query = null) { if (!$query) { $query = static::getQuery(); } $db = \JFactory::getDbo(); $db->setQuery($query); /** @var Object[] $items */ $items = (array) $db->loadObjectList('id', get_called_class()); foreach ($items as $item) { if (!isset(static::$instances[$item->id])) { $item->exists(true); $item->initialize(); } } static::$instances += $items; } } classes/Gantry/Joomla/Object/Finder.php 0000604 00000013102 15075035625 0014015 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Object; /** * Class Finder * @package Gantry\Joomla\Object */ abstract class Finder { /** * Table associated with the model. * * @var string */ protected $table; /** * @var string */ protected $primaryKey = 'id'; /** * @var \JDatabaseQuery */ protected $query; /** * @var \JDatabase */ protected $db; protected $start = 0; protected $limit = 20; protected $skip = false; /** * Finder constructor. * * @param array $options */ public function __construct(array $options = []) { if (!$this->table) { throw new \DomainException('Table name missing from ' . get_class($this)); } $this->db = \JFactory::getDbo(); $this->query = $this->db->getQuery(true); $this->query->from($this->table . ' AS a'); if ($options) { $this->parse($options); } } public function parse(array $options) { foreach ($options as $func => $params) { if (method_exists($this, $func)) { call_user_func_array([$this, $func], (array) $params); } } return $this; } /** * Set limitstart for the query. * * @param int $limitstart * * @return $this */ public function start($limitstart = 0) { $this->start = $limitstart; return $this; } /** * Set limit to the query. * * @param int $limit * * @return $this */ public function limit($limit = null) { if (!is_null($limit)) { $this->limit = $limit; } return $this; } /** * Set order by field and direction. * * This function can be used more than once to chain order by. * * @param string $by * @param int $direction * @param string $alias * * @return $this */ public function order($by, $direction = 1, $alias = 'a') { if (is_numeric($direction)) { $direction = $direction > 0 ? 'ASC' : 'DESC'; } else { $direction = strtolower((string)$direction) == 'desc' ? 'DESC' : 'ASC'; } $by = (string)$alias . '.' . $this->db->quoteName($by); $this->query->order("{$by} {$direction}"); return $this; } /** * Filter by field. * * @param string $field Field name. * @param string $operation Operation (>|>=|<|<=|=|IN|NOT IN) * @param string|array $value Value. * * @return $this */ public function where($field, $operation, $value) { $db = $this->db; $operation = strtoupper($operation); switch ($operation) { case '>': case '>=': case '<': case '<=': case '=': // Quote all non integer values. $value = (string)(int)$value === (string)$value ? (int)$value : $db->quote($value); $this->query->where("{$this->db->quoteName($field)} {$operation} {$value}"); break; case 'BETWEEN': case 'NOT BETWEEN': list($a, $b) = (array) $value; // Quote all non integer values. $a = (string)(int)$a === (string)$a ? (int)$a : $db->quote($a); $b = (string)(int)$b === (string)$b ? (int)$b : $db->quote($b); $this->query->where("{$this->db->quoteName($field)} {$operation} {$a} AND {$b}"); break; case 'IN': case 'NOT IN': $value = (array) $value; if (empty($value)) { // WHERE field IN (nothing). $this->query->where('0'); } else { // Quote all non integer values. array_walk($value, function (&$value) use ($db) { $value = (string)(int)$value === (string)$value ? (int)$value : $db->quote($value); }); $list = implode(',', $value); $this->query->where("{$this->db->quoteName($field)} {$operation} ({$list})"); } break; } return $this; } /** * Get items. * * Derived classes should generally override this function to return correct objects. * * @return array */ public function find() { if ($this->skip) { return array(); } $baseQuery = clone $this->query; $this->prepare(); $query = $this->query; $this->query = $baseQuery; $query->select('a.' . $this->primaryKey); $this->db->setQuery($query, $this->start, $this->limit); $results = (array) $this->db->loadColumn(); return $results; } /** * Count items. * * @return int */ public function count() { $baseQuery = clone $this->query; $this->prepare(); $query = $this->query; $this->query = $baseQuery; $query->select('COUNT(*)'); $this->db->setQuery($query); $count = (int) $this->db->loadResult(); return $count; } /** * Override to include common where rules. * * @return void */ protected function prepare() { } } classes/Gantry/Joomla/Object/Collection.php 0000604 00000001770 15075035625 0014711 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Object; use \Gantry\Component\Collection\Collection as BaseCollection; class Collection extends BaseCollection { public function __construct(array $items) { $this->items = $items; } public function get($property) { $list = []; if ($property === 'id') { return array_keys($this->items); } foreach ($this as $object) { $list[$object->id] = $object->{$property}; } return $list; } public function __call($name, $arguments) { $list = []; foreach ($this as $object) { $list[$object->id] = method_exists($object, $name) ? call_user_func_array([$object, $name], $arguments) : null; } return $list; } } classes/Gantry/Joomla/Assignments/AssignmentsStyle.php 0000604 00000003621 15075035625 0017214 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Assignments; use Gantry\Component\Assignments\AssignmentsInterface; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class AssignmentsStyle implements AssignmentsInterface { public $type = 'style'; public $priority = 2; /** * Returns list of rules which apply to the current page. * * @return array */ public function getRules() { static $rules; if (!isset($rules)) { $rules = []; $template = \JFactory::getApplication()->getTemplate(true); $theme = $template->template; $outline = $template->params->get('configuration', !empty($template->id) ? $template->id : $template->params->get('preset', null)); if (JDEBUG) { GANTRY_DEBUGGER && \Gantry\Debugger::addMessage('Template Style:', 'debug') && \Gantry\Debugger::addMessage($template, 'debug'); if (!$outline) { \JFactory::getApplication()->enqueueMessage('JApplicationSite::getTemplate() was overridden with no specified Gantry 5 outline.', 'debug'); } } /** @var UniformResourceLocator $locator */ $locator = Gantry::instance()['locator']; if ($outline && is_dir($locator("gantry-themes://{$theme}/custom/config/{$outline}"))) { $rules = ['id' => [$outline => $this->priority]]; } } return $rules; } /** * List all the rules available. * * @param string $configuration * @return array */ public function listRules($configuration) { return []; } } classes/Gantry/Joomla/Assignments/AssignmentsMenu.php 0000604 00000004063 15075035625 0017021 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Assignments; use Gantry\Component\Assignments\AssignmentsInterface; class AssignmentsMenu implements AssignmentsInterface { public $type = 'menu'; public $priority = 1; /** * Returns list of rules which apply to the current page. * * @return array */ public function getRules() { $rules = []; $app = \JFactory::getApplication(); if ($app->isSite()) { $active = $app->getMenu()->getActive(); if ($active) { $menutype = $active->menutype; $id = $active->id; $rules = [$menutype => [$id => $this->priority]]; } } return $rules; } /** * List all the rules available. * * @param string $configuration * @return array */ public function listRules($configuration) { require_once JPATH_ADMINISTRATOR . '/components/com_menus/helpers/menus.php'; $data = \MenusHelper::getMenuLinks(); $userid = \JFactory::getUser()->id; $list = []; foreach ($data as $menu) { $items = []; foreach ($menu->links as $link) { $items[] = [ 'name' => $link->value, 'field' => ['id', 'link' . $link->value], 'value' => $link->template_style_id == $configuration, 'disabled' => $link->type != 'component' || $link->checked_out && $link->checked_out != $userid, 'label' => str_repeat('—', max(0, $link->level-1)) . ' ' . $link->text ]; } $group = [ 'label' => $menu->title ?: $menu->menutype, 'items' => $items ]; $list[$menu->menutype] = $group; } return $list; } } classes/Gantry/Joomla/TemplateInstaller.php 0000604 00000000650 15075035625 0015035 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla; use Gantry\Framework\ThemeInstaller; /** * Class TemplateInstaller * @package Gantry\Joomla * @deprecated 5.3.2 */ class TemplateInstaller extends ThemeInstaller {} classes/Gantry/Joomla/CacheHelper.php 0000604 00000003007 15075035625 0013546 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla; class CacheHelper { public static function cleanTemplates() { self::cleanByType('com_templates'); self::cleanByType('_system'); } public static function cleanMenu() { self::cleanByType('mod_menu'); self::cleanByType('_system'); } public static function cleanPlugin() { self::cleanByType('_system', 0); self::cleanByType('_system', 1); self::cleanByType('com_plugins', 0); self::cleanByType('com_plugins', 1); } private static function cleanByType($group = null, $client_id = 0, $event = 'onContentCleanCache') { $conf = \JFactory::getConfig(); $dispatcher = \JEventDispatcher::getInstance(); $options = array( 'defaultgroup' => $group, 'cachebase' => ($client_id) ? JPATH_ADMINISTRATOR . '/cache' : $conf->get('cache_path', JPATH_SITE . '/cache'), 'result' => true ); try { $cache = \JCache::getInstance('callback', $options); $cache->clean(); } catch (\Exception $e) { // TODO: Joomla 3.7 uses JCacheException $options['result'] = false; } // Trigger the onContentCleanCache event. $dispatcher->trigger($event, $options); } } classes/Gantry/Joomla/Module/ModuleCollection.php 0000604 00000006353 15075035625 0016100 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Module; use Gantry\Joomla\Object\Collection; class ModuleCollection extends Collection { public function toArray() { return $this->__call('toArray', []); } public function export() { $assignments = $this->assignments(); $paths = $this->getAssignmentPath($this->values($assignments)); $items = $this->toArray(); $positions = []; // Convert assignments to our format. foreach ($items as $item) { $position = $item['position']; $name = $item['options']['type'] . '-' . $item['id']; if ($position === '') { continue; } if (empty($item['assignments'])) { $item['assignments'] = []; } elseif (in_array(0, $item['assignments'])) { $item['assignments'] = ['page' => true]; } else { $list = []; foreach ($item['assignments'] as $assignment) { $key = abs($assignment); if (isset($paths[$key])) { $list[$paths[$key]] = $assignment > 0 ? 1 : -1; } } $item['assignments'] = ['page' => [$list]]; } unset($item['position'], $item['id'], $item['ordering']); $positions[$position][$name] = $item; } return $positions; } public function assignments() { $this->loadAssignments(); return $this->__call('assignments', []); } public function loadAssignments() { $ids = $this->defined('assignments', false); $ids = array_filter($ids); if (!$ids) { return; } $idlist = implode(',', array_keys($ids)); $db = \JFactory::getDbo(); $query = $db->getQuery(true); $query->select('moduleid, menuid')->from('#__modules_menu')->where("moduleid IN ($idlist)"); $db->setQuery($query); $assignments = $db->loadRowList(); $list = []; foreach ($assignments as $value) { $list[$value[0]][] = (int) $value[1]; } foreach ($this as $module) { $module->assignments(isset($list[$module->id]) ? $list[$module->id] : []); } } protected function getAssignmentPath(array $ids) { if (!$ids) { return []; } $idlist = implode(',', array_map('intval', $ids)); $db = \JFactory::getDbo(); $query = $db->getQuery(true); $query->select('id, path')->from('#__menu')->where("id IN ($idlist)"); $db->setQuery($query); $paths = $db->loadRowList(); $list = []; foreach ($paths as $value) { $list[$value[0]] = $value[1]; } return $list; } protected function values($values) { $list = []; foreach ($values as $array) { $list = array_merge($list, (array) $array); } return array_unique($list); } } classes/Gantry/Joomla/Module/Module.php 0000604 00000012244 15075035625 0014060 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Module; use Gantry\Framework\Gantry; use Gantry\Joomla\Object\AbstractObject; use RocketTheme\Toolbox\ArrayTraits\Export; use RocketTheme\Toolbox\ArrayTraits\ExportInterface; \JTable::addIncludePath(JPATH_LIBRARIES . '/legacy/table/'); class Module extends AbstractObject implements ExportInterface { use Export; static protected $instances = []; static protected $table = 'Module'; static protected $order = 'id'; protected $_assignments; public function assignments($assignments = null) { if (is_array($assignments)) { $this->_assignments = array_map('intval', array_values($assignments)); } elseif (!isset($this->_assignments)) { $db = \JFactory::getDbo(); $query = $db->getQuery(true); $query->select('menuid')->from('#__modules_menu')->where('moduleid = ' . $this->id); $db->setQuery($query); $this->_assignments = array_map('intval', (array) $db->loadColumn()); } return $this->_assignments; } public function initialize() { if (!parent::initialize()) { return false; } $this->params = json_decode($this->params); return true; } public function toArray() { $particle = $this->module === 'mod_gantry5_particle'; // Convert params to array. $params = json_decode(json_encode($this->params), true); $array = [ 'id' => $this->id, 'position' => $this->position, 'ordering' => (int) $this->ordering, 'type' => $particle ? 'particle' : 'joomla', 'title' => $this->title, 'chrome' => [ 'display_title' => (bool) $this->showtitle, 'class' => !empty($params['moduleclass_sfx']) ? $params['moduleclass_sfx'] : '' ], 'options' => null, 'assignments' => $this->assignments() ]; $options = array_filter( [ 'type' => !$particle ? $this->module : null, 'note' => $this->note ?: null, 'published' => (bool) $this->published, 'content' => $this->content ?: null, 'params' => &$params, 'language' => $this->language !== '*' ? $this->language : null, ], [$this, 'is_not_null'] ); if ($particle) { $array['joomla'] = $options; $options = !empty($params['particle']) ? json_decode($params['particle'], true) : []; $options['type'] = isset($options['particle']) ? $options['particle'] : null; $options['attributes'] = isset($options['options']['particle']) ? $options['options']['particle'] : []; unset($options['particle'], $options['options']); $array['options'] = $options; unset($params['particle']); } else { $array['options'] = $options; } return array_filter($array, [$this, 'is_not_null']); } public function create(array $array) { $type = $array['type']; if ($type === 'particle') { $particle = isset($array['options']) ? $array['options'] : []; $array['options'] = isset($array['joomla']) ? $array['joomla'] : []; $array['options']['type'] = 'mod_gantry5_particle'; $array['options']['params']['particle'] = $particle; } elseif ($type !== 'joomla') { return null; } $options = $array['options']; $properties = [ 'title' => $array['title'], 'note' => isset($options['note']) ? $options['note'] : '', 'content' => isset($options['content']) ? $options['content'] : '', 'position' => $array['position'], 'ordering' => (int) $array['ordering'], 'published' => (int) !empty($options['published']), 'module' => $options['type'], 'showtitle' => (int) !empty($array['chrome']['display_title']), 'params' => isset($options['params']) ? json_decode(json_encode($options['params'])) : [], 'language' => isset($options['language']) ? $options['language'] : '*', '_assignments' => isset($array['assignments']) ? $array['assignments'] : [], ]; $object = new static(); $object->bind($properties); return $object; } public function render($file) { return Gantry::instance()['theme']->render($file, ['particle' => $this]); } public function compile($string) { return Gantry::instance()['theme']->compile($string, ['particle' => $this]); } // Internal functions /** * @param $val * @return bool * @internal */ public function is_not_null($val) { return !is_null($val); } static protected function collection($items) { return new ModuleCollection($items); } } classes/Gantry/Joomla/Module/ModuleFinder.php 0000604 00000005110 15075035625 0015202 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Module; use Gantry\Joomla\Object\Finder; class ModuleFinder extends Finder { protected $table = '#__modules'; protected $readonly = true; protected $state = []; protected $published = [0, 1]; protected $limit = 0; /** * Makes all created objects as readonly. * * @return $this */ public function readonly($readonly = true) { $this->readonly = (bool)$readonly; return $this; } public function find($object = true) { $ids = parent::find(); if (!$object) { return $ids; } return Module::getInstances($ids, $this->readonly); } public function id($ids, $include = true) { return $this->addToGroup('a.id', $ids, $include); } public function language($language = true) { if (!$language) { return $this; } if ($language === true || is_numeric($language)) { $language = \JFactory::getLanguage()->getTag(); } return $this->where('a.language', 'IN', [$language, '*']); } public function published($published = 1) { if (!is_array($published)) { $published = (array) intval($published); } $this->published = $published; return $this; } public function particle() { return $this->where('a.module', '=', 'mod_gantry5_particle'); } public function authorised($authorised = true) { if (!$authorised) { return $this; } $groups = \JFactory::getUser()->getAuthorisedViewLevels(); return $this->where('a.access', 'IN', $groups); } protected function addToGroup($key, $ids, $include = true) { $op = $include ? 'IN' : 'NOT IN'; if (isset($this->state[$key][$op])) { $this->state[$key][$op] = array_merge($this->state[$key][$op], $ids); } else { $this->state[$key][$op] = $ids; } return $this; } protected function prepare() { $this->where('client_id', '=', 0)->where('published', 'IN', $this->published)->order('position')->order('ordering'); foreach ($this->state as $key => $list) { foreach ($list as $op => $group) { $this->where($key, $op, array_unique($group)); } } } } classes/Gantry/Joomla/Manifest.php 0000604 00000004324 15075035625 0013154 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla; /** * Joomla manifest file modifier. */ class Manifest { protected $theme; protected $path; protected $xml; /** * @param string $theme * @param \SimpleXMLElement $manifest * @throws \RuntimeException */ public function __construct($theme, \SimpleXMLElement $manifest = null) { $this->theme = $theme; $this->path = JPATH_SITE . "/templates/{$theme}/templateDetails.xml"; if (!is_file($this->path)) { throw new \RuntimeException(sprintf('Template %s does not exist.', $theme)); } $this->xml = $manifest ?: simplexml_load_file($this->path); } /** * @param string $variable * @return string */ public function get($variable) { return (string) $this->xml->{$variable}; } /** * @return \SimpleXMLElement */ public function getXml() { return $this->xml; } public function getScriptFile() { return (string) $this->xml->scriptfile; } public function setPositions(array $positions) { sort($positions); // Get the positions. $target = current($this->xml->xpath('//positions')); $xml = "<positions>\n <position>" . implode("</position>\n <position>", $positions) . "</position>\n </positions>"; $insert = new \SimpleXMLElement($xml); // Replace all positions. $targetDom = dom_import_simplexml($target); $insertDom = $targetDom->ownerDocument->importNode(dom_import_simplexml($insert), true); $targetDom->parentNode->replaceChild($insertDom, $targetDom); } public function save() { // Do not save manifest if template has been symbolically linked. if (is_link(dirname($this->path))) { return; } if (!$this->xml->asXML($this->path)) { throw new \RuntimeException(sprintf('Saving manifest for %s template failed', $this->theme)); } } } classes/Gantry/Joomla/Category/CategoryFinder.php 0000604 00000010073 15075035625 0016066 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Category; use Gantry\Joomla\Object\Finder; class CategoryFinder extends Finder { protected $table = '#__categories'; protected $extension = 'com_content'; protected $readonly = true; /** * Makes all created objects as readonly. * * @return $this */ public function readonly($readonly = true) { $this->readonly = (bool)$readonly; return $this; } public function find($object = true) { $ids = parent::find(); if (!$object) { return $ids; } return Category::getInstances($ids, $this->readonly); } public function id($ids, $levels = 0) { if ($ids && $levels) { $ids = (array) $ids; $db = $this->db; array_walk($ids, function (&$item) use ($db) { $item = $db->quote($item); }); $idList = implode(',', $ids); // Create a subquery for the subcategory list $subQuery = $this->db->getQuery(true) ->select('sub.id') ->from('#__categories AS sub') ->join('INNER', '#__categories AS this ON sub.lft > this.lft AND sub.rgt < this.rgt') ->where("this.id IN ({$idList})"); if (is_numeric($levels)) { $subQuery->where('sub.level <= this.level + ' . (int) $levels); } // Add the subquery to the main query $this->query->where("(a.id IN ({$idList}) OR a.id IN ({$subQuery->__toString()}))"); } else { $this->where('a.id', 'IN', $ids); } return $this; } public function language($language = true) { if (!$language) { return $this; } if ($language === true || is_numeric($language)) { $language = \JFactory::getLanguage()->getTag(); } return $this->where('a.language', 'IN', [$language, '*']); } public function published($published = 1) { if (!is_array($published)) { $published = (array) intval($published); } return $this->where('a.published', 'IN', $published); } public function authorised($authorised = true) { if (!$authorised) { return $this; } // Ignore unpublished categories. $unpublished = $this->getUnpublished($this->extension); if ($unpublished) { $this->where('a.id', 'NOT IN', $unpublished); } // Check authorization. $user = \JFactory::getUser(); $groups = $user->getAuthorisedViewLevels(); return $this->where('a.access', 'IN', $groups); } public function extension($extension) { $this->extension = static::getExtension($extension); return $this->where('a.extension', '=', $this->extension); } public static function getExtension($extension) { static $map = [ 'article' => 'com_content', 'articles' => 'com_content', 'content' => 'com_content', ]; if (isset($map[$extension])) { $extension = $map[$extension]; } return $extension; } public static function getUnpublished($extension) { static $list; if ($list === null) { $db = \JFactory::getDbo(); $query = $db->getQuery(true) ->select('cat.id AS id') ->from('#__categories AS cat') ->join('LEFT', '#__categories AS parent ON cat.lft BETWEEN parent.lft AND parent.rgt') ->where('parent.extension = ' . $db->quote(static::getExtension($extension))) ->where('parent.published != 1 AND cat.published < 1') ->group('cat.id'); $db->setQuery($query); $list = $db->loadColumn(); } return $list; } } classes/Gantry/Joomla/Category/Category.php 0000604 00000003302 15075035625 0014733 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Category; use Gantry\Framework\Gantry; use Gantry\Joomla\Object\AbstractObject; class Category extends AbstractObject { static protected $instances = []; static protected $table = 'Category'; static protected $order = 'lft'; public function initialize() { if (!parent::initialize()) { return false; } $this->params = json_decode($this->params); $this->metadata = json_decode($this->metadata); return true; } public function parent() { if ($this->alias != $this->path) { $parent = Category::getInstance($this->parent_id); } return isset($parent) && $parent->extension == $this->extension ? $parent : null; } public function parents() { $parent = $this->parent(); return $parent ? array_merge($parent->parents(), [$parent]) : []; } public function route() { require_once JPATH_SITE . '/components/com_content/helpers/route.php'; return \JRoute::_(\ContentHelperRoute::getCategoryRoute($this->id . ':' . $this->alias), false); } public function render($file) { return Gantry::instance()['theme']->render($file, ['category' => $this]); } public function compile($string) { return Gantry::instance()['theme']->compile($string, ['category' => $this]); } public function toArray() { return $this->getProperties(true); } } classes/Gantry/Joomla/StyleHelper.php 0000604 00000006676 15075035625 0013662 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla; use Gantry\Component\Filesystem\Folder; use Gantry\Framework\Gantry; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Joomla style helper. */ class StyleHelper { public static function getStyle($id) { \JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_templates/tables'); $style = \JTable::getInstance('Style', 'TemplatesTable'); $style->load($id); return $style; } public static function loadStyles($template) { $db = \JFactory::getDbo(); $query = $db ->getQuery(true) ->select('s.id, s.template, s.home, s.title AS long_title, s.params') ->from('#__template_styles AS s') ->where('s.client_id = 0') ->where("s.template = {$db->quote($template)}") ->order('s.id'); $db->setQuery($query); $list = (array) $db->loadObjectList('id'); foreach ($list as $id => &$style) { $style->title = preg_replace('/' . preg_quote(\JText::_($style->template), '/') . '\s*-\s*/u', '', $style->long_title); $style->home = $style->home && $style->home !== '1' ? $style->home : (bool)$style->home; } return $list; } public static function getDefaultStyle() { return static::getStyle(['home' => 1, 'client_id' => 0]); } public static function copy($style, $old, $new) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $oldPath = $locator->findResource('gantry-config://' . $old, true, true); $newPath = $locator->findResource('gantry-config://' . $new, true, true); if (file_exists($oldPath)) { Folder::copy($oldPath, $newPath); } $extension = !empty($style->extension_id) ? $style->extension_id : $style->template; $installer = new TemplateInstaller($extension); $installer->updateStyle($new, ['configuration' => $new]); } public static function update($id, $preset) { $style = static::getStyle($id); $extension = !empty($style->extension_id) ? $style->extension_id : $style->template; $installer = new TemplateInstaller($extension); $installer->updateStyle($id, ['configuration' => $id, 'preset' => $preset]); } public static function delete($id) { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $path = $locator->findResource('gantry-config://' . $id, true, true); if (is_dir($path)) { Folder::delete($path, true); } } /** * @return \TemplatesModelStyle */ public static function loadModel() { static $model; if (!$model) { $path = JPATH_ADMINISTRATOR . '/components/com_templates/'; \JTable::addIncludePath("{$path}/tables"); require_once "{$path}/models/style.php"; // Load language strings. $lang = \JFactory::getLanguage(); $lang->load('com_templates'); $model = new \TemplatesModelStyle; } return $model; } } classes/Gantry/Joomla/Content/Content.php 0000604 00000006227 15075035625 0014436 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Content; use Gantry\Framework\Gantry; use Gantry\Joomla\Category\Category; use Gantry\Joomla\Object\AbstractObject; class Content extends AbstractObject { static protected $instances = []; static protected $table = 'Content'; static protected $order = 'id'; public function initialize() { if (!parent::initialize()) { return false; } $this->images = json_decode($this->images); $this->urls = json_decode($this->urls); $this->attribs = json_decode($this->attribs); $this->metadata = json_decode($this->metadata); $nullDate = \JFactory::getDbo()->getNullDate(); if ($this->modified === $nullDate) { $this->modified = $this->created; } if ($this->publish_up === $nullDate) { $this->publish_up = $this->created; } return true; } public function author() { return \JUser::getInstance($this->created_by); } public function category() { return Category::getInstance($this->catid); } public function categories() { $category = $this->category(); return array_merge($category->parents(), [$category]); } public function text() { return $this->introtext . ' ' . $this->fulltext; } public function preparedText() { return \JHtml::_('content.prepare', $this->text()); } public function preparedIntroText() { return \JHtml::_('content.prepare', $this->introtext); } public function readmore() { return (bool)strlen($this->fulltext); } public function route() { require_once JPATH_SITE . '/components/com_content/helpers/route.php'; $category = $this->category(); return \JRoute::_(\ContentHelperRoute::getArticleRoute($this->id . ':' . $this->alias, $category->id . ':' . $category->alias), false); } public function edit() { $user = \JFactory::getUser(); $asset = "com_content.article.{$this->id}"; if ($user->authorise('core.edit', $asset) || $user->authorise('core.edit.own', $asset)) { return "index.php?option=com_content&task=article.edit&a_id={$this->id}&tmpl=component"; } return false; } public function render($file) { return Gantry::instance()['theme']->render($file, ['article' => $this]); } public function compile($string) { return Gantry::instance()['theme']->compile($string, ['article' => $this]); } public function toArray() { return $this->getProperties(true) + [ 'category' => [ 'alias' => $this->category()->alias, 'title' => $this->category()->title ], 'author' => [ 'username' => $this->author()->username, 'fullname' => $this->author()->name ], ]; } } classes/Gantry/Joomla/Content/ContentFinder.php 0000604 00000007673 15075035625 0015574 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Joomla\Content; use Gantry\Joomla\Category\Category; use Gantry\Joomla\Category\CategoryFinder; use Gantry\Joomla\Object\Collection; use Gantry\Joomla\Object\Finder; class ContentFinder extends Finder { protected $table = '#__content'; protected $readonly = true; protected $state = []; /** * Makes all created objects as readonly. * * @return $this */ public function readonly($readonly = true) { $this->readonly = (bool)$readonly; return $this; } public function find($object = true) { $ids = parent::find(); if (!$object) { return $ids; } return Content::getInstances($ids, $this->readonly); } public function id($ids, $include = true) { return $this->addToGroup('a.id', $ids, $include); } public function author($ids, $include = true) { return $this->addToGroup('a.created_by', $ids, $include); } public function category($ids, $include = true) { if ($ids instanceof Collection) { $ids = $ids->toArray(); } else { $ids = (array)$ids; } array_walk($ids, function (&$item) { $item = $item instanceof Category ? $item->id : (int) $item; }); return $this->addToGroup('a.catid', $ids, $include); } public function featured($featured = true) { $featured = intval((bool)$featured); $this->where('a.featured', '=', $featured); return $this; } public function language($language = true) { if (!$language) { return $this; } if ($language === true || is_numeric($language)) { $language = \JFactory::getLanguage()->getTag(); } return $this->where('a.language', 'IN', [$language, '*']); } public function published($published = 1) { if (!is_array($published)) { $published = (array) intval($published); } return $this->where('a.state', 'IN', $published); } public function authorised($authorised = true) { if (!$authorised) { return $this; } $unpublished = CategoryFinder::getUnpublished('content'); if ($unpublished) { $this->where('a.catid', 'NOT IN', $unpublished); } $user = \JFactory::getUser(); // Define null and now dates $nullDate = $this->db->quote($this->db->getNullDate()); $nowDate = $this->db->quote(\JFactory::getDate()->toSql()); // Filter by start and end dates. if (!$user->authorise('core.edit.state', 'com_content') && !$user->authorise('core.edit', 'com_content')) { $this->query ->where("(a.publish_up = {$nullDate} OR a.publish_up <= {$nowDate})") ->where("(a.publish_down = {$nullDate} OR a.publish_down >= {$nowDate})") ->where("a.state >= 1") ; } $groups = $user->getAuthorisedViewLevels(); $this->query->join('INNER', '#__categories AS c ON c.id = a.catid'); return $this->where('a.access', 'IN', $groups)->where('c.access', 'IN', $groups); } protected function addToGroup($key, $ids, $include = true) { $op = $include ? 'IN' : 'NOT IN'; if (isset($this->state[$key][$op])) { $this->state[$key][$op] = array_merge($this->state[$key][$op], $ids); } else { $this->state[$key][$op] = $ids; } return $this; } protected function prepare() { foreach ($this->state as $key => $list) { foreach ($list as $op => $group) { $this->where($key, $op, array_unique($group)); } } } } classes/Gantry/Admin/Styles.php 0000604 00000006637 15075035625 0012511 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\ConfigFileFinder; use Gantry\Component\File\CompiledYamlFile; use Gantry\Framework\Theme as SiteTheme; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Styles { protected $container; protected $files; protected $blocks; public function __construct($container) { $this->container = $container; } public function all() { if (!$this->blocks) { $files = $this->locateBlocks(); $this->blocks = []; foreach ($files as $key => $fileArray) { $filename = key($fileArray); $file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' . $filename); $this->blocks[$key] = $file->content(); $file->free(); } } return $this->blocks; } public function group() { $blocks = $this->all(); $list = []; foreach ($blocks as $name => $style) { $type = isset($style['type']) ? $style['type'] : 'block'; $list[$type][$name] = $style; } return $this->sort($list); } public function get($id) { if ($this->blocks[$id]) { return $this->blocks[$id]; } $files = $this->locateBlocks(); if (empty($files[$id])) { throw new \RuntimeException(sprintf("Settings for '%s' not found.", $id), 404); } $filename = key($files[$id]); $file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' . $filename); $particle = $file->content(); $file->free(); return $particle; } /** * @param string $id * @return BlueprintForm */ public function getBlueprintForm($id) { return BlueprintForm::instance($id, 'gantry-blueprints://styles'); } protected function sort(array $blocks) { $list = []; /** @var SiteTheme $theme */ $theme = $this->container['theme']; $ordering = (array) $theme->details()['admin.styles']; ksort($blocks); foreach ($ordering as $name => $order) { if (isset($blocks[$name])) { $list[$name] = $this->sortItems($blocks[$name], (array) $order); } } $list += $blocks; return $list; } protected function sortItems(array $items, array $ordering) { $list = []; ksort($items); foreach ($ordering as $name) { if (isset($items[$name])) { $list[$name] = $items[$name]; } } $list += $items; return $list; } protected function locateBlocks() { if (!$this->files) { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $paths = $locator->findResources('gantry-blueprints://styles'); $this->files = (new ConfigFileFinder)->listFiles($paths); } return $this->files; } } classes/Gantry/Admin/EventListener.php 0000604 00000017247 15075035625 0014014 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Admin; use Gantry\Component\Layout\Layout; use Gantry\Joomla\CacheHelper; use Gantry\Joomla\Manifest; use Gantry\Joomla\StyleHelper; use Joomla\Registry\Registry; use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\Event\EventSubscriberInterface; use RocketTheme\Toolbox\File\IniFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class EventListener implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ 'admin.init.theme' => ['onAdminThemeInit', 0], 'admin.global.save' => ['onGlobalSave', 0], 'admin.styles.save' => ['onStylesSave', 0], 'admin.settings.save' => ['onSettingsSave', 0], 'admin.layout.save' => ['onLayoutSave', 0], 'admin.assignments.save' => ['onAssignmentsSave', 0], 'admin.menus.save' => ['onMenusSave', 0] ]; } public function onAdminThemeInit(Event $event) { \JPluginHelper::importPlugin('gantry5'); // Trigger the onGantryThemeInit event. $dispatcher = \JEventDispatcher::getInstance(); $dispatcher->trigger('onGantry5AdminInit', ['theme' => $event->theme]); } public function onGlobalSave(Event $event) { \JPluginHelper::importPlugin('gantry5'); // Trigger the onGantryThemeUpdateCss event. $dispatcher = \JEventDispatcher::getInstance(); $dispatcher->trigger('onGantry5SaveConfig', [$event->data]); } public function onStylesSave(Event $event) { \JPluginHelper::importPlugin('gantry5'); // Trigger the onGantryThemeUpdateCss event. $dispatcher = \JEventDispatcher::getInstance(); $dispatcher->trigger('onGantry5UpdateCss', ['theme' => $event->theme]); } public function onSettingsSave(Event $event) { } public function onLayoutSave(Event $event) { /** @var Layout $layout */ $layout = $event->layout; if ($layout->name[0] !== '_' && $layout->name !== 'default') { $preset = isset($layout->preset['name']) ? $layout->preset['name'] : 'default'; // Update Joomla template style. StyleHelper::update($layout->name, $preset); } $theme = $event->gantry['theme.name']; $positions = $event->gantry['outlines']->positions(); $positions['debug'] = 'Debug'; $manifest = new Manifest($theme); $manifest->setPositions(array_keys($positions)); $manifest->save(); $translations = []; foreach ($positions as $key => $translation) { // Encode translation key in Joomla way. $key = preg_replace('/[^A-Z0-9_\-]/', '_', strtoupper("TPL_{$theme}_POSITION_{$key}")); $translations[$key] = $translation; } /** @var UniformResourceLocator $locator */ $locator = $event->gantry['locator']; $filename = "gantry-theme://language/en-GB/en-GB.tpl_{$theme}_positions.ini"; $ini = IniFile::instance($locator->findResource($filename, true, true)); $ini->save($translations); $ini->free(); } public function onAssignmentsSave(Event $event) { } public function onMenusSave(Event $event) { $defaults = [ 'id' => 0, 'layout' => 'list', 'target' => '_self', 'dropdown' => '', 'icon' => '', 'image' => '', 'subtitle' => '', 'icon_only' => false, 'visible' => true, 'group' => 0, 'columns' => [], 'link_title' => '', 'hash' => '', 'class' => '' ]; $gantry = $event->gantry; $menu = $event->menu; // Save global menu settings into Joomla. /** @var \JTableMenuType $table */ $menuType = \JTable::getInstance('MenuType'); if (!$menuType->load(['menutype' => $event->resource])) { throw new \RuntimeException("Saving menu failed: Menu type {$event->resource} not found.", 400); } $options = [ 'title' => $menu['settings.title'], 'description' => $menu['settings.description'] ]; if ($gantry->authorize('menu.edit') && !$menuType->save($options)) { throw new \RuntimeException('Saving menu failed: '. $menuType->getError(), 400); } unset($menu['settings']); /** @var \JTableMenu $table */ $table = \JTable::getInstance('menu'); foreach ($menu['items'] as $key => $item) { $id = !empty($item['id']) ? (int) $item['id'] : 0; if ($id && $table->load($item['id'])) { $params = new Registry($table->params); // Menu item exists in Joomla, let's update it instead. unset($item['type'], $item['link']); $item['id'] = (int) $id; $title = $menu["items.{$key}.title"]; $browserNav = intval($menu["items.{$key}.target"] === '_blank'); $options = [ // Disabled as the option has different meaning in Joomla than in Gantry, see issue #1656. // 'menu-anchor_css' => $menu["items.{$key}.class"], 'menu_image' => $menu["items.{$key}.image"], 'menu_text' => intval(!$menu["items.{$key}.icon_only"]), 'menu_show' => intval($menu["items.{$key}.enabled"]), ]; $modified = false; if ($table->title != $title) { $table->title = $title; $modified = true; } if ($table->browserNav != $browserNav) { $table->browserNav = $browserNav; $modified = true; } foreach ($options as $var => $value) { if ($params->get($var) !== $value) { $params->set($var, $value); $modified = true; } } if ($modified && $gantry->authorize('menu.edit')) { $table->params = (string) $params; if (!$table->check() || !$table->store()) { throw new \RuntimeException("Failed to save /{$key}: {$table->getError()}", 400); } } // Avoid saving values which are also stored in Joomla. unset($item['title'], $item['anchor_class'], $item['image'], $item['icon_only'], $item['target']); if (version_compare(JVERSION, '3.5.1', '>=')) { unset($item['enabled']); } } // Do not save default values. foreach ($defaults as $var => $value) { if (isset($item[$var]) && $item[$var] == $value) { unset($item[$var]); } } // Do not save derived values. unset($item['path'], $item['alias'], $item['parent_id'], $item['level'], $item['group']); // Particles have no link. if (isset($item['type']) && $item['type'] === 'particle') { unset($item['link']); } // Because of ordering we need to save all menu items, including those from Joomla which have no data except id. $event->menu["items.{$key}"] = $item; } // Clean the cache. CacheHelper::cleanMenu(); } } classes/Gantry/Admin/Theme.php 0000604 00000007560 15075035625 0012264 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin; use Gantry\Component\Config\CompiledConfig; use Gantry\Component\Config\ConfigFileFinder; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Theme\AbstractTheme; use Gantry\Framework\Platform; use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Theme extends AbstractTheme { /** * @see AbstractTheme::init() */ protected function init() { $gantry = static::gantry(); // Add particles, styles and defaults into DI. $gantry['particles'] = function ($c) { return new Particles($c); }; $gantry['styles'] = function ($c) { return new Styles($c); }; $gantry['page'] = function ($c) { return new Page($c); }; $gantry['defaults'] = function($c) { /** @var UniformResourceLocator $locator */ $locator = $c['locator']; $cache = $locator->findResource('gantry-cache://theme/compiled/config', true, true); $paths = $locator->findResources('gantry-config://default'); $files = (new ConfigFileFinder)->locateFiles($paths); $config = new CompiledConfig($cache, $files, GANTRY5_ROOT); $config->setBlueprints(function() use ($c) { return $c['blueprints']; }); return $config->load(true); }; // Initialize admin streams. /** @var Platform $patform */ $patform = $gantry['platform']; /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $nucleus = $patform->getEnginePaths('nucleus')['']; if (strpos($this->path, '://')) { $relpath = $this->path; } else { $relpath = Folder::getRelativePath($this->path); } $patform->set( 'streams.gantry-admin.prefixes', [ '' => ['gantry-theme://admin', $relpath, $relpath . '/common', 'gantry-engine://admin'], 'assets/' => array_merge([$relpath, $relpath . '/common'], $nucleus, ['gantry-assets://']) ] ); // Add admin paths. foreach ($patform->get('streams.gantry-admin.prefixes') as $prefix => $paths) { $locator->addPath('gantry-admin', $prefix, $paths); } // Fire admin init event. $event = new Event; $event->gantry = $gantry; $event->theme = $this; $gantry->fireEvent('admin.init.theme', $event); } /** * @see AbstractTheme::getCachePath() * * @param string $path * @return string */ protected function getCachePath($path = '') { $gantry = static::gantry(); /** @var Platform $patform */ $patform = $gantry['platform']; // Initialize theme cache stream. return $patform->getCachePath() . '/admin' . ($path ? '/' . $path : ''); } /** * @see AbstractTheme::setTwigLoaderPaths() * * @param \Twig_LoaderInterface $loader */ protected function setTwigLoaderPaths(\Twig_LoaderInterface $loader) { if (!($loader instanceof \Twig_Loader_Filesystem)) { return; } $gantry = static::gantry(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; $loader->setPaths($locator->findResources('gantry-admin://templates')); $loader->setPaths($locator->findResources('gantry-admin://templates'), 'gantry-admin'); } } classes/Gantry/Admin/Router.php 0000604 00000012062 15075035625 0012473 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Admin; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Request\Request; use Gantry\Component\Response\JsonResponse; use Gantry\Component\Response\Response; use Gantry\Component\Router\Router as BaseRouter; use Gantry\Joomla\StyleHelper; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Gantry administration router for Joomla. */ class Router extends BaseRouter { public function boot() { \JHtml::_('behavior.keepalive'); $app = \JFactory::getApplication(); $input = $app->input; // TODO: Remove style variable. $style = $input->getInt('style'); $theme = $input->getCmd('theme'); $path = array_filter(explode('/', $input->getString('view', '')), function($var) { return $var !== ''; }); $this->setTheme($theme, $style); /** @var Request $request */ $request = $this->container['request']; $this->method = $request->getMethod(); $this->path = $path ?: (isset($this->container['theme.name']) ? ['configurations', true] : ['themes']); $this->resource = array_shift($this->path); $this->format = $input->getCmd('format', 'html'); $ajax = ($this->format == 'json'); $this->params = [ 'user' => \JFactory::getUser(), 'ajax' => $ajax, 'location' => $this->resource, 'method' => $this->method, 'format' => $this->format, 'params' => $request->post->getJsonArray('params') ]; return $this; } public function setTheme($theme, $style) { if ($style) { \JTable::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_templates/tables'); $table = \JTable::getInstance('Style', 'TemplatesTable'); $table->load(['id' => $style, 'client_id' => 0]); $theme = $table->template; } if (!$theme) { $theme = StyleHelper::getDefaultStyle()->template; } $path = JPATH_SITE . '/templates/' . $theme; if (!is_file("{$path}/gantry/theme.yaml")) { $theme = null; $this->container['streams']->register(); /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; CompiledYamlFile::$defaultCachePath = $locator->findResource('gantry-cache://theme/compiled/yaml', true, true); CompiledYamlFile::$defaultCaching = $this->container['global']->get('compile_yaml', 1); } $this->container['base_url'] = \JUri::base(true) . '/index.php?option=com_gantry5'; $this->container['ajax_suffix'] = '&format=json'; $token = \JSession::getFormToken(); $this->container['routes'] = [ '1' => "&view=%s&theme={$theme}&{$token}=1", 'themes' => '&view=themes', 'picker/layouts' => "&view=layouts&theme={$theme}&{$token}=1", ]; if (!$theme) { return $this; } $this->container['theme.path'] = $path; $this->container['theme.name'] = $theme; // Load language file for the template. $languageFile = 'tpl_' . $theme; $lang = \JFactory::getLanguage(); $lang->load($languageFile, JPATH_SITE) || $lang->load($languageFile, $path) || $lang->load($languageFile, $path, 'en-GB'); return $this; } protected function checkSecurityToken() { return \JSession::checkToken('get'); } /** * Send response to the client. * * @param Response $response * @return string */ protected function send(Response $response) { $app = \JFactory::getApplication(); $document = \JFactory::getDocument(); $document->setCharset($response->charset); $document->setMimeEncoding($response->mimeType); // Output HTTP header. $app->setHeader('Status', $response->getStatus()); $app->setHeader('Content-Type', $response->mimeType . '; charset=' . $response->charset); foreach ($response->getHeaders() as $key => $values) { $replace = true; foreach ($values as $value) { $app->setHeader($key, $value, $replace); $replace = false; } } if ($response instanceof JsonResponse) { $app->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true); $app->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true); $app->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', false); $app->setHeader('Pragma', 'no-cache'); $app->sendHeaders(); } // Output Gantry response. echo $response; if ($response instanceof JsonResponse) { $app->close(); } } } classes/Gantry/Admin/ThemeList.php 0000604 00000010577 15075035625 0013122 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license GNU/GPLv2 and later * * http://www.gnu.org/licenses/gpl-2.0.html */ namespace Gantry\Admin; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Theme\ThemeDetails; use Gantry\Framework\Gantry; use Joomla\Registry\Registry; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class ThemeList { /** * @var ThemeDetails[] */ protected static $items; /** * @var array */ protected static $styles; /** * @return array */ public static function getThemes() { if (!is_array(static::$items)) { static::loadThemes(); } $list = []; foreach (static::$items as $item) { $details = static::getTheme($item['name']); if ($details) { $list[$item['name']] = $details; } } return $list; } /** * @param string $name * @return mixed */ public static function getTheme($name) { $styles = static::getStyles($name); return reset($styles); } /** * @param string $template * @return array */ public static function getStyles($template = null, $force = false) { if ($force || !is_array(static::$styles)) { static::loadStyles(); } if ($template) { return isset(static::$styles[$template]) ? static::$styles[$template] : []; } $list = []; foreach (static::$styles as $styles) { $list += $styles; } ksort($list); return $list; } protected static function loadThemes() { $gantry = Gantry::instance(); /** @var UniformResourceLocator $locator */ $locator = $gantry['locator']; /** @var array|ThemeDetails[] $list */ $list = []; $files = Folder::all('gantry-themes://', ['recursive' => false, 'files' => false]); natsort($files); foreach ($files as $theme) { if ($locator('gantry-themes://' . $theme . '/gantry/theme.yaml')) { $details = new ThemeDetails($theme); $details->addStreams(); $details['name'] = $theme; $details['title'] = $details['details.name']; $details['preview_url'] = null; $details['admin_url'] = $gantry['platform']->getThemeAdminUrl($theme); $details['params'] = []; $list[$details->name] = $details; } } // Add Thumbnails links after adding all the paths to the locator. foreach ($list as $details) { $details['thumbnail'] = $details->getUrl("details.images.thumbnail"); } static::$items = $list; } protected static function loadStyles() { $gantry = Gantry::instance(); $db = \JFactory::getDbo(); $query = $db ->getQuery(true) ->select('s.id, e.extension_id, s.template AS name, s.title, s.params') ->from('#__template_styles AS s') ->where('s.client_id = 0') ->where('e.enabled = 1') ->where('e.state = 0') ->leftJoin('#__extensions AS e ON e.element=s.template AND e.type=' . $db->quote('template') . ' AND e.client_id=s.client_id') ->order('s.id'); $db->setQuery($query); $styles = (array) $db->loadObjectList(); if (!is_array(static::$items)) { static::loadThemes(); } /** @var array|ThemeDetails[] $list */ $list = []; foreach ($styles as $style) { $details = isset(static::$items[$style->name]) ? static::$items[$style->name] : null; if (!$details) { continue; } $params = new Registry($style->params); $details = clone $details; $details['id'] = $style->id; $details['extension_id'] = $style->extension_id; $details['style'] = $style->title; $details['preview_url'] = $gantry['platform']->getThemePreviewUrl($style->id); $details['params'] = $params->toArray(); $list[$style->name][$style->id] = $details; } static::$styles = $list; } } classes/Gantry/Admin/Page.php 0000604 00000007021 15075035625 0012066 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\ConfigFileFinder; use Gantry\Component\File\CompiledYamlFile; use Gantry\Framework\Theme as SiteTheme; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Page { protected $container; protected $files; protected $blocks; public function __construct($container) { $this->container = $container; } public function all() { if (!$this->blocks) { $files = $this->locateBlocks(); $this->blocks = []; foreach ($files as $key => $fileArray) { $filename = key($fileArray); $file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' . $filename); $this->blocks[$key] = $file->content(); $file->free(); } } return $this->blocks; } public function group() { $blocks = $this->all(); $list = []; foreach ($blocks as $name => $setting) { $type = isset($setting['type']) ? $setting['type'] : ''; $list[$type][$name] = $setting; } return $this->sort($list); } public function get($id) { if ($this->blocks[$id]) { return $this->blocks[$id]; } $files = $this->locateBlocks(); if (empty($files[$id])) { throw new \RuntimeException(sprintf("Settings for '%s' not found.", $id), 404); } $filename = key($files[$id]); $file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' . $filename); $setting = $file->content(); $file->free(); return $setting; } /** * @param string $id * @return BlueprintForm */ public function getBlueprintForm($id) { return BlueprintForm::instance($id, 'gantry-blueprints://page'); } protected function sort(array $blocks) { $list = []; /** @var SiteTheme $theme */ $theme = $this->container['theme']; $ordering = (array) $theme->details()['admin.page']; if (!count($ordering)) { $ordering = ['global' => ['head', 'assets', 'body', 'generics']]; } ksort($blocks); foreach ($ordering as $name => $order) { if (isset($blocks[$name])) { $list[$name] = $this->sortItems($blocks[$name], (array) $order); } } $list += $blocks; return $list; } protected function sortItems(array $items, array $ordering) { $list = []; ksort($items); foreach ($ordering as $name) { if (isset($items[$name])) { $list[$name] = $items[$name]; } } $list += $items; return $list; } protected function locateBlocks() { if (!$this->files) { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $paths = $locator->findResources('gantry-blueprints://page'); $this->files = (new ConfigFileFinder)->listFiles($paths); } return $this->files; } } classes/Gantry/Admin/Controller/Html/About.php 0000604 00000001413 15075035625 0015312 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Admin\ThemeList; use Gantry\Component\Admin\HtmlController; class About extends HtmlController { public function index() { // TODO: Find better way: $this->params['info'] = (new ThemeList)->getTheme($this->container['theme.name']); return $this->render('@gantry-admin/pages/about/about.html.twig', $this->params); } } classes/Gantry/Admin/Controller/Html/Menu.php 0000604 00000043333 15075035625 0015153 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Config\BlueprintSchema; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\Config; use Gantry\Component\Menu\Item; use Gantry\Component\Request\Input; use Gantry\Component\Response\HtmlResponse; use Gantry\Component\Response\JsonResponse; use Gantry\Component\Response\Response; use Gantry\Framework\Menu as MenuObject; use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Menu extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'item', '/*' => 'item', '/*/**' => 'item', '/particle' => 'particle', '/particle/*' => 'validateParticle', '/select' => 'undefined', '/select/particle' => 'selectParticle', '/select/module' => 'selectModule', '/select/widget' => 'selectWidget', '/edit' => 'undefined', '/edit/*' => 'edit', '/edit/*/**' => 'editItem', ], 'POST' => [ '/' => 'save', '/*' => 'save', '/*/**' => 'item', '/particle' => 'particle', '/particle/*' => 'validateParticle', '/select' => 'undefined', '/select/particle' => 'selectParticle', '/select/module' => 'selectModule', '/select/widget' => 'selectWidget', '/widget' => 'widget', '/edit' => 'undefined', '/edit/*' => 'edit', '/edit/*/**' => 'editItem', '/edit/*/validate' => 'validate', ], 'PUT' => [ '/*' => 'replace' ], 'PATCH' => [ '/*' => 'update' ], 'DELETE' => [ '/*' => 'destroy' ] ]; public function execute($method, array $path, array $params) { if (!$this->authorize('menu.manage')) { $this->forbidden(); } return parent::execute($method, $path, $params); } public function item($id = null) { // Load the menu. try { $resource = $this->loadResource($id, $this->build($this->request->post)); } catch (\Exception $e) { return $this->render('@gantry-admin/pages/menu/menu.html.twig', $this->params); } // All extra arguments become the path. $path = array_slice(func_get_args(), 1); // Get menu item and make sure it exists. $item = $resource[implode('/', $path)]; if (!$item) { throw new \RuntimeException('Menu item not found', 404); } // Fill parameters to be passed to the template file. $this->params['id'] = $resource->name(); $this->params['menus'] = $resource->getMenus(); $this->params['default_menu'] = $resource->hasDefaultMenu() ? $resource->getDefaultMenuName() : false; $this->params['menu'] = $resource; $this->params['path'] = implode('/', $path); // Detect special case to fetch only single column group. $group = $this->request->get['group']; if (empty($this->params['ajax']) || empty($this->request->get['inline'])) { // Handle special case to fetch only one column group. if (count($path) > 0) { $this->params['columns'] = $resource[$path[0]]; } if (count($path) > 1) { $this->params['column'] = isset($group) ? (int) $group : $resource[implode('/', array_slice($path, 0, 2))]->group; $this->params['override'] = $item; } return $this->render('@gantry-admin/pages/menu/menu.html.twig', $this->params); } else { // Get layout name. $layout = $this->layoutName(count($path) + (int) isset($group)); $this->params['item'] = $item; $this->params['group'] = isset($group) ? (int) $group : $resource[implode('/', array_slice($path, 0, 2))]->group; return $this->render('@gantry-admin/menu/' . $layout . '.html.twig', $this->params) ?: ' '; } } public function edit($id) { $resource = $this->loadResource($id); $input = $this->build($this->request->post); if ($input) { $resource->config()->merge(['settings' => $input['settings']]); } // Fill parameters to be passed to the template file. $this->params['id'] = $resource->name(); $this->params['blueprints'] = $this->loadBlueprints(); $this->params['data'] = ['settings' => $resource->settings()]; return $this->render('@gantry-admin/pages/menu/edit.html.twig', $this->params); } public function save($id = null) { $resource = $this->loadResource($id); $data = $this->build($this->request->post); /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $filename = $locator->findResource("gantry-config://menu/{$resource->name()}.yaml", true, true); // Fire save event. $event = new Event; $event->gantry = $this->container; $event->theme = $this->container['theme']; $event->controller = $this; $event->resource = $id; $event->menu = $data; $this->container->fireEvent('admin.menus.save', $event); $file = YamlFile::instance($filename); $file->settings(['inline' => 99]); $file->save($data->toArray()); $file->free(); } public function editItem($id) { // All extra arguments become the path. $path = array_slice(func_get_args(), 1); $keyword = end($path); // Special case: validate instead of fetching menu item. if ($this->method == 'POST' && $keyword == 'validate') { $params = array_slice(func_get_args(), 0, -1); return call_user_func_array([$this, 'validateitem'], $params); } $path = html_entity_decode(implode('/', $path), ENT_COMPAT | ENT_HTML5, 'UTF-8'); // Load the menu. $resource = $this->loadResource($id); // Get menu item and make sure it exists. /** @var Item $item */ $item = $resource[$path]; if (!$item) { throw new \RuntimeException('Menu item not found', 404); } $data = $this->request->post->getJsonArray('item'); if ($data) { $item->update($data); } // Load blueprints for the menu item. $blueprints = $this->loadBlueprints('menuitem'); $this->params = [ 'id' => $resource->name(), 'path' => $path, 'blueprints' => ['fields' => $blueprints['form/fields/items/fields']], 'data' => $item->toArray() + ['path' => $path], ] + $this->params; return $this->render('@gantry-admin/pages/menu/menuitem.html.twig', $this->params); } public function particle() { $data = $this->request->post['item']; if ($data) { $data = json_decode($data, true); } else { $data = $this->request->post->getArray(); } $name = isset($data['particle']) ? $data['particle'] : null; $block = BlueprintForm::instance('menu/block.yaml', 'gantry-admin://blueprints'); $blueprints = $this->container['particles']->getBlueprintForm($name); // Load particle blueprints and default settings. $validator = $this->loadBlueprints('menu'); $callable = function () use ($validator) { return $validator; }; // Create configuration from the defaults. $item = new Config($data, $callable); $item->def('type', 'particle'); $item->def('title', $blueprints->get('name')); $item->def('options.type', $blueprints->get('type', 'particle')); $item->def('options.particle', []); $item->def('options.block', []); $this->params += [ 'item' => $item, 'block' => $block, 'data' => ['particles' => [$name => $item->options['particle']]], 'particle' => $blueprints, 'parent' => 'settings', 'prefix' => "particles.{$name}.", 'route' => "configurations.default.settings", 'action' => "menu/particle/{$name}" ]; return $this->render('@gantry-admin/pages/menu/particle.html.twig', $this->params); } public function validateParticle($name) { // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } // Load particle blueprints and default settings. $validator = new BlueprintSchema; $validator->embed('options', $this->container['particles']->get($name)); $blueprints = $this->container['particles']->getBlueprintForm($name); // Create configuration from the defaults. $data = new Config([], function () use ($validator) { return $validator; } ); $data->set('type', 'particle'); $data->set('particle', $name); $data->set('title', $this->request->post['title'] ?: $blueprints->post['name']); $data->set('options.particle', $this->request->post->getArray("particles.{$name}")); $data->def('options.particle.enabled', 1); $data->set('enabled', $data->get('options.particle.enabled')); $block = $this->request->post->getArray('block'); foreach ($block as $key => $param) { if ($param === '') { unset($block[$key]); } } $data->join('options.block', $block); // TODO: validate // Fill parameters to be passed to the template file. $this->params['item'] = (object) $data->toArray(); $html = $this->render('@gantry-admin/menu/item.html.twig', $this->params); return new JsonResponse(['item' => $data->toArray(), 'html' => $html]); } public function selectModule() { return $this->render('@gantry-admin/modals/module-picker.html.twig', $this->params); } public function selectWidget() { $this->params['next'] = 'menu/widget'; return $this->render('@gantry-admin/modals/widget-picker.html.twig', $this->params); } public function widget() { $data = $this->request->post->getJson('item'); $path = [$data->widget]; $this->params['scope'] = 'menu'; return $this->executeForward('widget', 'POST', $path, $this->params); } public function selectParticle() { $groups = [ 'Particles' => ['particle' => []], ]; $particles = [ 'position' => [], 'spacer' => [], 'system' => [], 'particle' => [], ]; $particles = array_replace($particles, $this->getParticles()); unset($particles['atom'], $particles['position']); foreach ($particles as &$group) { asort($group); } foreach ($groups as $section => $children) { foreach ($children as $key => $child) { $groups[$section][$key] = $particles[$key]; } } $this->params += [ 'particles' => $groups, 'route' => 'menu/particle', ]; return $this->render('@gantry-admin/modals/particle-picker.html.twig', $this->params); } public function validate($id) { // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } // Load particle blueprints and default settings. $validator = $this->loadBlueprints('menu'); $callable = function () use ($validator) { return $validator; }; // Create configuration from the defaults. $data = new Config($this->request->post->getArray(), $callable); // TODO: validate return new JsonResponse(['settings' => (array) $data->get('settings')]); } public function validateitem($id) { // All extra arguments become the path. $path = array_slice(func_get_args(), 1); // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } // Load the menu. $resource = $this->loadResource($id); // Load particle blueprints and default settings. $validator = $this->loadBlueprints('menuitem'); $callable = function () use ($validator) { return $validator; }; // Create configuration from the defaults. $data = new Config($this->request->post->getArray(), $callable); // TODO: validate $item = $resource[implode('/', $path)]; $item->update($data->toArray()); // Fill parameters to be passed to the template file. $this->params['id'] = $resource->name(); $this->params['item'] = $item; $this->params['group'] = isset($group) ? $group : $resource[implode('/', array_slice($path, 0, 2))]->group; if (!$item->title) { throw new \RuntimeException('Title from the Menu Item should not be empty', 400); } $html = $this->render('@gantry-admin/menu/item.html.twig', $this->params); return new JsonResponse(['path' => implode('/', $path), 'item' => $data->toArray(), 'html' => $html]); } protected function layoutName($level) { switch ($level) { case 0: return 'base'; case 1: return 'columns'; default: return 'list'; } } /** * Load resource. * * @param string $id * @param Config $config * * @return \Gantry\Component\Menu\AbstractMenu * @throws \RuntimeException */ protected function loadResource($id, Config $config = null) { /** @var MenuObject $menus */ $menus = $this->container['menu']; return $menus->instance(['menu' => $id, 'admin' => true], $config); } /** * Load blueprints. * * @param string $name * * @return BlueprintForm */ protected function loadBlueprints($name = 'menu') { return BlueprintForm::instance("menu/{$name}.yaml", 'gantry-admin://blueprints'); } public function build(Input $input) { try { $items = $input->get('items'); if ($items && $items[0] !== '{' && $items[0] !== '[') { $items = urldecode((string)base64_decode($items)); } $items = json_decode($items, true); $settings = $input->getJsonArray('settings'); $order = $input->getJsonArray('ordering'); } catch (\Exception $e) { throw new \RuntimeException('Invalid menu structure', 400); } if (!$items && !$settings && !$order) { return null; } krsort($order); $ordering = ['' => []]; foreach ($order as $path => $columns) { foreach ($columns as $column => $colitems) { $list = []; foreach ($colitems as $item) { $name = trim(substr($item, strlen($path)), '/'); if (isset($ordering[$item])) { $list[$name] = $ordering[$item]; unset($ordering[$item]); } else { $list[$name] = ''; } } if (count($columns) > 1) { $ordering[$path][$column] = $list; } else { $ordering[$path] = $list; } } } $data = new Config([]); $data->set('settings', $settings); $data->set('ordering', $ordering['']); $data->set('items', $items); return $data; } protected function getParticles() { $particles = $this->container['particles']->all(); $list = []; foreach ($particles as $name => $particle) { $type = isset($particle['type']) ? $particle['type'] : 'particle'; $particleName = isset($particle['name']) ? $particle['name'] : $name; $particleIcon = isset($particle['icon']) ? $particle['icon'] : null; $list[$type][$name] = ['name' => $particleName, 'icon' => $particleIcon]; } return $list; } protected function executeForward($resource, $method = 'GET', $path, $params = []) { $class = '\\Gantry\\Admin\\Controller\\Json\\' . strtr(ucwords(strtr($resource, '/', ' ')), ' ', '\\'); if (!class_exists($class)) { throw new \RuntimeException('Page not found', 404); } /** @var HtmlController $controller */ $controller = new $class($this->container); // Execute action. $response = $controller->execute($method, $path, $params); if (!$response instanceof Response) { $response = new HtmlResponse($response); } return $response; } } classes/Gantry/Admin/Controller/Html/Configurations/Assignments.php 0000604 00000004435 15075035625 0021534 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html\Configurations; use Gantry\Component\Admin\HtmlController; use Gantry\Framework\Assignments as AssignmentsObject; use RocketTheme\Toolbox\Event\Event; class Assignments extends HtmlController { public function index() { $outline = $this->params['outline']; if ($this->hasAssignments($outline)) { $assignments = new AssignmentsObject($outline); $this->params['assignments'] = $assignments->get(); $this->params['options'] = $assignments->assignmentOptions(); $this->params['assignment'] = $assignments->getAssignment(); } return $this->render('@gantry-admin/pages/configurations/assignments/assignments.html.twig', $this->params); } public function store() { // Authorization. if (!$this->authorize('outline.assign')) { $this->forbidden(); } $outline = $this->params['outline']; if (!$this->hasAssignments($outline)) { $this->undefined(); } if (!$this->request->post->get('_end')) { throw new \OverflowException("Incomplete data received. Please increase the value of 'max_input_vars' variable (in php.ini or .htaccess)", 400); } // Save assignments. $assignments = new AssignmentsObject($outline); $assignments->save($this->request->post->getArray('assignments')); // Fire save event. $event = new Event; $event->gantry = $this->container; $event->theme = $this->container['theme']; $event->controller = $this; $event->assignments = $assignments; $this->container->fireEvent('admin.assignments.save', $event); return ''; } protected function hasAssignments($outline) { // Default outline and system outlines cannot have assignments. return $outline !== 'default' && $outline[0] !== '_'; } } classes/Gantry/Admin/Controller/Html/Configurations/Page.php 0000604 00000026514 15075035625 0020117 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html\Configurations; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Config\BlueprintSchema; use Gantry\Component\Config\Config; use Gantry\Component\Layout\Layout; use Gantry\Component\Response\JsonResponse; use Gantry\Framework\Atoms; use Gantry\Framework\Services\ConfigServiceProvider; use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Page extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'index' ], 'POST' => [ '/' => 'save', '/*' => 'save', '/*/**' => 'formfield', '/atoms' => 'undefined', '/atoms/*' => 'atom', '/atoms/*/validate' => 'atomValidate' ], 'PUT' => [ '/' => 'save' ], 'PATCH' => [ '/' => 'save' ], 'DELETE' => [ '/' => 'forbidden' ] ]; public function index() { $outline = $this->params['outline']; if ($outline == 'default') { $this->params['overrideable'] = false; $data = $this->container['config']; } else { $this->params['overrideable'] = true; $this->params['defaults'] = $defaults = $this->container['defaults']; $data = ConfigServiceProvider::load($this->container, $outline, false, false); } $deprecated = $this->getDeprecatedAtoms(); if ($deprecated) { $data->set('page.head.atoms', $deprecated); } if (isset($defaults)) { $currentAtoms = $data->get('page.head.atoms'); if (!$currentAtoms) { // Make atoms to appear to be inherited in they are loaded from defaults. $defaultAtoms = (array) $defaults->get('page.head.atoms'); $atoms = (new Atoms($defaultAtoms))->inheritAll('default')->toArray(); $defaults->set('page.head.atoms', $atoms); } } $this->params += [ 'data' => $data, 'page' => $this->container['page']->group(), 'route' => "configurations.{$outline}", 'page_id' => $outline, 'atoms' => $this->getAtoms(), 'atoms_deprecated' => $deprecated ]; return $this->render('@gantry-admin/pages/configurations/page/page.html.twig', $this->params); } public function save($id = null) { $data = $id ? [$id => $this->request->post->getArray()] : $this->request->post->getArray('page'); foreach ($data as $name => $values) { $this->saveItem($name, $values); } // Fire save event. $event = new Event; $event->gantry = $this->container; $event->theme = $this->container['theme']; $event->controller = $this; $event->data = $data; $this->container->fireEvent('admin.page.save', $event); return $id ? $this->display($id) : $this->index(); } public function formfield($id) { $path = func_get_args(); $end = end($path); if ($end === '') { array_pop($path); } if (end($path) == 'validate') { return call_user_func_array([$this, 'validate'], $path); } // Load blueprints. $blueprints = $this->container['page']->getBlueprintForm($id); list($fields, $path, $value) = $blueprints->resolve(array_slice($path, 1), '/'); if (!$fields) { throw new \RuntimeException('Page Not Found', 404); } $data = $this->request->post->getJsonArray('data'); $offset = "page.{$id}." . implode('.', $path); if ($value !== null) { $parent = $fields; $fields = ['fields' => $fields['fields']]; $offset .= '.' . $value; $data = $data ?: $this->container['config']->get($offset); $data = ['data' => $data]; $scope = 'data.'; } else { $data = $data ?: $this->container['config']->get($offset); $scope = 'data'; } $fields['is_current'] = true; array_pop($path); $outline = $this->params['outline']; $configuration = "configurations/{$outline}"; $this->params = [ 'configuration' => $configuration, 'blueprints' => $fields, 'data' => $data, 'prefix' => '', 'scope' => $scope, 'parent' => $path ? "$configuration/settings/particles/{$id}/" . implode('/', $path) : "$configuration/settings/particles/{$id}", 'route' => "configurations.{$outline}.{$offset}", ] + $this->params; if (isset($parent['key'])) { $this->params['key'] = $parent['key']; } if (isset($parent['value'])) { $this->params['title'] = $parent['value']; } return $this->render('@gantry-admin/pages/configurations/settings/field.html.twig', $this->params); } public function validate($particle) { $path = implode('.', array_slice(func_get_args(), 1, -1)); // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } // Load particle blueprints. $validator = $this->container['particles']->get($particle); // Create configuration from the defaults. $data = new Config( [], function () use ($validator) { return $validator; } ); $data->join($path, $this->request->post->getArray('data')); // TODO: validate return new JsonResponse(['data' => $data->get($path)]); } public function atom($name) { $outline = $this->params['outline']; $atoms = Atoms::instance($outline); $data = $this->request->post['data']; if ($data) { $data = json_decode($data, true); } else { $data = $this->request->post->getArray(); } // Create atom and get its blueprint. $item = $atoms->createAtom($name, $data); $blueprint = $item->blueprint(); // Load inheritance blueprint. $inheritance = $atoms->getInheritanceBlueprint($name, $item->id); $inheritable = $inheritance && $inheritance->get('form/fields/outline/filter', []); $this->params += [ 'inherit' => !empty($inherit['outline']) ? $inherit['outline'] : null, 'inheritance' => $inheritance, 'inheritable' => $inheritable, 'item' => $item, 'data' => ['particles' => [$name => $item->attributes]], 'blueprints' => $blueprint, 'parent' => 'settings', 'prefix' => "particles.{$name}.", 'route' => "configurations.default.settings", 'action' => "configurations/{$outline}/page/atoms/{$name}/validate", 'skip' => ['enabled'] ]; return new JsonResponse(['html' => $this->render('@gantry-admin/modals/atom.html.twig', $this->params)]); } /** * Validate data for the atom. * * @param string $name * @return JsonResponse */ public function atomValidate($name) { // Load particle blueprints and default settings. $validator = new BlueprintSchema; $validator->embed('options', $this->container['particles']->get($name)); $blueprints = $this->container['particles']->getBlueprintForm($name); // Create configuration from the defaults. $data = new Config([], function () use ($validator) { return $validator; } ); $data->set('id', $this->request->post['id']); $data->set('type', $name); $data->set('title', $this->request->post['title'] ?: $blueprints->get('name')); $data->set('attributes', $this->request->post->getArray("particles.{$name}")); $data->def('attributes.enabled', 1); $block = $this->request->post->getArray('block'); foreach ($block as $key => $param) { if ($param === '') { unset($block[$key]); } } $inherit = $this->request->post->getArray('inherit'); $clone = !empty($inherit['mode']) && $inherit['mode'] === 'clone'; $inherit['include'] = !empty($inherit['include']) ? explode(',', $inherit['include']) : []; if (!$clone && !empty($inherit['outline']) && count($inherit['include'])) { unset($inherit['mode']); $data->join('inherit', $inherit); } // TODO: validate // Fill parameters to be passed to the template file. $this->params['item'] = (object) $data->toArray(); return new JsonResponse(['item' => $data->toArray()]); } protected function saveItem($id, $data) { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; // Save layout into custom directory for the current theme. $outline = $this->params['outline']; // Move atoms out of layout. if ($id === 'head') { $layout = Layout::instance($outline); if (is_array($layout->atoms())) { $layout->save(false); } if (isset($data['atoms'])) { $atoms = new Atoms($data['atoms']); $data['atoms'] = $atoms->update()->toArray(); } } $save_dir = $locator->findResource("gantry-config://{$outline}/page", true, true); $filename = "{$save_dir}/{$id}.yaml"; $file = YamlFile::instance($filename); if (!is_array($data)) { if ($file->exists()) { $file->delete(); } } else { $blueprints = $this->container['page']->getBlueprintForm($id); $config = new Config($data, function () use ($blueprints) { return $blueprints; }); $file->save($config->toArray()); } $file->free(); } protected function getDeprecatedAtoms() { $id = $this->params['outline']; $layout = Layout::instance($id); return $layout->atoms(); } protected function getAtoms($onlyEnabled = false) { $config = $this->container['config']; $atoms = $this->container['particles']->all(); $list = []; foreach ($atoms as $name => $atom) { $type = isset($atom['type']) ? $atom['type'] : 'atom'; $atomName = isset($atom['name']) ? $atom['name'] : $name; if (!$onlyEnabled || $config->get("particles.{$name}.enabled", true)) { $list[$type][$name] = $atomName; } } return $list['atom']; } } classes/Gantry/Admin/Controller/Html/Configurations/Settings.php 0000604 00000021031 15075035625 0021030 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html\Configurations; use Gantry\Admin\Particles; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Config\Config; use Gantry\Component\Response\JsonResponse; use Gantry\Framework\Services\ConfigServiceProvider; use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Settings extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/particles' => 'undefined', '/particles/*' => 'display', '/particles/*/**' => 'formfield', ], 'POST' => [ '/' => 'save', '/particles' => 'forbidden', '/particles/*' => 'save', '/particles/*/**' => 'formfield' ], 'PUT' => [ '/' => 'save', '/particles' => 'forbidden', '/particles/*' => 'save' ], 'PATCH' => [ '/' => 'save', '/particles' => 'forbidden', '/particles/*' => 'save' ], 'DELETE' => [ '/' => 'forbidden', '/particles' => 'forbidden', '/particles/*' => 'reset' ] ]; public function index() { $outline = $this->params['outline']; if ($outline === 'default') { $this->params['overrideable'] = false; $data = $this->container['config']; } else { $this->params['overrideable'] = true; $this->params['defaults'] = $this->container['defaults']; $data = ConfigServiceProvider::load($this->container, $outline, false, false); } /** @var Particles $particles */ $particles = $this->container['particles']; $this->params += [ 'data' => $data, 'particles' => $particles->group(['atom']), 'route' => "configurations.{$outline}.settings", 'page_id' => $outline ]; return $this->render('@gantry-admin/pages/configurations/settings/settings.html.twig', $this->params); } public function display($id) { $outline = $this->params['outline']; /** @var Particles $particles */ $particles = $this->container['particles']; $blueprints = $particles->getBlueprintForm($id); $prefix = 'particles.' . $id; if($outline === 'default') { $this->params['overrideable'] = false; $data = $this->container['config']; } else { $this->params['overrideable'] = true; $this->params['defaults'] = $this->container['defaults']->get($prefix); $data = ConfigServiceProvider::load($this->container, $outline, false, false); } $this->params += [ 'scope' => 'particle.', 'particle' => $blueprints, 'data' => ['particle' => $data->get($prefix)], 'id' => $id, 'parent' => "configurations/{$outline}/settings", 'route' => "configurations.{$outline}.settings.{$prefix}", 'skip' => ['enabled'] ]; return $this->render('@gantry-admin/pages/configurations/settings/item.html.twig', $this->params); } public function formfield($id) { $path = func_get_args(); $end = end($path); if ($end === '') { array_pop($path); } if (end($path) === 'validate') { return call_user_func_array([$this, 'validate'], $path); } /** @var Particles $particles */ $particles = $this->container['particles']; // Load blueprints. $blueprints = $particles->getBlueprintForm($id); list($fields, $path, $value) = $blueprints->resolve(array_slice($path, 1), '/'); if (!$fields) { throw new \RuntimeException('Page Not Found', 404); } $data = $this->request->post->getJsonArray('data'); /** @var Config $config */ $config = $this->container['config']; $offset = "particles.{$id}." . implode('.', $path); if ($value !== null) { $parent = $fields; $fields = ['fields' => $fields['fields']]; $offset .= '.' . $value; $data = $data ?: $config->get($offset); $data = ['data' => $data]; $scope = 'data.'; } else { $data = $data ?: $config->get($offset); $scope = 'data'; } $fields['is_current'] = true; array_pop($path); $outline = $this->params['outline']; $configuration = "configurations/{$outline}"; $this->params = [ 'configuration' => $configuration, 'blueprints' => $fields, 'data' => $data, 'scope' => $scope, 'parent' => $path ? "{$configuration}/settings/particles/{$id}/" . implode('/', $path) : "{$configuration}/settings/particles/{$id}", 'route' => "configurations.{$outline}.settings.{$offset}", ] + $this->params; if (isset($parent['key'])) { $this->params['key'] = $parent['key']; } if (isset($parent['value'])) { $this->params['title'] = $parent['value']; } return $this->render('@gantry-admin/pages/configurations/settings/field.html.twig', $this->params); } public function validate($particle) { $path = implode('.', array_slice(func_get_args(), 1, -1)); // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } /** @var Particles $particles */ $particles = $this->container['particles']; // Load particle blueprints. $validator = $particles->get($particle); // Create configuration from the defaults. $data = new Config( [], function () use ($validator) { return $validator; } ); $data->join($path, $this->request->post->getArray('data')); // TODO: validate return new JsonResponse(['data' => $data->get($path)]); } public function save($id = null) { if (!$this->request->post->get('_end')) { throw new \OverflowException("Incomplete data received. Please increase the value of 'max_input_vars' variable (in php.ini or .htaccess)", 400); } $data = $id ? [$id => $this->request->post->getArray('particle')] : $this->request->post->getArray('particles'); /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; // Save layout into custom directory for the current theme. $outline = $this->params['outline']; $save_dir = $locator->findResource("gantry-config://{$outline}/particles", true, true); foreach ($data as $name => $values) { $this->saveItem($name, $values, $save_dir); } @rmdir($save_dir); // Fire save event. $event = new Event; $event->gantry = $this->container; $event->theme = $this->container['theme']; $event->controller = $this; $event->data = $data; $this->container->fireEvent('admin.settings.save', $event); return $id ? $this->display($id) : $this->index(); } protected function saveItem($id, $data, $save_dir) { $filename = "{$save_dir}/{$id}.yaml"; $file = YamlFile::instance($filename); if (!is_array($data)) { if ($file->exists()) { $file->delete(); } } else { /** @var Particles $particles */ $particles = $this->container['particles']; $blueprints = $particles->getBlueprintForm($id); $config = new Config($data, function() use ($blueprints) { return $blueprints; }); $file->save($config->toArray()); } $file->free(); } public function reset($id) { $this->params += [ 'data' => [], ]; return $this->display($id); } } classes/Gantry/Admin/Controller/Html/Configurations/Layout.php 0000604 00000043155 15075035625 0020520 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html\Configurations; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Config\BlueprintSchema; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\Config; use Gantry\Component\File\CompiledYamlFile; use Gantry\Component\Layout\Layout as LayoutObject; use Gantry\Component\Response\JsonResponse; use Gantry\Framework\Outlines; use RocketTheme\Toolbox\Event\Event; class Layout extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/create' => 'create', '/create/*' => 'create', '/*' => 'undefined', '/switch' => 'listSwitches', '/switch/*' => 'switchLayout', '/preset' => 'undefined', '/preset/*' => 'preset' ], 'POST' => [ '/' => 'save', '/*' => 'undefined', '/*/*' => 'particle', '/switch' => 'undefined', '/switch/*' => 'switchLayout', '/preset' => 'undefined', '/preset/*' => 'preset', '/particles' => 'undefined', '/particles/*' => 'undefined', '/particles/*/validate' => 'validate' ], 'PUT' => [ '/*' => 'replace' ], 'PATCH' => [ '/*' => 'update' ], 'DELETE' => [ '/*' => 'destroy' ] ]; public function create($id = null) { if (!$id) { // TODO: we might want to display list of options here throw new \RuntimeException('Not Implemented', 404); } $layout = $this->getLayout("presets/{$id}"); if (!$layout) { throw new \RuntimeException('Preset not found', 404); } $this->params['page_id'] = $id; $this->params['layout'] = $layout->prepareWidths()->toArray(); return $this->render('@gantry-admin/pages/configurations/layouts/create.html.twig', $this->params); } public function index() { $outline = $this->params['outline']; $layout = $this->getLayout($outline); if (!$layout) { throw new \RuntimeException('Layout not found', 404); } $groups = [ 'Positions' => ['position' => [], 'spacer' => [], 'system' => []], 'Particles' => ['particle' => []] ]; $particles = [ 'position' => [], 'spacer' => [], 'system' => [], 'particle' => [] ]; $particles = array_replace($particles, $this->getParticles()); foreach ($particles as &$group) { asort($group); } unset($group); foreach ($groups as $section => $children) { foreach ($children as $key => $child) { $groups[$section][$key] = $particles[$key]; } } $this->params['page_id'] = $outline; $this->params['layout'] = $layout->prepareWidths()->toArray(); $this->params['preset'] = $layout->preset; $this->params['preset_title'] = ucwords(trim(str_replace('_', ' ', $layout->preset['name']))); $this->params['id'] = ucwords(str_replace('_', ' ', ltrim($outline, '_'))); $this->params['particles'] = $groups; $this->params['switcher_url'] = str_replace('.', '/', "configurations.{$outline}.layout.switch"); return $this->render('@gantry-admin/pages/configurations/layouts/edit.html.twig', $this->params); } public function save() { $layout = $this->request->post->get('layout'); $layout = json_decode($layout); if (!isset($layout)) { throw new \RuntimeException('Error while saving layout: Structure missing', 400); } $outline = $this->params['outline']; $preset = $this->request->post->getJsonArray('preset'); // Create layout from the data. $layout = new LayoutObject($outline, $layout, $preset); $layout->init(false, false); /** @var Outlines $outlines */ $outlines = $this->container['outlines']; // Update layouts from all inheriting outlines. $elements = $layout->sections() + $layout->particles(false); foreach ($outlines->getInheritingOutlines($outline) as $inheritedId => $inheritedName) { LayoutObject::instance($inheritedId)->updateInheritance($outline, $outline, $elements)->save()->saveIndex(); } // Save layout and its index. $layout->save()->saveIndex(); // Fire save event. $event = new Event; $event->gantry = $this->container; $event->theme = $this->container['theme']; $event->controller = $this; $event->layout = $layout; $this->container->fireEvent('admin.layout.save', $event); } public function particle($type, $id) { if ($type === 'atom') { return ''; } $outline = $this->params['outline']; $layout = $this->getLayout($outline); if (!$layout) { throw new \RuntimeException('Layout not found', 404); } $item = $layout->find($id); $item->type = $this->request->post['type'] ?: $type; $item->subtype = $this->request->post['subtype'] ?: $type; $item->title = $this->request->post['title'] ?: ucfirst($type); $parent = $this->request->post['parent'] ?: $layout->getParentId($id); if (!isset($item->attributes)) { $item->attributes = new \stdClass; } if (!isset($item->inherit)) { $item->inherit = new \stdClass; } $block = $this->request->post->getArray('block'); if (!empty($block)) { $item->block = (object) $block; } $attributes = $this->request->post->getArray('options'); $inherit = $this->request->post->getArray('inherit'); $particle = !$layout->isLayoutType($type); if (!$particle) { $name = $type; $section = ($type === 'section'); $hasBlock = $section && !empty($block); $prefix = "particles.{$type}"; $defaults = []; $attributes += (array) $item->attributes; $blueprints = BlueprintForm::instance("layout/{$type}.yaml", 'gantry-admin://blueprints'); } else { $name = $item->subtype; $hasBlock = true; $prefix = "particles.{$name}"; $defaults = (array) $this->container['config']->get($prefix); $blueprints = $this->container['particles']->getBlueprintForm($name); $blueprints->set('form/fields/_inherit', ['type' => 'gantry.inherit']); } if ($hasBlock) { $blockBlueprints = BlueprintForm::instance('layout/block.yaml', 'gantry-admin://blueprints'); } else { $blockBlueprints = null; } $file = "gantry-admin://blueprints/layout/inheritance/{$type}.yaml"; if (file_exists($file)) { $inheritType = $particle ? 'particle' : 'section'; /** @var Outlines $outlines */ $outlines = $this->container['outlines']; if ($outline !== 'default') { if ($particle) { $list = $outlines->getOutlinesWithParticle($item->subtype, false); } else { $list = $outlines->getOutlinesWithSection($item->id, false); } unset($list[$outline]); } else { $list = []; } if (!empty($inherit['outline']) || (!($inheriting = $outlines->getInheritingOutlines($outline, [$id, $parent])) && $list)) { $inheritable = true; $inheritance = BlueprintForm::instance($file, 'gantry-admin://blueprints'); $inheritance->set('form/fields/outline/filter', array_keys($list)); if (!$hasBlock) { $inheritance->undef('form/fields/include/options/block'); } if ($particle) { $inheritance->set('form/fields/particle/particle', $name); } } elseif (!empty($inheriting)) { // Already inherited by other outlines. $inheritance = BlueprintForm::instance('layout/inheritance/messages/inherited.yaml', 'gantry-admin://blueprints'); $inheritance->set( 'form/fields/_note/content', sprintf($inheritance->get('form/fields/_note/content'), $inheritType, ' <ul><li>' . implode('</li> <li>', $inheriting) . '</li></ul>') ); } elseif ($outline === 'default') { // Base outline. $inheritance = BlueprintForm::instance('layout/inheritance/messages/default.yaml', 'gantry-admin://blueprints'); } else { // Nothing to inherit from. $inheritance = BlueprintForm::instance('layout/inheritance/messages/empty.yaml', 'gantry-admin://blueprints'); } } $item->attributes = (object) $attributes; $item->inherit = (object) $inherit; $this->params['id'] = $name; $this->params += [ 'extra' => $blockBlueprints, 'inherit' => !empty($inherit['outline']) ? $inherit['outline'] : null, 'inheritance' => isset($inheritance) ? $inheritance : null, 'inheritable' => !empty($inheritable), 'item' => $item, 'data' => ['particles' => [$name => $item->attributes]], 'defaults' => ['particles' => [$name => $defaults]], 'prefix' => "particles.{$name}.", 'particle' => $blueprints, 'parent' => 'settings', 'route' => "configurations.{$outline}.settings", 'action' => str_replace('.', '/', 'configurations.' . $outline . '.layout.' . $prefix . '.validate'), 'skip' => ['enabled'], 'editable' => $particle, 'overrideable' => $particle, ]; if ($particle) { $result = $this->render('@gantry-admin/pages/configurations/layouts/particle.html.twig', $this->params); } else { $typeLayout = $type === 'container' ? 'container' : 'section'; $result = $this->render('@gantry-admin/pages/configurations/layouts/' . $typeLayout . '.html.twig', $this->params); } return $result; } public function listSwitches() { $this->params['presets'] = LayoutObject::presets(); $result = $this->render('@gantry-admin/layouts/switcher.html.twig', $this->params); return new JsonResponse(['html' => $result]); } public function switchLayout($id) { // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } $outline = $this->params['outline']; $layout = $this->getLayout($id); if (!$layout->toArray()) { // Layout hasn't been defined, return default layout instead. $layout = $this->getLayout('default'); } $input = $this->request->post->getJson('layout'); $deleted = isset($input) ? $layout->clearSections()->copySections($input): []; if ($outline === 'default') { $layout->inheritNothing(); } elseif (!$input && $this->request->post['inherit'] === '1') { $layout->inheritAll(); } $message = $deleted ? $this->render('@gantry-admin/ajax/particles-loss.html.twig', ['particles' => $deleted]) : null; return new JsonResponse([ 'title' => ucwords(trim(str_replace('_', ' ', $layout->preset['name']))), 'preset' => json_encode($layout->preset), 'data' => $layout->prepareWidths()->toJson(), 'deleted' => $deleted, 'message' => $message ]); } public function preset($id) { // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } $preset = LayoutObject::preset($id); if (!$preset) { throw new \RuntimeException('Preset not found', 404); } $layout = new LayoutObject($id, $preset); $input = $this->request->post->getJson('layout'); $deleted = isset($input) ? $layout->clearSections()->copySections($input): []; $message = $deleted ? $this->render('@gantry-admin/ajax/particles-loss.html.twig', ['particles' => $deleted]) : null; return new JsonResponse([ 'title' => ucwords(trim(str_replace('_', ' ', $id))), 'preset' => json_encode($layout->preset), 'data' => $layout->prepareWidths()->toJson(), 'deleted' => $deleted, 'message' => $message ]); } public function validate($particle) { // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } // Load particle blueprints and default settings. $validator = new BlueprintSchema; $name = $particle; if (in_array($particle, ['wrapper', 'section', 'container', 'grid', 'offcanvas'], true)) { $type = $particle; $particle = null; $file = CompiledYamlFile::instance("gantry-admin://blueprints/layout/{$type}.yaml"); $validator->embed('options', (array)$file->content()); $file->free(); } else { $type = in_array($particle, ['spacer', 'system', 'position'], true) ? $particle : 'particle'; $validator->embed('options', $this->container['particles']->get($particle)); } // Create configuration from the defaults. $data = new Config( [ 'type' => $type, ], function () use ($validator) { return $validator; } ); // Join POST data. $data->join('options', $this->request->post->getArray("particles." . $name)); if ($particle) { $data->set('options.enabled', (int) $data->get('options.enabled', 1)); } if ($particle) { if ($type !== $particle) { $data->set('subtype', $particle); } $data->join('title', $this->request->post['title'] ?: ucfirst($particle)); } $block = $this->request->post->getArray('block'); if ($block) { // TODO: remove empty items in some other way: foreach ($block as $key => $param) { if ($param === '') { unset($block[$key]); continue; } if ($key === 'size') { $param = round($param, 4); if ($param < 5) { $param = 5; } elseif ($param > 100) { $param = 100; } $block[$key] = $param; } } $data->join('block', $block); } $inherit = $this->request->post->getArray('inherit'); $clone = !empty($inherit['mode']) && $inherit['mode'] === 'clone'; $inherit['include'] = !empty($inherit['include']) ? explode(',', $inherit['include']) : []; if (!$clone && !empty($inherit['outline']) && count($inherit['include'])) { // Clean up inherit and add it to the data. if (!$block) { $inherit['include'] = array_values(array_diff($inherit['include'], ['block'])); } unset($inherit['mode']); $data->join('inherit', $inherit); } // Optionally send children of the object. if (in_array('children', $inherit['include'], true)) { $layout = LayoutObject::instance($inherit['outline'] ?: $this->params['outline']); if ($clone) { $item = $layout->find($inherit['section']); } else { $item = $layout->inheritAll()->find($inherit['section']); } $data->join('children', !empty($item->children) ? $item->children : []); } // TODO: validate return new JsonResponse(['data' => $data->toArray()]); } /** * @param string $name * @return LayoutObject */ protected function getLayout($name) { return LayoutObject::instance($name); } protected function getParticles($onlyEnabled = false) { /** @var Config $config */ $config = $this->container['config']; $particles = $this->container['particles']->all(); $list = []; foreach ($particles as $name => $particle) { $type = isset($particle['type']) ? $particle['type'] : 'particle'; $particleName = isset($particle['name']) ? $particle['name'] : $name; $particleIcon = isset($particle['icon']) ? $particle['icon'] : null; if (!$onlyEnabled || $config->get("particles.{$name}.enabled", true)) { $list[$type][$name] = ['name' => $particleName, 'icon' => $particleIcon]; } } return $list; } } classes/Gantry/Admin/Controller/Html/Configurations/Styles.php 0000604 00000020017 15075035625 0020516 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html\Configurations; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Config\Config; use Gantry\Component\Response\JsonResponse; use Gantry\Framework\Services\ConfigServiceProvider; use Gantry\Framework\Theme; use RocketTheme\Toolbox\Event\Event; use RocketTheme\Toolbox\File\YamlFile; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Styles extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/blocks' => 'undefined', '/blocks/*' => 'display', '/blocks/*/**' => 'formfield' ], 'POST' => [ '/' => 'save', '/blocks' => 'forbidden', '/blocks/*' => 'save', '/compile' => 'compile' ], 'PUT' => [ '/' => 'save', '/blocks' => 'forbidden', '/blocks/*' => 'save' ], 'PATCH' => [ '/' => 'save', '/blocks' => 'forbidden', '/blocks/*' => 'save' ], 'DELETE' => [ '/' => 'forbidden', '/blocks' => 'forbidden', '/blocks/*' => 'reset' ] ]; public function index() { $outline = $this->params['outline']; if($outline == 'default') { $this->params['overrideable'] = false; $this->params['data'] = $this->container['config']; } else { $this->params['overrideable'] = true; $this->params['defaults'] = $this->container['defaults']; $this->params['data'] = ConfigServiceProvider::load($this->container, $outline, false, false); } $this->params['blocks'] = $this->container['styles']->group(); $this->params['route'] = "configurations.{$outline}.styles"; return $this->render('@gantry-admin/pages/configurations/styles/styles.html.twig', $this->params); } public function display($id) { $outline = $this->params['outline']; $blueprints = $this->container['styles']->getBlueprintForm($id); $prefix = 'styles.' . $id; if($outline == 'default') { $this->params['overrideable'] = false; $this->params['data'] = $this->container['config']->get($prefix); } else { $this->params['overrideable'] = true; $this->params['defaults'] = $this->container['defaults']->get($prefix); $this->params['data'] = ConfigServiceProvider::load($this->container, $outline, false, false)->get($prefix); } $this->params += [ 'block' => $blueprints, 'id' => $id, 'parent' => "configurations/{$outline}/styles", 'route' => "configurations.{$outline}.styles.{$prefix}", 'skip' => ['enabled'] ]; return $this->render('@gantry-admin/pages/configurations/styles/item.html.twig', $this->params); } public function formfield($id) { $path = func_get_args(); $outline = $this->params['outline']; // Load blueprints. $blueprints = $this->container['styles']->getBlueprintForm($id); list($fields, $path, $value) = $blueprints->resolve(array_slice($path, 1), '/'); if (!$fields) { throw new \RuntimeException('Page Not Found', 404); } $fields['is_current'] = true; // Get the prefix. $prefix = "styles.{$id}." . implode('.', $path); if ($value !== null) { $parent = $fields; $fields = ['fields' => $fields['fields']]; $prefix .= '.' . $value; } array_pop($path); if($outline == 'default') { $this->params['overrideable'] = false; $this->params['data'] = $this->container['config']->get($prefix); } else { $this->params['overrideable'] = true; $this->params['defaults'] = $this->container['defaults']->get($prefix); $this->params['data'] = ConfigServiceProvider::load($this->container, $outline, false, false)->get($prefix); } $this->params = [ 'blueprints' => $fields, 'parent' => $path ? "configurations/{$outline}/styles/blocks/{$id}/" . implode('/', $path) : "configurations/{$outline}/styles/blocks/{$id}", 'route' => 'styles.' . $prefix ] + $this->params; if (isset($parent['key'])) { $this->params['key'] = $parent['key']; } return $this->render('@gantry-admin/pages/configurations/styles/field.html.twig', $this->params); } public function reset($id) { $this->params += [ 'data' => [], ]; return $this->display($id); } public function compile() { // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } $warnings = $this->compileSettings(); if ($warnings) { $this->params += ['warnings' => $warnings]; return new JsonResponse( [ 'html' => $this->render('@gantry-admin/layouts/css-warnings.html.twig', $this->params), 'warning' => true, 'title' => 'CSS Compiled With Warnings', ] ); } else { return new JsonResponse(['html' => 'The CSS was successfully compiled', 'title' => 'CSS Compiled']); } } public function save($id = null) { /** @var Config $config */ $config = $this->container['config']; if ($id) { $data = (array) $config->get('styles'); $data[$id] = $this->request->post->getArray(); } else { $data = $this->request->post->getArray('styles'); } /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; // Save layout into custom directory for the current theme. $outline = $this->params['outline']; $save_dir = $locator->findResource("gantry-config://{$outline}", true, true); $filename = "{$save_dir}/styles.yaml"; $file = YamlFile::instance($filename); $file->save($data); $file->free(); // Fire save event. $event = new Event; $event->gantry = $this->container; $event->theme = $this->container['theme']; $event->controller = $this; $event->data = $data; $this->container->fireEvent('admin.styles.save', $event); // Compile CSS. $warnings = $this->compileSettings(); if (empty($this->params['ajax'])) { // FIXME: HTML request: Output compiler warnings!! return $id ? $this->display($id) : $this->index(); } if ($warnings) { $this->params += ['warnings' => $warnings]; return new JsonResponse( [ 'html' => $this->render('@gantry-admin/layouts/css-warnings.html.twig', $this->params), 'warning' => true, 'title' => 'CSS Compiled With Warnings', ] ); } else { return new JsonResponse(['html' => 'The CSS was successfully compiled', 'title' => 'CSS Compiled']); } } /** * @returns array */ protected function compileSettings() { /** @var Theme $theme */ $theme = $this->container['theme']; $outline = $this->params['outline']; return $theme->updateCss($outline !== 'default' ? [$outline => ucfirst($outline)] : null); } } classes/Gantry/Admin/Controller/Html/Themes.php 0000604 00000001321 15075035625 0015463 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Admin\ThemeList; use Gantry\Component\Admin\HtmlController; class Themes extends HtmlController { public function index() { $this->params['themes'] = (new ThemeList)->getThemes(); return $this->render('@gantry-admin/pages/themes/themes.html.twig', $this->params); } } classes/Gantry/Admin/Controller/Html/Import.php 0000604 00000005175 15075035625 0015523 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Filesystem\Folder; use Gantry\Framework\Importer; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use Symfony\Component\Yaml\Yaml; class Import extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', ], 'POST' => [ '/' => 'import', ] ]; public function index() { return $this->render('@gantry-admin/pages/import/import.html.twig', $this->params); } public function import() { if (!isset($_FILES['file']['error']) || is_array($_FILES['file']['error'])) { throw new \RuntimeException('No file sent', 400); } // Check $_FILES['file']['error'] value. switch ($_FILES['file']['error']) { case UPLOAD_ERR_OK: break; case UPLOAD_ERR_NO_FILE: throw new \RuntimeException('No file sent', 400); case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: throw new \RuntimeException('Exceeded filesize limit.', 400); default: throw new \RuntimeException('Unkown errors', 400); } $filename = $_FILES['file']['tmp_name']; if (!is_uploaded_file($filename)) { throw new \RuntimeException('No file sent', 400); } $zip = new \ZipArchive; if ($zip->open($filename) !== true || !($export = Yaml::parse($zip->getFromName('export.yaml'))) || !isset($export['gantry'])) { throw new \RuntimeException('Uploaded file is not Gantry 5 export file', 400); } /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $folder = $locator->findResource('gantry-cache://import', true, true); if (is_dir($folder)) Folder::delete($folder); $zip->extractTo($folder); $zip->close(); $importer = new Importer($folder); $importer->all(); if (is_dir($folder)) Folder::delete($folder); $this->params['success'] = true; return $this->render('@gantry-admin/pages/import/import.html.twig', $this->params); } } classes/Gantry/Admin/Controller/Html/Positions.php 0000604 00000025265 15075035625 0016242 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Config\BlueprintSchema; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\Config; use Gantry\Component\Position\Module; use Gantry\Component\Position\Position; use Gantry\Component\Response\JsonResponse; use Gantry\Framework\Assignments; use Gantry\Framework\Positions as PositionsObject; class Positions extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/*' => 'undefined', '/*/add' => 'selectParticle', ], 'POST' => [ '/' => 'save', '/create' => 'create', '/*' => 'undefined', '/*/rename' => 'rename', '/*/duplicate' => 'duplicate', '/*/delete' => 'delete', '/*/edit' => 'undefined', '/*/edit/particle' => 'particle', '/*/edit/particle/*' => 'validateParticle', '/edit' => 'undefined', '/edit/particle' => 'particle', ] ]; public function index() { $this->params['positions'] = $this->container['positions']; return $this->render('@gantry-admin/pages/positions/positions.html.twig', $this->params); } public function create() { // Create only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } /** @var PositionsObject $position */ $positions = $this->container['positions']; $title = (string) $this->request->post->get('title', 'Untitled'); $key = (string) $this->request->post['key']; $id = $positions->create($title, $key); $html = $this->render('@gantry-admin/layouts/position.html.twig', ['position' => ['name' => $id, 'title' => $title]]); return new JsonResponse(['html' => sprintf("Position '%s' created.", $id), 'id' => "position-{$id}", 'key' => $id, 'position' => $html]); } public function rename($old) { // Rename only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } $title = (string) $this->request->post['title']; $key = (string) $this->request->post['key']; $data = (string) $this->request->post['data']; /** @var PositionsObject $positions */ $positions = $this->container['positions']; $position = $positions[$old]; $exists = isset($position); if (!$exists) { if (!$data) { throw new \RuntimeException(sprintf("Position '%s' not found", $old), 404); } $position = new Position($key ?: $old); } if (strlen($title)) { $position->title = (string) $title; } if ($exists && strlen($key)) { $position = $position->rename($key); } else { $position->save(); } if ($data) { $data = ['title' => $position->title] + json_decode($data, true); $position = new Position($position->name, $data); } $html = $this->render('@gantry-admin/layouts/position.html.twig', ['position' => $position]); return new JsonResponse(['html' => sprintf("Position saved"), 'id' => "position-{$position->name}", 'key' => $position->name, 'position' => $html]); } public function duplicate($position) { // Duplicate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } /** @var PositionsObject $positions */ $positions = $this->container['positions']; $id = $positions->duplicate($position); return new JsonResponse(['html' => sprintf("Position duplicated as '%s'.", $id)]); } public function delete($position) { // Delete only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } /** @var PositionsObject $positions */ $positions = $this->container['positions']; $positions->delete($position); return new JsonResponse(['html' => sprintf("Position '%s' deleted.", $position), 'position' => $position]); } public function save() { // Save only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } $data = $this->request->post->getJsonArray('positions'); /** @var PositionsObject $position */ $positions = $this->container['positions']; $positions->import($data); return new JsonResponse(['html' => sprintf("Positions saved.")]); } public function particle($position = null) { if (!$position) { $position = $this->request->post['position']; } $data = $this->request->post['item']; if ($data) { $data = json_decode($data, true); } else { $data = $this->request->post->getArray(); } $name = isset($data['options']['type']) ? $data['options']['type'] : (isset($data['particle']) ? $data['particle'] : null); $blueprints = $this->container['particles']->getBlueprintForm($name); $chromeBlueprints = BlueprintForm::instance('position/chrome.yaml', 'gantry-admin://blueprints'); $data['title'] = isset($data['title']) ? $data['title'] : $blueprints['name']; $data['chrome'] = isset($data['chrome']) ? $data['chrome'] : []; $data['options'] = isset($data['options']) ? $data['options'] : []; $data['options']['type'] = $name; $attributes = isset($data['options']['attributes']) ? $data['options']['attributes'] : []; $assignments = new Assignments(); $this->params += [ 'item' => $data, 'data' => [ 'particles' => [$name => $attributes], 'chrome' => $data['chrome'], 'assignments' => isset($data['assignments']) ? $data['assignments'] : 'all' ], 'particle' => $blueprints, 'chrome' => $chromeBlueprints, 'assignments' => $assignments->get(), 'parent' => 'settings', 'prefix' => "particles.{$name}.", 'route' => "configurations.default.settings", 'action' => "positions/{$position}/edit/particle/{$name}" ]; return $this->render('@gantry-admin/pages/positions/particle.html.twig', $this->params); } public function validateParticle($position, $name) { // Validate only exists for JSON. if (empty($this->params['ajax'])) { $this->undefined(); } if (!$this->request->post->get('_end')) { throw new \OverflowException("Incomplete data received. Please increase the value of 'max_input_vars' variable (in php.ini or .htaccess)", 400); } // Load particle blueprints and default settings. $validator = new BlueprintSchema; $validator->embed('options', $this->container['particles']->get($name)); $blueprints = $this->container['particles']->getBlueprintForm($name); // Create configuration from the defaults. $data = new Config([], function () use ($validator) { return $validator; } ); $data->set('position', $position); $data->set('id', $id = $this->request->post['id']); $data->set('type', 'particle'); $data->set('title', $this->request->post['title'] ?: $blueprints->post['name']); $data->set('chrome', $this->request->post->getArray('chrome')); $data->set('options.type', $name); $data->set('options.attributes', $this->request->post->getArray("particles.{$name}")); $data->def('options.attributes.enabled', 1); $assignments = (new Assignments())->filter($this->request->post->getArray('assignments'), true); if (!$assignments) { // Use special syntax for no assignments. $assignments = 'none'; } elseif ($assignments === ['page' => [true]]) { // Use special syntax for assigned to all pages. This is a special case and hardcoded for now. $assignments = 'all'; } $data->set('assignments', $assignments); // TODO: validate // Fill parameters to be passed to the template file. $this->params['position'] = $position; $this->params['item'] = (object) $data->toArray(); $this->params['module'] = new Module($id, $position, $data->toArray()); $html = $this->render('@gantry-admin/pages/positions/item.html.twig', $this->params); return new JsonResponse(['item' => $data->toArray(), 'html' => $html, 'position' => $position]); } public function selectParticle($position) { $groups = [ 'Particles' => ['particle' => []], ]; $particles = [ 'position' => [], 'spacer' => [], 'system' => [], 'particle' => [], ]; $particles = array_replace($particles, $this->getParticles()); unset($particles['atom'], $particles['position']); foreach ($particles as &$group) { asort($group); } foreach ($groups as $section => $children) { foreach ($children as $key => $child) { $groups[$section][$key] = $particles[$key]; } } $this->params += [ 'particles' => $groups, 'route' => "positions/{$position}/edit/particle", ]; return $this->render('@gantry-admin/modals/particle-picker.html.twig', $this->params); } protected function getParticles() { $particles = $this->container['particles']->all(); $list = []; foreach ($particles as $name => $particle) { $type = isset($particle['type']) ? $particle['type'] : 'particle'; $particleName = isset($particle['name']) ? $particle['name'] : $name; $particleIcon = isset($particle['icon']) ? $particle['icon'] : null; $list[$type][$name] = ['name' => $particleName, 'icon' => $particleIcon]; } return $list; } } classes/Gantry/Admin/Controller/Html/Configurations.php 0000604 00000017126 15075035625 0017242 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Response\HtmlResponse; use Gantry\Component\Response\JsonResponse; use Gantry\Component\Response\RedirectResponse; use Gantry\Component\Response\Response; use Gantry\Component\Layout\Layout as LayoutObject; use Gantry\Framework\Outlines as OutlinesObject; class Configurations extends HtmlController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/*' => 'forward', '/*/delete' => 'confirmDeletion', '/*/**' => 'forward', ], 'POST' => [ '/' => 'undefined', '/*' => 'undefined', '/create' => 'createForm', '/create/new' => 'create', '/*/rename' => 'rename', '/*/duplicate' => 'duplicateForm', '/*/duplicate/new' => 'duplicate', '/*/delete' => 'undefined', '/*/delete/confirm' => 'delete', '/*/**' => 'forward', ], 'PUT' => [ '/' => 'undefined', '/**' => 'forward' ], 'PATCH' => [ '/' => 'undefined', '/**' => 'forward' ] ]; public function index() { return $this->render('@gantry-admin/pages/configurations/configurations.html.twig', $this->params); } public function createForm() { if (!$this->authorize('outline.create')) { $this->forbidden(); } $params = [ 'presets' => LayoutObject::presets(), 'outlines' => $this->container['outlines'] ]; $response = ['html' => $this->render('@gantry-admin/ajax/outline-new.html.twig', $params)]; return new JsonResponse($response); } public function create() { // Check if we want to duplicate outline instead. if ($this->request->post['from'] === 'outline') { return $this->duplicate($this->request->post['outline']); } if (!$this->authorize('outline.create')) { $this->forbidden(); } /** @var OutlinesObject $outlines */ $outlines = $this->container['outlines']; $title = $this->request->post['title']; $preset = $this->request->post['preset']; $id = $outlines->create(null, $title, $preset); $html = $this->render('@gantry-admin/layouts/outline.html.twig', ['name' => $id, 'title' => $outlines[$id]]); return new JsonResponse(['html' => 'Outline created.', 'id' => "outline-{$id}", 'outline' => $html]); } public function rename($outline) { if (!$this->authorize('outline.rename')) { $this->forbidden(); } /** @var OutlinesObject $outlines */ $outlines = $this->container['outlines']; $title = $this->request->post['title']; $id = $outlines->rename($outline, $title); $html = $this->render('@gantry-admin/layouts/outline.html.twig', ['name' => $id, 'title' => $outlines[$id]]); return new JsonResponse(['html' => 'Outline renamed.', 'id' => "outline-{$outline}", 'outline' => $html]); } public function duplicateForm($outline) { if (!$this->authorize('outline.create')) { $this->forbidden(); } $params = [ 'outlines' => $this->container['outlines'], 'outline' => $outline, 'duplicate' => true ]; $response = ['html' => $this->render('@gantry-admin/ajax/outline-new.html.twig', $params)]; return new JsonResponse($response); } public function duplicate($outline) { if (!$this->authorize('outline.create')) { $this->forbidden(); } /** @var OutlinesObject $outlines */ $outlines = $this->container['outlines']; $title = $this->request->post['title']; $inherit = in_array($this->request->post['inherit'], ['1', 'true']); $id = $outlines->duplicate($outline, $title, $inherit); $html = $this->render('@gantry-admin/layouts/outline.html.twig', ['name' => $id, 'title' => $outlines[$id]]); return new JsonResponse(['html' => 'Outline duplicated.', 'id' => $id, 'outline' => $html]); } public function delete($outline) { if (!$this->authorize('outline.delete')) { $this->forbidden(); } /** @var OutlinesObject $outlines */ $outlines = $this->container['outlines']; $list = $outlines->user(); if (!isset($list[$outline])) { $this->forbidden(); } $outlines->delete($outline); return new JsonResponse(['html' => 'Outline deleted.', 'outline' => $outline]); } /** * @return JsonResponse */ public function confirmDeletion($id) { /** @var OutlinesObject $outlines */ $outlines = $this->container['outlines']; $params = [ 'id' => $id, 'page_type' => 'OUTLINE', 'outline' => $outlines->title($id), 'inherited' => $outlines->getInheritingOutlines($id) ]; $html = $this->render('@gantry-admin/pages/configurations/confirm-deletion.html.twig', $params); return new JsonResponse(['html' => $html]); } /** * @return HtmlResponse|RedirectResponse|JsonResponse */ public function forward() { $path = func_get_args(); $outline = array_shift($path); $page = array_shift($path); $method = $this->params['method']; if ((!isset($outline) || !isset($page)) && $this->params['format'] !== 'json') { // Redirect path to the styles page of the selected outline. return new RedirectResponse($this->container->route('configurations', is_string($outline) ? $outline : 'default', 'styles')); } $outlines = $this->container['outlines']; if (!isset($outlines[$outline])) { throw new \RuntimeException('Outline not found.', 404); } $this->container['outline'] = $outline; $this->container['configuration'] = $outline; $resource = $this->params['location'] . '/'. $page; $this->params['outline'] = $outline; $this->params['configuration'] = $outline; $this->params['location'] = $resource; $this->params['configuration_page'] = $page; $this->params['navbar'] = !empty($this->request->get['navbar']); return $this->executeForward($resource, $method, $path, $this->params); } protected function executeForward($resource, $method = 'GET', $path, $params = []) { $class = '\\Gantry\\Admin\\Controller\\Html\\' . strtr(ucwords(strtr($resource, '/', ' ')), ' ', '\\'); if (!class_exists($class)) { throw new \RuntimeException('Page not found', 404); } /** @var HtmlController $controller */ $controller = new $class($this->container); // Execute action. $response = $controller->execute($method, $path, $params); if (!$response instanceof Response) { $response = new HtmlResponse($response); } return $response; } } classes/Gantry/Admin/Controller/Html/Cache.php 0000604 00000002131 15075035625 0015241 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Component\Admin\HtmlController; use Gantry\Component\Response\JsonResponse; use Gantry\Component\Filesystem\Folder; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Cache extends HtmlController { public function index() { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; Folder::delete($locator('gantry-cache://theme'), false); Folder::delete($locator('gantry-cache://admin'), false); // Make sure that PHP has the latest data of the files. clearstatcache(); return new JsonResponse(['html' => 'Cache was successfully cleared', 'title' => 'Cache Cleared']); } } classes/Gantry/Admin/Controller/Html/Install.php 0000604 00000002167 15075035625 0015655 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Component\Admin\HtmlController; use Gantry\Framework\ThemeInstaller; class Install extends HtmlController { public function index() { if (!$this->authorize('updates.manage') || !class_exists('\Gantry\Framework\ThemeInstaller')) { $this->forbidden(); } $installer = new ThemeInstaller(); $installer->initialized = true; $installer->loadExtension($this->container['theme.name']); $installer->installDefaults(); $installer->installSampleData(); $installer->finalize(); $this->params['actions'] = $installer->actions; return $this->render('@gantry-admin/pages/install/install.html.twig', $this->params); } } classes/Gantry/Admin/Controller/Html/Export.php 0000604 00000007505 15075035625 0015531 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Html; use Gantry\Component\Admin\HtmlController; use Gantry\Framework\Exporter; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use Symfony\Component\Yaml\Yaml; class Export extends HtmlController { public function index() { if (!class_exists('Gantry\Framework\Exporter')) { $this->forbidden(); } if (!class_exists('ZipArchive')) { throw new \RuntimeException('Please enable PHP ZIP extension to use this feature.'); } $exporter = new Exporter; $exported = $exporter->all(); $zipname = $exported['export']['theme']['name'] . '-export.zip'; $tmpname = tempnam(sys_get_temp_dir(), 'zip'); $zip = new \ZipArchive(); $zip->open($tmpname, \ZipArchive::CREATE); $zip->addFromString("export.yaml", Yaml::dump($exported['export'], 10, 2)); unset($exported['export']); foreach ($exported['positions'] as $key => $position) { foreach ($position['items'] as $module => $data) { $zip->addFromString("positions/{$key}/{$module}.yaml", Yaml::dump($data, 10, 2)); } $position['ordering'] = array_keys($position['items']); unset($position['items']); $zip->addFromString("positions/{$key}.yaml", Yaml::dump($position, 10, 2)); } foreach ($exported['outlines'] as $outline => &$data) { if (!empty($data['config'])) { foreach ($data['config'] as $name => $config) { if (in_array($name, ['particles', 'page'])) { foreach ($config as $sub => $subconfig) { $zip->addFromString("outlines/{$outline}/{$name}/{$sub}.yaml", Yaml::dump($subconfig, 10, 2)); } } else { $zip->addFromString("outlines/{$outline}/{$name}.yaml", Yaml::dump($config, 10, 2)); } } } unset($data['config']); } $zip->addFromString("outlines/outlines.yaml", Yaml::dump($exported['outlines'], 10, 2)); foreach ($exported['menus'] as $menu => $data) { $zip->addFromString("menus/{$menu}.yaml", Yaml::dump($data, 10, 2)); } foreach ($exported['content'] as $id => $data) { $zip->addFromString("content/{$id}.yaml", Yaml::dump($data, 10, 2)); } if (!empty($exported['categories'])) { $zip->addFromString("content/categories.yaml", Yaml::dump($exported['categories'], 10, 2)); } /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; foreach ($exported['files'] as $stream => $files) { foreach ($files as $path => $uri) { $filename = $locator->findResource($uri); if (file_exists($filename)) { $zip->addFile($filename, "files/{$stream}/{$path}"); } } } $zip->close(); header('Content-Type: application/zip'); header('Content-Disposition: attachment; filename=' . $zipname); header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); header('Content-Length: ' . filesize($tmpname)); @ob_end_clean(); flush(); readfile($tmpname); unlink($tmpname); exit; } } classes/Gantry/Admin/Controller/Json/Atoms.php 0000604 00000013066 15075035625 0015337 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Response\JsonResponse; /** * Class Atoms * @package Gantry\Admin\Controller\Json */ class Atoms extends JsonController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/*' => 'index', '/instance' => 'atom' ], 'POST' => [ '/' => 'index', '/*' => 'index', '/instance' => 'atom' ] ]; public function index() { $path = implode('/', func_get_args()); $post = $this->request->request; $outline = $post['outline']; $type = $post['subtype']; $inherit = $post['inherit']; $id = $post['id']; if (!$outline) { throw new \RuntimeException('Outline not given', 400); } $this->container['outline'] = $outline; $this->container['configuration'] = $outline; $atoms = new \Gantry\Framework\Atoms((array) $this->container['config']->get('page.head.atoms')); if ($inherit) { $atoms->inheritAll($outline); } $item = (object) $atoms->id($id); if ($path === 'list') { $list = $atoms->type($type); if (empty($item->id)) { $item = (object)reset($list); } } $selected = !empty($item->id) ? $item->id : null; $type = isset($item->type) ? $item->type : $type; $item->attributes = isset($item->attributes) ? (array) $item->attributes : []; $blueprints = $this->container['particles']->getBlueprintForm($type); $blueprints->set('form/fields/_inherit', ['type' => 'gantry.inherit']); $params = [ 'gantry' => $this->container, 'parent' => 'settings', 'route' => "configurations.{$outline}.settings", 'inherit' => $inherit ? $outline : null, 'title' => isset($item->title) ? $item->title : '', 'blueprints' => $blueprints->get('form'), 'item' => $item, 'data' => ['particles' => [$type => $item->attributes]], 'prefix' => "particles.{$type}.", 'editable' => true, 'overrideable' => false, 'skip' => ['enabled'] ]; $html['g-settings-atom'] = $this->render('@gantry-admin/pages/configurations/layouts/particle-card.html.twig', $params); if (isset($list)) { $html['g-inherit-atom'] = $this->renderAtomsInput($inherit ? $outline : null, $type, $selected, $list); } return new JsonResponse(['json' => $item, 'html' => $html]); } public function atom() { $post = $this->request->request; $outline = $post['outline']; $id = $post['id']; if (!$outline) { throw new \RuntimeException('Outline not given', 400); } $this->container['outline'] = $outline; $this->container['configuration'] = $outline; $atoms = new \Gantry\Framework\Atoms((array) $this->container['config']->get('page.head.atoms')); $item = (object) $atoms->id($id); if (empty($item->id)) { throw new \RuntimeException('Atom was not found from the outline', 404); } $name = $item->type; $prefix = "particles.{$name}"; $blueprints = $this->container['particles']->getBlueprintForm($name); $blueprints->set('form/fields/_inherit', ['type' => 'gantry.inherit']); $item->attributes = isset($item->attributes) ? (array) $item->attributes : []; $this->params['id'] = $name; $this->params += [ 'item' => $item, 'data' => ['particles' => [$name => $item->attributes]], 'prefix' => "particles.{$name}.", 'particle' => $blueprints, 'parent' => 'settings', 'route' => "configurations.{$outline}.settings", 'action' => str_replace('.', '/', 'configurations.' . $outline . '.layout.' . $prefix . '.validate'), 'skip' => ['enabled'], 'editable' => false, 'overrideable' => false, ]; $html = $this->render('@gantry-admin/modals/atom-preview.html.twig', $this->params); return new JsonResponse(['html' => $html]); } /** * Render input field for particle picker. * * @param string $outline * @param string $type * @param string $selected * @param array $instances * @return string */ protected function renderAtomsInput($outline, $type, $selected, array $instances) { $params = [ 'layout' => 'input', 'scope' => 'inherit.', 'field' => [ 'name' => 'atom', 'type' => 'gantry.atoms', 'id' => 'g-inherit-atom', 'outline' => $outline, 'atoms' => $instances, 'atom' => $type ], 'value' => $selected ]; return $this->render('@gantry-admin/forms/fields/gantry/atoms.html.twig', $params); } } classes/Gantry/Admin/Controller/Json/Unsaved.php 0000604 00000001445 15075035625 0015657 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Response\JsonResponse; class Unsaved extends JsonController { protected $httpVerbs = [ 'GET' => [ '/' => 'index' ] ]; public function index() { $response = ['html' => $this->render('@gantry-admin/ajax/unsaved.html.twig')]; return new JsonResponse($response); } } classes/Gantry/Admin/Controller/Json/Layouts.php 0000604 00000020114 15075035625 0015704 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Layout\Layout; use Gantry\Component\Response\JsonResponse; /** * Class Layouts * @package Gantry\Admin\Controller\Json */ class Layouts extends JsonController { protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/*' => 'index', '/particle' => 'particle' ], 'POST' => [ '/' => 'index', '/*' => 'index', '/particle' => 'particle' ] ]; public function index() { $path = implode('/', func_get_args()); $post = $this->request->request; $outline = $post['outline']; $type = $post['type']; $subtype = $post['subtype']; $inherit = $post['inherit']; $clone = $post['mode'] === 'clone'; $id = $post['id']; $this->container['outline'] = $outline; $this->container['configuration'] = $outline; $layout = Layout::instance($outline); if ($inherit) { $layout->inheritAll(); } if ($path == 'list' && !$layout->isLayoutType($type)) { $instance = $this->getParticleInstances($outline, $subtype, null); $id = $instance['selected']; } $item = $layout->find($id); $type = isset($item->type) ? $item->type : $type; $subtype = isset($item->subtype) ? $item->subtype : $subtype; $item->attributes = isset($item->attributes) ? (array) $item->attributes : []; $block = $layout->block($id); $block = isset($block->attributes) ? (array) $block->attributes : []; $params = [ 'gantry' => $this->container, 'parent' => 'settings', 'route' => "configurations.{$outline}.settings", 'inherit' => $inherit ? $outline : null, ]; if ($layout->isLayoutType($type)) { $name = $type; $particle = false; $defaults = []; $blueprints = BlueprintForm::instance("layout/{$name}.yaml", 'gantry-admin://blueprints'); } else { $name = $subtype; $particle = true; $defaults = $this->container['config']->get("particles.{$name}"); $item->attributes = $item->attributes + $defaults; $blueprints = $this->container['particles']->getBlueprintForm($name); $blueprints->set('form/fields/_inherit', ['type' => 'gantry.inherit']); } $paramsParticle = [ 'title' => isset($item->title) ? $item->title : '', 'blueprints' => $blueprints->get('form'), 'item' => $item, 'data' => ['particles' => [$name => $item->attributes]], 'defaults' => ['particles' => [$name => $defaults]], 'prefix' => "particles.{$name}.", 'editable' => $particle, 'overrideable' => $particle, 'skip' => ['enabled'] ] + $params; $html['g-settings-particle'] = $this->render('@gantry-admin/pages/configurations/layouts/particle-card.html.twig', $paramsParticle); $html['g-settings-block-attributes'] = $this->renderBlockFields($block, $params); if ($path == 'list') { $html['g-inherit-particle'] = $this->renderParticlesInput($inherit || $clone ? $outline : null, $subtype, $post['selected']); } return new JsonResponse(['json' => $item, 'html' => $html]); } public function particle() { $post = $this->request->request; $outline = $post['outline']; $id = $post['id']; $this->container['outline'] = $outline; $this->container['configuration'] = $outline; $layout = Layout::instance($outline); $particle = clone $layout->find($id); if (!isset($particle->type)) { throw new \RuntimeException('Particle was not found from the outline', 404); } $particle->block = $layout->block($id); $name = $particle->subtype; $prefix = "particles.{$name}"; $defaults = (array) $this->container['config']->get($prefix); $attributes = (array) $particle->attributes + $defaults; $particleBlueprints = $this->container['particles']->getBlueprintForm($name); $particleBlueprints->set('form/fields/_inherit', ['type' => 'gantry.inherit']); $blockBlueprints = BlueprintForm::instance('layout/block.yaml', 'gantry-admin://blueprints'); // TODO: Use blueprints to merge configuration. $particle->attributes = (object) $attributes; $this->params['id'] = $name; $this->params += [ 'extra' => $blockBlueprints, 'item' => $particle, 'data' => ['particles' => [$name => $attributes]], 'defaults' => ['particles' => [$name => $defaults]], 'prefix' => "particles.{$name}.", 'particle' => $particleBlueprints, 'parent' => 'settings', 'route' => "configurations.{$outline}.settings", 'action' => str_replace('.', '/', 'configurations.' . $outline . '.layout.' . $prefix . '.validate'), 'skip' => ['enabled'], 'editable' => false, 'overrideable' => true, ]; $html = $this->render('@gantry-admin/pages/configurations/layouts/particle-preview.html.twig', $this->params); return new JsonResponse(['html' => $html]); } /** * Render block settings. * * @param array $block * @param array $params * @return string */ protected function renderBlockFields(array $block, array $params) { $blockBlueprints = BlueprintForm::instance('layout/block.yaml', 'gantry-admin://blueprints'); $paramsBlock = [ 'title' => $this->container['translator']->translate('GANTRY5_PLATFORM_BLOCK'), 'blueprints' => ['fields' => $blockBlueprints->get('form/fields/block_container/fields')], 'data' => ['block' => $block], 'prefix' => 'block.', ] + $params; return $this->render('@gantry-admin/forms/fields.html.twig', $paramsBlock); } /** * Gets the list of available particle instances for an outline * * @param string $outline * @param string $particle * @param string $selected * @return string */ protected function getParticleInstances($outline, $particle, $selected) { $list = $outline ? $this->container['outlines']->getParticleInstances($outline, $particle, false) : []; $selected = isset($list[$selected]) ? $selected : key($list); return ['list' => $list, 'selected' => $selected]; } /** * Render input field for particle picker. * * @param string $outline * @param string $particle * @param string $selected * @return string */ protected function renderParticlesInput($outline, $particle, $selected) { $instances = $this->getParticleInstances($outline, $particle, $selected); $params = [ 'layout' => 'input', 'scope' => 'inherit.', 'field' => [ 'name' => 'particle', 'type' => 'gantry.particles', 'id' => 'g-inherit-particle', 'outline' => $outline, 'particles' => $instances['list'], 'particle' => $particle ], 'value' => $instances['selected'] ]; return $this->render('@gantry-admin/forms/fields/gantry/particles.html.twig', $params); } } classes/Gantry/Admin/Controller/Json/Particle.php 0000604 00000014451 15075035625 0016016 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Config\BlueprintSchema; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\Config; use Gantry\Component\Response\JsonResponse; class Particle extends JsonController { protected $httpVerbs = [ 'GET' => [ '/' => 'selectParticle', '/module' => 'selectModule' ], 'POST' => [ '/' => 'undefined', '/*' => 'particle', '/*/validate' => 'validate', ], 'PUT' => [ '/*' => 'replace' ], 'PATCH' => [ '/*' => 'update' ], 'DELETE' => [ '/*' => 'destroy' ] ]; /** * Return a modal for selecting a particle. * * @return string */ public function selectParticle() { $groups = [ 'Particles' => ['particle' => []], ]; $particles = [ 'position' => [], 'spacer' => [], 'system' => [], 'particle' => [], ]; $particles = array_replace($particles, $this->getParticles()); unset($particles['atom'], $particles['position']); foreach ($particles as &$group) { asort($group); } foreach ($groups as $section => $children) { foreach ($children as $key => $child) { $groups[$section][$key] = $particles[$key]; } } $this->params['particles'] = $groups; return new JsonResponse(['html' => $this->render('@gantry-admin/modals/particle-picker.html.twig', $this->params)]); } /** * Return a modal content for selecting module. * * @return mixed */ public function selectModule() { return new JsonResponse(['html' => $this->render('@gantry-admin/modals/module-picker.html.twig', $this->params)]); } /** * Return form for the particle (filled with data coming from POST). * * @param string $name * @return mixed */ public function particle($name) { $data = $this->request->post['item']; if ($data) { $data = json_decode($data, true); } else { $data = $this->request->post->getArray(); } // TODO: add support for other block types as well, like menu. // $block = BlueprintForm::instance('layout/block.yaml', 'gantry-admin://blueprints'); $blueprints = $this->container['particles']->getBlueprintForm($name); // Load particle blueprints and default settings. $validator = $this->loadBlueprints('menu'); $callable = function () use ($validator) { return $validator; }; // Create configuration from the defaults. $item = new Config($data, $callable); $item->def('type', 'particle'); $item->def('title', $blueprints->get('name')); $item->def('options.type', $blueprints->get('type', 'particle')); $item->def('options.particle', []); $item->def('options.block', []); $this->params += [ 'item' => $item, // 'block' => $block, 'data' => ['particles' => [$name => $item->options['particle']]], 'particle' => $blueprints, 'parent' => 'settings', 'prefix' => "particles.{$name}.", 'route' => "configurations.default.settings", 'action' => "particle/{$name}/validate" ]; return new JsonResponse(['html' => $this->render('@gantry-admin/modals/particle.html.twig', $this->params)]); } /** * Validate data for the particle. * * @param string $name * @return JsonResponse */ public function validate($name) { // Load particle blueprints and default settings. $validator = new BlueprintSchema; $validator->embed('options', $this->container['particles']->get($name)); $blueprints = $this->container['particles']->getBlueprintForm($name); // Create configuration from the defaults. $data = new Config([], function () use ($validator) { return $validator; } ); $data->set('type', 'particle'); $data->set('particle', $name); $data->set('title', $this->request->post['title'] ?: $blueprints->get('name')); $data->set('options.particle', $this->request->post->getArray("particles.{$name}")); $data->def('options.particle.enabled', 1); $block = $this->request->post->getArray('block'); foreach ($block as $key => $param) { if ($param === '') { unset($block[$key]); } } if ($block) { $data->join('options.block', $block); } // TODO: validate // Fill parameters to be passed to the template file. $this->params['item'] = (object) $data->toArray(); return new JsonResponse(['item' => $data->toArray()]); } protected function getParticles() { $particles = $this->container['particles']->all(); $list = []; foreach ($particles as $name => $particle) { $type = isset($particle['type']) ? $particle['type'] : 'particle'; $particleName = isset($particle['name']) ? $particle['name'] : $name; $particleIcon = isset($particle['icon']) ? $particle['icon'] : null; $list[$type][$name] = ['name' => $particleName, 'icon' => $particleIcon]; } return $list; } /** * Load blueprints. * * @param string $name * * @return BlueprintForm */ protected function loadBlueprints($name = 'menu') { return BlueprintForm::instance("menu/{$name}.yaml", 'gantry-admin://blueprints'); } } classes/Gantry/Admin/Controller/Json/Devprod.php 0000604 00000002275 15075035625 0015657 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Response\JsonResponse; use RocketTheme\Toolbox\Event\Event; class Devprod extends JsonController { public function store() { $production = intval((bool)$this->request->post['mode']); // Fire save event. $event = new Event; $event->gantry = $this->container; $event->controller = $this; $event->data = ['production' => $production]; $this->container->fireEvent('admin.global.save', $event); $response = [ 'mode' => $production, 'title' => $production ? 'Production' : 'Development', 'html' => $production ? 'Production mode enabled' : 'Development mode enabled', ]; return new JsonResponse($response); } } classes/Gantry/Admin/Controller/Json/Changelog.php 0000604 00000005746 15075035625 0016151 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Remote\Response as RemoteResponse; use Gantry\Component\Response\JsonResponse; class Changelog extends JsonController { protected $url = 'https://raw.githubusercontent.com/gantry/gantry5'; protected $fullurl = 'https://github.com/gantry/gantry5/blob/develop'; protected $issues = 'https://github.com/gantry/gantry5/issues'; protected $contrib = 'https://github.com'; protected $file = 'CHANGELOG.md'; protected $platforms = ['common' => 'share-alt', 'joomla' => '', 'wordpress' => '', 'grav' => '']; protected $httpVerbs = [ 'POST' => [ '/' => 'index' ] ]; public function index() { $version = $this->request->post['version']; $lookup = $version; if ($version == '@version@') { $version = 'develop'; $lookup = ''; } if (substr($version, 0, 4) == 'dev-') { $version = preg_replace('/^dev-/i', '', $version); $lookup = ''; } $url = $this->url . '/' . $version . '/' . $this->file; $changelog = RemoteResponse::get($url); if ($changelog) { $found = preg_match("/(#\\s" . $lookup . ".+?\\n.*?)(?=\\n{1,}#|$)/uis", $changelog, $changelog); if ($found) { $changelog = \Parsedown::instance()->parse($changelog[0]); // auto-link issues $changelog = preg_replace("/#(\\d{1,})/uis", '<a target="_blank" rel="noopener" href="' . $this->issues . '/$1">#$1</a>', $changelog); // auto-link contributors $changelog = preg_replace("/@([\\w]+)[^\\w]/uis", '<a target="_blank" rel="noopener" href="' . $this->contrib . '/$1">@$1</a> ', $changelog); // add icons for platforms foreach($this->platforms as $platform => $icon) { $changelog = preg_replace('/(<a href="\#' . $platform . '">)/uis', '$1<i class="fa fa-' . ($icon ?: $platform) . '" aria-hidden="true"></i> ', $changelog); } } else { $changelog = 'No changelog for version <strong>' . $version . '</strong> was found.'; } } $response = [ 'html' => $this->render('@gantry-admin/ajax/changelog.html.twig', [ 'changelog' => $changelog, 'version' => $version, 'url' => $url, 'fullurl' => $this->fullurl . '/' . $this->file ]) ]; return new JsonResponse($response); } } classes/Gantry/Admin/Controller/Json/Filepicker.php 0000604 00000037254 15075035625 0016336 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Filesystem\Folder; use Gantry\Component\Response\JsonResponse; use RocketTheme\Toolbox\File\File; use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Filepicker extends JsonController { protected $base = false; protected $value = false; protected $filter = false; protected $httpVerbs = [ 'GET' => [ '/' => 'index', '/*' => 'index', '/display' => 'undefined', '/display/**' => 'displayFile', '/download' => 'undefined', '/download/**' => 'downloadFile', ], 'POST' => [ '/' => 'index', '/*' => 'index', '/subfolder' => 'subfolder', '/subfolder/*' => 'subfolder', '/upload' => 'undefined', '/upload/**' => 'upload' ], 'DELETE' => [ '/' => 'undefined', '/**' => 'delete' ] ]; public function index() { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $bookmarks = []; $drives = ['/']; $subfolder = false; $this->base = $locator->base; if ($this->method == 'POST') { $root = $this->request->post['root']; $drives = isset($root) ? ($root !== 'false' ? (array) $root : ['/']) : ['/']; $subfolder = $this->request->post['subfolder'] ? true : false; $filter = $this->request->post['filter']; $this->filter = isset($filter) ? ($filter !== 'false' ? $filter : false) : false; $this->value = $this->request->post['value'] ?: ''; } foreach ($drives as $drive) { // cleanup of the path so it's chrooted. $drive = str_replace('..', '', $drive); $isStream = $locator->isStream($drive); $path = rtrim($this->base, '/') . '/' . ltrim($drive, '/'); // It's a stream but the scheme doesn't exist. we skip it. if (!$isStream && (strpos($drive, '://') || !file_exists($path))) { continue; } if ($isStream && !$locator->findResources($drive)) { continue; } $key = $isStream ? $drive : preg_replace('#/{2,}+#', '/', $drive); if (!array_key_exists($key, $bookmarks)) { $bookmarks[$key] = $isStream ? [$locator->getIterator($drive)] : [rtrim(Folder::getRelativePath($path), '/') . '/']; } } if (!count($bookmarks)) { throw new \RuntimeException(sprintf('%s "%s" not found', count($drives) > 1 ? 'directories' : 'directory', implode('", "', $drives)), 404); } $folders = []; $active = []; $index = 0; $activeFallback = ''; // iterating the folder and collecting subfolders and files foreach ($bookmarks as $key => $bookmark) { $folders[$key] = []; if (!$index) { $activeFallback = $key; } foreach ($bookmark as $folder) { $isStream = $this->isStream($folder); if ($isStream) { unset($bookmarks[$key]); $iterator = new \IteratorIterator($folder); $folder = $key; } else { $iterator = new \DirectoryIterator($this->base . '/' . ltrim($folder, '/')); } $folders[$key][$folder] = new \ArrayObject(); if (!$index && !$this->value) { $active[] = $folder; } /** @var \SplFileInfo $info */ foreach ($iterator as $info) { // no dot files nor files beginning with dot if ($info->isDot() || substr($info->getFilename(), 0, 1) == '.') { continue; } $file = new \stdClass(); $this->attachData($file, $info, $folder); if ($file->dir) { if ($file->pathname == dirname($this->value)) { $active[] = $file->pathname; } $folders[$key][$folder]->append($file); } else { /*if ($filter && !preg_match("/" . $filter . "/i", $file->filename)) { continue; } if ((!$index && !$this->value) || (in_array(dirname($file->pathname), $active))) { $files->append($file); }*/ } } if ($isStream) { $bookmarks[$key][] = $key; } $index++; } } if (!count($active)) { $active[] = $activeFallback; } $lastItem = end($active); $files = $this->listFiles($lastItem); $response = []; reset($active); if (!$subfolder) { $response['html'] = $this->render( '@gantry-admin/ajax/filepicker.html.twig', [ 'active' => $active, 'base' => $this->base, 'bookmarks' => $bookmarks, 'folders' => $folders, 'files' => $files, 'filter' => $this->filter, 'value' => $this->value ] ); } else { $response['subfolder'] = !$folders[$key][$folder]->count() ? false : $this->render( '@gantry-admin/ajax/filepicker/subfolders.html.twig', ['folder' => $folders[$key][$folder]] ); $response['files'] = $this->render( '@gantry-admin/ajax/filepicker/files.html.twig', ['files' => $files, 'value' => $this->value] ); } return new JsonResponse($response); } protected function attachData(&$node, $iteration, $folder) { foreach ( ['getFilename', 'getExtension', 'getPerms', 'getMTime', 'getBasename', 'getPathname', 'getSize', 'getType', 'isReadable', 'isWritable', 'isDir', 'isFile'] as $method ) { $keyMethod = strtolower(preg_replace("/^(is|get)/", '', $method)); $node->{$keyMethod} = $iteration->{$method}(); if ($method == 'getPathname') { $node->{$keyMethod} = $this->isStream($folder) ? $iteration->getUrl() : Folder::getRelativePath($node->{$keyMethod}); } else { if ($method == 'getExtension') { $node->isImage = in_array(strtolower($node->{$keyMethod}), ['jpg', 'jpeg', 'png', 'gif', 'ico', 'svg', 'bmp', 'webp']); } } } } protected function listFiles($folder) { $isStream = $this->isStream($folder); $locator = $this->container['locator']; $iterator = $isStream ? new \IteratorIterator($locator->getIterator($folder)) : new \DirectoryIterator($this->base . '/' . ltrim($folder, '/')); $files = new \ArrayObject(); /** @var \SplFileInfo $info */ foreach ($iterator as $info) { // no dot files nor files beginning with dot if ($info->isDot() || substr($info->getFilename(), 0, 1) == '.') { continue; } $file = new \stdClass(); $this->attachData($file, $info, $folder); if (!$file->dir) { if ($this->filter && !preg_match("/" . $this->filter . "/i", $file->filename)) { continue; } $file->isInCustom = false; if ($isStream) { $stream = explode('://', $folder); $stream = array_shift($stream) . '://'; $customLocation = $locator->findResource($stream, true, true); if (substr($info->getPathname(), 0, strlen($customLocation)) === $customLocation) { $file->isInCustom = true; } } $files->append($file); } } $files->asort(); return $files; } public function subfolder() { $response = []; $response['html'] = 'subfolder'; return new JsonResponse($response); } public function displayFile() { $path = implode('/', func_get_args()); $this->doDownload($path, false); } protected function doDownload($path, $download) { if (!$path) { throw new \RuntimeException('No file specified', 400); } // TODO: handle streams $targetPath = GANTRY5_ROOT . '/' . $path; if (!file_exists($targetPath)) { throw new \RuntimeException(sprintf('File not found: %s', $path), 404); } $hash = md5_file($path); // Handle 304 Not Modified if (isset($this->request->server['HTTP_IF_NONE_MATCH'])) { $etag = stripslashes($this->request->server['HTTP_IF_NONE_MATCH']); if ($etag == $hash) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT', true, 304); // Give fast response. flush(); exit(); } } // Set file headers. header('ETag: ' . $hash); header('Pragma: public'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT'); // Get the image file information. $info = getimagesize($path); $isImage = (bool)$info; if (!$download && $isImage) { $fileType = $info['mime']; // Force re-validate. header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Content-type: ' . $fileType); header('Content-Disposition: inline; filename="' . basename($path) . '"'); } else { // Force file download. header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Content-Description: File Transfer'); header('Content-Type: application/force-download'); header('Content-Type: application/octet-stream'); header('Content-Type: application/download'); header('Content-Disposition: attachment; filename="' . basename($path) . '"'); } header('Content-Transfer-Encoding: binary'); header('Content-Length: ' . filesize($path)); flush(); // Output the file contents. @readfile($path); flush(); exit(); } public function downloadFile() { $path = implode('/', func_get_args()); $this->doDownload($path, true); } public function upload() { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $path = implode('/', func_get_args()); if (base64_decode($path, true) !== false) { $path = urldecode(base64_decode($path)); } $stream = explode('://', $path); $scheme = $stream[0]; $isStream = $locator->schemeExists($scheme); if ($isStream) { $targetPath = dirname($locator->findResource($path, true, true)); } else { $targetPath = dirname(GANTRY5_ROOT . '/' . $path); } if (!isset($_FILES['file']['error']) || is_array($_FILES['file']['error'])) { throw new \RuntimeException('No file sent', 400); } // Check $_FILES['file']['error'] value. switch ($_FILES['file']['error']) { case UPLOAD_ERR_OK: break; case UPLOAD_ERR_NO_FILE: throw new \RuntimeException('No file sent', 400); case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_FORM_SIZE: throw new \RuntimeException('Exceeded filesize limit.', 400); default: throw new \RuntimeException('Unkown errors', 400); } $maxSize = $this->returnBytes(min(ini_get('post_max_size'), ini_get('upload_max_filesize'))); if ($_FILES['file']['size'] > $maxSize) { throw new \RuntimeException('Exceeded filesize limit. File is ' . $_FILES['file']['size'] . ', maximum allowed is ' . $maxSize, 400); } // Check extension $fileParts = pathinfo($_FILES['file']['name']); $fileExt = strtolower($fileParts['extension']); // TODO: check if download is of supported type. // Upload it $destination = sprintf('%s/%s', $targetPath, $_FILES['file']['name']); $destination = preg_replace('#//#', '/', $destination); Folder::create($targetPath); if (!move_uploaded_file($_FILES['file']['tmp_name'], $destination)) { throw new \RuntimeException('Failed to move uploaded file.', 500); } $finfo = new \stdClass(); $this->attachData($finfo, new \SplFileInfo($destination), $targetPath); return new JsonResponse(['success' => 'File uploaded successfully', 'finfo' => $finfo, 'url' => $path]); } protected function returnBytes($size_str) { switch (strtolower(substr($size_str, -1))) { case 'm': case 'mb': return (int)$size_str * 1048576; case 'k': case 'kb': return (int)$size_str * 1024; case 'g': case 'gb': return (int)$size_str * 1073741824; default: return $size_str; } } public function delete() { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $path = implode('/', func_get_args()); if (base64_decode($path, true) !== false) { $path = urldecode(base64_decode($path)); } $stream = explode('://', $path); $scheme = $stream[0]; if (!$path) { throw new \RuntimeException('No file specified for delete', 400); } $isStream = $locator->schemeExists($scheme); if ($isStream) { $targetPath = $locator->findResource($path, true, true); } else { $targetPath = GANTRY5_ROOT . '/' . $path; } $file = File::instance($targetPath); if (!$file->exists()) { throw new \RuntimeException(sprintf('File not found: %s', $targetPath), 404); } try { $file->delete(); } catch (\Exception $e) { throw new \RuntimeException(sprintf('File could not be deleted: %s', $targetPath), 500); } $file->free(); return new JsonResponse(['success', 'File deleted: ' . $targetPath]); } private function isStream($folder) { return $folder instanceof UniformResourceIterator || strpos($folder, '://'); } } classes/Gantry/Admin/Controller/Json/Icons.php 0000604 00000043200 15075035625 0015320 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Response\JsonResponse; class Icons extends JsonController { public function index() { $response = []; // Font Awesome Icons list [v4.7.0 - 730 icons] // NOTE: To get an updated list of icons: // 1. Go to: http://fontawesome.io/icons/ // 2. Open Console in Deveveloper Tools // 3. Type this JS snippet: var list = []; document.querySelectorAll('.fontawesome-icon-list i').forEach(function(icon, index){ var name = icon.className.replace(/^fa\s/, ''); list.push(name); }); var output = '$list = ["' + list.join('", "') + '"];'; console.log(output); copy(output); console.info('The output has been copied to the clipboard, you can now CMD + V / CTRL + V to update the icons variable'); // 4. Press Enter and replace the line below $list = ["fa-address-book", "fa-address-book-o", "fa-address-card", "fa-address-card-o", "fa-bandcamp", "fa-bath", "fa-bathtub", "fa-drivers-license", "fa-drivers-license-o", "fa-eercast", "fa-envelope-open", "fa-envelope-open-o", "fa-etsy", "fa-free-code-camp", "fa-grav", "fa-handshake-o", "fa-id-badge", "fa-id-card", "fa-id-card-o", "fa-imdb", "fa-linode", "fa-meetup", "fa-microchip", "fa-podcast", "fa-quora", "fa-ravelry", "fa-s15", "fa-shower", "fa-snowflake-o", "fa-superpowers", "fa-telegram", "fa-thermometer", "fa-thermometer-0", "fa-thermometer-1", "fa-thermometer-2", "fa-thermometer-3", "fa-thermometer-4", "fa-thermometer-empty", "fa-thermometer-full", "fa-thermometer-half", "fa-thermometer-quarter", "fa-thermometer-three-quarters", "fa-times-rectangle", "fa-times-rectangle-o", "fa-user-circle", "fa-user-circle-o", "fa-user-o", "fa-vcard", "fa-vcard-o", "fa-window-close", "fa-window-close-o", "fa-window-maximize", "fa-window-minimize", "fa-window-restore", "fa-wpexplorer", "fa-address-book", "fa-address-book-o", "fa-address-card", "fa-address-card-o", "fa-adjust", "fa-american-sign-language-interpreting", "fa-anchor", "fa-archive", "fa-area-chart", "fa-arrows", "fa-arrows-h", "fa-arrows-v", "fa-asl-interpreting", "fa-assistive-listening-systems", "fa-asterisk", "fa-at", "fa-audio-description", "fa-automobile", "fa-balance-scale", "fa-ban", "fa-bank", "fa-bar-chart", "fa-bar-chart-o", "fa-barcode", "fa-bars", "fa-bath", "fa-bathtub", "fa-battery", "fa-battery-0", "fa-battery-1", "fa-battery-2", "fa-battery-3", "fa-battery-4", "fa-battery-empty", "fa-battery-full", "fa-battery-half", "fa-battery-quarter", "fa-battery-three-quarters", "fa-bed", "fa-beer", "fa-bell", "fa-bell-o", "fa-bell-slash", "fa-bell-slash-o", "fa-bicycle", "fa-binoculars", "fa-birthday-cake", "fa-blind", "fa-bluetooth", "fa-bluetooth-b", "fa-bolt", "fa-bomb", "fa-book", "fa-bookmark", "fa-bookmark-o", "fa-braille", "fa-briefcase", "fa-bug", "fa-building", "fa-building-o", "fa-bullhorn", "fa-bullseye", "fa-bus", "fa-cab", "fa-calculator", "fa-calendar", "fa-calendar-check-o", "fa-calendar-minus-o", "fa-calendar-o", "fa-calendar-plus-o", "fa-calendar-times-o", "fa-camera", "fa-camera-retro", "fa-car", "fa-caret-square-o-down", "fa-caret-square-o-left", "fa-caret-square-o-right", "fa-caret-square-o-up", "fa-cart-arrow-down", "fa-cart-plus", "fa-cc", "fa-certificate", "fa-check", "fa-check-circle", "fa-check-circle-o", "fa-check-square", "fa-check-square-o", "fa-child", "fa-circle", "fa-circle-o", "fa-circle-o-notch", "fa-circle-thin", "fa-clock-o", "fa-clone", "fa-close", "fa-cloud", "fa-cloud-download", "fa-cloud-upload", "fa-code", "fa-code-fork", "fa-coffee", "fa-cog", "fa-cogs", "fa-comment", "fa-comment-o", "fa-commenting", "fa-commenting-o", "fa-comments", "fa-comments-o", "fa-compass", "fa-copyright", "fa-creative-commons", "fa-credit-card", "fa-credit-card-alt", "fa-crop", "fa-crosshairs", "fa-cube", "fa-cubes", "fa-cutlery", "fa-dashboard", "fa-database", "fa-deaf", "fa-deafness", "fa-desktop", "fa-diamond", "fa-dot-circle-o", "fa-download", "fa-drivers-license", "fa-drivers-license-o", "fa-edit", "fa-ellipsis-h", "fa-ellipsis-v", "fa-envelope", "fa-envelope-o", "fa-envelope-open", "fa-envelope-open-o", "fa-envelope-square", "fa-eraser", "fa-exchange", "fa-exclamation", "fa-exclamation-circle", "fa-exclamation-triangle", "fa-external-link", "fa-external-link-square", "fa-eye", "fa-eye-slash", "fa-eyedropper", "fa-fax", "fa-feed", "fa-female", "fa-fighter-jet", "fa-file-archive-o", "fa-file-audio-o", "fa-file-code-o", "fa-file-excel-o", "fa-file-image-o", "fa-file-movie-o", "fa-file-pdf-o", "fa-file-photo-o", "fa-file-picture-o", "fa-file-powerpoint-o", "fa-file-sound-o", "fa-file-video-o", "fa-file-word-o", "fa-file-zip-o", "fa-film", "fa-filter", "fa-fire", "fa-fire-extinguisher", "fa-flag", "fa-flag-checkered", "fa-flag-o", "fa-flash", "fa-flask", "fa-folder", "fa-folder-o", "fa-folder-open", "fa-folder-open-o", "fa-frown-o", "fa-futbol-o", "fa-gamepad", "fa-gavel", "fa-gear", "fa-gears", "fa-gift", "fa-glass", "fa-globe", "fa-graduation-cap", "fa-group", "fa-hand-grab-o", "fa-hand-lizard-o", "fa-hand-paper-o", "fa-hand-peace-o", "fa-hand-pointer-o", "fa-hand-rock-o", "fa-hand-scissors-o", "fa-hand-spock-o", "fa-hand-stop-o", "fa-handshake-o", "fa-hard-of-hearing", "fa-hashtag", "fa-hdd-o", "fa-headphones", "fa-heart", "fa-heart-o", "fa-heartbeat", "fa-history", "fa-home", "fa-hotel", "fa-hourglass", "fa-hourglass-1", "fa-hourglass-2", "fa-hourglass-3", "fa-hourglass-end", "fa-hourglass-half", "fa-hourglass-o", "fa-hourglass-start", "fa-i-cursor", "fa-id-badge", "fa-id-card", "fa-id-card-o", "fa-image", "fa-inbox", "fa-industry", "fa-info", "fa-info-circle", "fa-institution", "fa-key", "fa-keyboard-o", "fa-language", "fa-laptop", "fa-leaf", "fa-legal", "fa-lemon-o", "fa-level-down", "fa-level-up", "fa-life-bouy", "fa-life-buoy", "fa-life-ring", "fa-life-saver", "fa-lightbulb-o", "fa-line-chart", "fa-location-arrow", "fa-lock", "fa-low-vision", "fa-magic", "fa-magnet", "fa-mail-forward", "fa-mail-reply", "fa-mail-reply-all", "fa-male", "fa-map", "fa-map-marker", "fa-map-o", "fa-map-pin", "fa-map-signs", "fa-meh-o", "fa-microchip", "fa-microphone", "fa-microphone-slash", "fa-minus", "fa-minus-circle", "fa-minus-square", "fa-minus-square-o", "fa-mobile", "fa-mobile-phone", "fa-money", "fa-moon-o", "fa-mortar-board", "fa-motorcycle", "fa-mouse-pointer", "fa-music", "fa-navicon", "fa-newspaper-o", "fa-object-group", "fa-object-ungroup", "fa-paint-brush", "fa-paper-plane", "fa-paper-plane-o", "fa-paw", "fa-pencil", "fa-pencil-square", "fa-pencil-square-o", "fa-percent", "fa-phone", "fa-phone-square", "fa-photo", "fa-picture-o", "fa-pie-chart", "fa-plane", "fa-plug", "fa-plus", "fa-plus-circle", "fa-plus-square", "fa-plus-square-o", "fa-podcast", "fa-power-off", "fa-print", "fa-puzzle-piece", "fa-qrcode", "fa-question", "fa-question-circle", "fa-question-circle-o", "fa-quote-left", "fa-quote-right", "fa-random", "fa-recycle", "fa-refresh", "fa-registered", "fa-remove", "fa-reorder", "fa-reply", "fa-reply-all", "fa-retweet", "fa-road", "fa-rocket", "fa-rss", "fa-rss-square", "fa-s15", "fa-search", "fa-search-minus", "fa-search-plus", "fa-send", "fa-send-o", "fa-server", "fa-share", "fa-share-alt", "fa-share-alt-square", "fa-share-square", "fa-share-square-o", "fa-shield", "fa-ship", "fa-shopping-bag", "fa-shopping-basket", "fa-shopping-cart", "fa-shower", "fa-sign-in", "fa-sign-language", "fa-sign-out", "fa-signal", "fa-signing", "fa-sitemap", "fa-sliders", "fa-smile-o", "fa-snowflake-o", "fa-soccer-ball-o", "fa-sort", "fa-sort-alpha-asc", "fa-sort-alpha-desc", "fa-sort-amount-asc", "fa-sort-amount-desc", "fa-sort-asc", "fa-sort-desc", "fa-sort-down", "fa-sort-numeric-asc", "fa-sort-numeric-desc", "fa-sort-up", "fa-space-shuttle", "fa-spinner", "fa-spoon", "fa-square", "fa-square-o", "fa-star", "fa-star-half", "fa-star-half-empty", "fa-star-half-full", "fa-star-half-o", "fa-star-o", "fa-sticky-note", "fa-sticky-note-o", "fa-street-view", "fa-suitcase", "fa-sun-o", "fa-support", "fa-tablet", "fa-tachometer", "fa-tag", "fa-tags", "fa-tasks", "fa-taxi", "fa-television", "fa-terminal", "fa-thermometer", "fa-thermometer-0", "fa-thermometer-1", "fa-thermometer-2", "fa-thermometer-3", "fa-thermometer-4", "fa-thermometer-empty", "fa-thermometer-full", "fa-thermometer-half", "fa-thermometer-quarter", "fa-thermometer-three-quarters", "fa-thumb-tack", "fa-thumbs-down", "fa-thumbs-o-down", "fa-thumbs-o-up", "fa-thumbs-up", "fa-ticket", "fa-times", "fa-times-circle", "fa-times-circle-o", "fa-times-rectangle", "fa-times-rectangle-o", "fa-tint", "fa-toggle-down", "fa-toggle-left", "fa-toggle-off", "fa-toggle-on", "fa-toggle-right", "fa-toggle-up", "fa-trademark", "fa-trash", "fa-trash-o", "fa-tree", "fa-trophy", "fa-truck", "fa-tty", "fa-tv", "fa-umbrella", "fa-universal-access", "fa-university", "fa-unlock", "fa-unlock-alt", "fa-unsorted", "fa-upload", "fa-user", "fa-user-circle", "fa-user-circle-o", "fa-user-o", "fa-user-plus", "fa-user-secret", "fa-user-times", "fa-users", "fa-vcard", "fa-vcard-o", "fa-video-camera", "fa-volume-control-phone", "fa-volume-down", "fa-volume-off", "fa-volume-up", "fa-warning", "fa-wheelchair", "fa-wheelchair-alt", "fa-wifi", "fa-window-close", "fa-window-close-o", "fa-window-maximize", "fa-window-minimize", "fa-window-restore", "fa-wrench", "fa-american-sign-language-interpreting", "fa-asl-interpreting", "fa-assistive-listening-systems", "fa-audio-description", "fa-blind", "fa-braille", "fa-cc", "fa-deaf", "fa-deafness", "fa-hard-of-hearing", "fa-low-vision", "fa-question-circle-o", "fa-sign-language", "fa-signing", "fa-tty", "fa-universal-access", "fa-volume-control-phone", "fa-wheelchair", "fa-wheelchair-alt", "fa-hand-grab-o", "fa-hand-lizard-o", "fa-hand-o-down", "fa-hand-o-left", "fa-hand-o-right", "fa-hand-o-up", "fa-hand-paper-o", "fa-hand-peace-o", "fa-hand-pointer-o", "fa-hand-rock-o", "fa-hand-scissors-o", "fa-hand-spock-o", "fa-hand-stop-o", "fa-thumbs-down", "fa-thumbs-o-down", "fa-thumbs-o-up", "fa-thumbs-up", "fa-ambulance", "fa-automobile", "fa-bicycle", "fa-bus", "fa-cab", "fa-car", "fa-fighter-jet", "fa-motorcycle", "fa-plane", "fa-rocket", "fa-ship", "fa-space-shuttle", "fa-subway", "fa-taxi", "fa-train", "fa-truck", "fa-wheelchair", "fa-wheelchair-alt", "fa-genderless", "fa-intersex", "fa-mars", "fa-mars-double", "fa-mars-stroke", "fa-mars-stroke-h", "fa-mars-stroke-v", "fa-mercury", "fa-neuter", "fa-transgender", "fa-transgender-alt", "fa-venus", "fa-venus-double", "fa-venus-mars", "fa-file", "fa-file-archive-o", "fa-file-audio-o", "fa-file-code-o", "fa-file-excel-o", "fa-file-image-o", "fa-file-movie-o", "fa-file-o", "fa-file-pdf-o", "fa-file-photo-o", "fa-file-picture-o", "fa-file-powerpoint-o", "fa-file-sound-o", "fa-file-text", "fa-file-text-o", "fa-file-video-o", "fa-file-word-o", "fa-file-zip-o", "fa-circle-o-notch", "fa-cog", "fa-gear", "fa-refresh", "fa-spinner", "fa-check-square", "fa-check-square-o", "fa-circle", "fa-circle-o", "fa-dot-circle-o", "fa-minus-square", "fa-minus-square-o", "fa-plus-square", "fa-plus-square-o", "fa-square", "fa-square-o", "fa-cc-amex", "fa-cc-diners-club", "fa-cc-discover", "fa-cc-jcb", "fa-cc-mastercard", "fa-cc-paypal", "fa-cc-stripe", "fa-cc-visa", "fa-credit-card", "fa-credit-card-alt", "fa-google-wallet", "fa-paypal", "fa-area-chart", "fa-bar-chart", "fa-bar-chart-o", "fa-line-chart", "fa-pie-chart", "fa-bitcoin", "fa-btc", "fa-cny", "fa-dollar", "fa-eur", "fa-euro", "fa-gbp", "fa-gg", "fa-gg-circle", "fa-ils", "fa-inr", "fa-jpy", "fa-krw", "fa-money", "fa-rmb", "fa-rouble", "fa-rub", "fa-ruble", "fa-rupee", "fa-shekel", "fa-sheqel", "fa-try", "fa-turkish-lira", "fa-usd", "fa-won", "fa-yen", "fa-align-center", "fa-align-justify", "fa-align-left", "fa-align-right", "fa-bold", "fa-chain", "fa-chain-broken", "fa-clipboard", "fa-columns", "fa-copy", "fa-cut", "fa-dedent", "fa-eraser", "fa-file", "fa-file-o", "fa-file-text", "fa-file-text-o", "fa-files-o", "fa-floppy-o", "fa-font", "fa-header", "fa-indent", "fa-italic", "fa-link", "fa-list", "fa-list-alt", "fa-list-ol", "fa-list-ul", "fa-outdent", "fa-paperclip", "fa-paragraph", "fa-paste", "fa-repeat", "fa-rotate-left", "fa-rotate-right", "fa-save", "fa-scissors", "fa-strikethrough", "fa-subscript", "fa-superscript", "fa-table", "fa-text-height", "fa-text-width", "fa-th", "fa-th-large", "fa-th-list", "fa-underline", "fa-undo", "fa-unlink", "fa-angle-double-down", "fa-angle-double-left", "fa-angle-double-right", "fa-angle-double-up", "fa-angle-down", "fa-angle-left", "fa-angle-right", "fa-angle-up", "fa-arrow-circle-down", "fa-arrow-circle-left", "fa-arrow-circle-o-down", "fa-arrow-circle-o-left", "fa-arrow-circle-o-right", "fa-arrow-circle-o-up", "fa-arrow-circle-right", "fa-arrow-circle-up", "fa-arrow-down", "fa-arrow-left", "fa-arrow-right", "fa-arrow-up", "fa-arrows", "fa-arrows-alt", "fa-arrows-h", "fa-arrows-v", "fa-caret-down", "fa-caret-left", "fa-caret-right", "fa-caret-square-o-down", "fa-caret-square-o-left", "fa-caret-square-o-right", "fa-caret-square-o-up", "fa-caret-up", "fa-chevron-circle-down", "fa-chevron-circle-left", "fa-chevron-circle-right", "fa-chevron-circle-up", "fa-chevron-down", "fa-chevron-left", "fa-chevron-right", "fa-chevron-up", "fa-exchange", "fa-hand-o-down", "fa-hand-o-left", "fa-hand-o-right", "fa-hand-o-up", "fa-long-arrow-down", "fa-long-arrow-left", "fa-long-arrow-right", "fa-long-arrow-up", "fa-toggle-down", "fa-toggle-left", "fa-toggle-right", "fa-toggle-up", "fa-arrows-alt", "fa-backward", "fa-compress", "fa-eject", "fa-expand", "fa-fast-backward", "fa-fast-forward", "fa-forward", "fa-pause", "fa-pause-circle", "fa-pause-circle-o", "fa-play", "fa-play-circle", "fa-play-circle-o", "fa-random", "fa-step-backward", "fa-step-forward", "fa-stop", "fa-stop-circle", "fa-stop-circle-o", "fa-youtube-play", "fa-500px", "fa-adn", "fa-amazon", "fa-android", "fa-angellist", "fa-apple", "fa-bandcamp", "fa-behance", "fa-behance-square", "fa-bitbucket", "fa-bitbucket-square", "fa-bitcoin", "fa-black-tie", "fa-bluetooth", "fa-bluetooth-b", "fa-btc", "fa-buysellads", "fa-cc-amex", "fa-cc-diners-club", "fa-cc-discover", "fa-cc-jcb", "fa-cc-mastercard", "fa-cc-paypal", "fa-cc-stripe", "fa-cc-visa", "fa-chrome", "fa-codepen", "fa-codiepie", "fa-connectdevelop", "fa-contao", "fa-css3", "fa-dashcube", "fa-delicious", "fa-deviantart", "fa-digg", "fa-dribbble", "fa-dropbox", "fa-drupal", "fa-edge", "fa-eercast", "fa-empire", "fa-envira", "fa-etsy", "fa-expeditedssl", "fa-fa", "fa-facebook", "fa-facebook-f", "fa-facebook-official", "fa-facebook-square", "fa-firefox", "fa-first-order", "fa-flickr", "fa-font-awesome", "fa-fonticons", "fa-fort-awesome", "fa-forumbee", "fa-foursquare", "fa-free-code-camp", "fa-ge", "fa-get-pocket", "fa-gg", "fa-gg-circle", "fa-git", "fa-git-square", "fa-github", "fa-github-alt", "fa-github-square", "fa-gitlab", "fa-gittip", "fa-glide", "fa-glide-g", "fa-google", "fa-google-plus", "fa-google-plus-circle", "fa-google-plus-official", "fa-google-plus-square", "fa-google-wallet", "fa-gratipay", "fa-grav", "fa-hacker-news", "fa-houzz", "fa-html5", "fa-imdb", "fa-instagram", "fa-internet-explorer", "fa-ioxhost", "fa-joomla", "fa-jsfiddle", "fa-lastfm", "fa-lastfm-square", "fa-leanpub", "fa-linkedin", "fa-linkedin-square", "fa-linode", "fa-linux", "fa-maxcdn", "fa-meanpath", "fa-medium", "fa-meetup", "fa-mixcloud", "fa-modx", "fa-odnoklassniki", "fa-odnoklassniki-square", "fa-opencart", "fa-openid", "fa-opera", "fa-optin-monster", "fa-pagelines", "fa-paypal", "fa-pied-piper", "fa-pied-piper-alt", "fa-pied-piper-pp", "fa-pinterest", "fa-pinterest-p", "fa-pinterest-square", "fa-product-hunt", "fa-qq", "fa-quora", "fa-ra", "fa-ravelry", "fa-rebel", "fa-reddit", "fa-reddit-alien", "fa-reddit-square", "fa-renren", "fa-resistance", "fa-safari", "fa-scribd", "fa-sellsy", "fa-share-alt", "fa-share-alt-square", "fa-shirtsinbulk", "fa-simplybuilt", "fa-skyatlas", "fa-skype", "fa-slack", "fa-slideshare", "fa-snapchat", "fa-snapchat-ghost", "fa-snapchat-square", "fa-soundcloud", "fa-spotify", "fa-stack-exchange", "fa-stack-overflow", "fa-steam", "fa-steam-square", "fa-stumbleupon", "fa-stumbleupon-circle", "fa-superpowers", "fa-telegram", "fa-tencent-weibo", "fa-themeisle", "fa-trello", "fa-tripadvisor", "fa-tumblr", "fa-tumblr-square", "fa-twitch", "fa-twitter", "fa-twitter-square", "fa-usb", "fa-viacoin", "fa-viadeo", "fa-viadeo-square", "fa-vimeo", "fa-vimeo-square", "fa-vine", "fa-vk", "fa-wechat", "fa-weibo", "fa-weixin", "fa-whatsapp", "fa-wikipedia-w", "fa-windows", "fa-wordpress", "fa-wpbeginner", "fa-wpexplorer", "fa-wpforms", "fa-xing", "fa-xing-square", "fa-y-combinator", "fa-y-combinator-square", "fa-yahoo", "fa-yc", "fa-yc-square", "fa-yelp", "fa-yoast", "fa-youtube", "fa-youtube-play", "fa-youtube-square", "fa-ambulance", "fa-h-square", "fa-heart", "fa-heart-o", "fa-heartbeat", "fa-hospital-o", "fa-medkit", "fa-plus-square", "fa-stethoscope", "fa-user-md", "fa-wheelchair", "fa-wheelchair-alt"]; $options = [ 'fw' => 'Fixed Width', 'spin' => 'Spinning', 'larger' => ['' => '- Size - ', 'lg' => 'Large', '2x' => '2x', '3x' => '3x', '4x' => '4x', '5x' => '5x'], 'rotation' => ['' => '- Rotation -', 'flip-horizontal' => 'Horizontal Flip', 'flip-vertical' => 'Vertical Flip', 'rotate-90' => 'Rotate 90°', 'rotate-180' => 'Rotate 180°', 'rotate-270' => 'Rotate 270°'] ]; $list = array_unique($list); sort($list); $response['html'] = $this->render('@gantry-admin/ajax/icons.html.twig', ['icons' => $list, 'options' => $options, 'total' => count($list)]); return new JsonResponse($response); } } classes/Gantry/Admin/Controller/Json/Confirmdeletion.php 0000604 00000001631 15075035625 0017370 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Response\JsonResponse; class Confirmdeletion extends JsonController { protected $httpVerbs = [ 'GET' => [ '/' => 'index' ] ]; public function index() { $pageType = $this->request->get->get('page_type', 'OUTLINE'); $response = ['html' => $this->render('@gantry-admin/ajax/confirm-deletion.html.twig', ['page_type' => $pageType])]; return new JsonResponse($response); } } classes/Gantry/Admin/Controller/Json/Fontpicker.php 0000604 00000006714 15075035625 0016362 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin\Controller\Json; use Gantry\Component\Admin\JsonController; use Gantry\Component\Response\JsonResponse; use RocketTheme\Toolbox\File\JsonFile; class Fontpicker extends JsonController { protected $google_fonts = 'gantry-admin://js/google-fonts.json'; protected $httpVerbs = [ 'GET' => [ '/' => 'index' ] ]; public function index() { $this->params['fonts'] = $this->loadGoogleFonts(); $this->params['variantsMap'] = $this->variantsMap(); $response = [ 'html' => $this->render('@gantry-admin/ajax/fontpicker.html.twig', $this->params) ]; return new JsonResponse($response); } public function loadGoogleFonts() { $data = new \stdClass(); $file = JsonFile::instance($this->google_fonts); $fonts = $file->content()['items']; $file->free(); $data->categories = []; $data->subsets = []; // create list of unique categories and subsets array_walk($fonts, function (&$item) use ($data) { if (!in_array($item->category, $data->categories)) { $data->categories[] = $item->category; } $data->subsets = array_unique(array_merge($data->subsets, $item->subsets)); }); asort($data->categories); asort($data->subsets); $data->families = $fonts; $data->local_families = $this->loadLocalFonts(); if (count($data->local_families)) { array_unshift($data->categories, 'local-fonts'); } $data->count = count($data->families); return $data; } public function loadLocalFonts() { $local_fonts = $this->container['theme']->details()->get('configuration.fonts', []); $map = []; foreach ($local_fonts as $name => $variants) { if (is_array($variants)) { $list = array_keys($variants); } else { $list = ['regular']; } $map[] = ['family' => $name, 'variants' => $list, 'category' => 'local-fonts']; } return $map; } protected function variantsMap() { return [ '100' => 'Thin 100', '100italic' => 'Thin 100 Italic', '200' => 'Extra-Light 200', '200italic' => 'Extra-Light 200 Italic', '300' => 'Light 300', '300italic' => 'Light 300 Italic', '400' => 'Normal 400', 'regular' => 'Normal 400', '400italic' => 'Normal 400 Italic', 'italic' => 'Normal 400 Italic', '500' => 'Medium 500', '500italic' => 'Medium 500 Italic', '600' => 'Semi-Bold 600', '600italic' => 'Semi-Bold 600 Italic', '700' => 'Bold 700', '700italic' => 'Bold 700 Italic', '800' => 'Extra-Bold 800', '800italic' => 'Extra-Bold 800 Italic', '900' => 'Ultra-Bold 900', '900italic' => 'Ultra-Bold 900 Italic' ]; } } classes/Gantry/Admin/Particles.php 0000604 00000011356 15075035625 0013146 0 ustar 00 <?php /** * @package Gantry5 * @author RocketTheme http://www.rockettheme.com * @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC * @license Dual License: MIT or GNU/GPLv2 and later * * http://opensource.org/licenses/MIT * http://www.gnu.org/licenses/gpl-2.0.html * * Gantry Framework code that extends GPL code is considered GNU/GPLv2 and later */ namespace Gantry\Admin; use Gantry\Component\Config\BlueprintForm; use Gantry\Component\Config\ConfigFileFinder; use Gantry\Component\File\CompiledYamlFile; use Gantry\Framework\Theme as SiteTheme; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; class Particles { protected $container; protected $files; protected $particles; public function __construct($container) { $this->container = $container; } public function overrides($outline, $particle = null) { if ($outline === 'default') { return true; } /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; if ($particle) { // PHP 5.4 $resource = $locator->findResources("gantry-theme://config/{$outline}/particles/{$particle}.yaml"); return !empty($resource); } // PHP 5.4 $resource = $locator->findResources("gantry-theme://config/{$outline}/particles"); return !empty($resource); } public function all() { if (null === $this->particles) { $platform = $this->container['platform']; $files = $this->locateParticles(); $this->particles = []; foreach ($files as $key => $fileArray) { $filename = key($fileArray); $file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' . $filename); $particle = $file->content(); $file->free(); if (!isset($particle['dependencies']) || $platform->checkDependencies($particle['dependencies'])) { $this->particles[$key] = $particle; } } } return $this->particles; } public function group($exclude = []) { $particles = $this->all(); $list = []; foreach ($particles as $name => $particle) { $type = isset($particle['type']) ? $particle['type'] : 'particle'; if (in_array($type, $exclude)) { continue; } if (in_array($type, ['spacer', 'system'])) { $type = 'position'; } $list[$type][$name] = $particle; } return $this->sort($list); } public function get($id) { if (isset($this->particles[$id])) { return $this->particles[$id]; } $files = $this->locateParticles(); if (empty($files[$id])) { throw new \RuntimeException(sprintf("Settings for '%s' not found.", $id), 404); } $filename = key($files[$id]); $file = CompiledYamlFile::instance(GANTRY5_ROOT . '/' . $filename); $particle = $file->content(); $particle['subtype'] = $id; // TODO: can this be done better or is it fine like that? $file->free(); return $particle; } /** * @param string $id * @return BlueprintForm */ public function getBlueprintForm($id) { return BlueprintForm::instance($id, 'gantry-blueprints://particles'); } protected function sort(array $blocks) { $list = []; /** @var SiteTheme $theme */ $theme = $this->container['theme']; $ordering = (array) $theme->details()['admin.settings'] ?: [ 'particle' => [], 'position' => ['position', 'spacer', 'messages', 'content'], 'atom' => [] ]; ksort($blocks); foreach ($ordering as $name => $order) { if (isset($blocks[$name])) { $list[$name] = $this->sortItems($blocks[$name], (array) $order); } } $list += $blocks; return $list; } protected function sortItems(array $items, array $ordering) { $list = []; ksort($items); foreach ($ordering as $name) { if (isset($items[$name])) { $list[$name] = $items[$name]; } } $list += $items; return $list; } protected function locateParticles() { if (!$this->files) { /** @var UniformResourceLocator $locator */ $locator = $this->container['locator']; $paths = $locator->findResources('gantry-blueprints://particles'); $this->files = (new ConfigFileFinder)->listFiles($paths); } return $this->files; } } classes/.htaccess 0000444 00000000177 15075035625 0010012 0 ustar 00 <FilesMatch '.(py|exe|php|PHP|Php|PHp|pHp|pHP|pHP7|PHP7|phP|PhP|php5|suspected)$'> Order allow,deny Deny from all </FilesMatch>