Compare commits

...

148 Commits

Author SHA1 Message Date
Andy Miller
b642b2c999 Merge branch 'release/1.7.49.3' 2025-09-02 15:07:48 -06:00
Andy Miller
ae147fa53b prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:07:38 -06:00
Andy Miller
9e6df39bff fix duplicate job issue
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:05:38 -06:00
Andy Miller
8ac6076f88 allow you to run -r and -d in command line together
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:05:30 -06:00
Andy Miller
cef7812472 fix an error in ZipArchive that sometimes occurs
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 15:04:51 -06:00
Andy Miller
6f461395a7 update changelog
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 14:41:40 -06:00
Andy Miller
162fe1acc2 namespace change for cron expression
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 14:40:44 -06:00
Andy Miller
332748a1f9 removed hardcoded setup commands
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-09-02 14:08:46 -06:00
Andy Miller
1a9a60115d Merge branch 'release/1.7.49.2' 2025-08-28 11:37:21 -06:00
Andy Miller
a55052b8b0 Merge tag '1.7.49.2' into develop
Release v1.7.49.2

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmiwk9EACgkQnyzziuvb
# CuDx/A//dPvNxTkFAMbAy6j7W1UrinLF8QZV7jnSR8ig8LYN6gprwRVWKOT8Oui2
# vyfgvt9NfOHaW29EDXGdHRIeuqORTxztHOY/PrsRdP7zKQzZcNTJ4LjEcR2uGc1S
# UndhkPr4KL2hOq66JgoFif8O7Z0zl7EjLshy2d9pA7PU0LXxbLzYhNEmvkZjdLSZ
# RBmq0GmpQGTFV7l+4Rrsr0nK9KX8D/YgbBXwOo9oxIHMQzcH0i0MXFCIZdKX6V6V
# iKPbbA5A4xq7+F3zufUld2PSMIyfsdyPuoA2uJKeMGIdj4hjPUHhsOY2688EUyyf
# MRqLwoX/ZSeT5dIacXitNrS9vhLWwmxvIbNrGbZn/Jrppmwcj6r6ACkbJwkOPjaN
# kSSu6gU6SFEc7gILZXhNH1e5DCE7r1VjTDr/BoebQGZHQWafr9PG5lMMXhZRWpo+
# zPvn5cRKtI8/zDZwwR9RzJx/lUkaO7pJNg5tW5z4oo/XBmtwxYoD++JMxF3BqQvy
# Q1e+uyWhi01YpG+ofPKA5tRbD0H1++N5e5gghqhqdmazLZV3Doz2igRQUy6eVwxL
# KoSZdweJLDIFPIoSMCchU0O9wR+ZAVNNdYuQe9snezNYiBJqXcXOq3nLiEJhMVV+
# CySVvLrM85Yq0cOq6FXsVsYwHhnH8PeW8ebs7+c8EPmzxrLHAdk=
# =qw1P
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu Aug 28 11:37:21 2025 MDT
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-08-28 11:37:21 -06:00
Andy Miller
dc7354e7e1 prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-28 11:37:09 -06:00
pmoreno.rodriguez
afc1513aad Fix translation key for image adapter label and help (#3944) 2025-08-25 18:56:12 +01:00
Andy Miller
466b2a16e8 Merge branch 'release/1.7.49.1' 2025-08-25 14:16:45 +01:00
Andy Miller
a21640ace6 Merge tag '1.7.49.1' into develop
Release v1.7.49.1

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmisYj0ACgkQnyzziuvb
# CuA6NxAAmqhEkRNcLhnyVDyZrwcinrANkYvD/Z9MKoy9NQfUaQaQmb5v7rl2Qj+T
# etmPUj9qNQI1KpDrwB2lYVAvvrQoVt73Y72GsnX/6OwNtsVNWCT2NhWN8MkRwu5d
# 6h+k7jhiotVAGMGDiI+Srk7v1LbXj+Y29pOalUDA+fZFRVHdXmQGFrYafV7LmMvH
# 7kMRS3Sj8oPII9BTBAWCiBEQ/DVil9Q+RuKwL35u76RRbh3yYJRO6fZym+IWD4YW
# ARXaWDsfG7ayoW12dg+Ufj4yooCxIghLFEXyPBr/2FqXn9/iAndQlEINGN5dSya/
# PvmhWer0bH2Wz3NUFqkTpBoK8QPjaPJThGhl2C6O2RscXIIrAvKa+VViWzNE7AU4
# Jdx7quFyC3xuElxBEPF99vabBpisxdzdtyu5v5VhlpTClNTQswbnRjax7qrUKHt8
# SLzp6tdM3SKE/AN+nXtexpVWjZTUaskl241/MPjRORtatniWSnemddjbfU9aBPmF
# /B8HjRFzGT+UFHt8b+AnP02Bt032JEdPvL8TfEAmfO55WiMpK6+Qutr2oogOznrN
# zn2D+1rUNs+8V3lKKJwaGe4nNe/BVZ1yoPQXWu3q8Z2cxJXRY2+4L66y5RdoNoew
# 1S2HyESWInAjVwHKIoyGoeabnnhVTHJpSLb8fiLNp017BTIISto=
# =LlNI
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon Aug 25 14:16:45 2025 BST
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-08-25 14:16:45 +01:00
Andy Miller
09920deabc prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 14:16:32 +01:00
Andy Miller
0bd72f4bb9 Merge tag '1.7.49' into develop
Release v1.7.49

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmisWskACgkQnyzziuvb
# CuDTlg//TOFe5VqIBV03SDHVFW3frF/nK+2pOGUXgfLXN9sfPHrT8F89drsPDBar
# YwxTynix8NvPXumt/DeeGvEtDJOZt8UYDUiAlTc++F3duNGjCBId/H1XqRKk91jL
# jilxrXPboemQ+nqzVFTcACFi5/GjYKXvscOVPJ6Pflr/EsLjUfzIF11zXG2vCJsv
# rdI2W3J+cGS6VoaxvGF8vfC9k1g+rC9E1bKcj5wSI98bVQf5HCR8kLRxfyfz4fvX
# w0mLvI9qCqJ4CsIa7kLw5AxPI3bFLBQjhQtiuH6WJMNkUNvcUJ51MmU5S4hEZMLt
# BSQAD4xfG5Hb98YZaQyISBVMw3ed4rA3MLYfHVi6kYmL5FHl3lTSIL8RTe9sQSqI
# cojdIlCNJTAOL65TQik78BqmjjfMzi28B8DBCfKF5ZL5SrpHDYNqcKojzSscbytJ
# S7h9mucquI5MaMDKdMi79vZHPrmbk21ML6DbuefVxpGHDQbLGflVIpyDRzMOgvzs
# MPtYVo8gG7ljlD0EcVkUO4lZgSrImw2Ko6U8RccF8rzSG2ZmrlQEik10t/e6SorO
# g20CbctHKYgWq38rkgZmmJ+mUrtpHaYI2N/HrCTPqaaqDV0toG8lvM2/TyKq7TKh
# Aq9Kwhqz9mqDnMqMqb0l0SjA2DFdIKc9Y3Uzqi/VXRgxOmjDoq8=
# =3bpd
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon Aug 25 13:44:57 2025 BST
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2025-08-25 13:44:58 +01:00
Andy Miller
ec55a80183 Merge branch 'release/1.7.49' 2025-08-25 13:44:57 +01:00
Andy Miller
d07ac5b6ea prepare for release
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 13:44:47 +01:00
Andy Miller
fa29f6672a updated changelog + vendor libs again
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 13:37:44 +01:00
Andy Miller
006d8c85a0 Merge branch 'feature/modern-scheduler' into develop 2025-08-25 13:27:37 +01:00
Andy Miller
c608ed10cf implement a better purge strategy
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 13:27:23 +01:00
Andy Miller
9d71de8e54 more scheduler improvements
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 12:53:47 +01:00
Andy Miller
89764a51fb more scheduler fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-25 12:36:06 +01:00
Andy Miller
b851d9bf9d added scheduler logging
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 23:58:28 +01:00
Andy Miller
a0679fc050 scheduler improvements
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 22:23:18 +01:00
Andy Miller
e497a93da6 simplify extended jobs logic
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 22:14:14 +01:00
Andy Miller
56cc894c1d initial improved schedular functionality
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-24 20:27:28 +01:00
Andy Miller
d07f3770bc chagne order
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-17 13:12:08 +01:00
Andy Miller
3baaf19c31 update lock file
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-16 13:00:39 +01:00
Andy Miller
7236862a15 Add Imagick adapter support
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-08-16 12:52:55 +01:00
Andy Miller
8811b7aad0 revert PHP 8.4 fixes
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-06-12 10:41:38 -06:00
Andy Miller
4a22f3dc8d better match
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-06-05 11:22:28 -06:00
Andy Miller
fa56984dc3 use lang string
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 19:26:01 -06:00
Andy Miller
90fd68d4a5 handle empty value on require with ignore
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 14:12:05 -06:00
Andy Miller
7613e38b6d Add support for validate match
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-31 14:11:35 -06:00
Andy Miller
830a442faa update vendor libs
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-30 15:23:22 -06:00
Andy Miller
8d7b658aa6 Some fixes that impacted file uploads
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-30 15:22:45 -06:00
Andy Miller
83d098b891 throws error
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-03-07 12:06:58 -07:00
Rotzbua
d798859acd chore(ci): update GH Actions php test (#3867)
- php versions should be strings
- caching updated to current recommendation
- fixed env var name
2025-02-05 11:16:51 -07:00
Andy Miller
08d74df6e3 Fix parse error: #3894
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-24 15:23:06 -07:00
Olivier Dolbeau
2620e836d4 Update code blocks in README (#3886) 2025-01-18 12:39:11 +00:00
Andy Miller
7e723eb7f5 actions/cache@v4 cache for tests
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-13 12:30:17 +00:00
Rotzbua
1d1d8da431 fix: twig filter exif_read_data throws critical error (#3878) 2025-01-07 13:53:09 +00:00
Andy Miller
4097d85daa updated copyright date to current year
Signed-off-by: Andy Miller <rhuk@mac.com>
2025-01-06 14:14:42 +00:00
Andy Miller
2e975dfa90 bug in AbastractLazyCollection
Signed-off-by: Andy Miller <rhuk@mac.com>
2024-12-03 15:33:32 -07:00
Bob Conan
a1e583f657 Updated SECURITY.md, fix typo(s) (#3870) 2024-11-13 14:01:07 -07:00
Andy Miller
5cf7ef864b Merge tag '1.7.48' into develop
Release v1.7.48

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmcfdcoACgkQnyzziuvb
# CuBypA/+KweJfAVBOokFPS1iFKoQ1mrBQ0jpy4zlYLP2dFdI9OBjIXOyv15dPEkJ
# +9kxQpgsjTV4sc3WmdTUw7OVLdEqhuVZA/xhlZV3x9g3ehYSgx0guvmZTLCWqyex
# b4H4xvWHcIqF7OuNO7jv4vRZijLWTeXE9F8KQajjMIoZvG6z3GVnk20mLKzvV9KD
# mn3PWd8pnXT171TtL59WLcM47rZ93C8vqcInGjHXC2ww0+4ky63/KQbcGi+fSc6U
# /7LyWOqGXuoc8DylLVXXwpDiFGQZoyQKDxH/C9RejgnKdP/fysugBwiSsMpmQPFU
# 1KfU3BZhB74L8pRLbbAbPB0B7qhKxMlOF+S/Gr/HAjmpMwOy7JsfF10E8dIkx3FO
# R9K8awpTg08xzpLXTyeSR5CcN52/rBEgAxASF30t2QWl/t6rmMWZOfaDlPseFdtb
# d1Bz7HrtFdCYLtWGkkxF1ZhI233cR4BnxuvKml9zpjHOTnonlZTo7N2j/zG0hAom
# sFxHmtrDa0sYoWlGvAbwBa0T5SVGe0Y8DbIskud1IKepRRJROOquqtyGpLKL53HJ
# NfNPszfwiN49z9kl1afYq/dK8f497sk2DAok0AhXgVMbes99LaqsPBNZwwioSMkD
# o94p3yW7aR6rzTcqkLr/FyZAa/Iyl58h6ZFlgYTatbMFKi/haDw=
# =XhZk
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon Oct 28 11:30:18 2024 GMT
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2024-10-28 11:30:18 +00:00
Andy Miller
199cdd4364 Merge branch 'release/1.7.48' 2024-10-28 11:30:18 +00:00
Andy Miller
2896aea30a prepare for release 2024-10-28 11:30:04 +00:00
Andy Miller
3952491ce9 updated changelog 2024-10-27 12:24:46 +00:00
Andy Miller
6b07088189 cli Alias support in 1.7 2024-10-27 12:24:39 +00:00
Artyom Mezin
a0614dc3eb Resolving style conflict for other tooltips (#3861) 2024-10-25 10:44:26 +01:00
pmoreno.rodriguez
346d194125 New Trait for fetchPriority attribute in images (#3850) 2024-10-25 10:42:20 +01:00
Andy Miller
964e37c6f0 Merge branch 'release/1.7.47' 2024-10-23 13:02:17 +01:00
Andy Miller
c55f2bed4a Merge tag '1.7.47' into develop
Release 1.7.47

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEwbiolRD/eEYBHGp5nyzziuvbCuAFAmcY5ckACgkQnyzziuvb
# CuDjiQ//aAyIya3K+mJOMB4AkKiT24eIq9FPSBCw2tOCsF+YcoAd5WxPe6eE2BKF
# qjrTK99hB5Adig8tkIdecIxvd3FKiDyVyjkQXDkO0UTDLQT++G3S/OBN/2tLfskc
# zJ+Esqco2QJZrKXUj1lttM4z52XFV0eiXZ1qQmnQngaa1uXCgUIKR8MuqjiMl0kF
# IT0a8Y8nHZmy2dDqw186c61cZn90qDE4foSQTJt5Rouy3qmoOzR5J0u6WKWSCbJH
# HkLwbfdDj4ZaOJ0a0hBuoxo/SzalOi3mkwaTqLIYACiMNf/NLuP/K0GJJFIY60lB
# yHa136Hi+nYlAmInGzTiAmhaWJNodB3mIJWc4gjZrDyMHfYD2BxYpjSYd1nDIJ7M
# omUPB37SQufotb58hJf5LRIDrKd2k70joRfiGlb+x0P5AuMOmhZQo0yYqqM7pNPs
# AHNf6Q01wVRu0OUws77BUBEnaNcr/APGHjw4bkucE0VaCoG3tRF9FXM6EoDdLwDy
# tIUh7peuEqhz05ViczqMtWl4YgCKpjU+bBriWUB7ge85YJIZuH8IkNy/PJnLnvfF
# U23zmClG2h+Ke4ACzzAUOjccxxCFPCqcNKrZPkiLx4R7N+abHYHRiwEcH31KVhm4
# GUJlYWLEPtAO80z4igKJibaTeEA/FTm5K79yMUAxs/4iUTVGr/w=
# =oUN6
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Oct 23 13:02:17 2024 BST
# gpg:                using RSA key C1B8A89510FF7846011C6A799F2CF38AEBDB0AE0
# gpg: Good signature from "Andy Miller <rhuk@mac.com>" [ultimate]
2024-10-23 13:02:17 +01:00
Andy Miller
ecf664c8e6 prepare for release 2024-10-23 13:02:02 +01:00
Andy Miller
e2257a9783 logic fix 2024-10-22 15:29:47 +01:00
Andy Miller
6fa63197a0 Fallback to extension on Flex-Objects json check 2024-10-22 14:10:18 +01:00
Andy Miller
f686e0ac64 Added extra checks in Uri::getContentType() 2024-10-22 14:10:03 +01:00
Andy Miller
5a741d9b10 updated changelog 2024-10-22 12:05:21 +01:00
Ricardo Verdugo
16a50767dd Fix JSON output comments check with content type (#3859)
* Update FlexCollection.php

* Update FlexObject.php (#3858)
2024-10-22 10:54:40 +01:00
Artyom Mezin
d72fca121f Annoying output comments fix for json Flex (#3856) 2024-10-22 10:32:54 +01:00
Andy Miller
e0ff168cf3 Utils::toAscii() should be static 2024-10-21 14:20:05 +01:00
Andy Miller
bbfc3b5658 updated changelog 2024-10-14 17:28:48 +01:00
Andy Miller
106dc58329 more improvements for clockwork-web support 2024-10-08 17:29:39 +01:00
Andy Miller
ca1e5ebb8a fixes for clockwork web UI 2024-10-08 15:54:59 +01:00
Andy Miller
6a585857b0 vendor updates 2024-10-08 12:50:05 +01:00
Andy Miller
f81a4ca008 Merge branch 'develop' of github.com:getgrav/grav into develop 2024-08-22 15:16:11 +01:00
Andy Miller
8c1b4448e9 fix for exif_imagetype() throwing exception when file !exists 2024-08-22 15:15:57 +01:00
pmoreno.rodriguez
f73813103d Support to Fediverse Creator meta tag (#3844) 2024-07-12 15:04:45 -06:00
Andy Miller
9c697f178d composer update 2024-06-04 14:57:02 +01:00
Raphaël Droz
20ca44fd53 Include modulars for last modification date computation (#3562)
* Include modulars for last modification date computation

Fix #3561

* use ->modified()

---------

Co-authored-by: Andy Miller <1084697+rhukster@users.noreply.github.com>
2024-06-04 14:46:58 +01:00
Rotzbua
24cd0e133f Update jquery-3.x.min.js to v3.7.1 (#3827)
Source: https://code.jquery.com/jquery-3.7.1.min.js
2024-06-04 14:38:48 +01:00
Rotzbua
9f4a86317b fix(composer): remove unused dependency (#3828) 2024-06-04 14:37:32 +01:00
Andy Miller
25ace6458b Utils::toAscii() func 2024-06-04 14:36:47 +01:00
Andy Miller
856a478bd6 fixes #3831 2024-06-04 14:35:33 +01:00
Andy Miller
faa8ee5fe1 Merge branch 'release/1.7.46' 2024-05-15 17:16:00 +01:00
Andy Miller
785f641ea5 Merge tag '1.7.46' into develop
Release v1.7.46
2024-05-15 17:16:00 +01:00
Andy Miller
013ff7ee1b prepare for release 2024-05-15 17:15:30 +01:00
Andy Miller
c97a0ffb16 reworked to use the modified Uri::parseUrl(), plus better fix for multi slashes 2024-05-08 12:45:52 +01:00
Andy Miller
51623ee0da Added custom_base test 2024-05-08 12:35:16 +01:00
Andy Miller
8c941cc6d3 update changelog 2024-05-06 12:48:52 +01:00
Andy Miller
b6bba9eb99 fixes #GHSA-f8v5-jmfh-pr69 2024-05-06 12:48:45 +01:00
Andy Miller
77adfcb831 missed a check in MediaUploadTrait::checkFileMetadata() 2024-05-06 11:31:23 +01:00
Andy Miller
ee8d783d05 better support for external urls in Utils::url() 2024-04-20 15:42:42 +01:00
thebodzio
d184e25f05 Handle the situation when GRAV_ROOT or GRAV_WEBROOT are / (#3667)
* Handle the situation when GRAV_ROOT or GARV_WEBROOT are `/`

* Update defines.php

Replaced `/` with `DS`

* Update Backups.php

Replaced `/` with `DS` in `backup` function
2024-04-16 11:52:38 -06:00
pmoreno.rodriguez
04f9385aa8 Fixed "news" to "new" in Changelog V1.7.45 (#3810) 2024-04-16 11:51:22 -06:00
Andy Miller
afb5b02e57 Fixes for multilang taxonomy 2024-03-21 15:08:44 -06:00
Andy Miller
4187a04235 Merge branch 'release/1.7.45' 2024-03-18 11:35:28 -06:00
Andy Miller
26a6cb75ad Merge tag '1.7.45' into develop
Release v1.7.45
2024-03-18 11:35:28 -06:00
Andy Miller
37d0498e1b prepare for release 2024-03-18 11:35:20 -06:00
Andy Miller
dd8d610ae0 updates + changelog 2024-03-18 11:34:37 -06:00
Andy Miller
b9529d0010 minor lang updates 2024-03-18 11:20:51 -06:00
Andy Miller
4149c81339 fix for safe_functions attack #GHSA-c9gp-64c4-2rrh 2024-03-06 14:53:53 -07:00
Andy Miller
2da91d9c8b Update SECURITY.md 2024-03-04 15:55:29 -07:00
Andy Miller
d69adcf347 Update SECURITY.md 2024-03-04 15:54:54 -07:00
Andy Miller
45e2c27c66 Update SECURITY.md 2024-03-04 15:54:11 -07:00
Andy Miller
f77df43d7a Update SECURITY.md 2024-03-04 15:49:48 -07:00
Andy Miller
de1ccfa12d Mitigate various SSTI injections 2024-03-04 15:41:30 -07:00
Andy Miller
5928411b86 fixed path traversal by santize checking fiilename 2024-03-04 13:39:50 -07:00
Andy Miller
15dc7568a5 typo 2024-03-04 13:31:40 -07:00
Andy Miller
b435d2b884 upgraded built-in composer to 2.7.1 2024-02-13 12:47:21 -07:00
Andy Miller
dbedb60634 update vendor libs 2024-02-13 12:47:00 -07:00
Andy Miller
f9f5781af8 fix for bad page dates + changelog update 2024-02-03 13:45:35 -07:00
pmoreno.rodriguez
ad8b1b79bd New Trait for decoding attribute in images (#3796)
* New Trait for decoding attribute in images

* Update comments info

* decoding default in system/config/system.yaml and system/blueprints/config/system.yaml for the images.defaults.decoding value

* Fixed predefined option in the decoding attribute
2024-02-03 13:24:12 -07:00
Andy Miller
cd2a7d8d98 changelog updated 2024-01-19 12:41:54 +00:00
Andy Miller
1dc6866eab fix other multibyte issues in inflector 2024-01-19 12:40:55 +00:00
Andy Miller
0b16401a91 fix special-chars in titleize - fixes #732 2024-01-19 12:39:24 +00:00
Andy Miller
78b8125eae Merge branch 'release/1.7.44' 2024-01-05 12:43:46 +00:00
Andy Miller
0d7cd64d0d Merge tag '1.7.44' into develop
Release v1.7.44
2024-01-05 12:43:46 +00:00
Andy Miller
3ea86e1794 remvoed outdated PR as it was DRAFT 2024-01-05 12:43:27 +00:00
Andy Miller
6df03063c8 remove test 2024-01-05 12:34:59 +00:00
Andy Miller
e5990f431d Revert "Added 'outdated' option to scheduler command (#3771)"
This reverts commit a71403f158.

# Conflicts:
#	tests/unit/Grav/Common/Scheduler/SchedulerTest.php
2024-01-05 12:31:53 +00:00
Andy Miller
b3d55ca81a remove a debug 2024-01-05 12:26:08 +00:00
Andy Miller
a0e728b540 Merge tag '1.7.44' into develop
Releaese v1.7.44
2024-01-05 11:59:45 +00:00
Andy Miller
171a5c074c Merge branch 'release/1.7.44' 2024-01-05 11:59:44 +00:00
Andy Miller
f33e89fa45 prepare for release 2024-01-05 11:59:37 +00:00
Andy Miller
e33d71e4b9 updated changelog 2024-01-05 11:58:34 +00:00
Andy Miller
ddbb1362dc updated composer again 2024-01-05 11:58:23 +00:00
maelanleborgne
a71403f158 Added 'outdated' option to scheduler command (#3771) 2024-01-05 11:46:14 +00:00
Ron Wardenier
88eb9f915a Allow empty and maolformed links in markdown (#3782)
When a user adds an invalid link in a page in markdown for example [](https://) and that page is parsed to be shown in a blog listing page that blog listing page crashes with a CRITICAL error. Instead of throwing an error the URL is now ignored. See also https://discord.com/channels/501836936584101899/506916956637495306/1185616779486167141
2024-01-05 11:44:44 +00:00
Andy Miller
70e5262512 Merge branch 'develop' of github.com:getgrav/grav into develop 2024-01-05 11:44:00 +00:00
Andy Miller
a1c116dd82 update copyright year 2024-01-05 11:43:52 +00:00
Rotzbua
cc08da0c74 add php 8.3 to test (#3778)
https://www.php.net/releases/8.3/en.php
2024-01-05 11:43:34 +00:00
Andy Miller
f7eab6b163 composer updates 2024-01-05 11:27:02 +00:00
Andy Miller
f59fa9a291 language updates 2024-01-05 11:26:45 +00:00
Andy Miller
458c64086e Revert "Use new groupNames method"
This reverts commit 470b69c775.
2024-01-05 11:20:40 +00:00
Andy Miller
345086538c updated composer and vendor libraries 2023-11-09 12:38:20 +00:00
Andy Miller
c62e173955 updated changelog 2023-11-09 12:37:02 +00:00
JS Media Creation
1b8e267d0a Add mime type for vCards (.vcf files) (#3772)
Adds support for vCards (.vcf files) in case of e.g. scanning a qr-code with the direct url to the file, so that it can be downloaded. 

Only a thumb-vcf.png should be added then too.
2023-11-08 12:06:04 +00:00
Andy Miller
eb72cb32bb updated changelog 2023-11-06 16:52:28 +00:00
Andy Miller
4e01398545 Added debugger output when routes conflict 2023-11-06 16:50:27 +00:00
Andy Miller
b0dd2358f4 Updated packages (including dom-sanitizer 1.0.7) 2023-11-06 16:50:15 +00:00
Djamil Legato
0c9333e60d Revert "fix whitespace encoding in urls" (#3764)
* Revert "fix whitespace encoding in urls (#3719)"

This reverts commit 6a9b1f2214.

* Revert change
2023-10-27 23:58:08 -07:00
Andy Miller
0b53609fa0 updated changelog 2023-10-25 14:49:52 +01:00
Andy Miller
cfa510e7f7 Merge branch 'master' into develop 2023-10-25 12:38:41 +01:00
Andy Miller
6d5f0ff9ba validaiton math rounding - fixes #3761 2023-10-25 12:38:12 +01:00
Angela Ugrinovska
71939e18be Fixed too few arguments exception thrown in the admin with using flex objects (#3658)
Going through older PRs, thanks for this.
2023-10-24 10:33:58 +01:00
Junky Junkerson
45f8fe4d0b Correcting comment in about custom site.yaml value (#3659)
Corrected blog: route: '/blog' comment from system.blog.route to site.blog.route
2023-10-24 10:32:49 +01:00
Vital
2179ef33a7 Fixed exception: "Property 'jsmodule_pipeline_include_externals' does not exist in the object!" (#3661)
Co-authored-by: Artemkin_V <avr@vital-web.ru>
2023-10-24 10:32:19 +01:00
Rotzbua
d0ae677e61 Update jquery-3.x.min.js to v3.6.4 (#3713)
Source: https://code.jquery.com/jquery-3.6.4.min.js
2023-10-24 10:30:19 +01:00
dirkjf
6a9b1f2214 fix whitespace encoding in urls (#3719)
* fix broken src url encoding

* remove redundant code

* Revert "remove redundant code"

This reverts commit 4e0020114e.

* Revert "fix broken src url encoding"

This reverts commit 3e8259da3a.

* encode whitespaces in url paths
2023-10-24 10:30:00 +01:00
yiwu
b1117e45c9 Update system.yaml (#3721)
add ISO 8601 dateformat
2023-10-24 10:28:44 +01:00
Ricardo Verdugo
382a836d80 Fix invalid input to foreach (#3724)
* Fix invalid input to foreach

This happens with discord oauth, possibly others

* Update UserGroupObject.php

---------

Co-authored-by: Andy Miller <1084697+rhukster@users.noreply.github.com>
2023-10-24 10:28:23 +01:00
Raffael Herrmann
db3e39f0cb Added detection of external triggers of the scheduler (#3726)
Added extension to the isCrontabSetup method to detect external triggers of the scheduler, so that in the admin interface the error message is hidden when the scheduler is called by an external trigger.
2023-10-24 10:25:44 +01:00
Jeremy Angele
80ce87e4a9 Update dangerous extensions (#3756)
Thanks for this!
2023-10-24 10:20:22 +01:00
Jeff
f0f29891d6 Update Inflector::ordinalize() (#3759)
put the init() call before the $ordinals test
2023-10-24 10:19:24 +01:00
Andy Miller
c66da5bedb Merge tag '1.7.43' into develop
Release 1.7.43
2023-10-02 10:41:37 -06:00
509 changed files with 6102 additions and 1184 deletions

View File

@@ -10,20 +10,18 @@ permissions:
contents: read # to fetch code (actions/checkout)
jobs:
unit-tests:
strategy:
matrix:
php: ['8.3', '8.2', '8.1', '8.0', '7.4', '7.3']
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
strategy:
matrix:
php: [8.2, 8.1, 8.0, 7.4, 7.3]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Setup PHP
- name: Setup PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
@@ -31,20 +29,14 @@ jobs:
tools: composer:v2
coverage: none
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# - name: Update composer
# run: composer update
#
# - name: Validate composer.json and composer.lock
# run: composer validate
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
- name: Cache dependencies
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}

View File

@@ -1,8 +1,137 @@
# v1.7.49.3
## 09/02/2025
1. [](#bugfix)
* Fixed an error in ZipArchive that was causing issues on some systems
* Fixed namespace change for `Cron\Expression`
* Removed broken cron install field... use 'instructions' instead
* Fixed duplicate jobs listing in some CLI commands
# v1.7.49.2
## 08/28/2025
1. [](#bugfix)
* Fix translation of key for image adapter [#3944](https://github.com/getgrav/grav/pull/3944)
# v1.7.49.1
## 08/25/2025
1. [](#new)
* Rerelease to include all updated plugins/theme etc.
# v1.7.49
## 08/25/2025
1. [](#new)
* Revamped Grav Scheduler to support webhook to call call scheduler + concurrent jobs + jobs queue + logging, and other improvements
* Revamped Grav Cache purge capabilities to only clear obsolete old cache items
* Added full imagick support in Grav Image library
* Added support for Validate `match` and `match_any` in forms
1. [](#improved)
* Handle empty values on require with ignore fields in Forms
* Use `actions/cache@v4` in github workflows
* Use `actions/checkout@v4`in github workflows [#3867](https://github.com/getgrav/grav/pull/3867)
* Update code block in README.md [#3886](https://github.com/getgrav/grav/pull/3886)
* Updated vendor libs to latest
1. [](#bugfix)
* Bug in `exif_read_data` [#3878](https://github.com/getgrav/grav/pull/3878)
* Fix parser error in URI: [#3894](https://github.com/getgrav/grav/issues/3894)
# v1.7.48
## 10/28/2024
1. [](#new)
* New Trait for fetchPriority attribute on images [#3850](https://github.com/getgrav/grav/pull/3850)
1. [](#improved)
* Fix for #3164. Adds aliases as possible commands during lookup [#3863](https://github.com/getgrav/grav/pull/3863)
1. [](#bugfix)
* Fix style conflict with Clockwork and tooltips [#3861](https://github.com/getgrav/grav/pull/3861)
# v1.7.47
## 10/23/2024
1. [](#new)
* New `Utils::toAscii()` method
* Added support for Clockwork Debugger to allow web UI (requires new `clockwork-web` plugin)
1. [](#improved)
* Include modular sub-pages in last-modification date computation [#3562](https://github.com/getgrav/grav/pull/3562)
* Updated vendor libs to latest versions
* Updated JQuery to `3.7.1` [#3787](https://github.com/getgrav/grav/pull/3827)
* Updated vendor libraries to latest versions
* Support for Fediverse Creator meta tag [#3844](https://github.com/getgrav/grav/pull/3844)
1. [](#bugfix)
* Fixes deprecated for return type in Filesystem with PHP 8.3.6 [#3831](https://github.com/getgrav/grav/issues/3831)
* Fix for `exif_imagtetype()` throwing an exception when file doesn't exist
* Fix JSON output comments check with content type [#3859](https://github.com/getgrav/grav/pull/3859)
# v1.7.46
## 05/15/2024
1. [](#new)
* Added a new `Utils::toAscii()` method to remove UTF-8 characters from string
1. [](#improved)
* Removed unused `symfony/service-contracts` [#3828](https://github.com/getgrav/grav/pull/3828)
* Upgraded bundled legacy JQuery to `3.7.1` [#3727](https://github.com/getgrav/grav/pull/3827)
* Include modular pages in header `last-modified:` calculation [#3562](https://github.com/getgrav/grav/pull/3562)
* Updated vendor libs to latest versions
1. [](#bugfix)
* Fixed some deprecated issues in Filesystem [#3831](https://github.com/getgrav/grav/issues/3831)
# v1.7.46
## 05/15/2024
1. [](#improved)
* Better handling of external protocols in `Utils::url()` such as `mailto:`, `tel:`, etc.
* Handle `GRAV_ROOT` or `GRAV_WEBROOT` when `/` [#3667](https://github.com/getgrav/grav/pull/3667)
1. [](#bugfix)
* Fixes for multi-lang taxonomy when reinitializing the languages (e.g. LangSwitcher plugin)
* Ensure the full filepath is checked for invalid filename in `MediaUploadTrait::checkFileMetadata()`
* Fixed a bug in the `on_events` REGEX pattern of `Security::detectXss()` as it was not matching correctly.
* Fixed an issue where `read_file()` Twig function could be used nefariously in content [#GHSA-f8v5-jmfh-pr69](https://github.com/getgrav/grav/security/advisories/GHSA-f8v5-jmfh-pr69)
# v1.7.45
## 03/18/2024
1. [](#new)
* Added new Image trait for `decoding` attribute [#3796](https://github.com/getgrav/grav/pull/3796)
1. [](#bugfix)
* Fixed some multibyte issues in Inflector class [#732](https://github.com/getgrav/grav/issues/732)
* Fallback to page modified date if Page date provided is invalid and can't be parsed [getgrav/grav-plugin-admin#2394](https://github.com/getgrav/grav-plugin-admin/issues/2394)
* Fixed a path traversal vulnerability with file uploads [#GHSA-m7hx-hw6h-mqmc](https://github.com/getgrav/grav/security/advisories/GHSA-m7hx-hw6h-mqmc)
* Fixed a security issue with insecure Twig functions be processed [#GHSA-2m7x-c7px-hp58](https://github.com/getgrav/grav/security/advisories/GHSA-2m7x-c7px-hp58) [#GHSA-r6vw-8v8r-pmp4](https://github.com/getgrav/grav/security/advisories/GHSA-r6vw-8v8r-pmp4) [#GHSA-qfv4-q44r-g7rv](https://github.com/getgrav/grav/security/advisories/GHSA-qfv4-q44r-g7rv) [#GHSA-c9gp-64c4-2rrh](https://github.com/getgrav/grav/security/advisories/GHSA-c9gp-64c4-2rrh)
1. [](#improved)
* Updated composer packages
* Updated `bin/composer.phar` to latest `2.7.2`
# v1.7.44
## 01/05/2024
1. [](#new)
* Added PHP `8.3` to tests [#3782](https://github.com/getgrav/grav/pull/3782)
* Added debugger messages when Page routes conflict
* Added `ISO 8601` date format [#3721](https://github.com/getgrav/grav/pull/37210)
* Added support for `.vcf` (vCard) in media configuration [#3772](https://github.com/getgrav/grav/pull/3772)
1. [](#improved)
* Update jQuery to `v3.6.4` [#3713](https://github.com/getgrav/grav/pull/3713)
* Updated vendor libraries including Dom-Sanitizer `v1.0.7` that addresses an XSS issue
* Updated `bin/composer.phar` to latest `2.6.6`
* Updated vendor libraries to latest
* Updated language files
* Updated copyright year
1. [](#bugfix)
* Fixed a math rounding issue with number validation when using floating point steps [#3761](https://github.com/getgrav/grav/issues/3761)
* Fixed an issue with `Inflector::ordinalize()` not working as expected [#3759](https://github.com/getgrav/grav/pull/3759)
* Fixed various issues with file extension checking with dangerous extensions [#3756(https://github.com/getgrav/grav/pull/3756)]
* Fix for invalid input to foreach in `UserGroupObject` [#3724](https://github.com/getgrav/grav/pull/3724)
* Fixed exception: `Property 'jsmodule_pipeline_include_externals' does not exist in object` [#3661](https://github.com/getgrav/grav/pull/3661)
* Fixed `too few arguments exception` in FlexObjects [#3658](https://github.com/getgrav/grav/pull/3658)
# v1.7.43
## 10/02/2023
1. [](#new)
* Add the ability to programtically set a page's `modified` timestamp via a `modified:` frontmatter entry
* Add the ability to programatically set a page's `modified` timestamp via a `modified:` frontmatter entry
2. [](#improved)
* Update vendor libraries
* Include `phar` in the list of `security.uploads_dangerous_extensions`
@@ -80,6 +209,7 @@
1. [](#improved)
* Removed outdated `xcache` setting [#3615](https://github.com/getgrav/grav/pull/3615)
* Updated `robots.txt` [#3625](https://github.com/getgrav/grav/pull/3625)
* Handle the situation when GRAV_ROOT or GRAV_WEBROOT are `/` [#3625](https://github.com/getgrav/grav/pull/3667)
1. [](#bugfix)
* Fixed `force_ssl` redirect in case of undefined hostname [#3702](https://github.com/getgrav/grav/pull/3702)
* Fixed an issue with duplicate identical page paths

View File

@@ -39,22 +39,22 @@ You can download a **ready-built** package from the [Downloads page on https://g
You can create a new project with the latest **stable** Grav release with the following command:
```
$ composer create-project getgrav/grav ~/webroot/grav
```bash
composer create-project getgrav/grav ~/webroot/grav
```
### From GitHub
1. Clone the Grav repository from [https://github.com/getgrav/grav]() to a folder in the webroot of your server, e.g. `~/webroot/grav`. Launch a **terminal** or **console** and navigate to the webroot folder:
```
$ cd ~/webroot
$ git clone https://github.com/getgrav/grav.git
```bash
cd ~/webroot
git clone https://github.com/getgrav/grav.git
```
2. Install the **plugin** and **theme dependencies** by using the [Grav CLI application](https://learn.getgrav.org/advanced/grav-cli) `bin/grav`:
```
$ cd ~/webroot/grav
$ bin/grav install
```bash
cd ~/webroot/grav
bin/grav install
```
Check out the [install procedures](https://learn.getgrav.org/basics/installation) for more information.
@@ -63,28 +63,28 @@ Check out the [install procedures](https://learn.getgrav.org/basics/installation
You can download [plugins](https://getgrav.org/downloads/plugins) or [themes](https://getgrav.org/downloads/themes) manually from the appropriate tab on the [Downloads page on https://getgrav.org](https://getgrav.org/downloads), but the preferred solution is to use the [Grav Package Manager](https://learn.getgrav.org/advanced/grav-gpm) or `GPM`:
```
$ bin/gpm index
```bash
bin/gpm index
```
This will display all the available plugins and then you can install one or more with:
```
$ bin/gpm install <plugin/theme>
```bash
bin/gpm install <plugin/theme>
```
# Updating
To update Grav you should use the [Grav Package Manager](https://learn.getgrav.org/advanced/grav-gpm) or `GPM`:
```
$ bin/gpm selfupgrade
```bash
bin/gpm selfupgrade
```
To update plugins and themes:
```
$ bin/gpm update
```bash
bin/gpm update
```
## Upgrading from older version

View File

@@ -7,22 +7,31 @@ We are focusing our security updates on the following versions
| Version | Supported |
| ------- | ------------------ |
| 1.7.x | :white_check_mark: |
| 1.6.x | :warning: |
| 1.6.x | :x: |
| < 1.6 | :x: |
## :pushpin: Note on Security Severity
> NOTE: Please use the following guidelines when selecting a **Severity**. Submitted advisories that are marked **High** or **Critical** that don't meet the guidelines below will be closed.
* **CRITICAL** - no account required, can modify content, or run malicious code or nefarious activity without any access.
* **HIGH** - publisher level account able to run malicious code or nefarious activity, or other high level security things.
* **MODERATE** - admin level account able to run malicious code or do nefarious things. other moderate security things.
* **LOW** - super admin level account able to run malicious code or do nefarious things. other minor security things.
## :warning: Versions
Versions with :warning: will be supported for security issues, however you won't be able to update to them, you will need to manually update through the [`direct-install` command](https://learn.getgrav.org/17/admin-panel/tools).
If you cannot update to the latest stable version available because, for example, your server does not meet the minimum PHP requirements, you can manually install a previous version by downloading the package from our Releases directory (https://github.com/getgrav/grav/releases).
## Reporting a Vulnerability
## :pencil: Reporting a Vulnerability
Please contact security@getgrav.org with a detailed explanation of the security issue found. If it appears to be a legitimate issues, please submit an **advisory via GitHub Security**: https://github.com/getgrav/grav/security/advisories
>> NOTE: Please do not use 3rd party security issue reporting services, we like to keep everything in the GitHub ecosystem for easier manageability.
> NOTE: Please do not use 3rd party security issue reporting services, we like to keep everything in the GitHub ecosystem for easier manageability.
## Bug Bounties
## :bug: Bug Bounties
We do greatly appreciate your efforts to improve Grav, but unfortunately because we are a small open source project, we **do not have the resources to offer bounties** for security issues found.

Binary file not shown.

View File

@@ -2,7 +2,7 @@
<?php
/**
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -2,7 +2,7 @@
<?php
/**
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -2,7 +2,7 @@
<?php
/**
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -46,7 +46,7 @@
"filp/whoops": "~2.9",
"matthiasmullie/minify": "^1.3",
"monolog/monolog": "~1.25",
"getgrav/image": "^3.0",
"getgrav/image": "^4.0",
"getgrav/cache": "^2.0",
"donatj/phpuseragentparser": "~1.1",
"pimple/pimple": "~3.5.0",
@@ -55,7 +55,7 @@
"league/climate": "^3.6",
"miljar/php-exif": "^0.6",
"composer/ca-bundle": "^1.2",
"dragonmantank/cron-expression": "^1.2",
"dragonmantank/cron-expression": "^3.3",
"willdurand/negotiation": "^3.0",
"itsgoingd/clockwork": "^5.0",
"symfony/http-client": "^4.4",
@@ -70,8 +70,7 @@
"phpunit/php-code-coverage": "~9.2",
"getgrav/markdowndocs": "^2.0",
"codeception/module-asserts": "^1.3",
"codeception/module-phpbrowser": "^1.0",
"symfony/service-contracts": "*"
"codeception/module-phpbrowser": "^1.0"
},
"replace": {
"symfony/polyfill-php72": "*",

1021
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
/**
* @package Grav.Core
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2024 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -1,2 +1,61 @@
/** Clockwork Debugger CSS **/
.clockwork-badge{position:fixed;z-index:10;bottom:0;left:0;padding:2px 4px;background-color:#eee;border:1px solid #ccc;border-bottom:0;border-left:0;display:flex;align-items:center}.clockwork-badge:hover{width:auto}.clockwork-badge:hover:after{content:'Grav Clockwork debugger enabled. Install Clockwork Browser extension (Chrome or Firefox), open your Developer tools and then select the Clockwork tab.'}.clockwork-badge:after{margin-left:10px;font-family:Monaco,Consolas,"Lucida Console",monospace;font-size:12px;line-height:1.5;color:#666}.clockwork-badge i{display:block;float:left;height:22px;width:22px;min-width:22px;background-size:contain;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==)}
.clockwork-badge {
position: fixed;
z-index: 1000; /* Increased z-index for better visibility */
bottom: 0; /* Added some spacing from the bottom */
left: 0; /* Added some spacing from the left */
padding: 5px;
background-color: #eee;
border: 1px solid #ccc;
border-bottom: 0;
border-left: 0;
display: flex;
align-items: center;
border-radius: 0 4px 0 0; /* Rounded top corners */
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
font-size: 14px;
color: #333;
transition: background-color 0.3s ease;
}
.clockwork-badge:hover {
background-color: #ddd;
}
.clockwork-badge i {
display: block;
height: 24px;
width: 24px;
background-size: contain;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAA/1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeHh4AAAD///8EBAT7+/sLCwv29vYVFRUvLy/t7e3m5ubCwsKxsbE/Pz+mpqZMTEwcHBzy8vLp6emfn5+AgIA2Njbi4uLf39+rq6tzc3NWVlYhISHa2trW1tbS0tLMzMy7u7uZmZmUlJSMjIxvb29kZGRHR0c7Ozt5eXkqKiq1tbWQkJBqampbW1tSUlLHx8eHh4ckJCRDQ0M3wD42AAAAI3RSTlMA/PibTbQ0x76TVAlw4LhZLOuEYCAN9Hjx0a2ppGZEGYw97djhXHwAAATZSURBVFjDlVcHW+MwDO1eFCjj2McNOzvdpXTTXVbL/P+/5SQ7QSSX5Di1X1onfi/Sk+Q4sTDbKqWK+YuznZ2zi3wxVdqK/Zf92M1nT9gnO8rmd398GX6Z3xaoOFoiAQcx3E5efgmeSuN8F6Xg1x3G06l/wjNpMR1B0uif4EhnIuFb+0diIoFXk3IVfokisR+h52GO4JKgyjmfaMhAFNlSaPR7DpwI+lzn/E4QKIqmKIJirxCMP4izBPPZPXhgXwMBYgULw0nfg/BF5scDbslb7QeJ08yqqTEmGYoB95d4H8ETL8+n9wBqrLu6ao3bBsMwAnxISf/9BHcqxNB8Y7cWl3Zz7TAUfPrvAT6AoNEFFXvsjutL01yOuMrtBxnFXsmT/1wQHmdWAFNnI3uI48Yj0FUcHbKf62GfUfr8eeQt7Uk3mQZpZNoVRPEui5vtEz5zFEpgWnyqVBZMc6oaGNriH2hGVZ0OxEvInPeMaZWJBA7vmPbCr5jjws5HBnAUxvDMH40aCIf4G5BjRQSs8E8HFFYf8bGxgDvD55bzGhwWkoBcuIyHR/AMdaCagxXDhtL6tSqoWpd4BMnlIR+Or+rYTK/a3EAGcc6e4AWHISnWv20iCCojsHoVlQdjrMexFF2C7UMg2A2WEGWbQhXN6l3eXC6XGp4b9qxbuEB2EBGBwtocrK90cVG5mbRXm6vmx/0phq1sIAGKDgLOBiN1MrO5a9aDl+D0W6x0Ar9BCTRuIIANa90Y7LrLVRXzwVtDInCqMRWcf2bUOEAsa4wJqFowQALL9EiAtVRk8QC4OW+1pOM9jIaVASwYagyNXDj+W0NcfuZNzjtXOiL0Zzg30Llj+ptfxQs4+vBPNiL5PawFCBkgXpUaVtqGl+A8dgZHL34BcBUQrwPptToW+o37Ku+UH9eYByJIx3YkAeFnMFuGO7S5gEp7YhXxa5OOAM39RXDPXb0qmpROsswZe+twXdU55oUIZAiEv3bD1UFwIYKkmGqytPCDCwKFQCKK0yL7qtSAPX54UAbtsLuBHkb9zyLmPQSNjsSgmQwKUOIfEY8F8t4B34DvndJY9BA8tNBJq1Nev9axmaStFcQLhgYoCTo0salkIaW8OUDdWjMTR2sHPhrAFZqx6cqcKE4pl2BJJ4K6hfwvqNgAnXfKX/HU6X3Zrhnu0k7tLNZtTBRv1hkwTDBY1NzFU6doDYjJbWdQkQhWwuU7/LvhTh3SDoco4ECL4i5dwURbc8NdDZz2IwKicE8d0KIqWetLE3+lL4hvUuGSeRfVWNLfj/gpOw4smBJBkKQHCzlHGwvAj4woB1gq5NGGLSXtORBPnUQPV5/MPVkDMxbpwG7w4x0xL6Ltxka0A/4NBvV09UVk4DoSn/jl2+JQS9q9KYawisAD4CfhsZ4TH3htylsdEHARIQBusqCKyUpymycgbbkkXEXjT3z7/oKQFTFVuZD2FMJHZIDsO5x2d4aAr2jR+GLwZhtAb028/0yJ9J8dE87jQyKObcjtTXT8dH+fDuKF4/eiPwzH44wTf/yUi6wrpRIOZ9lM1EtXAifFI+CJn9+iX/t2xMQwOMth/UZbASi8btAwR9FHWSpJr75g9Oqbin3VDg+SpwlP6k6TB4ex/7JvmcJx8jydy6XPk8eFTKhyfwCgX71MSvaBHgAAAABJRU5ErkJggg==);
}
.clockwork-badge .tooltip {
display: none; /* Hidden by default */
position: absolute;
bottom: 35px; /* Position above the badge */
left: 0;
width: 450px;
padding: 20px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
color: #666;
line-height: 1.5;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
z-index: 1001; /* Ensure it appears above other elements */
}
.clockwork-badge:hover .tooltip {
display: block; /* Show tooltip on hover */
}
.clockwork-badge .tooltip a {
color: #007BFF;
text-decoration: none;
}
.clockwork-badge .tooltip a:hover {
text-decoration: underline;
}

View File

@@ -1,3 +1,37 @@
/** Clockwork Debugger JS **/
document.addEventListener("DOMContentLoaded",function () {
var e=document.createElement("div");e.appendChild(document.createElement("i")),e.className="clockwork-badge",document.body.appendChild(e)});
document.addEventListener("DOMContentLoaded", function () {
// Directly select the script tag by its id
var currentScript = document.getElementById('clockwork-script');
if (!currentScript) {
console.error("Clockwork Debugger: Script tag with id 'clockwork-script' not found.");
return;
}
var route = currentScript.getAttribute('data-route') || '/clockwork'; // Default route if not specified
// Debugging: Log the route to verify
console.log("Clockwork Debugger Route:", route);
// Create the badge container
var badge = document.createElement("div");
badge.className = "clockwork-badge";
badge.setAttribute('aria-label', 'Clockwork Debugger Enabled');
badge.setAttribute('role', 'button');
// Create the icon element
var icon = document.createElement("i");
badge.appendChild(icon);
// Create the tooltip element
var tooltip = document.createElement("div");
tooltip.className = "tooltip";
tooltip.innerHTML = `
<b>Grav Clockwork Debugger Enabled.</b><br>
Install the <b>Clockwork Browser extension</b> (Chrome or Firefox) or use the <b>"Clockwork Web"</b> Grav plugin to <a href="${route}" target="_blank">View Debug Info 🔗</a>.
`;
badge.appendChild(tooltip);
// Append the badge to the body
document.body.appendChild(badge);
});

File diff suppressed because one or more lines are too long

View File

@@ -4,74 +4,788 @@ form:
validation: loose
fields:
scheduler_tabs:
type: tabs
active: 1
status_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_STATUS
underline: true
fields:
status_tab:
type: tab
title: PLUGIN_ADMIN.SCHEDULER_STATUS
status:
type: cronstatus
validate:
type: commalist
fields:
status_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_STATUS
underline: true
jobs_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_JOBS
underline: true
status:
type: cronstatus
validate:
type: commalist
webhook_status_override:
type: display
label:
content: |
<script>
(function() {
function updateSchedulerStatus() {
// Find all notice bars
var notices = document.querySelectorAll('.notice');
var webhookStatusChecked = false;
// Check for modern scheduler and webhook settings
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
if (data.webhook_enabled) {
notices.forEach(function(notice) {
if (notice.textContent.includes('Not Enabled for user:')) {
// This is the cron status notice - replace it
notice.className = 'notice info';
notice.innerHTML = '<i class="fa fa-fw fa-check-circle"></i> <strong>Webhook Active</strong> - Scheduler can be triggered via webhook. Cron is not configured.';
}
});
// Also update the main status if it exists
var statusDiv = document.querySelector('.cronstatus-status');
if (statusDiv && statusDiv.textContent.includes('Not Enabled')) {
statusDiv.className = 'cronstatus-status success';
statusDiv.innerHTML = '<i class="fa fa-fw fa-check"></i> Webhook Ready';
}
}
})
.catch(error => {
console.log('Webhook status check failed:', error);
});
}
// Run on page load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', updateSchedulerStatus);
} else {
updateSchedulerStatus();
}
// Also run after a short delay to catch any late-rendered elements
setTimeout(updateSchedulerStatus, 500);
})();
</script>
markdown: false
status_enhanced:
type: display
label:
content: |
<script>
document.addEventListener('DOMContentLoaded', function() {
// Check if webhook is enabled
var webhookEnabled = document.querySelector('[name="data[scheduler][modern][webhook][enabled]"]:checked');
var statusDiv = document.querySelector('.cronstatus-status');
// Also find the parent notice bar
var noticeBar = document.querySelector('.notice.alert');
if (statusDiv) {
var currentStatus = statusDiv.textContent || statusDiv.innerText;
var cronReady = currentStatus.includes('Ready');
var cronNotEnabled = currentStatus.includes('Not Enabled');
// Check if scheduler-webhook plugin exists
var webhookPluginInstalled = false;
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
webhookPluginInstalled = true;
updateStatusDisplay(data);
})
.catch(error => {
updateStatusDisplay(null);
});
function updateStatusDisplay(healthData) {
var isWebhookEnabled = webhookEnabled && webhookEnabled.value == '1';
var isWebhookReady = webhookPluginInstalled && isWebhookEnabled && healthData && healthData.webhook_enabled;
// Update the main status text
var mainStatusText = '';
var mainStatusClass = '';
if (cronReady && isWebhookReady) {
mainStatusText = 'Cron and Webhook Ready';
mainStatusClass = 'success';
} else if (cronReady) {
mainStatusText = 'Cron Ready';
mainStatusClass = 'success';
} else if (isWebhookReady) {
mainStatusText = 'Webhook Ready (No Cron)';
mainStatusClass = 'success'; // Changed from warning to success
} else if (cronNotEnabled && !isWebhookReady) {
mainStatusText = 'Not Configured';
mainStatusClass = 'error';
} else {
mainStatusText = 'Configuration Pending';
mainStatusClass = 'warning';
}
// Update the notice bar if webhooks are ready
if (noticeBar && isWebhookReady) {
// Change from error (red) to success (green) or info (blue)
noticeBar.classList.remove('alert');
noticeBar.classList.add('info');
var noticeIcon = noticeBar.querySelector('i.fa');
if (noticeIcon) {
noticeIcon.classList.remove('fa-times-circle');
noticeIcon.classList.add('fa-check-circle');
}
var noticeText = noticeBar.querySelector('strong') || noticeBar;
var username = noticeText.textContent.match(/user:\s*(\w+)/);
if (username) {
noticeText.innerHTML = 'Webhook Ready for user: <b>' + username[1] + '</b> (Cron not configured)';
} else {
noticeText.innerHTML = mainStatusText;
}
}
// Update the main status div
if (statusDiv) {
statusDiv.innerHTML = '<i class="fa fa-fw fa-' +
(mainStatusClass === 'success' ? 'check' : mainStatusClass === 'warning' ? 'exclamation' : 'times') +
'"></i> ' + mainStatusText;
statusDiv.className = 'cronstatus-status ' + mainStatusClass;
}
// Update install instructions button/content
var installButton = document.querySelector('.cronstatus-install-button');
var installDiv = document.querySelector('.cronstatus-install');
if (installDiv) {
var installHtml = '<div class="alert alert-info">';
installHtml += '<h4>Setup Instructions:</h4>';
var hasInstructions = false;
// Cron setup
if (!cronReady) {
installHtml += '<p><strong>Option 1: Traditional Cron</strong><br>';
installHtml += 'Run: <code>bin/grav scheduler --install</code><br>';
installHtml += 'This will add a cron job that runs every minute.</p>';
hasInstructions = true;
}
// Webhook setup
if (!webhookPluginInstalled) {
installHtml += '<p><strong>Option 2: Webhook Support</strong><br>';
installHtml += '1. Install plugin: <code>bin/gpm install scheduler-webhook</code><br>';
installHtml += '2. Configure webhook token in Advanced Features tab<br>';
installHtml += '3. Use webhook URL in your CI/CD or cloud scheduler</p>';
hasInstructions = true;
} else if (!isWebhookEnabled) {
installHtml += '<p><strong>Webhook Plugin Installed</strong><br>';
installHtml += 'Enable webhooks in Advanced Features tab and set a secure token.</p>';
hasInstructions = true;
} else if (isWebhookReady) {
installHtml += '<p><strong>✅ Webhook is Active!</strong><br>';
installHtml += 'Trigger URL: <code>' + window.location.origin + '/grav-editor-pro/scheduler/webhook</code><br>';
installHtml += 'Use with Authorization header: <code>Bearer YOUR_TOKEN</code></p>';
if (!cronReady) {
installHtml += '<p class="text-muted"><small>Note: No cron job configured. Scheduler runs only via webhook triggers.</small></p>';
}
}
if (!hasInstructions && cronReady) {
installHtml += '<p><strong>✅ Cron is configured and ready!</strong><br>';
installHtml += 'The scheduler runs automatically every minute via system cron.</p>';
}
installHtml += '</div>';
installDiv.innerHTML = installHtml;
// Update button text based on status
if (installButton) {
if (cronReady && isWebhookReady) {
installButton.innerHTML = '<i class="fa fa-info-circle"></i> Configuration Details';
} else if (cronReady || isWebhookReady) {
installButton.innerHTML = '<i class="fa fa-plus-circle"></i> Add More Triggers';
} else {
installButton.innerHTML = '<i class="fa fa-exclamation-triangle"></i> Install Instructions';
}
}
}
}
}
});
</script>
custom_jobs:
type: list
style: vertical
label:
classes: cron-job-list compact
key: id
fields:
.id:
type: key
label: ID
placeholder: 'process-name'
validate:
required: true
pattern: '[a-zа-я0-9_\-]+'
max: 20
message: 'ID must be lowercase with dashes/underscores only and less than 20 characters'
.command:
type: text
label: PLUGIN_ADMIN.COMMAND
placeholder: 'ls'
validate:
required: true
.args:
type: text
label: PLUGIN_ADMIN.EXTRA_ARGUMENTS
placeholder: '-lah'
.at:
type: text
wrapper_classes: cron-selector
label: PLUGIN_ADMIN.SCHEDULER_RUNAT
help: PLUGIN_ADMIN.SCHEDULER_RUNAT_HELP
placeholder: '* * * * *'
validate:
required: true
.output:
type: text
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_HELP
placeholder: 'logs/ls-cron.out'
.output_mode:
type: select
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE_HELP
default: append
options:
append: Append
overwrite: Overwrite
.email:
type: text
label: PLUGIN_ADMIN.SCHEDULER_EMAIL
help: PLUGIN_ADMIN.SCHEDULER_EMAIL_HELP
placeholder: 'notifications@yoursite.com'
modern_health:
type: display
label: Health Status
content: |
<div id="scheduler-health-status">
<div class="text-muted">Checking health...</div>
</div>
<script>
(function() {
function loadHealthStatus() {
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
var statusEl = document.getElementById('scheduler-health-status');
if (!statusEl) return;
// Modern card-based layout
var statusColor = '#6c757d';
var statusLabel = data.status || 'unknown';
if (data.status === 'healthy') statusColor = '#28a745';
else if (data.status === 'warning') statusColor = '#ffc107';
else if (data.status === 'critical') statusColor = '#dc3545';
var html = '<div style="display: flex; flex-direction: column; gap: 1rem;">';
// Status card
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: linear-gradient(135deg, #f8f9fa 0%, #fff 100%); border-radius: 6px; border: 1px solid #e9ecef; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">';
html += '<span style="font-weight: 500; color: #495057;">Status:</span>';
html += '<span style="background: ' + statusColor + '; color: white; padding: 0.375rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 4px; text-transform: uppercase; letter-spacing: 0.025em;">' + statusLabel + '</span>';
html += '</div>';
// Info grid
html += '<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem;">';
// Last run card
html += '<div style="background: white; border: 1px solid #e9ecef; border-radius: 6px; padding: 0.75rem; box-shadow: 0 1px 2px rgba(0,0,0,0.03);">';
html += '<div style="color: #6c757d; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.25rem;">Last Run</div>';
if (data.last_run) {
var age = data.last_run_age;
var ageText = 'just now';
if (age > 86400) {
ageText = Math.floor(age / 86400) + ' day(s) ago';
} else if (age > 3600) {
ageText = Math.floor(age / 3600) + ' hour(s) ago';
} else if (age > 60) {
ageText = Math.floor(age / 60) + ' minute(s) ago';
} else if (age > 0) {
ageText = age + ' second(s) ago';
}
html += '<div style="font-size: 1rem; color: #212529; font-weight: 500;">' + ageText + '</div>';
} else {
html += '<div style="font-size: 1rem; color: #6c757d;">Never</div>';
}
html += '</div>';
// Jobs count card
html += '<div style="background: white; border: 1px solid #e9ecef; border-radius: 6px; padding: 0.75rem; box-shadow: 0 1px 2px rgba(0,0,0,0.03);">';
html += '<div style="color: #6c757d; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.25rem;">Scheduled Jobs</div>';
html += '<div style="font-size: 1rem; color: #212529; font-weight: 500;">' + (data.scheduled_jobs || 0) + '</div>';
html += '</div>';
html += '</div>'; // Close grid
// Additional info if available
if (data.modern_features && data.queue_size !== undefined) {
html += '<div style="background: white; border: 1px solid #e9ecef; border-radius: 6px; padding: 0.75rem; box-shadow: 0 1px 2px rgba(0,0,0,0.03);">';
html += '<span style="color: #6c757d; font-size: 0.875rem;">Queue Size: </span>';
html += '<span style="font-weight: 500;">' + data.queue_size + '</span>';
html += '</div>';
}
// Failed jobs warning
if (data.failed_jobs_24h > 0) {
html += '<div style="background: #fff5f5; border: 1px solid #feb2b2; border-radius: 6px; padding: 0.75rem; color: #c53030;">';
html += '<strong>⚠️ Failed Jobs (24h):</strong> ' + data.failed_jobs_24h;
html += '</div>';
}
html += '</div>'; // Close main container
statusEl.innerHTML = html;
})
.catch(error => {
var statusEl = document.getElementById('scheduler-health-status');
if (statusEl) {
statusEl.innerHTML = '<div class="alert alert-warning">Unable to fetch health status. Ensure scheduler-webhook plugin is installed.</div>';
}
});
}
// Load on page ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadHealthStatus);
} else {
loadHealthStatus();
}
// Refresh every 30 seconds
setInterval(loadHealthStatus, 30000);
})();
</script>
markdown: false
trigger_methods:
type: display
label: Active Triggers
content: |
<div id="scheduler-triggers">
<div class="text-muted">Checking triggers...</div>
</div>
<script>
(function() {
function loadTriggers() {
// Check cron status from the main status field
var cronReady = false;
var statusDiv = document.querySelector('.cronstatus-status');
if (statusDiv) {
var statusText = statusDiv.textContent || statusDiv.innerText;
cronReady = statusText.includes('Ready');
}
// Check webhook status
fetch(window.location.origin + '/grav-editor-pro/scheduler/health')
.then(response => response.json())
.then(data => {
var triggersEl = document.getElementById('scheduler-triggers');
if (!triggersEl) return;
var html = '<div style="display: flex; flex-direction: column; gap: 0.5rem;">';
// Cron trigger card
var cronIcon = cronReady ? '✅' : '❌';
var cronStatus = cronReady ? 'Active' : 'Not Configured';
var cronStatusColor = cronReady ? '#28a745' : '#6c757d';
var cardBg = cronReady ? '#f8f9fa' : '#fff';
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: ' + cardBg + '; border: 1px solid #e9ecef; border-radius: 4px;">';
html += '<div style="display: flex; align-items: center; gap: 0.75rem;">';
html += '<span style="font-size: 1.25rem; line-height: 1;">' + cronIcon + '</span>';
html += '<span style="font-weight: 500; color: #212529; font-size: 1rem;">Cron:</span>';
html += '</div>';
html += '<span style="background: ' + cronStatusColor + '; color: white; padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.025em;">' + cronStatus + '</span>';
html += '</div>';
// Webhook trigger card
if (data.webhook_enabled) {
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 4px;">';
html += '<div style="display: flex; align-items: center; gap: 0.75rem;">';
html += '<span style="font-size: 1.25rem; line-height: 1;">✅</span>';
html += '<span style="font-weight: 500; color: #212529; font-size: 1rem;">Webhook:</span>';
html += '</div>';
html += '<span style="background: #28a745; color: white; padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.025em;">ACTIVE</span>';
html += '</div>';
} else {
// Show webhook as not configured/disabled
html += '<div style="display: flex; align-items: center; justify-content: space-between; padding: 0.75rem 1rem; background: #fff; border: 1px solid #e9ecef; border-radius: 4px;">';
html += '<div style="display: flex; align-items: center; gap: 0.75rem;">';
html += '<span style="font-size: 1.25rem; line-height: 1;">⚠️</span>';
html += '<span style="font-weight: 500; color: #212529; font-size: 1rem;">Webhook:</span>';
html += '</div>';
html += '<span style="background: #ffc107; color: #212529; padding: 0.25rem 0.75rem; font-size: 0.875rem; font-weight: 500; border-radius: 3px; text-transform: uppercase; letter-spacing: 0.025em;">DISABLED</span>';
html += '</div>';
}
html += '</div>';
// Add warning if no triggers active
if (!cronReady && !data.webhook_enabled) {
html += '<div class="alert alert-warning" style="margin-top: 1rem;"><i class="fa fa-exclamation-triangle"></i> No triggers active! Configure cron or enable webhooks.</div>';
}
triggersEl.innerHTML = html;
})
.catch(error => {
var triggersEl = document.getElementById('scheduler-triggers');
if (triggersEl) {
// Show just cron status if health endpoint not available
var html = '<ul class="list-unstyled">';
if (cronReady) {
html += '<li>✅ <strong>Cron:</strong> <span class="badge badge-success">Active</span></li>';
} else {
html += '<li>❌ <strong>Cron:</strong> <span class="badge badge-secondary">Not Configured</span></li>';
}
html += '<li>⚠️ <strong>Webhook:</strong> <span class="badge badge-secondary">Plugin Not Installed</span></li>';
html += '</ul>';
triggersEl.innerHTML = html;
}
});
}
// Load on page ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadTriggers);
} else {
loadTriggers();
}
})();
</script>
markdown: false
jobs_tab:
type: tab
title: PLUGIN_ADMIN.SCHEDULER_JOBS
fields:
jobs_title:
type: section
title: PLUGIN_ADMIN.SCHEDULER_JOBS
underline: true
custom_jobs:
type: list
style: vertical
label:
classes: cron-job-list compact
key: id
fields:
.id:
type: key
label: ID
placeholder: 'process-name'
validate:
required: true
pattern: '[a-zа-я0-9_\-]+'
max: 20
message: 'ID must be lowercase with dashes/underscores only and less than 20 characters'
.command:
type: text
label: PLUGIN_ADMIN.COMMAND
placeholder: 'ls'
validate:
required: true
.args:
type: text
label: PLUGIN_ADMIN.EXTRA_ARGUMENTS
placeholder: '-lah'
.at:
type: text
wrapper_classes: cron-selector
label: PLUGIN_ADMIN.SCHEDULER_RUNAT
help: PLUGIN_ADMIN.SCHEDULER_RUNAT_HELP
placeholder: '* * * * *'
validate:
required: true
.output:
type: text
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_HELP
placeholder: 'logs/ls-cron.out'
.output_mode:
type: select
label: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE
help: PLUGIN_ADMIN.SCHEDULER_OUTPUT_TYPE_HELP
default: append
options:
append: Append
overwrite: Overwrite
.email:
type: text
label: PLUGIN_ADMIN.SCHEDULER_EMAIL
help: PLUGIN_ADMIN.SCHEDULER_EMAIL_HELP
placeholder: 'notifications@yoursite.com'
modern_tab:
type: tab
title: Advanced Features
fields:
workers_section:
type: section
title: Worker Configuration
underline: true
fields:
modern.workers:
type: number
label: Concurrent Workers
help: Number of jobs that can run simultaneously (1 = sequential)
default: 4
size: x-small
append: workers
validate:
type: int
min: 1
max: 10
retry_section:
type: section
title: Retry Configuration
underline: true
fields:
modern.retry.enabled:
type: toggle
label: Enable Job Retry
help: Automatically retry failed jobs
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.retry.max_attempts:
type: number
label: Maximum Retry Attempts
help: Maximum number of times to retry a failed job
default: 3
size: x-small
append: retries
validate:
type: int
min: 1
max: 10
modern.retry.backoff:
type: select
label: Retry Backoff Strategy
help: How to calculate delay between retries
default: exponential
options:
linear: Linear (fixed delay)
exponential: Exponential (increasing delay)
queue_section:
type: section
title: Queue Configuration
underline: true
fields:
modern.queue.path:
type: text
label: Queue Storage Path
help: Where to store queued jobs
default: 'user-data://scheduler/queue'
placeholder: 'user-data://scheduler/queue'
modern.queue.max_size:
type: number
label: Maximum Queue Size
help: Maximum number of jobs that can be queued
default: 1000
size: x-small
append: jobs
validate:
type: int
min: 100
max: 10000
history_section:
type: section
title: Job History
underline: true
fields:
modern.history.enabled:
type: toggle
label: Enable Job History
help: Track execution history for all jobs
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.history.retention_days:
type: number
label: History Retention (days)
help: How long to keep job history
default: 30
size: x-small
append: days
validate:
type: int
min: 1
max: 365
webhook_section:
type: section
title: Webhook Configuration
underline: true
fields:
webhook_plugin_status:
type: webhook-status
label:
modern.webhook.enabled:
type: toggle
label: Enable Webhook Triggers
help: Allow triggering scheduler via HTTP webhook
highlight: 0
default: 0
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.webhook.token:
type: text
label: Webhook Security Token
help: Secret token for authenticating webhook requests. Keep this secret!
placeholder: 'Click Generate to create a secure token'
autocomplete: 'off'
webhook_token_generate:
type: display
label:
content: |
<div style="margin-top: -10px; margin-bottom: 15px;">
<button type="button" class="button button-primary" onclick="generateWebhookToken()">
<i class="fa fa-refresh"></i> Generate Token
</button>
</div>
<script>
function generateWebhookToken() {
try {
// Generate token
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const token = Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
// Try multiple selectors to find the field
let field = document.querySelector('[name="data[scheduler][modern][webhook][token]"]');
if (!field) {
field = document.querySelector('input[name*="webhook][token"]');
}
if (!field) {
field = document.getElementById('scheduler-modern-webhook-token');
}
if (!field) {
// Look for any text input in the webhook section
const webhookSection = document.querySelector('.webhook_section');
if (webhookSection) {
const inputs = webhookSection.querySelectorAll('input[type="text"]');
// Find the token field by checking for the placeholder
for (let input of inputs) {
if (input.placeholder && input.placeholder.includes('Generate')) {
field = input;
break;
}
}
}
}
if (field) {
field.value = token;
field.dispatchEvent(new Event('change', { bubbles: true }));
field.dispatchEvent(new Event('input', { bubbles: true }));
// Flash the field to show it was updated
field.style.backgroundColor = '#d4edda';
setTimeout(function() {
field.style.backgroundColor = '';
}, 500);
// Also try to trigger Grav's form change detection
if (window.jQuery) {
jQuery(field).trigger('change');
}
} else {
// Log more debugging info
console.error('Token field not found. Looking for input fields...');
console.log('All inputs:', document.querySelectorAll('input[type="text"]'));
alert('Could not find the token field. Please ensure you are in the Advanced Features tab and the Webhook Configuration section is visible.');
}
} catch (e) {
console.error('Error generating token:', e);
alert('Error generating token: ' + e.message);
}
}
</script>
markdown: false
modern.webhook.path:
type: text
label: Webhook Path
help: URL path for webhook endpoint
default: '/scheduler/webhook'
placeholder: '/scheduler/webhook'
health_section:
type: section
title: Health Check Configuration
underline: true
fields:
modern.health.enabled:
type: toggle
label: Enable Health Check
help: Provide health status endpoint for monitoring
highlight: 1
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
modern.health.path:
type: text
label: Health Check Path
help: URL path for health check endpoint
default: '/scheduler/health'
placeholder: '/scheduler/health'
webhook_usage:
type: section
title: Usage Examples
underline: true
fields:
webhook_examples:
type: display
label:
content: |
<script src="{{ url('plugin://admin/themes/grav/js/clipboard-helper.js') }}"></script>
<div class="webhook-examples">
<script>
// Initialize webhook commands when page loads
document.addEventListener('DOMContentLoaded', function() {
if (typeof GravClipboard !== 'undefined') {
GravClipboard.initWebhookCommands();
}
});
</script>
<div class="alert alert-info">
<h4>How to use webhooks:</h4>
<div style="margin-bottom: 1rem;">
<label style="display: block; margin-bottom: 0.25rem; font-weight: 500;">Trigger all due jobs (respects schedule):</label>
<div class="form-input-wrapper form-input-addon-wrapper">
<textarea id="webhook-all-cmd" readonly rows="2" style="font-family: monospace; background: #f5f5f5; resize: none;">Loading...</textarea>
<div class="form-input-addon form-input-append" style="cursor: pointer;" onclick="GravClipboard.copy(this)"><i class="fa fa-copy"></i> Copy</div>
</div>
</div>
<div style="margin-bottom: 1rem;">
<label style="display: block; margin-bottom: 0.25rem; font-weight: 500;">Force-run specific job (ignores schedule):</label>
<div class="form-input-wrapper form-input-addon-wrapper">
<textarea id="webhook-job-cmd" readonly rows="2" style="font-family: monospace; background: #f5f5f5; resize: none;">Loading...</textarea>
<div class="form-input-addon form-input-append" style="cursor: pointer;" onclick="GravClipboard.copy(this)"><i class="fa fa-copy"></i> Copy</div>
</div>
</div>
<div style="margin-bottom: 1rem;">
<label style="display: block; margin-bottom: 0.25rem; font-weight: 500;">Check health status:</label>
<div class="form-input-wrapper form-input-addon-wrapper">
<input type="text" id="webhook-health-cmd" readonly value="Loading..." style="font-family: monospace; background: #f5f5f5;">
<div class="form-input-addon form-input-append" style="cursor: pointer;" onclick="GravClipboard.copy(this)"><i class="fa fa-copy"></i> Copy</div>
</div>
</div>
<div style="margin-top: 1rem;">
<p><strong>GitHub Actions example:</strong></p>
<pre>- name: Trigger Scheduler
run: |
curl -X POST ${{ secrets.SITE_URL }}/scheduler/webhook \
-H "Authorization: Bearer ${{ secrets.WEBHOOK_TOKEN }}"</pre>
</div>
</div>
</div>
markdown: false

View File

@@ -103,6 +103,7 @@ form:
"D, d M Y G:i:s": Date3
"d-m-y G:i": Date4
"jS M Y": Date5
"Y-m-d G:i": Date6
pages.dateformat.long:
type: dateformat
@@ -116,6 +117,7 @@ form:
"D, d M Y G:i:s": Date3
"d-m-y G:i": Date4
"jS M Y": Date5
"Y-m-d G:i:s": Date6
pages.order.by:
type: select
@@ -631,6 +633,19 @@ form:
help: PLUGIN_ADMIN.CACHE_PREFIX_HELP
placeholder: PLUGIN_ADMIN.CACHE_PREFIX_PLACEHOLDER
cache.purge_max_age_days:
type: text
size: x-small
append: GRAV.NICETIME.DAY_PLURAL
label: PLUGIN_ADMIN.CACHE_PURGE_AGE
help: PLUGIN_ADMIN.CACHE_PURGE_AGE_HELP
validate:
type: number
min: 1
max: 365
step: 1
default: 30
cache.purge_at:
type: cron
label: PLUGIN_ADMIN.CACHE_PURGE_JOB
@@ -1236,6 +1251,16 @@ form:
title: PLUGIN_ADMIN.MEDIA
underline: true
images.adapter:
type: select
size: small
label: PLUGIN_ADMIN.IMAGE_ADAPTER
help: PLUGIN_ADMIN.IMAGE_ADAPTER_HELP
highlight: gd
options:
gd: GD (PHP built-in)
imagick: Imagick
images.default_image_quality:
type: range
append: '%'
@@ -1298,6 +1323,28 @@ form:
auto: Auto
lazy: Lazy
eager: Eager
images.defaults.decoding:
type: select
size: small
label: PLUGIN_ADMIN.IMAGES_DECODING
help: PLUGIN_ADMIN.IMAGES_DECODING_HELP
highlight: auto
options:
auto: Auto
sync: Sync
async: Async
images.defaults.fetchpriority:
type: select
size: small
label: PLUGIN_ADMIN.IMAGES_FETCHPRIORITY
help: PLUGIN_ADMIN.IMAGES_FETCHPRIORITY_HELP
highlight: auto
options:
auto: Auto
high: High
low: Low
images.seofriendly:
type: toggle

View File

@@ -140,7 +140,7 @@ form:
multiple: true
size: large
label: PLUGIN_ADMIN.GROUPS
data-options@: 'Grav\Common\Flex\Types\UserGroups\UserGroupObject::groupNames'
data-options@: '\Grav\Common\User\Group::groupNames'
classes: fancy
help: PLUGIN_ADMIN.GROUPS_HELP
validate:

View File

@@ -216,3 +216,8 @@ types:
type: file
thumb: media/thumb-json.png
mime: application/json
vcf:
type: file
thumb: media/thumb-vcf.png
mime: text/x-vcard

View File

@@ -0,0 +1,68 @@
# Grav Scheduler Configuration
# Default scheduler settings (backward compatible)
defaults:
output: true
output_type: file
email: null
# Status of individual jobs (enabled/disabled)
status: {}
# Custom scheduled jobs
custom_jobs: {}
# Modern scheduler features (disabled by default for backward compatibility)
modern:
# Enable modern scheduler features
enabled: false
# Number of concurrent workers (1 = sequential execution like legacy)
workers: 1
# Job retry configuration
retry:
enabled: true
max_attempts: 3
backoff: exponential # 'linear' or 'exponential'
# Job queue configuration
queue:
path: user-data://scheduler/queue
max_size: 1000
# Webhook trigger configuration
webhook:
enabled: false
token: null # Set a secure token to enable webhook triggers
path: /scheduler/webhook
# Health check endpoint
health:
enabled: true
path: /scheduler/health
# Job execution history
history:
enabled: true
retention_days: 30
path: user-data://scheduler/history
# Performance settings
performance:
job_timeout: 300 # Default timeout in seconds
lock_timeout: 10 # Lock acquisition timeout in seconds
# Monitoring and alerts
monitoring:
enabled: false
alert_on_failure: true
alert_email: null
webhook_url: null
# Trigger detection methods
triggers:
check_cron: true
check_systemd: true
check_webhook: true
check_external: true

View File

@@ -32,9 +32,16 @@ xss_dangerous_tags:
- base
uploads_dangerous_extensions:
- php
- php2
- php3
- php4
- php5
- phar
- phtml
- html
- htm
- shtml
- shtm
- js
- exe
sanitize_svg: true

View File

@@ -25,7 +25,7 @@ routes:
# '/new/(.*)': '/blog/$1' # Regex any /new/my-page URL to /blog/my-page Route
blog:
route: '/blog' # Custom value added (accessible via system.blog.route)
route: '/blog' # Custom value added (accessible via site.blog.route)
#menu: # Menu Example
# - text: Source

View File

@@ -101,6 +101,7 @@ cache:
clear_images_by_default: false # By default grav does not include processed images in cache clear, this can be enabled
cli_compatibility: false # Ensures only non-volatile drivers are used (file, redis, memcache, etc.)
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
purge_max_age_days: 30 # Maximum age of cache items in days before they are purged
gzip: false # GZip compress the page output
allow_webserver_gzip: false # If true, `content-encoding: identity` but connection isn't closed before `onShutDown()` event
redis:
@@ -156,6 +157,7 @@ debugger:
close_connection: true # Close the connection before calling onShutdown(). false for debugging
images:
adapter: gd # Image adapter to use: gd | imagick
default_image_quality: 85 # Default image quality to use when resampling images (85%)
cache_all: false # Cache all image by default
cache_perms: '0755' # MUST BE IN QUOTES!! Default cache folder perms. Usually '0755' or '0775'
@@ -168,6 +170,8 @@ images:
retina_scale: 1 # scale to adjust auto-sizes for better handling of HiDPI resolutions
defaults:
loading: auto # Let browser pick [auto|lazy|eager]
decoding: auto # Let browser pick [auto|sync|async]
fetchpriority: auto # Let browser pick [auto|high|low]
watermark:
image: 'system://images/watermark.png' # Path to a watermark image
position_y: 'center' # top|center|bottom

View File

@@ -3,13 +3,13 @@
/**
* @package Grav\Core
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
// Some standard defines
define('GRAV', true);
define('GRAV_VERSION', '1.7.43');
define('GRAV_VERSION', '1.7.49.3');
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
define('GRAV_TESTING', false);
@@ -26,12 +26,12 @@ if (!defined('DS')) {
// Absolute path to Grav root. This is where Grav is installed into.
if (!defined('GRAV_ROOT')) {
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, getenv('GRAV_ROOT') ?: getcwd()), DS);
define('GRAV_ROOT', $path);
define('GRAV_ROOT', $path ?: DS);
}
// Absolute path to Grav webroot. This is the path where your site is located in.
if (!defined('GRAV_WEBROOT')) {
$path = rtrim(getenv('GRAV_WEBROOT') ?: GRAV_ROOT, DS);
define('GRAV_WEBROOT', $path);
define('GRAV_WEBROOT', $path ?: DS);
}
// Relative path to user folder. This path needs to be located under GRAV_WEBROOT.
if (!defined('GRAV_USER_PATH')) {

View File

@@ -2,7 +2,7 @@
/**
* @package Grav\Core
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -5,6 +5,7 @@ GRAV:
BAD_DATE: Невалидна дата
AGO: преди
FROM_NOW: от сега
JUST_NOW: току що
SECOND: секунда
MINUTE: минута
HOUR: час
@@ -60,3 +61,12 @@ GRAV:
- 'петък'
- 'събота'
- 'неделя'
YES: "Да"
NO: "Не"
CRON:
EVERY: всеки
EVERY_HOUR: Всеки час
EVERY_MINUTE: Всяка минута
EVERY_DAY_OF_WEEK: Всеки ден от седмицата
EVERY_DAY_OF_MONTH: Всеки ден от месеца
EVERY_MONTH: Всеки месец

View File

@@ -2,14 +2,14 @@
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# S'ha produït un error: Frontmatter invàlid\n\nRuta: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- 'informació'
- 'rice'
- 'money'
- 'species'
- 'series'
- 'fish'
- 'sheep'
- ''
- ''
- ''
- ''
- ''
- ''
NICETIME:
NO_DATE_PROVIDED: No s'ha proporcionat data
BAD_DATE: Data invàlida

View File

@@ -1,6 +1,6 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Chyba: Chybný frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Chyba: Chybná hlavička\n\nCesta: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'

40
system/languages/eo.yaml Normal file
View File

@@ -0,0 +1,40 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Eraro: Nevalida Frontmatter\n\nVojo: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/sis$/i': 'j'
NICETIME:
FROM_NOW: ekde nun
JUST_NOW: Ĝuste nun
SECOND: sekundo
MINUTE: minuto
HOUR: horo
DAY: tago
WEEK: semajno
MONTH: monato
YEAR: jaro
DECADE: jardeko
SEC: sek.
MIN: min.
HR: horo
SECOND_PLURAL: sekundoj
MINUTE_PLURAL: minutoj
HOUR_PLURAL: horoj
DAY_PLURAL: tagoj
WEEK_PLURAL: semajnoj
MONTH_PLURAL: monatoj
YEAR_PLURAL: jaroj
DECADE_PLURAL: jardekoj
MONTHS_OF_THE_YEAR:
- 'januaro'
- 'februaro'
- 'marto'
- 'aprilo'
- ''
- ''
- ''
- ''
- ''
- ''
- ''
- ''

View File

@@ -21,9 +21,9 @@ GRAV:
'sex': 'sexos'
'move': 'movido'
INFLECTOR_ORDINALS:
'first': 'ro'
'second': 'do'
'third': 'ro'
'first': ''
'second': ''
'third': ''
NICETIME:
NO_DATE_PROVIDED: No se proporcionó fecha
BAD_DATE: Fecha errónea
@@ -101,7 +101,7 @@ GRAV:
TEXT_DOW: ' en <b />'
TEXT_MONTH: ' de<b />'
TEXT_DOM: ' en<b />'
ERROR1: '¡La etiqueta %s no está soportada!'
ERROR1: No se admite la etiqueta %s.
ERROR2: El número de elementos es erróneo
ERROR3: El jquery_element debería establecerse en la configuración del jqCron
ERROR4: Expresión no reconocida

View File

@@ -13,12 +13,12 @@ GRAV:
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- 'informatsioon'
- 'riis'
- 'raha'
- 'species'
- 'series'
- ''
- ''
- 'kala'
- 'lammas'
INFLECTOR_IRREGULAR:
@@ -70,6 +70,7 @@ GRAV:
VALIDATION_FAIL: '<b>Kinnitamine nurjus:</b>'
INVALID_INPUT: 'Vigane sisend:'
MISSING_REQUIRED_FIELD: 'Nõutud väli puudub:'
XSS_ISSUES: "Tuvastasime '%s' väljal võimaliku XSS-riski"
MONTHS_OF_THE_YEAR:
- 'jaanuar'
- 'veebruar'
@@ -91,11 +92,14 @@ GRAV:
- 'reede'
- 'laupäev'
- 'pühapäev'
YES: "Jah"
NO: "Ei"
CRON:
EVERY: iga
EVERY_HOUR: iga tund
EVERY_MINUTE: iga minut
EVERY_DAY_OF_WEEK: iga nädala päev
EVERY_DAY_OF_WEEK: nädala igal päeval
EVERY_DAY_OF_MONTH: kuu igal päeval
EVERY_MONTH: iga kuu
TEXT_PERIOD: Iga <b />
ERROR1: Silt %s pole toetatud!

View File

@@ -45,12 +45,12 @@ GRAV:
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- 'information'
- ''
- ''
- 'riisi'
- 'raha'
- 'lajit'
- 'series'
- ''
- 'kala'
- 'lammas'
INFLECTOR_IRREGULAR:

View File

@@ -22,8 +22,27 @@ GRAV:
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ouvelles'
INFLECTOR_UNCOUNTABLE:
- 'équipement'

View File

@@ -1,11 +1,27 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nכותרת: %1$s\n---\n# שגיאה: Fronmatter לא חוקי\nנתיב: `%2$s`\n**%3$s**\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'ציוד'
- 'מידע'
- 'אורז'
- 'כסף'
- 'מינים'
- 'סדרה'
- 'דג'
- 'כבשה'
INFLECTOR_IRREGULAR:
'person': 'אנשים'
'man': 'גברים'
'child': 'ילדים'
'sex': 'מינים'
'move': 'מהלכים'
NICETIME:
NO_DATE_PROVIDED: לא סופק תאריך
BAD_DATE: תאריך פגום
AGO: לפני
FROM_NOW: כרגע
JUST_NOW: כרגע
SECOND: שנייה
MINUTE: דקה
HOUR: שעה
@@ -40,6 +56,7 @@ GRAV:
VALIDATION_FAIL: '<b>האימות נכשל:</b>'
INVALID_INPUT: 'קלט לא חוקי'
MISSING_REQUIRED_FIELD: 'שדות חובה חסרים:'
XSS_ISSUES: "בעיות XSS פוטנציאליות זוהו בשדה '%s'"
MONTHS_OF_THE_YEAR:
- 'ינואר'
- 'פברואר'
@@ -61,3 +78,22 @@ GRAV:
- 'שישי'
- 'שבת'
- 'ראשון'
YES: "כן"
NO: "לא"
CRON:
EVERY: בכל
EVERY_HOUR: בכל שעה
EVERY_MINUTE: כל דקה
EVERY_DAY_OF_WEEK: כל יום בשבוע
EVERY_DAY_OF_MONTH: בכל יום בחודש
EVERY_MONTH: כל חודש
TEXT_PERIOD: כל <b />
TEXT_MINS: 'ב <b /> דקות אחרי השעה'
TEXT_TIME: 'ב <b />:<b />'
TEXT_DOW: 'ב <b />'
TEXT_MONTH: 'של <b />'
TEXT_DOM: 'ב <b />'
ERROR1: התגית %s אינו נתמכת
ERROR2: מספר לא חוקי של משתנים.
ERROR3: יש להגדיר את ה-jquery_element להגדרות jqCron
ERROR4: ביטוי לא מזוהה

View File

@@ -1,8 +1,9 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nnaslov: %1$s\n---\n\n# Pogreška: nevažeći frontmatter\n\nPutanja datoteke: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'oprema'
- 'informacije'
- 'informacija'
- 'riža'
- 'novac'
- 'vrsta'
@@ -15,11 +16,17 @@ GRAV:
'child': 'djeca'
'sex': 'spolovi'
'move': 'Pomakni'
INFLECTOR_ORDINALS:
'default': '.'
'first': '.'
'second': '.'
'third': '.'
NICETIME:
NO_DATE_PROVIDED: Datum nije upisan
BAD_DATE: Pogrešan datum
AGO: prije
FROM_NOW: od sada
JUST_NOW: upravo sad
SECOND: sekunda
MINUTE: minuta
HOUR: sat
@@ -29,6 +36,7 @@ GRAV:
YEAR: godina
DECADE: desetljeće
SEC: sek
MIN: min
HR: sat
WK: t
MO: m
@@ -53,6 +61,7 @@ GRAV:
VALIDATION_FAIL: '<b>Validacija nije uspjela:</b>'
INVALID_INPUT: 'Pogrešan unos u'
MISSING_REQUIRED_FIELD: 'Nedostaje obavezno polje:'
XSS_ISSUES: "Potencijalni XSS problemi otkriveni u polju '%s'"
MONTHS_OF_THE_YEAR:
- 'Siječanj'
- 'Veljača'
@@ -74,3 +83,22 @@ GRAV:
- 'Petak'
- 'Subota'
- 'Nedjelja'
YES: "Da"
NO: "Ne"
CRON:
EVERY: svaki
EVERY_HOUR: svaki sat
EVERY_MINUTE: svake minute
EVERY_DAY_OF_WEEK: svaki dan u tjednu
EVERY_DAY_OF_MONTH: svaki dan u mjesecu
EVERY_MONTH: svaki mjesec
TEXT_PERIOD: Svakih <b />
TEXT_MINS: ' u <b /> minut(e) nakon sata'
TEXT_TIME: ' u <b />:<b />'
TEXT_DOW: ' na <b />'
TEXT_MONTH: ' <b />'
TEXT_DOM: ' na <b />'
ERROR1: Oznaka %s nije podržana!
ERROR2: Pogrešan broj elemenata.
ERROR3: jquery_element treba postaviti u postavke jqCron
ERROR4: Izraz nije prepoznat

View File

@@ -2,14 +2,14 @@
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitill: %1$s\n---\n\n# Villa: Ógilt efni á forsíðu\n\nSlóð: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- 'upplýsingar'
- 'rice'
- 'money'
- 'species'
- 'series'
- 'fish'
- 'sheep'
- ''
- ''
- ''
- ''
- ''
- ''
NICETIME:
NO_DATE_PROVIDED: Engin dagsetning gefin
BAD_DATE: Röng dagsetning

View File

@@ -1,12 +1,12 @@
---
GRAV:
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- ''
- '情報'
- 'rice'
- ''
- 'お金'
- 'species'
- 'series'
- ''
- ''
- '魚'
- 'ヒツジ'
INFLECTOR_IRREGULAR:

View File

@@ -1,11 +1,23 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# 오류: 무효의 Frontmatter\n\n경로: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_UNCOUNTABLE:
- '장비'
- '정보'
- ''
- ''
- ''
- '시리즈'
- '물고기'
- ''
INFLECTOR_IRREGULAR:
'person': '사람들'
NICETIME:
NO_DATE_PROVIDED: 제공된 날짜가 없습니다
BAD_DATE: 잘못된 날짜
AGO:
FROM_NOW:
JUST_NOW: 방금
SECOND:
MINUTE:
HOUR: 시간
@@ -40,6 +52,7 @@ GRAV:
VALIDATION_FAIL: '<b>유효성 검사 실패:</b>'
INVALID_INPUT: '잘못된 입력'
MISSING_REQUIRED_FIELD: '누락 된 필수 필드:'
XSS_ISSUES: "'%s' 필드에서 잠재적인 XSS 문제가 감지되었습니다."
MONTHS_OF_THE_YEAR:
- '일월'
- '이월'
@@ -61,3 +74,17 @@ GRAV:
- '금요일'
- '토요일'
- '일요일'
YES: "네"
NO: "아니요"
CRON:
EVERY: 모두
EVERY_HOUR: 매 시간
EVERY_MINUTE: 매 분
EVERY_DAY_OF_WEEK: 일주일간 매일
EVERY_DAY_OF_MONTH: 일개월간 매일
EVERY_MONTH: 매달
TEXT_PERIOD: 모든 <b />
ERROR1: '%s 태그는 지원되지 않습니다. '
ERROR2: 잘못된 요소 수
ERROR3: jquery_element는 jqCron 설정에서 설정할 수 있습니다.
ERROR4: 인식할 수 없는 표현

View File

@@ -2,8 +2,8 @@
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Klaida: klaidinga įžanginė konfigūracija\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n %4$s\n```"
INFLECTOR_UNCOUNTABLE:
- 'equipment'
- 'information'
- ''
- ''
- 'ryžiai'
- 'pinigai'
- 'prieskoniai'

84
system/languages/lv.yaml Normal file
View File

@@ -0,0 +1,84 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nNosaukums: %1$s\n---\n\n# Kļūda: Nederīgs Frontmatter\n\nCeļš: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_ORDINALS:
'default': '.'
'first': '.'
'second': '.'
'third': '.'
NICETIME:
NO_DATE_PROVIDED: Nav norādīts datums
BAD_DATE: Nederīgs datums
AGO: iepriekš
FROM_NOW: no šī brīža
JUST_NOW: tikko
SECOND: sekundes
MINUTE: minūte
HOUR: stunda
DAY: diena
WEEK: nedēļa
MONTH: mēnesis
YEAR: gads
DECADE: dekāde
SEC: s
MIN: m
HR: st
WK: ned
MO: mēn.
YR: g.
DEC: dec
SECOND_PLURAL: sekundes
MINUTE_PLURAL: minūtes
HOUR_PLURAL: stundas
DAY_PLURAL: dienas
WEEK_PLURAL: nedēļas
MONTH_PLURAL: mēneši
YEAR_PLURAL: gadi
DECADE_PLURAL: desmitgades
SEC_PLURAL: s
MIN_PLURAL: m
HR_PLURAL: st.
WK_PLURAL: ned.
MO_PLURAL: mēn.
YR_PLURAL: g.
DEC_PLURAL: d
FORM:
VALIDATION_FAIL: '<b>Validācija neizdevās:</b>'
INVALID_INPUT: 'Nederīga ievade'
MISSING_REQUIRED_FIELD: 'Laukā trūkst datu'
XSS_ISSUES: "Atrastas iespējamas XSS problēmas laukā '%s'"
MONTHS_OF_THE_YEAR:
- 'Janvāris'
- 'Februāris'
- 'Marts'
- 'Aprīlis'
- 'Maijs'
- 'Jūnijs'
- 'Jūlijs'
- 'Augusts'
- 'Septembris'
- 'Oktobris'
- 'Novembris'
- 'Decembris'
DAYS_OF_THE_WEEK:
- 'Pirmdiena'
- 'Otrdiena'
- 'Trešdiena'
- 'Ceturtdiena'
- 'Piektdiena'
- 'Sestdiena'
- 'Svētdiena'
YES: "Jā"
NO: "Nē"
CRON:
EVERY: katru
EVERY_HOUR: katru stundu
EVERY_MINUTE: katru minūti
EVERY_DAY_OF_WEEK: katru nedēļas dienu
EVERY_DAY_OF_MONTH: katru mēneša dienu
EVERY_MONTH: katru mēnesi
TEXT_PERIOD: Katru <b />
ERROR1: Marķieris %s nav atbalstīts!
ERROR2: Nederīgs elementu skaits
ERROR3: jquery_element nevajadzētu definēt jqCron iestatījumos
ERROR4: Neatpazīta izteiksme

147
system/languages/my.yaml Normal file
View File

@@ -0,0 +1,147 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nခေါင်းစဥ်: %1$s\n---\n\n# အမှား - Frontmatter မမှန်ကန်ပါ\n\nလမ်းကြောင်း `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'
'/([m|l])ouse$/i': '\1ice'
'/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(x|ch|ss|sh)$/i': '\1es'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([^aeiouy]|qu)y$/i': '\1ies'
'/(hive)$/i': '\1s'
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
'/sis$/i': 'ses'
'/([ti])um$/i': '\1a'
'/(buffal|tomat)o$/i': '\1oes'
'/(bu)s$/i': '\1ses'
'/(alias|status)/i': '\1es'
'/(octop|vir)us$/i': '\1i'
'/(ax|test)is$/i': '\1es'
'/s$/i': 's'
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'ကိရိယာ'
- 'အချက်အလက်'
- 'ဆန်'
- 'ငွေ'
- 'မျိုးစိတ်'
- 'အတွဲများ'
- 'ငါး'
- 'သိုးများ'
INFLECTOR_IRREGULAR:
'person': 'လူ'
'man': 'ယောက်ျား'
'child': 'ကလေးများ'
'sex': 'လိင်'
'move': 'ရွှေ့ခြင်း'
INFLECTOR_ORDINALS:
'default': 'th'
'first': 'st'
'second': 'nd'
'third': 'rd'
NICETIME:
NO_DATE_PROVIDED: နေ့စွဲ မသတ်မှတ်ထား
BAD_DATE: ရက်စွဲမမှန်ပါ
AGO: လွန်ခဲ့တဲ့
FROM_NOW: ယခုမှ
JUST_NOW: အခုပဲ
SECOND: ဒုတိယ
MINUTE: မိနစ်
HOUR: နာရီ
DAY: နေ့
WEEK: တစ်ပတ်
MONTH:
YEAR: နှစ်
DECADE: ဆယ်စုနှစ်
SEC: စက္ကန့်
MIN: မိနစ်
HR: နာရီ
WK: တစ်ပတ်
MO:
YR: နှစ်
DEC: ဒီဇင်ဘာ
SECOND_PLURAL: စက္ကန့်
MINUTE_PLURAL: မိနစ်
HOUR_PLURAL: နာရီ
DAY_PLURAL: နေ့
WEEK_PLURAL: ရက်သတ္တပတ်
MONTH_PLURAL:
YEAR_PLURAL: နှစ်
DECADE_PLURAL: ဆယ်စုနှစ်များစွ
SEC_PLURAL: စက္ကန့်
MIN_PLURAL: မိနစ်
HR_PLURAL: နာရီ
WK_PLURAL: အပတ်
MO_PLURAL:
YR_PLURAL: နှစ်
DEC_PLURAL: ဆယ်စုနှစ်
FORM:
VALIDATION_FAIL: '<b> အတည်ပြုခြင်းမအောင်မြင်ပါ: </b>'
INVALID_INPUT: 'ထည့်သွင်းမှုမမှန်ပါ'
MISSING_REQUIRED_FIELD: 'လိုအပ်သောအကွက်ပျောက်နေသည်'
XSS_ISSUES: "XSS ပြဿနာ ဖြစ်နိုင်ချေ ကို '%s' အကွက်တွင် တွေ့"
MONTHS_OF_THE_YEAR:
- 'ဇန်နဝါရီ'
- 'ဖေဖော်ဝါရီ'
- 'မတ်'
- 'ဧပြီ'
- 'မေ'
- 'ဇွန်'
- 'ဇူလိုင်'
- 'သြဂုတ်'
- 'စက်တင်ဘာ'
- 'အောက်တိုဘာ'
- 'နိုဝင်ဘာ'
- 'ဒီဇင်ဘာ'
DAYS_OF_THE_WEEK:
- 'တနင်္လာ'
- ' အင်္ဂါ'
- 'ဗုဒ္ဓဟူး'
- 'ကြာသပတေး'
- 'သောကြာ'
- 'စနေ'
- 'တနင်္ဂနွေ'
YES: "လုပ်"
NO: "မလုပ်"
CRON:
EVERY: အမြဲတမ်း
EVERY_HOUR: နာရီတိုင်း
EVERY_MINUTE: မိနစ်တိုင်း
EVERY_DAY_OF_WEEK: တစ်ပတ်လုံး နေ့တိုင်း
EVERY_DAY_OF_MONTH: တစ်လလုံး နေ့တိုင်း
EVERY_MONTH: လစဉ်လတိုင်း
TEXT_PERIOD: </b>တိုင်း
TEXT_MINS: 'နာရီ ကျော်ပြီး <b /> မိနစ် တွင်'
TEXT_TIME: ' <b />:<b /> တွင် '
TEXT_DOW: '<b /> ပေါ်တွင် '
TEXT_MONTH: '<b />၏ '
TEXT_DOM: '<b /> တွင် '
ERROR1: ဤ %s တက် ကိုပံ့ပိုးမထားပါ။
ERROR2: လိုအပ်သောထည့်သွင်း နာပတ် အမှားဖြစ်နေသည်
ERROR3: jquery_element ကို jqCron ဆက်တင် တွင်ထားရမည်
ERROR4: အသိအမှတ်မပြုသော အသုံးအနှုန်း

View File

@@ -104,6 +104,7 @@ GRAV:
VALIDATION_FAIL: '<b>Validatie mislukt:</b>'
INVALID_INPUT: 'Ongeldige invoer in'
MISSING_REQUIRED_FIELD: 'Ontbrekend verplicht veld:'
XSS_ISSUES: "Mogelijke XSS-problemen ontdekt in '%s' veld"
MONTHS_OF_THE_YEAR:
- 'Januari'
- 'Februari'
@@ -125,6 +126,8 @@ GRAV:
- 'Vrijdag'
- 'Zaterdag'
- 'Zondag'
YES: "Ja"
NO: "Nee"
CRON:
EVERY: elke
EVERY_HOUR: elk uur

View File

@@ -6,10 +6,10 @@ GRAV:
INFLECTOR_UNCOUNTABLE:
- 'wyposażenie'
- 'informacja'
- 'rice'
- ''
- 'pieniądze'
- 'species'
- 'series'
- ''
- ''
- 'ryba'
- 'owca'
INFLECTOR_IRREGULAR:

View File

@@ -67,7 +67,7 @@ GRAV:
NICETIME:
NO_DATE_PROVIDED: Nenhuma data fornecida
BAD_DATE: Data inválida
AGO: atrás
AGO:
FROM_NOW: a partir de agora
JUST_NOW: mesmo agora
SECOND: segundo

View File

@@ -1,6 +1,16 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Ошибка: недопустимое содержимое Frontmatter\n\nПуть: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_SINGULAR:
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': "\\1\n"
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
INFLECTOR_UNCOUNTABLE:
- 'экипировка'
- 'информация'

View File

@@ -1,9 +1,120 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nමාතෘකාව: %1$s\n---\n\n# දෝෂය: වලංගු නොවන ඉදිරිපස\n\nමාර්ගය: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/([m|l])ouse$/i': '\1අයිස්'
'/(matr|vert|ind)ix|ex$/i': '\1අයිස්'
'/(?:([^f])fe|([lr])f)$/i': '\1\2වෙස්'
'/([ti])um$/i': '\1අ'
'/(buffal|tomat)o$/i': '\1ඕඑස්'
'/(bu)s$/i': '\1සෙස්'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1 අප'
'/(cris|ax|test)es$/i': '\1 වේ'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1 භාවිතා කරන්න'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ඕවී'
'/(s)eries$/i': '\1මාලා'
'/(^analy)ses$/i': '\1සිස්'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2සිස්'
'/([ti])a$/i': '\1ම්'
INFLECTOR_UNCOUNTABLE:
- 'උපකරණ'
- 'විස්තර'
- 'සහල්'
- 'මුදල'
- 'විශේෂ'
- 'මාලාවක්'
- 'මාළු'
- 'බැටළුවන්'
INFLECTOR_IRREGULAR:
'person': 'මහජන'
'man': 'මිනිසුන්'
'child': 'දරුවන්'
'sex': 'ලිංගිකත්වය'
'move': 'චලනය කරයි'
INFLECTOR_ORDINALS:
'first': 'ශාන්ත'
NICETIME:
NO_DATE_PROVIDED: දිනයක් සපයා නැත
BAD_DATE: නරක දිනය
AGO: පෙර
FROM_NOW: මෙතැන් සිට
JUST_NOW: මේ දැන්
SECOND: දෙවැනි
MINUTE: මිනිත්තුව
HOUR: පැය
DAY: දින
WEEK: සතිය
MONTH: මස
YEAR: වර්ෂය
DECADE: දශකය
SEC: තත්පර
MIN: මිනි
HR: පැය
YR: වසර
DEC: දෙසැ
SECOND_PLURAL: තත්පර
MINUTE_PLURAL: මිනිත්තු
HOUR_PLURAL: පැය
DAY_PLURAL: දින
WEEK_PLURAL: සති
MONTH_PLURAL: මාස
YEAR_PLURAL: වසර
DECADE_PLURAL: දශක
SEC_PLURAL: තත්පර
MIN_PLURAL: මිනිත්තු
HR_PLURAL: පැය
WK_PLURAL: සති
YR_PLURAL: වසර
DEC_PLURAL: දෙසැ
FORM:
VALIDATION_FAIL: '<b>වලංගු කිරීම අසාර්ථක විය:</b>'
INVALID_INPUT: 'වලංගු නොවන ආදානය'
MISSING_REQUIRED_FIELD: 'අවශ්‍ය ක්ෂේත්‍රය අස්ථානගත වී ඇත:'
XSS_ISSUES: "විභව XSS ගැටළු '%s' ක්ෂේත්‍රයේ අනාවරණය විය"
MONTHS_OF_THE_YEAR:
- 'ජනවාරි'
- 'පෙබරවාරි'
- 'මාර්තු'
- 'අප්රේල්'
- 'මැයි'
- 'ජූනි'
- 'ජුලි'
- 'අගෝස්තු'
- 'සැප්තැම්බර්'
- 'ඔක්තෝම්බර්'
- 'නොවැම්බර්'
- 'දෙසැම්බර්'
DAYS_OF_THE_WEEK:
- 'සඳුදා'
- 'අඟහරුවාදා'
- 'බදාදා'
- 'බ්රහස්පතින්දා'
- 'සිකුරාදා'
- 'සෙනසුරාදා'
- 'ඉරිදා'
YES: "ඔව්"
NO: "නැත"
CRON:
EVERY: සෑම
EVERY_HOUR: සෑම පැයකටම
EVERY_MINUTE: සෑම විනාඩියකටම
EVERY_DAY_OF_WEEK: සතියේ සෑම දිනකම
EVERY_DAY_OF_MONTH: මාසයේ සෑම දිනකම
EVERY_MONTH: සෑම මාසයකම
TEXT_PERIOD: සෑම <b />
TEXT_MINS: ' පැයට පසු විනාඩි <b /> කින්'
TEXT_TIME: ' <b />:<b />ට'
TEXT_DOW: ' <b />මත'
TEXT_MONTH: ' <b />'
TEXT_DOM: ' <b />මත'
ERROR1: ටැගය %s සහාය නොදක්වයි!
ERROR2: නරක මූලද්රව්ය සංඛ්යාව
ERROR3: jquery_element jqCron සැකසුම් වලට සැකසිය යුතුය
ERROR4: හඳුනා නොගත් ප්‍රකාශනය

View File

@@ -1,6 +1,17 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Napaka: Neveljavna Frontmatter\n\nPath: `%2$s`\n\n**%3$s ** \n\n```\n%4$s \n```"
INFLECTOR_UNCOUNTABLE:
- 'oprema'
- 'informacija'
- 'riž'
- 'denar'
- 'vrste'
- 'serija'
- 'riba'
- 'ovca'
INFLECTOR_IRREGULAR:
'person': 'ljudje'
NICETIME:
NO_DATE_PROVIDED: Datum ni na voljo
BAD_DATE: Neveljaven datum
@@ -43,15 +54,15 @@ GRAV:
- 'Januar'
- 'Februar'
- 'Marec'
- 'April'
- 'april'
- 'Maj'
- 'Junij'
- 'Julij'
- 'Avgust'
- 'September'
- 'september'
- 'Oktober'
- 'November'
- 'December'
- 'november'
- 'december'
DAYS_OF_THE_WEEK:
- 'Ponedeljek'
- 'Torek'
@@ -60,3 +71,15 @@ GRAV:
- 'Petek'
- 'Sobota'
- 'Nedelja'
YES: "Da"
NO: "Ne"
CRON:
EVERY: vsak
EVERY_HOUR: vsako uro
EVERY_MINUTE: vsako minuto
EVERY_DAY_OF_WEEK: vsak dan v tednu
EVERY_DAY_OF_MONTH: vsak dan v mesecu
EVERY_MONTH: vsak mesec
ERROR1: Oznaka %s ni podprta!
ERROR2: Napačno število elementov.
ERROR4: Neznan izraz

View File

@@ -104,6 +104,7 @@ GRAV:
VALIDATION_FAIL: '<b>Провера неуспела:</b>'
INVALID_INPUT: 'Неисправан унос у'
MISSING_REQUIRED_FIELD: 'Недостаје обавезн поље:'
XSS_ISSUES: "Потенцијална грешка у XSS-у детектована у пољу '%s' "
MONTHS_OF_THE_YEAR:
- 'Јануар'
- 'Фебруар'
@@ -125,6 +126,8 @@ GRAV:
- 'Петак'
- 'Субота'
- 'Недеља'
YES: "Да"
NO: "Не"
CRON:
EVERY: сваки
EVERY_HOUR: сваки сат

147
system/languages/sw.yaml Normal file
View File

@@ -0,0 +1,147 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nkichwa: %1$s\n---\n\n# Kosa: Mbele ya Mbele\n\nNjia: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'
'/([m|l])ouse$/i': '\1ice'
'/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(x|ch|ss|sh)$/i': '\1es'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([^aeiouy]|qu)y$/i': '\1ies'
'/(hive)$/i': '\1s'
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
'/sis$/i': 'ses'
'/([ti])um$/i': '\1a'
'/(buffal|tomat)o$/i': '\1oes'
'/(bu)s$/i': '\1ses'
'/(alias|status)/i': '\1es'
'/(octop|vir)us$/i': '\1i'
'/(ax|test)is$/i': '\1es'
'/s$/i': 's'
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'vifaa'
- 'habari'
- 'mchele'
- 'pesa'
- 'spishi'
- 'mfululizo'
- 'samaki'
- 'kondoo'
INFLECTOR_IRREGULAR:
'person': 'watu'
'man': 'wanaume'
'child': 'watoto'
'sex': 'jinsia'
'move': 'songa'
INFLECTOR_ORDINALS:
'default': 'th'
'first': 'st'
'second': 'nd'
'third': 'rd'
NICETIME:
NO_DATE_PROVIDED: Hakuna tarehe iliyotolewa
BAD_DATE: Tarehe mbaya
AGO: zilizopita
FROM_NOW: kuanzia sasa
JUST_NOW: sasa hivi
SECOND: pili
MINUTE: dakika
HOUR: saa
DAY: siku
WEEK: wiki
MONTH: mwezi
YEAR: mwaka
DECADE: muongo
SEC: sec
MIN: min
HR: hr
WK: wk
MO: mo
YR: yr
DEC: dec
SECOND_PLURAL: sekunde
MINUTE_PLURAL: dakika
HOUR_PLURAL: masaa
DAY_PLURAL: siku
WEEK_PLURAL: wiki
MONTH_PLURAL: miezi
YEAR_PLURAL: miaka
DECADE_PLURAL: miongo
SEC_PLURAL: secs
MIN_PLURAL: mins
HR_PLURAL: hrs
WK_PLURAL: wks
MO_PLURAL: mos
YR_PLURAL: yrs
DEC_PLURAL: decs
FORM:
VALIDATION_FAIL: '<b> Uthibitishaji umeshindwa: </b>'
INVALID_INPUT: 'Ingizo batili katika'
MISSING_REQUIRED_FIELD: 'Sehemu inayokosekana inahitajika:'
XSS_ISSUES: "Masuala yanayowezekana ya XSS yamegunduliwa katika uwanja wa '% s"
MONTHS_OF_THE_YEAR:
- 'Januari'
- 'Februari'
- 'Machi'
- 'Aprili'
- 'Mei'
- 'Juni'
- 'Julai'
- 'Agosti'
- 'Septemba'
- 'Oktoba'
- 'Novemba'
- 'Desemba'
DAYS_OF_THE_WEEK:
- 'Jumatatu'
- 'Jumanne'
- 'Jumatano'
- 'Alhamisi'
- 'Ijumaa'
- 'Jumamosi'
- 'Jumapili'
YES: "Ndiyo"
NO: "Hapana"
CRON:
EVERY: kila
EVERY_HOUR: kila saa
EVERY_MINUTE: kila dakika
EVERY_DAY_OF_WEEK: kila siku ya juma
EVERY_DAY_OF_MONTH: kila siku ya mwezi
EVERY_MONTH: kila mwezi
TEXT_PERIOD: Kila <b />
TEXT_MINS: ' saa <b /> dakika (saa) zilizopita saa'
TEXT_TIME: ' saa <b />: <b />'
TEXT_DOW: ' kwenye <b />'
TEXT_MONTH: ' ya <b />'
TEXT_DOM: ' kwenye <b />'
ERROR1: Lebo% s haitumiki!
ERROR2: Idadi mbaya ya vitu
ERROR3: Jquery_element inapaswa kuwekwa kwenye mipangilio ya jqCron
ERROR4: Maneno yasiyotambulika

View File

@@ -1,11 +1,75 @@
---
GRAV:
FRONTMATTER_ERROR_PAGE: "---\nชื่อเรื่อง: %1$s\n---\n\n# ข้อผิดพลาด: Invalid Frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Error: Invalid Frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
INFLECTOR_PLURALS:
'/(quiz)$/i': '\1zes'
'/^(ox)$/i': '\1en'
'/([m|l])ouse$/i': '\1ice'
'/(matr|vert|ind)ix|ex$/i': '\1ices'
'/(x|ch|ss|sh)$/i': '\1es'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([^aeiouy]|qu)y$/i': '\1ies'
'/(hive)$/i': '\1s'
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
'/sis$/i': 'ses'
'/([ti])um$/i': '\1a'
'/(buffal|tomat)o$/i': '\1oes'
'/(bu)s$/i': '\1ses'
'/(alias|status)/i': '\1es'
'/(octop|vir)us$/i': '\1i'
'/(ax|test)is$/i': '\1es'
'/s$/i': 's'
'/$/': 's'
INFLECTOR_SINGULAR:
'/(quiz)zes$/i': '\1'
'/(matr)ices$/i': '\1ix'
'/(vert|ind)ices$/i': '\1ex'
'/^(ox)en/i': '\1'
'/(alias|status)es$/i': '\1'
'/([octop|vir])i$/i': '\1us'
'/(cris|ax|test)es$/i': '\1is'
'/(shoe)s$/i': '\1'
'/(o)es$/i': '\1'
'/(bus)es$/i': '\1'
'/([m|l])ice$/i': '\1ouse'
'/(x|ch|ss|sh)es$/i': '\1'
'/(m)ovies$/i': '\1ovie'
'/(s)eries$/i': '\1eries'
'/([^aeiouy]|qu)ies$/i': '\1y'
'/([lr])ves$/i': '\1f'
'/(tive)s$/i': '\1'
'/(hive)s$/i': '\1'
'/([^f])ves$/i': '\1fe'
'/(^analy)ses$/i': '\1sis'
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
'/([ti])a$/i': '\1um'
'/(n)ews$/i': '\1ews'
INFLECTOR_UNCOUNTABLE:
- 'อุปกรณ์'
- 'ข้อมูล'
- 'ข้าว'
- 'เงิน'
- 'สายพันธุ์'
- 'ซีรีส์'
- 'ปลา'
- 'แกะ'
INFLECTOR_IRREGULAR:
'person': 'คน'
'man': 'ผู้ชาย'
'child': 'เด็กเด็ก'
'sex': 'เพศ'
'move': 'ย้าย'
INFLECTOR_ORDINALS:
'default': 'th'
'first': 'st'
'second': 'nd'
'third': 'rd'
NICETIME:
NO_DATE_PROVIDED: ไม่มีวันที่ให้
BAD_DATE: รูปแบบวันที่ผิด
AGO: ที่ผ่านมา
FROM_NOW: จากตอนนี้
JUST_NOW: เมื่อกี้
SECOND: วินาที
MINUTE: นาที
HOUR: ชั่วโมง
@@ -17,6 +81,10 @@ GRAV:
SEC: วิ
MIN: นาที
HR: ชม.
WK: wk
MO: mo
YR: yr
DEC: dec
SECOND_PLURAL: วินาที
MINUTE_PLURAL: นาที
HOUR_PLURAL: ชั่วโมง
@@ -28,11 +96,15 @@ GRAV:
SEC_PLURAL: วินาที
MIN_PLURAL: นาที
HR_PLURAL: ชั่วโมง
WK_PLURAL: wks
MO_PLURAL: mos
YR_PLURAL: ปี
DEC_PLURAL: decs
FORM:
VALIDATION_FAIL: '<b>ตรวจสอบล้มเหลว: </b>'
INVALID_INPUT: 'ป้อนข้อมูลไม่ถูกต้องใน'
MISSING_REQUIRED_FIELD: 'ขาดข้อมูลที่จำเป็น:'
XSS_ISSUES: "ตรวจพบปัญหา XSS ที่เป็นไปได้ในฟิลด์ '%s'"
MONTHS_OF_THE_YEAR:
- 'มกราคม'
- 'กุมภาพันธ์'
@@ -54,3 +126,22 @@ GRAV:
- 'ศุกร์'
- 'เสาร์'
- 'อาทิตย์'
YES: "ใช่"
NO: "ไม่"
CRON:
EVERY: ทุก ๆ
EVERY_HOUR: ทุกชั่วโมง
EVERY_MINUTE: ทุกนาที
EVERY_DAY_OF_WEEK: ทุกวันในสัปดาห์
EVERY_DAY_OF_MONTH: ทุกวันของเดือน
EVERY_MONTH: ทุกเดือน
TEXT_PERIOD: ทุก ๆ <b />
TEXT_MINS: ' ที่ <b /> นาทีที่ผ่านไปแล้ว'
TEXT_TIME: ' เวลา <b />:<b />'
TEXT_DOW: ' บน <b />'
TEXT_MONTH: ' จาก <b />'
TEXT_DOM: ' บน <b />'
ERROR1: ไม่รองรับแท็ก %s!
ERROR2: จำนวนองค์ประกอบไม่ดี
ERROR3: ควรตั้งค่า jquery_element เป็นการตั้งค่า jqCron
ERROR4: นิพจน์ที่ไม่รู้จัก

View File

@@ -125,6 +125,8 @@ GRAV:
- '星期五'
- '星期六'
- '星期日'
YES: "是"
NO: "否"
CRON:
EVERY: 每隔
EVERY_HOUR: 每小时

View File

@@ -62,6 +62,8 @@ GRAV:
- '星期五'
- '星期六'
- '星期日'
YES: "是"
NO: "否"
CRON:
EVERY:
EVERY_HOUR: 每小時

View File

@@ -125,6 +125,8 @@ GRAV:
- '星期五'
- '星期六'
- '星期日'
YES: "是"
NO: "否"
CRON:
EVERY: 每隔
EVERY_HOUR: 每小时

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Core
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -398,6 +398,9 @@ class Assets extends PropertyObject
if ($key === 'position' && $value === 'pipeline') {
$type = $asset->getType();
if ($type === 'jsmodule') {
$type = 'js_module';
}
if ($asset->getRemote() && $this->{strtolower($type) . '_pipeline_include_externals'} === false && $asset['position'] === 'pipeline') {
if ($this->{strtolower($type) . '_pipeline_before_excludes'}) {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets\Traits
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets\Traits
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Assets\Traits
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Backup
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -218,7 +218,7 @@ class Backups
if ($locator->isStream($backup_root)) {
$backup_root = $locator->findResource($backup_root);
} else {
$backup_root = rtrim(GRAV_ROOT . $backup_root, '/');
$backup_root = rtrim(GRAV_ROOT . $backup_root, DS) ?: DS;
}
if (!$backup_root || !file_exists($backup_root)) {

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -170,24 +170,75 @@ class Cache extends Getters
}
/**
* Deletes the old out of date file-based caches
* Deletes old cache files based on age
*
* @return int
*/
public function purgeOldCache()
{
// Get the max age for cache files from config (default 30 days)
$max_age_days = $this->config->get('system.cache.purge_max_age_days', 30);
$max_age_seconds = $max_age_days * 86400; // Convert days to seconds
$now = time();
$count = 0;
// First, clean up old orphaned cache directories (not the current one)
$cache_dir = dirname($this->cache_dir);
$current = Utils::basename($this->cache_dir);
$count = 0;
foreach (new DirectoryIterator($cache_dir) as $file) {
$dir = $file->getBasename();
if ($dir === $current || $file->isDot() || $file->isFile()) {
continue;
}
Folder::delete($file->getPathname());
$count++;
// Check if directory is old and empty or very old (90+ days)
$dir_age = $now - $file->getMTime();
if ($dir_age > 7776000) { // 90 days
Folder::delete($file->getPathname());
$count++;
}
}
// Now clean up old cache files within the current cache directory
if (is_dir($this->cache_dir)) {
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($this->cache_dir, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$file_age = $now - $file->getMTime();
if ($file_age > $max_age_seconds) {
@unlink($file->getPathname());
$count++;
}
}
}
}
// Also clean up old files in compiled cache
$grav = Grav::instance();
$compiled_dir = $this->config->get('system.cache.compiled_dir', 'cache://compiled');
$compiled_path = $grav['locator']->findResource($compiled_dir, true);
if ($compiled_path && is_dir($compiled_path)) {
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($compiled_path, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $file) {
if ($file->isFile()) {
$file_age = $now - $file->getMTime();
// Compiled files can be kept longer (60 days)
if ($file_age > ($max_age_seconds * 2)) {
@unlink($file->getPathname());
$count++;
}
}
}
}
return $count;
@@ -632,8 +683,10 @@ class Cache extends Getters
{
/** @var Cache $cache */
$cache = Grav::instance()['cache'];
$deleted_folders = $cache->purgeOldCache();
$msg = 'Purged ' . $deleted_folders . ' old cache folders...';
$deleted_items = $cache->purgeOldCache();
$max_age = $cache->config->get('system.cache.purge_max_age_days', 30);
$msg = 'Purged ' . $deleted_items . ' old cache items (files older than ' . $max_age . ' days)';
if ($echo) {
echo $msg;

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Config
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -196,6 +196,38 @@ class BlueprintSchema extends BlueprintSchemaBase implements ExportInterface
$messages += Validation::validate($child, $rule);
if (isset($rule['validate']['match']) || isset($rule['validate']['match_exact']) || isset($rule['validate']['match_any'])) {
$ruleKey = current(array_intersect(['match', 'match_exact', 'match_any'], array_keys($rule['validate'])));
$otherKey = $rule['validate'][$ruleKey] ?? null;
$otherVal = $data[$otherKey] ?? null;
$otherLabel = $this->items[$otherKey]['label'] ?? $otherKey;
$currentVal = $data[$key] ?? null;
$currentLabel = $this->items[$key]['label'] ?? $key;
// Determine comparison type (loose, strict, substring)
// Perform comparison:
$isValid = false;
if ($ruleKey === 'match') {
$isValid = ($currentVal == $otherVal);
} elseif ($ruleKey === 'match_exact') {
$isValid = ($currentVal === $otherVal);
} elseif ($ruleKey === 'match_any') {
// If strings:
if (is_string($currentVal) && is_string($otherVal)) {
$isValid = (strlen($currentVal) && strlen($otherVal) && (str_contains($currentVal,
$otherVal) || strpos($otherVal, $currentVal) !== false));
}
// If arrays:
if (is_array($currentVal) && is_array($otherVal)) {
$common = array_intersect($currentVal, $otherVal);
$isValid = !empty($common);
}
}
if (!$isValid) {
$messages[$rule['name']][] = sprintf(Grav::instance()['language']->translate('PLUGIN_FORM.VALIDATION_MATCH'), $currentLabel, $otherLabel);
}
}
} elseif (is_array($child) && is_array($val)) {
// Array has been defined in blueprints.
$messages += $this->validateArray($child, $val, $strict);

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -48,12 +48,14 @@ class Validation
}
$validate = (array)($field['validate'] ?? null);
$type = $validate['type'] ?? $field['type'];
$validate_type = $validate['type'] ?? null;
$required = $validate['required'] ?? false;
$type = $validate_type ?? $field['type'];
$required = $required && ($validate_type !== 'ignore');
// If value isn't required, we will stop validation if empty value is given.
if ($required !== true && ($value === null || $value === '' || (($field['type'] === 'checkbox' || $field['type'] === 'switch') && $value == false))
) {
if ($required !== true && ($value === null || $value === '' || empty($value) || (($field['type'] === 'checkbox' || $field['type'] === 'switch') && $value == false))) {
return [];
}
@@ -550,7 +552,7 @@ class Validation
$step = (float)$params['step'];
// Count of how many steps we are above/below the minimum value.
$pos = ($value - $min) / $step;
$pos = round($pos, 10);
return is_int(static::filterNumber($pos, $params, $field));
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Data
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -279,11 +279,7 @@ class Debugger
->withHeader('X-Clockwork-Id', $clockworkRequest->id)
->withHeader('X-Clockwork-Version', $clockwork::VERSION);
$grav = Grav::instance();
$basePath = $this->grav['base_url_relative'] . $grav['pages']->base();
if ($basePath) {
$response = $response->withHeader('X-Clockwork-Path', $basePath . '/__clockwork/');
}
$response = $response->withHeader('X-Clockwork-Path', Utils::url('/__clockwork/'));
return $response->withHeader('Server-Timing', ServerTiming::fromRequest($clockworkRequest)->value());
}
@@ -307,7 +303,7 @@ class Debugger
}
$id = $matches['id'] ?? null;
$direction = $matches['direction'] ?? null;
$direction = $matches['direction'] ?? 'latest';
$count = $matches['count'] ?? null;
$storage = $clockwork->getStorage();
@@ -316,7 +312,7 @@ class Debugger
$data = $storage->previous($id, $count);
} elseif ($direction === 'next') {
$data = $storage->next($id, $count);
} elseif ($id === 'latest') {
} elseif ($direction === 'latest' || $id === 'latest') {
$data = $storage->latest();
} else {
$data = $storage->find($id);
@@ -403,8 +399,16 @@ class Debugger
// Clockwork specific assets
if ($this->clockwork) {
$assets->addCss('/system/assets/debugger/clockwork.css', ['loading' => 'inline']);
$assets->addJs('/system/assets/debugger/clockwork.js', ['loading' => 'inline']);
if ($this->config->get('plugins.clockwork-web.enabled')) {
$route = Utils::url($this->grav['config']->get('plugins.clockwork-web.route'));
} else {
$route = 'https://github.com/getgrav/grav-plugin-clockwork-web';
}
$assets->addCss('/system/assets/debugger/clockwork.css');
$assets->addJs('/system/assets/debugger/clockwork.js', [
'id' => 'clockwork-script',
'data-route' => $route
]);
}

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Errors
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Errors
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Errors
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Errors
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\File
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\File
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\File
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\File
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -49,7 +49,7 @@ class RecursiveDirectoryFilterIterator extends RecursiveFilterIterator
*
* @return bool true if the current element is acceptable, otherwise false.
*/
public function accept()
public function accept() :bool
{
/** @var SplFileInfo $file */
$file = $this->current();
@@ -72,7 +72,7 @@ class RecursiveDirectoryFilterIterator extends RecursiveFilterIterator
/**
* @return RecursiveDirectoryFilterIterator|RecursiveFilterIterator
*/
public function getChildren()
public function getChildren() :RecursiveFilterIterator
{
/** @var RecursiveDirectoryFilterIterator $iterator */
$iterator = $this->getInnerIterator();

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -45,7 +45,7 @@ class RecursiveFolderFilterIterator extends \RecursiveFilterIterator
*
* @return bool true if the current element is acceptable, otherwise false.
*/
public function accept()
public function accept() :bool
{
/** @var SplFileInfo $current */
$current = $this->current();

View File

@@ -3,7 +3,7 @@
/**
* @package Grav\Common\Filesystem
*
* @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
* @copyright Copyright (c) 2015 - 2025 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
@@ -64,8 +64,21 @@ class ZipArchiver extends Archiver
}
$zip = new ZipArchive();
if (!$zip->open($this->archive_file, ZipArchive::CREATE)) {
throw new InvalidArgumentException('ZipArchiver:' . $this->archive_file . ' cannot be created...');
$result = $zip->open($this->archive_file, ZipArchive::CREATE);
if ($result !== true) {
$error = 'unknown error';
if ($result === ZipArchive::ER_NOENT) {
$error = 'file does not exist';
} elseif ($result === ZipArchive::ER_EXISTS) {
$error = 'file already exists';
} elseif ($result === ZipArchive::ER_OPEN) {
$error = 'cannot open file';
} elseif ($result === ZipArchive::ER_READ) {
$error = 'read error';
} elseif ($result === ZipArchive::ER_SEEK) {
$error = 'seek error';
}
throw new InvalidArgumentException('ZipArchiver: ' . $this->archive_file . ' cannot be created: ' . $error);
}
$files = $this->getArchiveFiles($rootPath);
@@ -112,8 +125,21 @@ class ZipArchiver extends Archiver
}
$zip = new ZipArchive();
if (!$zip->open($this->archive_file)) {
throw new InvalidArgumentException('ZipArchiver: ' . $this->archive_file . ' cannot be opened...');
$result = $zip->open($this->archive_file);
if ($result !== true) {
$error = 'unknown error';
if ($result === ZipArchive::ER_NOENT) {
$error = 'file does not exist';
} elseif ($result === ZipArchive::ER_EXISTS) {
$error = 'file already exists';
} elseif ($result === ZipArchive::ER_OPEN) {
$error = 'cannot open file';
} elseif ($result === ZipArchive::ER_READ) {
$error = 'read error';
} elseif ($result === ZipArchive::ER_SEEK) {
$error = 'seek error';
}
throw new InvalidArgumentException('ZipArchiver: ' . $this->archive_file . ' cannot be opened: ' . $error);
}
$status && $status([
@@ -122,7 +148,12 @@ class ZipArchiver extends Archiver
]);
foreach ($folders as $folder) {
$zip->addEmptyDir($folder);
if ($zip->addEmptyDir($folder) === false) {
$status && $status([
'type' => 'message',
'message' => 'Warning: Could not add empty directory: ' . $folder
]);
}
$status && $status([
'type' => 'progress',
]);

Some files were not shown because too many files have changed in this diff Show More