restored dashboard from usable
@@ -0,0 +1,54 @@
|
||||
div.phpdebugbar {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.phpdebugbar pre {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.phpdebugbar div.phpdebugbar-header > div > * {
|
||||
padding: 5px 15px;
|
||||
}
|
||||
|
||||
.phpdebugbar div.phpdebugbar-header > div.phpdebugbar-header-right > * {
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
.phpdebugbar div.phpdebugbar-header, .phpdebugbar a.phpdebugbar-restore-btn {
|
||||
background-image: url(grav.png);
|
||||
}
|
||||
|
||||
.phpdebugbar a.phpdebugbar-restore-btn {
|
||||
width: 13px;
|
||||
}
|
||||
|
||||
.phpdebugbar a.phpdebugbar-tab.phpdebugbar-active {
|
||||
background: #3DB9EC;
|
||||
color: #fff;
|
||||
margin-top: -1px;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.phpdebugbar .phpdebugbar-widgets-toolbar {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.phpdebugbar input[type=text] {
|
||||
padding: 0;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.phpdebugbar dl.phpdebugbar-widgets-varlist, ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label {
|
||||
font-family: "DejaVu Sans Mono", Menlo, Monaco, Consolas, Courier, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
ul.phpdebugbar-widgets-timeline li span.phpdebugbar-widgets-label {
|
||||
text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.phpdebugbar pre, .phpdebugbar code {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
After Width: | Height: | Size: 548 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,19 @@
|
||||
body header {
|
||||
background: #8552A2;
|
||||
}
|
||||
|
||||
body .left-panel {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
body .exc-title-primary {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
body .exc-title {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
body .frame:not(.active):hover {
|
||||
background: #e6e6e6;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
title: PLUGIN_ADMIN.MEDIA
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
@@ -0,0 +1,116 @@
|
||||
title: PLUGIN_ADMIN.SITE
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.DEFAULTS
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
title:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.SITE_TITLE
|
||||
size: large
|
||||
placeholder: PLUGIN_ADMIN.SITE_TITLE_PLACEHOLDER
|
||||
help: PLUGIN_ADMIN.SITE_TITLE_HELP
|
||||
|
||||
author.name:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.DEFAULT_AUTHOR
|
||||
help: PLUGIN_ADMIN.DEFAULT_AUTHOR_HELP
|
||||
|
||||
author.email:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.DEFAULT_EMAIL
|
||||
help: PLUGIN_ADMIN.DEFAULT_EMAIL_HELP
|
||||
validate:
|
||||
type: email
|
||||
|
||||
taxonomies:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.TAXONOMY_TYPES
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.TAXONOMY_TYPES_HELP
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
summary:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.PAGE_SUMMARY
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
summary.enabled:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ENABLED
|
||||
highlight: 1
|
||||
help: PLUGIN_ADMIN.ENABLED_HELP
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
summary.size:
|
||||
type: text
|
||||
size: x-small
|
||||
label: PLUGIN_ADMIN.SUMMARY_SIZE
|
||||
help: PLUGIN_ADMIN.SUMMARY_SIZE_HELP
|
||||
validate:
|
||||
type: int
|
||||
min: 0
|
||||
max: 65536
|
||||
|
||||
summary.format:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FORMAT
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.FORMAT_HELP
|
||||
highlight: short
|
||||
options:
|
||||
'short': PLUGIN_ADMIN.SHORT
|
||||
'long': PLUGIN_ADMIN.LONG
|
||||
|
||||
summary.delimiter:
|
||||
type: text
|
||||
size: x-small
|
||||
label: PLUGIN_ADMIN.DELIMITER
|
||||
help: PLUGIN_ADMIN.DELIMITER_HELP
|
||||
|
||||
metadata:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.METADATA
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
metadata:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.METADATA
|
||||
help: PLUGIN_ADMIN.METADATA_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.METADATA_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.METADATA_VALUE
|
||||
|
||||
routes:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.REDIRECTS_AND_ROUTES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
redirects:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.CUSTOM_REDIRECTS
|
||||
help: PLUGIN_ADMIN.CUSTOM_REDIRECTS_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.CUSTOM_REDIRECTS_PLACEHOLDER_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.CUSTOM_REDIRECTS_PLACEHOLDER_VALUE
|
||||
|
||||
routes:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.CUSTOM_ROUTES
|
||||
help: PLUGIN_ADMIN.CUSTOM_ROUTES_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.CUSTOM_ROUTES_PLACEHOLDER_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.CUSTOM_ROUTES_PLACEHOLDER_VALUE
|
||||
@@ -0,0 +1,7 @@
|
||||
title: PLUGIN_ADMIN.FILE_STREAMS
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
schemes.xxx:
|
||||
type: array
|
||||
@@ -0,0 +1,900 @@
|
||||
title: PLUGIN_ADMIN.SYSTEM
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
home.alias:
|
||||
type: pages
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.HOME_PAGE
|
||||
show_all: false
|
||||
show_modular: false
|
||||
show_root: false
|
||||
help: PLUGIN_ADMIN.HOME_PAGE_HELP
|
||||
|
||||
home.hide_in_urls:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.HIDE_HOME_IN_URLS
|
||||
help: PLUGIN_ADMIN.HIDE_HOME_IN_URLS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
pages.theme:
|
||||
type: themeselect
|
||||
classes: fancy
|
||||
selectize: true
|
||||
size: medium
|
||||
label: PLUGIN_ADMIN.DEFAULT_THEME
|
||||
help: PLUGIN_ADMIN.DEFAULT_THEME_HELP
|
||||
|
||||
pages.process:
|
||||
type: checkboxes
|
||||
label: PLUGIN_ADMIN.PROCESS
|
||||
help: PLUGIN_ADMIN.PROCESS_HELP
|
||||
default: [markdown: true, twig: true]
|
||||
options:
|
||||
markdown: Markdown
|
||||
twig: Twig
|
||||
use: keys
|
||||
|
||||
timezone:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.TIMEZONE
|
||||
size: medium
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.TIMEZONE_HELP
|
||||
'@data-options': '\Grav\Common\Utils::timezones'
|
||||
default: ''
|
||||
options:
|
||||
'': 'Default (Server Timezone)'
|
||||
|
||||
pages.dateformat.default:
|
||||
type: select
|
||||
size: medium
|
||||
selectize:
|
||||
create: true
|
||||
label: PLUGIN_ADMIN.DEFAULT_DATE_FORMAT
|
||||
help: PLUGIN_ADMIN.DEFAULT_DATE_FORMAT_HELP
|
||||
placeholder: PLUGIN_ADMIN.DEFAULT_DATE_FORMAT_PLACEHOLDER
|
||||
'@data-options': '\Grav\Common\Utils::dateFormats'
|
||||
options:
|
||||
"": Auto Guess or Enter Custom
|
||||
validate:
|
||||
type: string
|
||||
|
||||
pages.dateformat.short:
|
||||
type: dateformat
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.SHORT_DATE_FORMAT
|
||||
help: PLUGIN_ADMIN.SHORT_DATE_FORMAT_HELP
|
||||
default: "jS M Y"
|
||||
options:
|
||||
"F jS \\a\\t g:ia": Date1
|
||||
"l jS \\of F g:i A": Date2
|
||||
"D, d M Y G:i:s": Date3
|
||||
"d-m-y G:i": Date4
|
||||
"jS M Y": Date5
|
||||
|
||||
pages.dateformat.long:
|
||||
type: dateformat
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.LONG_DATE_FORMAT
|
||||
help: PLUGIN_ADMIN.LONG_DATE_FORMAT_HELP
|
||||
options:
|
||||
"F jS \\a\\t g:ia": Date1
|
||||
"l jS \\of F g:i A": Date2
|
||||
"D, d M Y G:i:s": Date3
|
||||
"d-m-y G:i": Date4
|
||||
"jS M Y": Date5
|
||||
|
||||
pages.order.by:
|
||||
type: select
|
||||
size: long
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.DEFAULT_ORDERING
|
||||
help: PLUGIN_ADMIN.DEFAULT_ORDERING_HELP
|
||||
options:
|
||||
default: PLUGIN_ADMIN.DEFAULT_ORDERING_DEFAULT
|
||||
folder: PLUGIN_ADMIN.DEFAULT_ORDERING_FOLDER
|
||||
title: PLUGIN_ADMIN.DEFAULT_ORDERING_TITLE
|
||||
date: PLUGIN_ADMIN.DEFAULT_ORDERING_DATE
|
||||
|
||||
pages.order.dir:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.DEFAULT_ORDER_DIRECTION
|
||||
highlight: asc
|
||||
default: desc
|
||||
help: PLUGIN_ADMIN.DEFAULT_ORDER_DIRECTION_HELP
|
||||
options:
|
||||
asc: PLUGIN_ADMIN.ASCENDING
|
||||
desc: PLUGIN_ADMIN.DESCENDING
|
||||
|
||||
pages.list.count:
|
||||
type: text
|
||||
size: x-small
|
||||
label: PLUGIN_ADMIN.DEFAULT_PAGE_COUNT
|
||||
help: PLUGIN_ADMIN.DEFAULT_PAGE_COUNT_HELP
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
|
||||
pages.publish_dates:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.DATE_BASED_PUBLISHING
|
||||
help: PLUGIN_ADMIN.DATE_BASED_PUBLISHING_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.events:
|
||||
type: checkboxes
|
||||
label: PLUGIN_ADMIN.EVENTS
|
||||
help: PLUGIN_ADMIN.EVENTS_HELP
|
||||
default: [page: true, twig: true]
|
||||
options:
|
||||
page: Page Events
|
||||
twig: Twig Events
|
||||
use: keys
|
||||
|
||||
pages.append_url_extension:
|
||||
type: text
|
||||
placeholder: "e.g. .html"
|
||||
label: PLUGIN_ADMIN.APPEND_URL_EXT
|
||||
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
|
||||
|
||||
pages.redirect_default_route:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE
|
||||
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_ROUTE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.redirect_default_code:
|
||||
type: select
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE
|
||||
help: PLUGIN_ADMIN.REDIRECT_DEFAULT_CODE_HELP
|
||||
options:
|
||||
301: 301 - Permanent
|
||||
303: 303 - Other
|
||||
307: 307 - Temporary
|
||||
|
||||
pages.redirect_trailing_slash:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH
|
||||
help: PLUGIN_ADMIN.REDIRECT_TRAILING_SLASH_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.ignore_hidden:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.IGNORE_HIDDEN
|
||||
help: PLUGIN_ADMIN.IGNORE_HIDDEN_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.ignore_files:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.IGNORE_FILES
|
||||
help: PLUGIN_ADMIN.IGNORE_FILES_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
pages.ignore_folders:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.IGNORE_FOLDERS
|
||||
help: PLUGIN_ADMIN.IGNORE_FOLDERS_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
pages.url_taxonomy_filters:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ALLOW_URL_TAXONOMY_FILTERS
|
||||
help: PLUGIN_ADMIN.ALLOW_URL_TAXONOMY_FILTERS_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.twig_first:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TWIG_FIRST
|
||||
highlight: asc
|
||||
default: desc
|
||||
help: PLUGIN_ADMIN.TWIG_FIRST_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.LANGUAGES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
|
||||
languages.supported:
|
||||
type: selectize
|
||||
size: large
|
||||
placeholder: "e.g. en, fr"
|
||||
label: PLUGIN_ADMIN.SUPPORTED
|
||||
help: PLUGIN_ADMIN.SUPPORTED_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
languages.include_default_lang:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.INCLUDE_DEFAULT_LANG
|
||||
help: PLUGIN_ADMIN.INCLUDE_DEFAULT_LANG_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
languages.translations:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TRANSLATIONS_ENABLED
|
||||
help: PLUGIN_ADMIN.TRANSLATIONS_ENABLED_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.translations_fallback:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TRANSLATIONS_FALLBACK
|
||||
help: PLUGIN_ADMIN.TRANSLATIONS_FALLBACK_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.session_store_active:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ACTIVE_LANGUAGE_IN_SESSION
|
||||
help: PLUGIN_ADMIN.ACTIVE_LANGUAGE_IN_SESSION_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.http_accept_language:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.HTTP_ACCEPT_LANGUAGE
|
||||
help: PLUGIN_ADMIN.HTTP_ACCEPT_LANGUAGE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.override_locale:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.OVERRIDE_LOCALE
|
||||
help: PLUGIN_ADMIN.OVERRIDE_LOCALE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
http_headers:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.HTTP_HEADERS
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.expires:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.EXPIRES
|
||||
help: PLUGIN_ADMIN.EXPIRES_HELP
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
pages.last_modified:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.LAST_MODIFIED
|
||||
help: PLUGIN_ADMIN.LAST_MODIFIED_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.etag:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ETAG
|
||||
help: PLUGIN_ADMIN.ETAG_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.vary_accept_encoding:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.VARY_ACCEPT_ENCODING
|
||||
help: PLUGIN_ADMIN.VARY_ACCEPT_ENCODING_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
markdown:
|
||||
type: section
|
||||
title: Markdown
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.markdown.extra:
|
||||
type: toggle
|
||||
label: Markdown extra
|
||||
help: PLUGIN_ADMIN.MARKDOWN_EXTRA_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.auto_line_breaks:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.AUTO_LINE_BREAKS
|
||||
help: PLUGIN_ADMIN.AUTO_LINE_BREAKS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.auto_url_links:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.AUTO_URL_LINKS
|
||||
help: PLUGIN_ADMIN.AUTO_URL_LINKS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.escape_markup:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ESCAPE_MARKUP
|
||||
help: PLUGIN_ADMIN.ESCAPE_MARKUP_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
caching:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.CACHING
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
cache.enabled:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.CACHING
|
||||
help: PLUGIN_ADMIN.CACHING_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
cache.check.method:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.CACHE_CHECK_METHOD
|
||||
help: PLUGIN_ADMIN.CACHE_CHECK_METHOD_HELP
|
||||
options:
|
||||
file: File
|
||||
folder: Folder
|
||||
none: None
|
||||
|
||||
cache.driver:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.CACHE_DRIVER
|
||||
help: PLUGIN_ADMIN.CACHE_DRIVER_HELP
|
||||
options:
|
||||
auto: Auto detect
|
||||
file: File
|
||||
apc: APC
|
||||
xcache: XCache
|
||||
memcache: MemCache
|
||||
wincache: WinCache
|
||||
|
||||
cache.prefix:
|
||||
type: text
|
||||
size: x-small
|
||||
label: PLUGIN_ADMIN.CACHE_PREFIX
|
||||
help: PLUGIN_ADMIN.CACHE_PREFIX_HELP
|
||||
placeholder: PLUGIN_ADMIN.CACHE_PREFIX_PLACEHOLDER
|
||||
|
||||
cache.lifetime:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.LIFETIME
|
||||
help: PLUGIN_ADMIN.LIFETIME_HELP
|
||||
validate:
|
||||
type: number
|
||||
|
||||
cache.gzip:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.GZIP_COMPRESSION
|
||||
help: PLUGIN_ADMIN.GZIP_COMPRESSION_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
twig:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.TWIG_TEMPLATING
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
twig.cache:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TWIG_CACHING
|
||||
help: PLUGIN_ADMIN.TWIG_CACHING_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.debug:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TWIG_DEBUG
|
||||
help: PLUGIN_ADMIN.TWIG_DEBUG_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.auto_reload:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.DETECT_CHANGES
|
||||
help: PLUGIN_ADMIN.DETECT_CHANGES_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.autoescape:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.AUTOESCAPE_VARIABLES
|
||||
help: PLUGIN_ADMIN.AUTOESCAPE_VARIABLES_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig.umask_fix:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.TWIG_UMASK_FIX
|
||||
help: PLUGIN_ADMIN.TWIG_UMASK_FIX_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ASSETS
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
assets.css_pipeline:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.CSS_PIPELINE
|
||||
help: PLUGIN_ADMIN.CSS_PIPELINE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.css_minify:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.CSS_MINIFY
|
||||
help: PLUGIN_ADMIN.CSS_MINIFY_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.css_minify_windows:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.CSS_MINIFY_WINDOWS_OVERRIDE
|
||||
help: PLUGIN_ADMIN.CSS_MINIFY_WINDOWS_OVERRIDE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.css_rewrite:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.CSS_REWRITE
|
||||
help: PLUGIN_ADMIN.CSS_REWRITE_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.js_pipeline:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE
|
||||
help: PLUGIN_ADMIN.JAVASCRIPT_PIPELINE_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.js_minify:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.JAVASCRIPT_MINIFY
|
||||
help: PLUGIN_ADMIN.JAVASCRIPT_MINIFY_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.enable_asset_timestamp:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ENABLED_TIMESTAMPS_ON_ASSETS
|
||||
help: PLUGIN_ADMIN.ENABLED_TIMESTAMPS_ON_ASSETS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.collections:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.COLLECTIONS
|
||||
placeholder_key: collection_name
|
||||
placeholder_value: collection_path
|
||||
|
||||
errors:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ERROR_HANDLER
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
errors.display:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.DISPLAY_ERRORS
|
||||
help: PLUGIN_ADMIN.DISPLAY_ERRORS_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
errors.log:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.LOG_ERRORS
|
||||
help: PLUGIN_ADMIN.LOG_ERRORS_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.DEBUGGER
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
debugger.enabled:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.DEBUGGER
|
||||
help: PLUGIN_ADMIN.DEBUGGER_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger.shutdown.close_connection:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.SHUTDOWN_CLOSE_CONNECTION
|
||||
help: PLUGIN_ADMIN.SHUTDOWN_CLOSE_CONNECTION_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
media:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.MEDIA
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
images.default_image_quality:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.DEFAULT_IMAGE_QUALITY
|
||||
help: PLUGIN_ADMIN.DEFAULT_IMAGE_QUALITY_HELP
|
||||
classes: x-small
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
max: 100
|
||||
|
||||
images.cache_all:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.CACHE_ALL
|
||||
help: PLUGIN_ADMIN.CACHE_ALL_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
images.cache_perms:
|
||||
type: select
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.CACHE_PERMS
|
||||
help: PLUGIN_ADMIN.CACHE_PERMS_HELP
|
||||
highlight: '0755'
|
||||
options:
|
||||
'0755': '0755'
|
||||
'0775': '0775'
|
||||
|
||||
|
||||
images.debug:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.IMAGES_DEBUG
|
||||
help: PLUGIN_ADMIN.IMAGES_DEBUG_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
media.upload_limit:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.UPLOAD_LIMIT
|
||||
help: PLUGIN_ADMIN.UPLOAD_LIMIT_HELP
|
||||
classes: small
|
||||
validate:
|
||||
type: number
|
||||
|
||||
media.enable_media_timestamp:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ENABLE_MEDIA_TIMESTAMP
|
||||
help: PLUGIN_ADMIN.ENABLE_MEDIA_TIMESTAMP_HELP
|
||||
highlight: 0
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
|
||||
media.allowed_fallback_types:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.FALLBACK_TYPES
|
||||
help: PLUGIN_ADMIN.FALLBACK_TYPES_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
media.unsupported_inline_types:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.INLINE_TYPES
|
||||
help: PLUGIN_ADMIN.INLINE_TYPES_HELP
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
session:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.SESSION
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
session.enabled:
|
||||
type: hidden
|
||||
label: PLUGIN_ADMIN.ENABLED
|
||||
help: PLUGIN_ADMIN.SESSION_ENABLED_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
default: true
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
session.timeout:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.TIMEOUT
|
||||
help: PLUGIN_ADMIN.TIMEOUT_HELP
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
|
||||
session.name:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.NAME
|
||||
help: PLUGIN_ADMIN.SESSION_NAME_HELP
|
||||
|
||||
session.secure:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.SESSION_SECURE
|
||||
help: PLUGIN_ADMIN.SESSION_SECURE_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
default: false
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
session.httponly:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.SESSION_HTTPONLY
|
||||
help: PLUGIN_ADMIN.SESSION_HTTPONLY_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
default: true
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
advanced:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ADVANCED
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
proxy_url:
|
||||
type: text
|
||||
size: medium
|
||||
placeholder: "e.g. 127.0.0.1:3128"
|
||||
label: PLUGIN_ADMIN.PROXY_URL
|
||||
help: PLUGIN_ADMIN.PROXY_URL_HELP
|
||||
|
||||
reverse_proxy_setup:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.REVERSE_PROXY
|
||||
highlight: 0
|
||||
help: PLUGIN_ADMIN.REVERSE_PROXY_HELP
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
wrapped_site:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.WRAPPED_SITE
|
||||
highlight: 0
|
||||
help: PLUGIN_ADMIN.WRAPPED_SITE_HELP
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
absolute_urls:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.ABSOLUTE_URLS
|
||||
highlight: 0
|
||||
help: PLUGIN_ADMIN.ABSOLUTE_URLS_HELP
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
param_sep:
|
||||
type: select
|
||||
size: medium
|
||||
label: PLUGIN_ADMIN.PARAMETER_SEPARATOR
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.PARAMETER_SEPARATOR_HELP
|
||||
default: ''
|
||||
options:
|
||||
':': ': (default)'
|
||||
';': '; (for Apache running on Windows)'
|
||||
@@ -0,0 +1,7 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
alt_text:
|
||||
type: string
|
||||
label: Alt Text
|
||||
@@ -0,0 +1,8 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PAGE
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
@@ -0,0 +1,8 @@
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
new_file_name:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN_PRO.NEW_FILE_NAME
|
||||
validate:
|
||||
required: true
|
||||
@@ -0,0 +1,281 @@
|
||||
title: PLUGIN_ADMIN.DEFAULT
|
||||
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
fields:
|
||||
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
|
||||
fields:
|
||||
header.title:
|
||||
type: text
|
||||
autofocus: true
|
||||
style: vertical
|
||||
label: PLUGIN_ADMIN.TITLE
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
validate:
|
||||
type: textarea
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
||||
|
||||
options:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.OPTIONS
|
||||
|
||||
fields:
|
||||
|
||||
publishing:
|
||||
type: section
|
||||
title: Publishing
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.published:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.PUBLISHED
|
||||
help: PLUGIN_ADMIN.PUBLISHED_HELP
|
||||
highlight: 1
|
||||
size: medium
|
||||
options:
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.date:
|
||||
type: datetime
|
||||
label: PLUGIN_ADMIN.DATE
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.DATE_HELP
|
||||
|
||||
header.publish_date:
|
||||
type: datetime
|
||||
label: PLUGIN_ADMIN.PUBLISHED_DATE
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.PUBLISHED_DATE_HELP
|
||||
|
||||
header.unpublish_date:
|
||||
type: datetime
|
||||
label: PLUGIN_ADMIN.UNPUBLISHED_DATE
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.UNPUBLISHED_DATE_HELP
|
||||
|
||||
header.metadata:
|
||||
toggleable: true
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.METADATA
|
||||
help: PLUGIN_ADMIN.METADATA_HELP
|
||||
placeholder_key: PLUGIN_ADMIN.METADATA_KEY
|
||||
placeholder_value: PLUGIN_ADMIN.METADATA_VALUE
|
||||
|
||||
taxonomies:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.TAXONOMIES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.taxonomy:
|
||||
type: taxonomy
|
||||
label: PLUGIN_ADMIN.TAXONOMY
|
||||
multiple: true
|
||||
validate:
|
||||
type: array
|
||||
|
||||
advanced:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.ADVANCED
|
||||
|
||||
fields:
|
||||
columns:
|
||||
type: columns
|
||||
fields:
|
||||
column1:
|
||||
type: column
|
||||
fields:
|
||||
|
||||
settings:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.SETTINGS
|
||||
underline: true
|
||||
|
||||
ordering:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
validate:
|
||||
type: slug
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parentsRawRoutes'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.PAGE_FILE
|
||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
||||
default: default
|
||||
'@data-options': '\Grav\Common\Page\Pages::pageTypes'
|
||||
|
||||
header.body_classes:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.BODY_CLASSES
|
||||
|
||||
|
||||
column2:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
order_title:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ORDERING
|
||||
underline: true
|
||||
|
||||
order:
|
||||
type: order
|
||||
label: PLUGIN_ADMIN.PAGE_ORDER
|
||||
sitemap:
|
||||
|
||||
overrides:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.OVERRIDES
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
|
||||
header.menu:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.MENU
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.MENU_HELP
|
||||
|
||||
header.slug:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.SLUG
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.SLUG_HELP
|
||||
validate:
|
||||
message: PLUGIN_ADMIN.SLUG_VALIDATE_MESSAGE
|
||||
rule: slug
|
||||
|
||||
header.redirect:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.REDIRECT
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.REDIRECT_HELP
|
||||
|
||||
header.process:
|
||||
type: checkboxes
|
||||
label: PLUGIN_ADMIN.PROCESS
|
||||
toggleable: true
|
||||
'@config-default': system.pages.process
|
||||
default:
|
||||
markdown: true
|
||||
twig: false
|
||||
options:
|
||||
markdown: Markdown
|
||||
twig: Twig
|
||||
use: keys
|
||||
|
||||
header.child_type:
|
||||
type: select
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.DEFAULT_CHILD_TYPE
|
||||
default: default
|
||||
placeholder: PLUGIN_ADMIN.USE_GLOBAL
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
|
||||
header.routable:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.ROUTABLE
|
||||
help: PLUGIN_ADMIN.ROUTABLE_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.cache_enable:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.CACHING
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.visible:
|
||||
type: toggle
|
||||
toggleable: true
|
||||
label: PLUGIN_ADMIN.VISIBLE
|
||||
help: PLUGIN_ADMIN.VISIBLE_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.template:
|
||||
type: select
|
||||
toggleable: true
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.DISPLAY_TEMPLATE
|
||||
default: default
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
|
||||
header.append_url_extension:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.APPEND_URL_EXT
|
||||
toggleable: true
|
||||
help: PLUGIN_ADMIN.APPEND_URL_EXT_HELP
|
||||
|
||||
header.order_by:
|
||||
type: hidden
|
||||
|
||||
header.order_manual:
|
||||
type: hidden
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
@@ -0,0 +1,47 @@
|
||||
title: PLUGIN_ADMIN.MODULAR
|
||||
@extends:
|
||||
type: default
|
||||
context: blueprints://pages
|
||||
|
||||
form:
|
||||
fields:
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
fields:
|
||||
|
||||
header.content.items:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.ITEMS
|
||||
default: '@self.modular'
|
||||
options:
|
||||
'@self.modular': Children
|
||||
|
||||
header.content.order.by:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.ORDER_BY
|
||||
default: date
|
||||
options:
|
||||
folder: PLUGIN_ADMIN.FOLDER
|
||||
title: PLUGIN_ADMIN.TITLE
|
||||
date: PLUGIN_ADMIN.DATE
|
||||
default: PLUGIN_ADMIN.DEFAULT
|
||||
|
||||
header.content.order.dir:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.ORDER
|
||||
default: desc
|
||||
options:
|
||||
asc: PLUGIN_ADMIN.ASCENDING
|
||||
desc: PLUGIN_ADMIN.DESCENDING
|
||||
|
||||
header.process:
|
||||
type: ignore
|
||||
content:
|
||||
type: ignore
|
||||
uploads:
|
||||
type: ignore
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
section:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ADD_MODULAR_CONTENT
|
||||
|
||||
title:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.PAGE_TITLE
|
||||
validate:
|
||||
required: true
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PAGE
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'': PLUGIN_ADMIN.DEFAULT_OPTION_SELECT
|
||||
validate:
|
||||
required: true
|
||||
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.MODULAR_TEMPLATE
|
||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
||||
default: default
|
||||
'@data-options': '\Grav\Common\Page\Pages::modularTypes'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
modular:
|
||||
type: hidden
|
||||
default: 1
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
@@ -0,0 +1,97 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
|
||||
fields:
|
||||
frontmatter:
|
||||
type: frontmatter
|
||||
label: PLUGIN_ADMIN.FRONTMATTER
|
||||
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
||||
|
||||
|
||||
options:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.OPTIONS
|
||||
|
||||
fields:
|
||||
|
||||
columns:
|
||||
type: columns
|
||||
|
||||
fields:
|
||||
column1:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
|
||||
ordering:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.FILENAME
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'': PLUGIN_ADMIN.DEFAULT_OPTION_SELECT
|
||||
validate:
|
||||
required: true
|
||||
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.MODULAR_TEMPLATE
|
||||
default: default
|
||||
'@data-options': '\Grav\Common\Page\Pages::modularTypes'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
column2:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
order:
|
||||
type: order
|
||||
label: PLUGIN_ADMIN.ORDERING
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
@@ -0,0 +1,17 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
@@ -0,0 +1,66 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
section:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ADD_PAGE
|
||||
|
||||
title:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.PAGE_TITLE
|
||||
help: PLUGIN_ADMIN.PAGE_TITLE_HELP
|
||||
validate:
|
||||
required: true
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT_PAGE
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::getLastPageRoute'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
validate:
|
||||
required: true
|
||||
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.PAGE_FILE
|
||||
help: PLUGIN_ADMIN.PAGE_FILE_HELP
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
'@data-default': '\Grav\Plugin\admin::getLastPageName'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
visible:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.VISIBLE
|
||||
help: PLUGIN_ADMIN.VISIBLE_HELP
|
||||
highlight: ''
|
||||
default: ''
|
||||
options:
|
||||
'': Auto
|
||||
1: PLUGIN_ADMIN.YES
|
||||
0: PLUGIN_ADMIN.NO
|
||||
validate:
|
||||
type: bool
|
||||
required: true
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
@@ -0,0 +1,35 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
section:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ADD_PAGE
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT_PAGE
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::getLastPageRoute'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
validate:
|
||||
required: true
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
@@ -0,0 +1,96 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.CONTENT
|
||||
|
||||
fields:
|
||||
frontmatter:
|
||||
type: frontmatter
|
||||
label: PLUGIN_ADMIN.FRONTMATTER
|
||||
autofocus: true
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
showPreview: true
|
||||
|
||||
uploads:
|
||||
type: pagemedia
|
||||
label: PLUGIN_ADMIN.PAGE_MEDIA
|
||||
|
||||
options:
|
||||
type: tab
|
||||
title: PLUGIN_ADMIN.OPTIONS
|
||||
|
||||
fields:
|
||||
|
||||
columns:
|
||||
type: columns
|
||||
|
||||
fields:
|
||||
column1:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
|
||||
ordering:
|
||||
type: toggle
|
||||
label: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX
|
||||
help: PLUGIN_ADMIN.FOLDER_NUMERIC_PREFIX_HELP
|
||||
highlight: 1
|
||||
options:
|
||||
1: PLUGIN_ADMIN.ENABLED
|
||||
0: PLUGIN_ADMIN.DISABLED
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.FOLDER_NAME
|
||||
help: PLUGIN_ADMIN.FOLDER_NAME_HELP
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.PARENT
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Common\Page\Pages::parents'
|
||||
'@data-default': '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': PLUGIN_ADMIN.DEFAULT_OPTION_ROOT
|
||||
|
||||
name:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: PLUGIN_ADMIN.DISPLAY_TEMPLATE
|
||||
help: PLUGIN_ADMIN.DISPLAY_TEMPLATE_HELP
|
||||
default: default
|
||||
'@data-options': '\Grav\Common\Page\Pages::types'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
column2:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
order:
|
||||
type: order
|
||||
label: PLUGIN_ADMIN.ORDERING
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
@@ -0,0 +1,85 @@
|
||||
title: Site
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ACCOUNT
|
||||
|
||||
fields:
|
||||
username:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.USERNAME
|
||||
disabled: true
|
||||
readonly: true
|
||||
|
||||
email:
|
||||
type: email
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.EMAIL
|
||||
validate:
|
||||
type: email
|
||||
message: PLUGIN_ADMIN.EMAIL_VALIDATION_MESSAGE
|
||||
required: true
|
||||
|
||||
password:
|
||||
type: password
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.PASSWORD
|
||||
validate:
|
||||
required: false
|
||||
message: PLUGIN_ADMIN.PASSWORD_VALIDATION_MESSAGE
|
||||
pattern: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}'
|
||||
|
||||
fullname:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.FULL_NAME
|
||||
validate:
|
||||
required: true
|
||||
|
||||
title:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.TITLE
|
||||
|
||||
language:
|
||||
type: select
|
||||
label: PLUGIN_ADMIN.LANGUAGE
|
||||
size: medium
|
||||
classes: fancy
|
||||
'@data-options': '\Grav\Plugin\admin::adminLanguages'
|
||||
default: 'en'
|
||||
help: PLUGIN_ADMIN.LANGUAGE_HELP
|
||||
|
||||
security:
|
||||
title: PLUGIN_ADMIN.ACCESS_LEVELS
|
||||
type: section
|
||||
security: admin.super
|
||||
|
||||
fields:
|
||||
groups:
|
||||
type: selectize
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.GROUPS
|
||||
'@data-options': '\Grav\User\Groups::groups'
|
||||
classes: fancy
|
||||
help: PLUGIN_ADMIN.GROUPS_HELP
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
@@ -0,0 +1,16 @@
|
||||
title: PLUGIN_ADMIN.ADD_ACCOUNT
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN.ADD_ACCOUNT
|
||||
|
||||
username:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN.USERNAME
|
||||
help: PLUGIN_ADMIN.USERNAME_HELP
|
||||
validate:
|
||||
required: true
|
||||
@@ -0,0 +1,44 @@
|
||||
title: Group
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
fields:
|
||||
spacer:
|
||||
type: spacer
|
||||
text: '<br>'
|
||||
|
||||
groupname:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.NAME
|
||||
disabled: true
|
||||
readonly: true
|
||||
|
||||
readableName:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN_PRO.READABLE_NAME
|
||||
|
||||
description:
|
||||
type: text
|
||||
size: large
|
||||
label: PLUGIN_ADMIN.DESCRIPTION
|
||||
|
||||
icon:
|
||||
type: text
|
||||
size: small
|
||||
label: PLUGIN_ADMIN_PRO.ICON
|
||||
|
||||
access.admin:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.ADMIN_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
|
||||
access.site:
|
||||
type: array
|
||||
label: PLUGIN_ADMIN.SITE_ACCESS
|
||||
multiple: false
|
||||
validate:
|
||||
type: array
|
||||
@@ -0,0 +1,16 @@
|
||||
title: PLUGIN_ADMIN_PRO.ADD_GROUP
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
content:
|
||||
type: section
|
||||
title: PLUGIN_ADMIN_PRO.ADD_GROUP
|
||||
|
||||
groupname:
|
||||
type: text
|
||||
label: PLUGIN_ADMIN_PRO.GROUP_NAME
|
||||
help: PLUGIN_ADMIN_PRO.GROUP_NAME_HELP
|
||||
validate:
|
||||
required: true
|
||||
@@ -0,0 +1,194 @@
|
||||
defaults:
|
||||
type: file
|
||||
thumb: media/thumb.png
|
||||
mime: application/octet-stream
|
||||
image:
|
||||
filters:
|
||||
default:
|
||||
- enableProgressive
|
||||
|
||||
jpg:
|
||||
type: image
|
||||
thumb: media/thumb-jpg.png
|
||||
mime: image/jpeg
|
||||
jpe:
|
||||
type: image
|
||||
thumb: media/thumb-jpg.png
|
||||
mime: image/jpeg
|
||||
jpeg:
|
||||
type: image
|
||||
thumb: media/thumb-jpeg.png
|
||||
mime: image/jpeg
|
||||
png:
|
||||
type: image
|
||||
thumb: media/thumb-png.png
|
||||
mime: image/png
|
||||
gif:
|
||||
type: animated
|
||||
thumb: media/thumb-gif.png
|
||||
mime: image/gif
|
||||
|
||||
svg:
|
||||
type: vector
|
||||
thumb: media/thumb-gif.png
|
||||
mime: image/svg+xml
|
||||
|
||||
mp4:
|
||||
type: video
|
||||
thumb: media/thumb-mp4.png
|
||||
mime: video/mp4
|
||||
mov:
|
||||
type: video
|
||||
thumb: media/thumb-mov.png
|
||||
mime: video/quicktime
|
||||
m4v:
|
||||
type: video
|
||||
thumb: media/thumb-m4v.png
|
||||
mime: video/x-m4v
|
||||
swf:
|
||||
type: video
|
||||
thumb: media/thumb-swf.png
|
||||
mime: video/x-flv
|
||||
flv:
|
||||
type: video
|
||||
thumb: media/thumb-flv.png
|
||||
mime: video/x-flv
|
||||
|
||||
mp3:
|
||||
type: audio
|
||||
thumb: media/thumb-mp3.png
|
||||
mime: audio/mp3
|
||||
ogg:
|
||||
type: audio
|
||||
thumb: media/thumb-ogg.png
|
||||
mime: audio/ogg
|
||||
wma:
|
||||
type: audio
|
||||
thumb: media/thumb-wma.png
|
||||
mime: audio/wma
|
||||
m4a:
|
||||
type: audio
|
||||
thumb: media/thumb-m4a.png
|
||||
mime: audio/m4a
|
||||
wav:
|
||||
type: audio
|
||||
thumb: media/thumb-wav.png
|
||||
mime: audio/wav
|
||||
aiff:
|
||||
type: audio
|
||||
mime: audio/aiff
|
||||
aif:
|
||||
type: audio
|
||||
mime: audio/aif
|
||||
|
||||
txt:
|
||||
type: file
|
||||
thumb: media/thumb-txt.png
|
||||
mime: text/plain
|
||||
xml:
|
||||
type: file
|
||||
thumb: media/thumb-xml.png
|
||||
mime: application/xml
|
||||
doc:
|
||||
type: file
|
||||
thumb: media/thumb-doc.png
|
||||
mime: application/msword
|
||||
docx:
|
||||
type: file
|
||||
mime: application/msword
|
||||
xls:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlt:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlm:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xld:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xla:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlc:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xlw:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
xll:
|
||||
type: file
|
||||
mime: application/vnd.ms-excel
|
||||
ppt:
|
||||
type: file
|
||||
mime: application/vnd.ms-powerpoint
|
||||
pps:
|
||||
type: file
|
||||
mime: application/vnd.ms-powerpoint
|
||||
rtf:
|
||||
type: file
|
||||
mime: application/rtf
|
||||
|
||||
bmp:
|
||||
type: file
|
||||
mime: image/bmp
|
||||
tiff:
|
||||
type: file
|
||||
mime: image/tiff
|
||||
mpeg:
|
||||
type: file
|
||||
mime: video/mpeg
|
||||
mpg:
|
||||
type: file
|
||||
mime: video/mpeg
|
||||
mpe:
|
||||
type: file
|
||||
mime: video/mpeg
|
||||
avi:
|
||||
type: file
|
||||
mime: video/msvideo
|
||||
wmv:
|
||||
type: file
|
||||
mime: video/x-ms-wmv
|
||||
|
||||
html:
|
||||
type: file
|
||||
thumb: media/thumb-html.png
|
||||
mime: text/html
|
||||
htm:
|
||||
type: file
|
||||
thumb: media/thumb-html.png
|
||||
mime: text/html
|
||||
pdf:
|
||||
type: file
|
||||
thumb: media/thumb-pdf.png
|
||||
mime: application/pdf
|
||||
zip:
|
||||
type: file
|
||||
thumb: media/thumb-zip.png
|
||||
mime: application/zip
|
||||
7z:
|
||||
type: file
|
||||
thumb: media/thumb-7zip.png
|
||||
mime: application/x-7z-compressed
|
||||
gz:
|
||||
type: file
|
||||
thumb: media/thumb-gz.png
|
||||
mime: application/gzip
|
||||
tar:
|
||||
type: file
|
||||
mime: application/x-tar
|
||||
css:
|
||||
type: file
|
||||
thumb: media/thumb-css.png
|
||||
mime: text/css
|
||||
js:
|
||||
type: file
|
||||
thumb: media/thumb-js.png
|
||||
mime: application/javascript
|
||||
json:
|
||||
type: file
|
||||
thumb: media/thumb-json.png
|
||||
mime: application/json
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
title: Grav # Name of the site
|
||||
|
||||
author:
|
||||
name: John Appleseed # Default author name
|
||||
email: 'john@email.com' # Default author email
|
||||
|
||||
taxonomies: [category,tag] # Arbitrary list of taxonomy types
|
||||
|
||||
metadata:
|
||||
description: 'My Grav Site' # Site description
|
||||
|
||||
summary:
|
||||
enabled: true # enable or disable summary of page
|
||||
format: short # long = summary delimiter will be ignored; short = use the first occurrence of delimiter or size
|
||||
size: 300 # Maximum length of summary (characters)
|
||||
delimiter: === # The summary delimiter
|
||||
|
||||
redirects:
|
||||
# /redirect-test: / # Redirect test goes to home page
|
||||
# /old/(.*): /new/$1 # Would redirect /old/my-page to /new/my-page
|
||||
|
||||
routes:
|
||||
# /something/else: '/blog/sample-3' # Alias for /blog/sample-3
|
||||
# /new/(.*): '/blog/$1' # Regex any /new/my-page URL to /blog/my-page Route
|
||||
|
||||
blog:
|
||||
route: '/blog' # Custom value added (accessible via system.blog.route)
|
||||
|
||||
#menu: # Sample Menu Example
|
||||
# - text: Source
|
||||
# icon: github
|
||||
# url: https://github.com/getgrav/grav
|
||||
# - icon: twitter
|
||||
# url: http://twitter.com/getgrav
|
||||
@@ -0,0 +1,16 @@
|
||||
schemes:
|
||||
image:
|
||||
type: ReadOnlyStream
|
||||
paths:
|
||||
- user://images
|
||||
- system://images
|
||||
|
||||
page:
|
||||
type: ReadOnlyStream
|
||||
paths:
|
||||
- user://pages
|
||||
|
||||
account:
|
||||
type: ReadOnlyStream
|
||||
paths:
|
||||
- user://accounts
|
||||
@@ -0,0 +1,118 @@
|
||||
absolute_urls: false # Absolute or relative URLs for `base_url`
|
||||
timezone: '' # Valid values: http://php.net/manual/en/timezones.php
|
||||
default_locale: # Default locale (defaults to system)
|
||||
param_sep: ':' # Parameter separator, use ';' for Apache on windows
|
||||
wrapped_site: false # For themes/plugins to know if Grav is wrapped by another platform
|
||||
reverse_proxy_setup: false # Running in a reverse proxy scenario with different webserver ports than proxy
|
||||
proxy_url: # Configure a manual proxy URL for GPM (eg 127.0.0.1:3128)
|
||||
|
||||
languages:
|
||||
supported: [] # List of languages supported. eg: [en, fr, de]
|
||||
include_default_lang: true # Include the default lang prefix in all URLs
|
||||
translations: true # Enable translations by default
|
||||
translations_fallback: true # Fallback through supported translations if active lang doesn't exist
|
||||
session_store_active: false # Store active language in session
|
||||
http_accept_language: false # Attempt to set the language based on http_accept_language header in the browser
|
||||
override_locale: false # Override the default or system locale with language specific one
|
||||
|
||||
home:
|
||||
alias: '/home' # Default path for home, ie /
|
||||
hide_in_urls: false # Hide the home route in URLs
|
||||
|
||||
pages:
|
||||
theme: antimatter # Default theme (defaults to "antimatter" theme)
|
||||
order:
|
||||
by: default # Order pages by "default", "alpha" or "date"
|
||||
dir: asc # Default ordering direction, "asc" or "desc"
|
||||
list:
|
||||
count: 20 # Default item count per page
|
||||
dateformat:
|
||||
default: # The default date format Grav expects in the `date: ` field
|
||||
short: 'jS M Y' # Short date format
|
||||
long: 'F jS \a\t g:ia' # Long date format
|
||||
publish_dates: true # automatically publish/unpublish based on dates
|
||||
process:
|
||||
markdown: true # Process Markdown
|
||||
twig: false # Process Twig
|
||||
twig_first: false # Process Twig before markdown when processing both on a page
|
||||
events:
|
||||
page: true # Enable page level events
|
||||
twig: true # Enable twig level events
|
||||
markdown:
|
||||
extra: false # Enable support for Markdown Extra support (GFM by default)
|
||||
auto_line_breaks: false # Enable automatic line breaks
|
||||
auto_url_links: false # Enable automatic HTML links
|
||||
escape_markup: false # Escape markup tags into entities
|
||||
special_chars: # List of special characters to automatically convert to entities
|
||||
'>': 'gt'
|
||||
'<': 'lt'
|
||||
types: [txt,xml,html,htm,json,rss,atom] # list of valid page types
|
||||
append_url_extension: '' # Append page's extension in Page urls (e.g. '.html' results in /path/page.html)
|
||||
expires: 604800 # Page expires time in seconds (604800 seconds = 7 days)
|
||||
last_modified: false # Set the last modified date header based on file modifcation timestamp
|
||||
etag: false # Set the etag header tag
|
||||
vary_accept_encoding: false # Add `Vary: Accept-Encoding` header
|
||||
redirect_default_route: false # Automatically redirect to a page's default route
|
||||
redirect_default_code: 301 # Default code to use for redirects
|
||||
redirect_trailing_slash: true # Handle automatically or 301 redirect a trailing / URL
|
||||
ignore_files: [.DS_Store] # Files to ignore in Pages
|
||||
ignore_folders: [.git, .idea] # Folders to ignore in Pages
|
||||
ignore_hidden: true # Ignore all Hidden files and folders
|
||||
url_taxonomy_filters: true # Enable auto-magic URL-based taxonomy filters for page collections
|
||||
|
||||
cache:
|
||||
enabled: true # Set to true to enable caching
|
||||
check:
|
||||
method: file # Method to check for updates in pages: file|folder|none
|
||||
driver: auto # One of: auto|file|apc|xcache|memcache|wincache
|
||||
prefix: 'g' # Cache prefix string (prevents cache conflicts)
|
||||
lifetime: 604800 # Lifetime of cached data in seconds (0 = infinite)
|
||||
gzip: false # GZip compress the page output
|
||||
|
||||
twig:
|
||||
cache: true # Set to true to enable twig caching
|
||||
debug: false # Enable Twig debug
|
||||
auto_reload: true # Refresh cache on changes
|
||||
autoescape: false # Autoescape Twig vars
|
||||
undefined_functions: true # Allow undefined functions
|
||||
undefined_filters: true # Allow undefined filters
|
||||
umask_fix: false # By default Twig creates cached files as 755, fix switches this to 775
|
||||
|
||||
assets: # Configuration for Assets Manager (JS, CSS)
|
||||
css_pipeline: false # The CSS pipeline is the unification of multiple CSS resources into one file
|
||||
css_minify: true # Minify the CSS during pipelining
|
||||
css_minify_windows: false # Minify Override for Windows platforms. False by default due to ThreadStackSize
|
||||
css_rewrite: true # Rewrite any CSS relative URLs during pipelining
|
||||
js_pipeline: false # The JS pipeline is the unification of multiple JS resources into one file
|
||||
js_minify: true # Minify the JS during pipelining
|
||||
enable_asset_timestamp: false # Enable asset timestamps
|
||||
collections:
|
||||
jquery: system://assets/jquery/jquery-2.x.min.js
|
||||
|
||||
errors:
|
||||
display: false # Display full backtrace-style error page
|
||||
log: true # Log errors to /logs folder
|
||||
|
||||
debugger:
|
||||
enabled: false # Enable Grav debugger and following settings
|
||||
shutdown:
|
||||
close_connection: true # Close the connection before calling onShutdown(). false for debugging
|
||||
|
||||
images:
|
||||
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'
|
||||
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
|
||||
|
||||
media:
|
||||
enable_media_timestamp: false # Enable media timetsamps
|
||||
upload_limit: 0 # Set maximum upload size in bytes (0 is unlimited)
|
||||
unsupported_inline_types: [] # Array of supported media types to try to display inline
|
||||
allowed_fallback_types: [] # Array of allowed media types of files found if accessed via Page route
|
||||
|
||||
session:
|
||||
enabled: true # Enable Session support
|
||||
timeout: 1800 # Timeout in seconds
|
||||
name: grav-site # Name prefix of the session cookie. Use alphanumeric, dashes or underscores only. Do not use dots in the session name
|
||||
secure: false # Set session secure. If true, indicates that communication for this cookie must be over an encrypted transmission. Enable this only on sites that run exclusively on HTTPS
|
||||
httponly: true # Set session HTTP only. If true, indicates that cookies should be used only over HTTP, and JavaScript modification is not allowed.
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.0.9');
|
||||
define('DS', '/');
|
||||
define('GRAV_PHP_MIN', '5.5.9');
|
||||
|
||||
// Directories and Paths
|
||||
if (!defined('GRAV_ROOT')) {
|
||||
define('GRAV_ROOT', str_replace(DIRECTORY_SEPARATOR, DS, getcwd()));
|
||||
}
|
||||
define('ROOT_DIR', GRAV_ROOT . '/');
|
||||
define('USER_PATH', 'user/');
|
||||
define('USER_DIR', ROOT_DIR . USER_PATH);
|
||||
define('SYSTEM_DIR', ROOT_DIR .'system/');
|
||||
define('CACHE_DIR', ROOT_DIR . 'cache/');
|
||||
define('LOG_DIR', ROOT_DIR .'logs/');
|
||||
|
||||
// DEPRECATED: Do not use!
|
||||
define('ASSETS_DIR', ROOT_DIR . 'assets/');
|
||||
define('IMAGES_DIR', ROOT_DIR . 'images/');
|
||||
define('ACCOUNTS_DIR', USER_DIR .'accounts/');
|
||||
define('PAGES_DIR', USER_DIR .'pages/');
|
||||
define('DATA_DIR', USER_DIR .'data/');
|
||||
define('LIB_DIR', SYSTEM_DIR .'src/');
|
||||
define('PLUGINS_DIR', USER_DIR .'plugins/');
|
||||
define('THEMES_DIR', USER_DIR .'themes/');
|
||||
define('VENDOR_DIR', ROOT_DIR .'vendor/');
|
||||
// END DEPRECATED
|
||||
|
||||
// Some extensions
|
||||
define('CONTENT_EXT', '.md');
|
||||
define('TEMPLATE_EXT', '.html.twig');
|
||||
define('TWIG_EXT', '.twig');
|
||||
define('PLUGIN_EXT', '.php');
|
||||
define('YAML_EXT', '.yaml');
|
||||
|
||||
// Content types
|
||||
define('RAW_CONTENT', 1);
|
||||
define('TWIG_CONTENT', 2);
|
||||
define('TWIG_CONTENT_LIST', 3);
|
||||
define('TWIG_TEMPLATES', 4);
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 123 B |
@@ -0,0 +1,80 @@
|
||||
---
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- vybavení
|
||||
- informace
|
||||
- rýže
|
||||
- peníze
|
||||
- druhy
|
||||
- série
|
||||
- ryba
|
||||
- ovce
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: lidé
|
||||
man: muži
|
||||
child: děti
|
||||
sex: pohlaví
|
||||
move: pohyby
|
||||
INFLECTOR_ORDINALS:
|
||||
default: '.'
|
||||
first: '.'
|
||||
second: '.'
|
||||
third: '.'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Datum nebylo vloženo
|
||||
BAD_DATE: Chybné datum
|
||||
AGO: zpět
|
||||
FROM_NOW: od teď
|
||||
SECOND: sekunda
|
||||
MINUTE: minuta
|
||||
HOUR: hodina
|
||||
DAY: den
|
||||
WEEK: týden
|
||||
MONTH: měsíc
|
||||
YEAR: rok
|
||||
DECADE: dekáda
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: hod
|
||||
WK: t
|
||||
MO: m
|
||||
YR: r
|
||||
DEC: dek
|
||||
SECOND_PLURAL: sekundy
|
||||
MINUTE_PLURAL: minuty
|
||||
HOUR_PLURAL: hodiny
|
||||
DAY_PLURAL: dny
|
||||
WEEK_PLURAL: týdny
|
||||
MONTH_PLURAL: měsíce
|
||||
YEAR_PLURAL: roky
|
||||
DECADE_PLURAL: dekády
|
||||
SEC_PLURAL: sek
|
||||
MIN_PLURAL: min
|
||||
HR_PLURAL: hod
|
||||
WK_PLURAL: t
|
||||
MO_PLURAL: m
|
||||
YR_PLURAL: r
|
||||
DEC_PLURAL: dek
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Ověření se nezdařilo:</b>'
|
||||
MISSING_REQUIRED_FIELD: 'Chybí požadované pole:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- ledna
|
||||
- února
|
||||
- března
|
||||
- dubna
|
||||
- května
|
||||
- června
|
||||
- července
|
||||
- srpna
|
||||
- září
|
||||
- října
|
||||
- listopadu
|
||||
- prosince
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Pondělí
|
||||
- Úterý
|
||||
- Středa
|
||||
- Čtvrtek
|
||||
- Pátek
|
||||
- Sobota
|
||||
- Neděle
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
FRONTMATTER_ERROR_PAGE: |
|
||||
---
|
||||
title: %1$s
|
||||
---
|
||||
# Fehler: Frontmatter enthält Fehler
|
||||
|
||||
Pfad: `%2$s`
|
||||
|
||||
**%3$s **
|
||||
|
||||
```
|
||||
%4$s
|
||||
```
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
1: Informationen
|
||||
2: Reis
|
||||
3: Geld
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: Personen
|
||||
man: Menschen
|
||||
child: Kinder
|
||||
sex: Geschlecht
|
||||
move: Züge
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Keine Daten vorhanden
|
||||
BAD_DATE: Falsches Datum
|
||||
AGO: her
|
||||
FROM_NOW: ab jetzt
|
||||
SECOND: Sekunde
|
||||
MINUTE: Minute
|
||||
HOUR: Stunde
|
||||
DAY: Tag
|
||||
WEEK: Woche
|
||||
MONTH: Monat
|
||||
YEAR: Jahr
|
||||
DECADE: Dekade
|
||||
SEC: sek
|
||||
MIN: Min
|
||||
HR: std
|
||||
WK: wo
|
||||
YR: yh
|
||||
DEC: Jz
|
||||
SECOND_PLURAL: Sekunden
|
||||
MINUTE_PLURAL: Minuten
|
||||
HOUR_PLURAL: Stunden
|
||||
DAY_PLURAL: Tage
|
||||
WEEK_PLURAL: Wochen
|
||||
MONTH_PLURAL: Monate
|
||||
YEAR_PLURAL: Jahre
|
||||
DECADE_PLURAL: Dekaden
|
||||
SEC_PLURAL: Sekunden
|
||||
MIN_PLURAL: Minuten
|
||||
HR_PLURAL: Stunden
|
||||
WK_PLURAL: Wochen
|
||||
MO_PLURAL: Monate
|
||||
YR_PLURAL: Jahre
|
||||
DEC_PLURAL: Dekaden
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Überprüfung fehlgeschlagen:</b>'
|
||||
INVALID_INPUT: Ungültige Eingabe in
|
||||
MISSING_REQUIRED_FIELD: 'Erforderliches Feld fehlt:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Januar
|
||||
- Februar
|
||||
- März
|
||||
- April
|
||||
- Mai
|
||||
- Juni
|
||||
- Juli
|
||||
- August
|
||||
- Semptember
|
||||
- Oktober
|
||||
- November
|
||||
- Dezember
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Montag
|
||||
- Dienstag
|
||||
- Mittwoch
|
||||
- Donnerstag
|
||||
- Freitag
|
||||
- Samstag
|
||||
- Sonntag
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Ιανουάριος
|
||||
- Φεβρουάριος
|
||||
- Μάρτιος
|
||||
- Απρίλιος
|
||||
- Μάιος
|
||||
- Ιούνιος
|
||||
- Ιούλιος
|
||||
- Αύγουστος
|
||||
- Σεπτέμβριος
|
||||
- Οκτώβριος
|
||||
- Νοέμβριος
|
||||
- Δεκέμβριος
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Δευτέρα
|
||||
- Τρλιτη
|
||||
- Τετάρτη
|
||||
- Πέμπτη
|
||||
- Παρασκευή
|
||||
- Σαββάτο
|
||||
- Κυριακή
|
||||
@@ -0,0 +1,100 @@
|
||||
FRONTMATTER_ERROR_PAGE: "---\ntitle: %1$s\n---\n\n# Error: Invalid Frontmatter\n\nPath: `%2$s`\n\n**%3$s**\n\n```\n%4$s\n```"
|
||||
INFLECTOR_PLURALS:
|
||||
'/(quiz)$/i': '\1zes'
|
||||
'/^(ox)$/i': '\1en'
|
||||
'/([m|l])ouse$/i': '\1ice'
|
||||
'/(matr|vert|ind)ix|ex$/i': '\1ices'
|
||||
'/(x|ch|ss|sh)$/i': '\1es'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([^aeiouy]|qu)y$/i': '\1ies'
|
||||
'/(hive)$/i': '\1s'
|
||||
'/(?:([^f])fe|([lr])f)$/i': '\1\2ves'
|
||||
'/sis$/i': 'ses'
|
||||
'/([ti])um$/i': '\1a'
|
||||
'/(buffal|tomat)o$/i': '\1oes'
|
||||
'/(bu)s$/i': '\1ses'
|
||||
'/(alias|status)/i': '\1es'
|
||||
'/(octop|vir)us$/i': '\1i'
|
||||
'/(ax|test)is$/i': '\1es'
|
||||
'/s$/i': 's'
|
||||
'/$/': 's'
|
||||
INFLECTOR_SINGULAR:
|
||||
'/(quiz)zes$/i': '\1'
|
||||
'/(matr)ices$/i': '\1ix'
|
||||
'/(vert|ind)ices$/i': '\1ex'
|
||||
'/^(ox)en/i': '\1'
|
||||
'/(alias|status)es$/i': '\1'
|
||||
'/([octop|vir])i$/i': '\1us'
|
||||
'/(cris|ax|test)es$/i': '\1is'
|
||||
'/(shoe)s$/i': '\1'
|
||||
'/(o)es$/i': '\1'
|
||||
'/(bus)es$/i': '\1'
|
||||
'/([m|l])ice$/i': '\1ouse'
|
||||
'/(x|ch|ss|sh)es$/i': '\1'
|
||||
'/(m)ovies$/i': '\1ovie'
|
||||
'/(s)eries$/i': '\1eries'
|
||||
'/([^aeiouy]|qu)ies$/i': '\1y'
|
||||
'/([lr])ves$/i': '\1f'
|
||||
'/(tive)s$/i': '\1'
|
||||
'/(hive)s$/i': '\1'
|
||||
'/([^f])ves$/i': '\1fe'
|
||||
'/(^analy)ses$/i': '\1sis'
|
||||
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i': '\1\2sis'
|
||||
'/([ti])a$/i': '\1um'
|
||||
'/(n)ews$/i': '\1ews'
|
||||
'/s$/i': ''
|
||||
INFLECTOR_UNCOUNTABLE: ['equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep']
|
||||
INFLECTOR_IRREGULAR:
|
||||
'person': 'people'
|
||||
'man': 'men'
|
||||
'child': 'children'
|
||||
'sex': 'sexes'
|
||||
'move': 'moves'
|
||||
INFLECTOR_ORDINALS:
|
||||
'default': 'th'
|
||||
'first': 'st'
|
||||
'second': 'nd'
|
||||
'third': 'rd'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: No date provided
|
||||
BAD_DATE: Bad date
|
||||
AGO: ago
|
||||
FROM_NOW: from now
|
||||
SECOND: second
|
||||
MINUTE: minute
|
||||
HOUR: hour
|
||||
DAY: day
|
||||
WEEK: week
|
||||
MONTH: month
|
||||
YEAR: year
|
||||
DECADE: decade
|
||||
SEC: sec
|
||||
MIN: min
|
||||
HR: hr
|
||||
DAY: day
|
||||
WK: wk
|
||||
MO: mo
|
||||
YR: yr
|
||||
DEC: dec
|
||||
SECOND_PLURAL: seconds
|
||||
MINUTE_PLURAL: minutes
|
||||
HOUR_PLURAL: hours
|
||||
DAY_PLURAL: days
|
||||
WEEK_PLURAL: weeks
|
||||
MONTH_PLURAL: months
|
||||
YEAR_PLURAL: years
|
||||
DECADE_PLURAL: decades
|
||||
SEC_PLURAL: secs
|
||||
MIN_PLURAL: mins
|
||||
HR_PLURAL: hrs
|
||||
DAY_PLURAL: days
|
||||
WK_PLURAL: wks
|
||||
MO_PLURAL: mos
|
||||
YR_PLURAL: yrs
|
||||
DEC_PLURAL: decs
|
||||
FORM:
|
||||
VALIDATION_FAIL: <b>Validation failed:</b>
|
||||
INVALID_INPUT: Invalid input in
|
||||
MISSING_REQUIRED_FIELD: Missing required field:
|
||||
MONTHS_OF_THE_YEAR: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
|
||||
DAYS_OF_THE_WEEK: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
0: equipo
|
||||
1: información
|
||||
3: dinero
|
||||
5: series
|
||||
6: pescado
|
||||
7: oveja
|
||||
INFLECTOR_IRREGULAR:
|
||||
man: hombres
|
||||
child: niños
|
||||
sex: sexos
|
||||
INFLECTOR_ORDINALS:
|
||||
first: ro
|
||||
second: do
|
||||
third: ro
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: No se proporcionó fecha
|
||||
BAD_DATE: Fecha erronea
|
||||
AGO: antes
|
||||
FROM_NOW: desde ahora
|
||||
SECOND: segundo
|
||||
MINUTE: minuto
|
||||
HOUR: hora
|
||||
DAY: día
|
||||
WEEK: semana
|
||||
MONTH: mes
|
||||
YEAR: año
|
||||
DECADE: década
|
||||
SEC: seg
|
||||
MIN: min
|
||||
HR: h
|
||||
WK: sem
|
||||
MO: mes
|
||||
YR: año
|
||||
DEC: dec
|
||||
SECOND_PLURAL: segundos
|
||||
MINUTE_PLURAL: minutos
|
||||
HOUR_PLURAL: horas
|
||||
DAY_PLURAL: días
|
||||
WEEK_PLURAL: semanas
|
||||
MONTH_PLURAL: meses
|
||||
YEAR_PLURAL: años
|
||||
DECADE_PLURAL: décadas
|
||||
SEC_PLURAL: segs
|
||||
MIN_PLURAL: mins
|
||||
HR_PLURAL: hs
|
||||
WK_PLURAL: sem
|
||||
MO_PLURAL: mes
|
||||
YR_PLURAL: años
|
||||
DEC_PLURAL: décadas
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Falló la validación. </b>'
|
||||
INVALID_INPUT: 'Dato inválido en: '
|
||||
MISSING_REQUIRED_FIELD: 'Falta el campo requerido: '
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Enero
|
||||
- Febrero
|
||||
- Marzo
|
||||
- Abril
|
||||
- Mayo
|
||||
- Junio
|
||||
- Julio
|
||||
- Agosto
|
||||
- Septiembre
|
||||
- Octubre
|
||||
- Noviembre
|
||||
- Diciembre
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Lunes
|
||||
- Martes
|
||||
- Miércoles
|
||||
- Jueves
|
||||
- Viernes
|
||||
- Sábado
|
||||
- Domingo
|
||||
@@ -0,0 +1 @@
|
||||
---
|
||||
@@ -0,0 +1,138 @@
|
||||
---
|
||||
FRONTMATTER_ERROR_PAGE: |
|
||||
---
|
||||
title: %1$s
|
||||
---
|
||||
|
||||
# Erreur : Frontmatter invalide
|
||||
|
||||
Path: `%2$s`
|
||||
|
||||
**%3$s**
|
||||
|
||||
```
|
||||
%4$s
|
||||
```
|
||||
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:
|
||||
- équipement
|
||||
- informations
|
||||
- riz
|
||||
- argent
|
||||
- espèces
|
||||
- séries
|
||||
- poisson
|
||||
- mouton
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: personnes
|
||||
man: hommes
|
||||
child: enfants
|
||||
sex: sexes
|
||||
move: déplacements
|
||||
INFLECTOR_ORDINALS:
|
||||
default: ème
|
||||
first: er
|
||||
second: ème
|
||||
third: ème
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Aucune date fournie
|
||||
BAD_DATE: Date erronée
|
||||
AGO: plus tôt
|
||||
FROM_NOW: à partir de maintenant
|
||||
SECOND: seconde
|
||||
MINUTE: minute
|
||||
HOUR: heure
|
||||
DAY: jour
|
||||
WEEK: semaine
|
||||
MONTH: mois
|
||||
YEAR: année
|
||||
DECADE: décennie
|
||||
SEC: s
|
||||
MIN: m
|
||||
HR: h
|
||||
WK: sem
|
||||
MO: m
|
||||
YR: an
|
||||
DEC: déc
|
||||
SECOND_PLURAL: secondes
|
||||
MINUTE_PLURAL: minutes
|
||||
HOUR_PLURAL: heures
|
||||
DAY_PLURAL: jours
|
||||
WEEK_PLURAL: semaines
|
||||
MONTH_PLURAL: mois
|
||||
YEAR_PLURAL: années
|
||||
DECADE_PLURAL: décennies
|
||||
SEC_PLURAL: s
|
||||
MIN_PLURAL: m
|
||||
HR_PLURAL: h
|
||||
WK_PLURAL: sem
|
||||
MO_PLURAL: mois
|
||||
YR_PLURAL: a
|
||||
DEC_PLURAL: décs
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>La validation a échoué :</b>'
|
||||
INVALID_INPUT: Saisie non valide
|
||||
MISSING_REQUIRED_FIELD: 'Champ obligatoire manquant :'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Janvier
|
||||
- Février
|
||||
- Mars
|
||||
- Avril
|
||||
- Mai
|
||||
- Juin
|
||||
- Juillet
|
||||
- Août
|
||||
- Septembre
|
||||
- Octobre
|
||||
- Novembre
|
||||
- Décembre
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Lundi
|
||||
- Mardi
|
||||
- Mercredi
|
||||
- Jeudi
|
||||
- Vendredi
|
||||
- Samedi
|
||||
- Dimanche
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- oprema
|
||||
- informacije
|
||||
- riža
|
||||
- novac
|
||||
- vrsta
|
||||
- serija
|
||||
- riba
|
||||
- ovca
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: osobe
|
||||
man: ljudi
|
||||
child: djeca
|
||||
sex: spolovi
|
||||
move: Pomakni
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Datum nije upisan
|
||||
BAD_DATE: Pogrešan datum
|
||||
AGO: prije
|
||||
FROM_NOW: od sada
|
||||
SECOND: sekunda
|
||||
MINUTE: minuta
|
||||
HOUR: sat
|
||||
DAY: dan
|
||||
WEEK: tjedan
|
||||
MONTH: mjesec
|
||||
YEAR: godina
|
||||
DECADE: desetljeće
|
||||
SEC: sek
|
||||
HR: sat
|
||||
WK: t
|
||||
MO: m
|
||||
YR: g
|
||||
DEC: des
|
||||
SECOND_PLURAL: sekundi
|
||||
MINUTE_PLURAL: minuta
|
||||
HOUR_PLURAL: sati
|
||||
DAY_PLURAL: dan
|
||||
WEEK_PLURAL: tjedana
|
||||
MONTH_PLURAL: mjeseci
|
||||
YEAR_PLURAL: godina
|
||||
DECADE_PLURAL: desetljeća
|
||||
SEC_PLURAL: sek
|
||||
MIN_PLURAL: min
|
||||
HR_PLURAL: sat
|
||||
WK_PLURAL: t
|
||||
MO_PLURAL: m
|
||||
YR_PLURAL: g
|
||||
DEC_PLURAL: des
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Validacija nije uspjela:</b>'
|
||||
INVALID_INPUT: Pogrešan unos u
|
||||
MISSING_REQUIRED_FIELD: 'Nedostaje obavezno polje:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Siječanj
|
||||
- Veljača
|
||||
- Ožujak
|
||||
- Travanj
|
||||
- Svibanj
|
||||
- Lipanj
|
||||
- Srpanj
|
||||
- Kolovoz
|
||||
- Rujan
|
||||
- Listopad
|
||||
- Studeni
|
||||
- Prosinac
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Ponedjeljak
|
||||
- Utorak
|
||||
- Srijeda
|
||||
- Četvrtak
|
||||
- Petak
|
||||
- Subota
|
||||
- Nedjelja
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
FRONTMATTER_ERROR_PAGE: |
|
||||
---
|
||||
cím: %1$s
|
||||
---
|
||||
|
||||
# Hiba: Érvénytelen Frontmatter
|
||||
|
||||
Elérési út: `%2$s`
|
||||
|
||||
**%3$s**
|
||||
|
||||
```
|
||||
%4$s
|
||||
```
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: személyek
|
||||
man: férfiak
|
||||
child: gyerekek
|
||||
sex: nemek
|
||||
move: lépések
|
||||
INFLECTOR_ORDINALS:
|
||||
default: '.'
|
||||
first: '.'
|
||||
second: '.'
|
||||
third: '.'
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Nincs dátum megadva
|
||||
BAD_DATE: Hibás dátum
|
||||
AGO: elteltével
|
||||
FROM_NOW: mostantól
|
||||
SECOND: másodperc
|
||||
MINUTE: perc
|
||||
HOUR: óra
|
||||
DAY: nap
|
||||
WEEK: hét
|
||||
MONTH: hónap
|
||||
YEAR: év
|
||||
DECADE: évtized
|
||||
SEC: mp
|
||||
MIN: p
|
||||
HR: ó
|
||||
WK: hét
|
||||
MO: hó
|
||||
YR: év
|
||||
DEC: évt
|
||||
SECOND_PLURAL: másodperc
|
||||
MINUTE_PLURAL: perc
|
||||
HOUR_PLURAL: óra
|
||||
DAY_PLURAL: nap
|
||||
WEEK_PLURAL: hét
|
||||
MONTH_PLURAL: hónap
|
||||
YEAR_PLURAL: év
|
||||
DECADE_PLURAL: évtized
|
||||
SEC_PLURAL: mp
|
||||
MIN_PLURAL: perc
|
||||
HR_PLURAL: ó
|
||||
WK_PLURAL: hét
|
||||
MO_PLURAL: hó
|
||||
YR_PLURAL: év
|
||||
DEC_PLURAL: évt
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>A validáció hibát talált:</b>'
|
||||
INVALID_INPUT: 'Az itt megadott érték érvénytelen:'
|
||||
MISSING_REQUIRED_FIELD: 'Ez a kötelező mező nincs kitöltve:'
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Nessuna data fornita
|
||||
BAD_DATE: Data errata
|
||||
AGO: fa
|
||||
FROM_NOW: da adesso
|
||||
SECOND: secondo
|
||||
MINUTE: minuto
|
||||
HOUR: ora
|
||||
DAY: giorno
|
||||
WEEK: settimana
|
||||
MONTH: mese
|
||||
YEAR: anno
|
||||
SECOND_PLURAL: secondi
|
||||
MINUTE_PLURAL: minuti
|
||||
HOUR_PLURAL: ore
|
||||
DAY_PLURAL: giorni
|
||||
WEEK_PLURAL: settimane
|
||||
MONTH_PLURAL: mesi
|
||||
YEAR_PLURAL: anni
|
||||
DECADE_PLURAL: decadi
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Validazione fallita:</b>'
|
||||
INVALID_INPUT: Input invalido in
|
||||
MISSING_REQUIRED_FIELD: 'Campo richiesto mancante:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Gennaio
|
||||
- Febbraio
|
||||
- Marzo
|
||||
- Aprile
|
||||
- Maggio
|
||||
- Giugno
|
||||
- Luglio
|
||||
- Agosto
|
||||
- Settembre
|
||||
- Ottobre
|
||||
- Novembre
|
||||
- Dicembre
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Lunedi
|
||||
- Martedi
|
||||
- Mercoledi
|
||||
- Giovedi
|
||||
- Venerdi
|
||||
- Sabato
|
||||
- Domenica
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
2: ryžiai
|
||||
3: pinigai
|
||||
4: prieskoniai
|
||||
5: serijos
|
||||
6: žuvis
|
||||
7: avis
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: žmonės
|
||||
man: žmogus
|
||||
child: vaikai
|
||||
sex: lytys
|
||||
move: juda
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Nenurodyta data
|
||||
BAD_DATE: Neteisinga data
|
||||
AGO: prieš
|
||||
FROM_NOW: nuo dabar
|
||||
SECOND: sekundė
|
||||
MINUTE: minutė
|
||||
HOUR: valanda
|
||||
DAY: diena
|
||||
WEEK: savaitė
|
||||
MONTH: mėnuo
|
||||
YEAR: metai
|
||||
DECADE: dešimtmetis
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: val
|
||||
WK: sav
|
||||
MO: mėn
|
||||
YR: m
|
||||
MINUTE_PLURAL: minutės
|
||||
HOUR_PLURAL: valandos
|
||||
DAY_PLURAL: dienos
|
||||
WEEK_PLURAL: savaitės
|
||||
MONTH_PLURAL: mėnesiai
|
||||
YEAR_PLURAL: metai
|
||||
DECADE_PLURAL: dešimtmečiai
|
||||
SEC_PLURAL: sek
|
||||
MIN_PLURAL: min
|
||||
HR_PLURAL: val
|
||||
WK_PLURAL: sav
|
||||
MO_PLURAL: mėn
|
||||
YR_PLURAL: m
|
||||
FORM:
|
||||
MISSING_REQUIRED_FIELD: 'Būtina užpildyti laukelį:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Sausis
|
||||
- Vasaris
|
||||
- Kovas
|
||||
- Balandis
|
||||
- Gegužė
|
||||
- Birželis
|
||||
- Liepa
|
||||
- Rugpjūtis
|
||||
- Rugsėjis
|
||||
- Spalis
|
||||
- Lakpritis
|
||||
- Gruodis
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Pirmadienis
|
||||
- Antradienis
|
||||
- Trečiadienis
|
||||
- Ketvirtadienis
|
||||
- Penktadienis
|
||||
- Šeštadienis
|
||||
- Sekmadienis
|
||||
@@ -0,0 +1,2 @@
|
||||
MONTHS_OF_THE_YEAR: ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember']
|
||||
DAYS_OF_THE_WEEK: ['mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag']
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: personen
|
||||
man: mensen
|
||||
child: kinderen
|
||||
sex: geslacht
|
||||
move: verplaatsen
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: geen datum opgegeven
|
||||
BAD_DATE: Datumformaat onjuist
|
||||
AGO: geleden
|
||||
FROM_NOW: vanaf nu
|
||||
SECOND: seconde
|
||||
MINUTE: minuut
|
||||
HOUR: uur
|
||||
DAY: dag
|
||||
MONTH: maand
|
||||
YEAR: jaar
|
||||
DECADE: decenium
|
||||
MO: ma
|
||||
SECOND_PLURAL: seconden
|
||||
MINUTE_PLURAL: minuten
|
||||
HOUR_PLURAL: uren
|
||||
DAY_PLURAL: dagen
|
||||
WEEK_PLURAL: weken
|
||||
MONTH_PLURAL: maanden
|
||||
YEAR_PLURAL: jaren
|
||||
DECADE_PLURAL: decennia
|
||||
SEC_PLURAL: seconden
|
||||
MIN_PLURAL: minuten
|
||||
HR_PLURAL: uren
|
||||
WK_PLURAL: weken
|
||||
MO_PLURAL: maanden
|
||||
YR_PLURAL: jaren
|
||||
MONTHS_OF_THE_YEAR:
|
||||
0: Januari
|
||||
1: Februari
|
||||
2: Maart
|
||||
4: Mei
|
||||
5: Juni
|
||||
6: Juli
|
||||
7: Augustus
|
||||
9: Oktober
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Maandag
|
||||
- Dinsdag
|
||||
- Woensdag
|
||||
- Donderdag
|
||||
- Vrijdag
|
||||
- Zaterdag
|
||||
- Zondag
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
FRONTMATTER_ERROR_PAGE: |
|
||||
---
|
||||
Tittel: %1$s
|
||||
---
|
||||
|
||||
# Feilmelding: Ugyldig Frontmatter
|
||||
|
||||
Pane: '%2$s'
|
||||
|
||||
**%3$s **
|
||||
|
||||
```
|
||||
%4$s
|
||||
```
|
||||
INFLECTOR_PLURALS:
|
||||
/(quiz)$/i: '\1zes'
|
||||
/^(ox)$/i: '\1en'
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
- utstyr
|
||||
- informasjon
|
||||
- ris
|
||||
- penger
|
||||
- arter
|
||||
- serier
|
||||
- fisk
|
||||
- sau
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: folk
|
||||
man: menn
|
||||
child: barn
|
||||
sex: kjønn
|
||||
move: trekk
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Ingen dato gitt
|
||||
BAD_DATE: Dårlig dato
|
||||
AGO: siden
|
||||
FROM_NOW: fra nå
|
||||
SECOND: sekund
|
||||
MINUTE: minutt
|
||||
HOUR: time
|
||||
DAY: dag
|
||||
WEEK: uke
|
||||
MONTH: måned
|
||||
YEAR: år
|
||||
DECADE: tiår
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: t
|
||||
WK: uke
|
||||
MO: må
|
||||
YR: år
|
||||
DEC: des
|
||||
SECOND_PLURAL: sekunder
|
||||
MINUTE_PLURAL: minutter
|
||||
HOUR_PLURAL: timer
|
||||
DAY_PLURAL: dager
|
||||
WEEK_PLURAL: uker
|
||||
MONTH_PLURAL: måneder
|
||||
YEAR_PLURAL: år
|
||||
DECADE_PLURAL: tiår
|
||||
SEC_PLURAL: sek
|
||||
MIN_PLURAL: min
|
||||
HR_PLURAL: timer
|
||||
WK_PLURAL: uker
|
||||
YR_PLURAL: år
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Validering mislyktes:</b>'
|
||||
INVALID_INPUT: Ugyldig innhold i
|
||||
MISSING_REQUIRED_FIELD: 'Mangler påkrevd felt:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- januar
|
||||
- februar
|
||||
- mars
|
||||
- april
|
||||
- mai
|
||||
- juni
|
||||
- juli
|
||||
- august
|
||||
- september
|
||||
- oktober
|
||||
- november
|
||||
- desember
|
||||
DAYS_OF_THE_WEEK:
|
||||
- mandag
|
||||
- tirsdag
|
||||
- onsdag
|
||||
- torsdag
|
||||
- fredag
|
||||
- lørdag
|
||||
- søndag
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
FRONTMATTER_ERROR_PAGE: |
|
||||
---
|
||||
title: %1$s
|
||||
---
|
||||
|
||||
# Error: Nieprawidłowy Frontmatter
|
||||
|
||||
Path: `%2$s`
|
||||
|
||||
**%3$s**
|
||||
|
||||
```
|
||||
%4$s
|
||||
```
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Nie podano daty
|
||||
BAD_DATE: Zła data
|
||||
AGO: temu
|
||||
FROM_NOW: od teraz
|
||||
SECOND: sekunda
|
||||
MINUTE: minuta
|
||||
HOUR: godzina
|
||||
DAY: dzień
|
||||
WEEK: tydzień
|
||||
MONTH: miesiąc
|
||||
YEAR: rok
|
||||
DECADE: dekada
|
||||
SEC: sek
|
||||
MIN: min
|
||||
HR: godz
|
||||
WK: tydź
|
||||
MO: mieś
|
||||
YR: rok
|
||||
DEC: dekada
|
||||
SECOND_PLURAL: sekund
|
||||
MINUTE_PLURAL: minut
|
||||
HOUR_PLURAL: godzin
|
||||
DAY_PLURAL: dni
|
||||
WEEK_PLURAL: tygodnie
|
||||
MONTH_PLURAL: miesięcy
|
||||
YEAR_PLURAL: lat
|
||||
DECADE_PLURAL: dekad
|
||||
SEC_PLURAL: sekund
|
||||
MIN_PLURAL: minut
|
||||
HR_PLURAL: godz
|
||||
WK_PLURAL: tyg
|
||||
MO_PLURAL: mieś
|
||||
YR_PLURAL: lat
|
||||
DEC_PLURAL: dekad
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Weryfikacja nie powiodła się:</b>'
|
||||
INVALID_INPUT: Nieprawidłowe dane w
|
||||
MISSING_REQUIRED_FIELD: 'Opuszczono wymagane pole:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Styczeń
|
||||
- Luty
|
||||
- Marzec
|
||||
- Kwiecień
|
||||
- Maj
|
||||
- Czerwiec
|
||||
- Lipiec
|
||||
- Sierpień
|
||||
- Wrzesień
|
||||
- Październik
|
||||
- Listopad
|
||||
- Grudzień
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Poniedziałek
|
||||
- Wtorek
|
||||
- Środa
|
||||
- Czwartek
|
||||
- Piątek
|
||||
- Sobota
|
||||
- Niedziela
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
INFLECTOR_UNCOUNTABLE:
|
||||
1: informação
|
||||
2: arroz
|
||||
3: dinheiro
|
||||
INFLECTOR_IRREGULAR:
|
||||
man: homens
|
||||
sex: sexos
|
||||
NICETIME:
|
||||
SECOND: segundo
|
||||
MINUTE: minuto
|
||||
HOUR: hora
|
||||
DAY: dia
|
||||
WEEK: semana
|
||||
MONTH: mês
|
||||
YEAR: ano
|
||||
DECADE: década
|
||||
SEC: seg
|
||||
MIN: mín
|
||||
MO: mês
|
||||
YR: ano
|
||||
SECOND_PLURAL: segundos
|
||||
MINUTE_PLURAL: minutos
|
||||
HOUR_PLURAL: horas
|
||||
DAY_PLURAL: dias
|
||||
WEEK_PLURAL: semanas
|
||||
MONTH_PLURAL: meses
|
||||
YEAR_PLURAL: anos
|
||||
DECADE_PLURAL: décadas
|
||||
SEC_PLURAL: seg
|
||||
MIN_PLURAL: mins
|
||||
HR_PLURAL: hrs
|
||||
YR_PLURAL: anos
|
||||
FORM:
|
||||
VALIDATION_FAIL: '<b>Validação falhada: </b>'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Janeiro
|
||||
- Fevereiro
|
||||
- Março
|
||||
- Abril
|
||||
- Maio
|
||||
- Junho
|
||||
- Julho
|
||||
- Agosto
|
||||
- Setembro
|
||||
- Outubro
|
||||
- Novembro
|
||||
- Dezembro
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Segunda
|
||||
- Terça
|
||||
- Quarta
|
||||
- Quinta
|
||||
- Sexta
|
||||
- Sábado
|
||||
- Domingo
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
MONTHS_OF_THE_YEAR:
|
||||
0: Ianuarie
|
||||
1: Februarie
|
||||
2: Martie
|
||||
3: Aprilue
|
||||
4: Mai
|
||||
5: Iunie
|
||||
6: Iulie
|
||||
8: Septembrie
|
||||
9: Octombrie
|
||||
10: Noiembrie
|
||||
11: Decembrie
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Luni
|
||||
- Marti
|
||||
- Miercuri
|
||||
- Joi
|
||||
- Vineri
|
||||
- Sâmbătă
|
||||
- Duminică
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
INFLECTOR_IRREGULAR:
|
||||
person: люди
|
||||
man: человек
|
||||
child: ребенок
|
||||
sex: пол
|
||||
move: движется
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Дата не указана
|
||||
BAD_DATE: Неверная дата
|
||||
AGO: назад
|
||||
FROM_NOW: теперь
|
||||
SECOND: секунда
|
||||
MINUTE: минута
|
||||
HOUR: час
|
||||
DAY: д
|
||||
WEEK: неделя
|
||||
MONTH: месяц
|
||||
YEAR: год
|
||||
DECADE: десятилетие
|
||||
SEC: с
|
||||
MIN: мин
|
||||
HR: ч
|
||||
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: 'Отсутствует необходимое поле:'
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- Январь
|
||||
- Февраль
|
||||
- Март
|
||||
- Апрель
|
||||
- Май
|
||||
- Июнь
|
||||
- Июль
|
||||
- Август
|
||||
- Сентябрь
|
||||
- Октябрь
|
||||
- Ноябрь
|
||||
- Декабрь
|
||||
DAYS_OF_THE_WEEK:
|
||||
- Понедельник
|
||||
- Вторник
|
||||
- Среда
|
||||
- Четверг
|
||||
- Пятница
|
||||
- Суббота
|
||||
- Воскресенье
|
||||
@@ -0,0 +1 @@
|
||||
---
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
NICETIME:
|
||||
DAY: dag
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
NICETIME:
|
||||
NO_DATE_PROVIDED: Tarih yok
|
||||
BAD_DATE: Yanlış tarih
|
||||
AGO: önce
|
||||
FROM_NOW: (şimdiden)
|
||||
SECOND: saniye
|
||||
MINUTE: dakika
|
||||
HOUR: saat
|
||||
DAY: gün
|
||||
WEEK: hafta
|
||||
MONTH: ay
|
||||
YEAR: yıl
|
||||
DECADE: onyıl
|
||||
SEC: sn
|
||||
MIN: dk
|
||||
HR: sa
|
||||
WK: hft
|
||||
MO: ay
|
||||
YR: yl
|
||||
DEC: onyl
|
||||
SECOND_PLURAL: saniye
|
||||
MINUTE_PLURAL: dakika
|
||||
HOUR_PLURAL: saat
|
||||
DAY_PLURAL: gün
|
||||
WEEK_PLURAL: hafta
|
||||
MONTH_PLURAL: ay
|
||||
YEAR_PLURAL: yıl
|
||||
DECADE_PLURAL: onyıl
|
||||
SEC_PLURAL: sn
|
||||
MIN_PLURAL: dk
|
||||
HR_PLURAL: sa
|
||||
WK_PLURAL: hft
|
||||
MO_PLURAL: ay
|
||||
YR_PLURAL: yl
|
||||
DEC_PLURAL: onyl
|
||||
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
namespace Grav\Common\Backup;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
use Grav\Common\Inflector;
|
||||
|
||||
/**
|
||||
* The ZipBackup class lets you create simple zip-backups of a grav site
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class ZipBackup
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected static $ignorePaths = [
|
||||
'backup',
|
||||
'cache',
|
||||
'images',
|
||||
'logs'
|
||||
];
|
||||
|
||||
protected static $ignoreFolders = [
|
||||
'.git',
|
||||
'.svn',
|
||||
'.hg',
|
||||
'.idea'
|
||||
];
|
||||
|
||||
/**
|
||||
* Backup
|
||||
*
|
||||
* @param null $destination
|
||||
* @param callable|null $messager
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public static function backup($destination = null, callable $messager = null)
|
||||
{
|
||||
if (!$destination) {
|
||||
$destination = self::getGrav()['locator']->findResource('backup://', true);
|
||||
|
||||
if (!$destination)
|
||||
throw new \RuntimeException('The backup folder is missing.');
|
||||
|
||||
Folder::mkdir($destination);
|
||||
}
|
||||
|
||||
$name = self::getGrav()['config']->get('site.title', basename(GRAV_ROOT));
|
||||
|
||||
$inflector = new Inflector();
|
||||
|
||||
if (is_dir($destination)) {
|
||||
$date = date('YmdHis', time());
|
||||
$filename = trim($inflector->hyphenize($name), '-') . '-' . $date . '.zip';
|
||||
$destination = rtrim($destination, DS) . DS . $filename;
|
||||
}
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => 'Creating new Backup "' . $destination . '"'
|
||||
]);
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => ''
|
||||
]);
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
$zip->open($destination, \ZipArchive::CREATE);
|
||||
|
||||
$max_execution_time = ini_set('max_execution_time', 600);
|
||||
|
||||
static::folderToZip(GRAV_ROOT, $zip, strlen(rtrim(GRAV_ROOT, DS) . DS), $messager);
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'progress',
|
||||
'percentage' => false,
|
||||
'complete' => true
|
||||
]);
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => ''
|
||||
]);
|
||||
$messager && $messager([
|
||||
'type' => 'message',
|
||||
'level' => 'info',
|
||||
'message' => 'Saving and compressing archive...'
|
||||
]);
|
||||
|
||||
$zip->close();
|
||||
|
||||
if ($max_execution_time !== false) {
|
||||
ini_set('max_execution_time', $max_execution_time);
|
||||
}
|
||||
|
||||
return $destination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $folder
|
||||
* @param $zipFile
|
||||
* @param $exclusiveLength
|
||||
* @param $messager
|
||||
*/
|
||||
private static function folderToZip($folder, \ZipArchive &$zipFile, $exclusiveLength, callable $messager = null)
|
||||
{
|
||||
$handle = opendir($folder);
|
||||
while (false !== $f = readdir($handle)) {
|
||||
if ($f != '.' && $f != '..') {
|
||||
$filePath = "$folder/$f";
|
||||
// Remove prefix from file path before add to zip.
|
||||
$localPath = substr($filePath, $exclusiveLength);
|
||||
|
||||
if (in_array($f, static::$ignoreFolders)) {
|
||||
continue;
|
||||
} elseif (in_array($localPath, static::$ignorePaths)) {
|
||||
$zipFile->addEmptyDir($f);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_file($filePath)) {
|
||||
$zipFile->addFile($filePath, $localPath);
|
||||
|
||||
$messager && $messager([
|
||||
'type' => 'progress',
|
||||
'percentage' => false,
|
||||
'complete' => false
|
||||
]);
|
||||
} elseif (is_dir($filePath)) {
|
||||
// Add sub-directory.
|
||||
$zipFile->addEmptyDir($localPath);
|
||||
static::folderToZip($filePath, $zipFile, $exclusiveLength, $messager);
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
namespace Grav\Common;
|
||||
|
||||
/**
|
||||
* Handles browser and platform versions
|
||||
*
|
||||
* Internally uses the PhpUserAgent package https://github.com/donatj/PhpUserAgent
|
||||
*
|
||||
* @author RocketTHeme
|
||||
* @licence MIT
|
||||
*/
|
||||
class Browser
|
||||
{
|
||||
protected $useragent = [];
|
||||
|
||||
/**
|
||||
* Browser constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->useragent = parse_user_agent();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->useragent = parse_user_agent("Mozilla/5.0 (compatible; Unknown;)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current browser identifier
|
||||
*
|
||||
* Currently detected browsers:
|
||||
*
|
||||
* Android Browser
|
||||
* BlackBerry Browser
|
||||
* Camino
|
||||
* Kindle / Silk
|
||||
* Firefox / Iceweasel
|
||||
* Safari
|
||||
* Internet Explorer
|
||||
* IEMobile
|
||||
* Chrome
|
||||
* Opera
|
||||
* Midori
|
||||
* Vivaldi
|
||||
* TizenBrowser
|
||||
* Lynx
|
||||
* Wget
|
||||
* Curl
|
||||
*
|
||||
* @return string the lowercase browser name
|
||||
*/
|
||||
public function getBrowser()
|
||||
{
|
||||
return strtolower($this->useragent['browser']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current platform identifier
|
||||
*
|
||||
* Currently detected platforms:
|
||||
*
|
||||
* Desktop
|
||||
* -> Windows
|
||||
* -> Linux
|
||||
* -> Macintosh
|
||||
* -> Chrome OS
|
||||
* Mobile
|
||||
* -> Android
|
||||
* -> iPhone
|
||||
* -> iPad / iPod Touch
|
||||
* -> Windows Phone OS
|
||||
* -> Kindle
|
||||
* -> Kindle Fire
|
||||
* -> BlackBerry
|
||||
* -> Playbook
|
||||
* -> Tizen
|
||||
* Console
|
||||
* -> Nintendo 3DS
|
||||
* -> New Nintendo 3DS
|
||||
* -> Nintendo Wii
|
||||
* -> Nintendo WiiU
|
||||
* -> PlayStation 3
|
||||
* -> PlayStation 4
|
||||
* -> PlayStation Vita
|
||||
* -> Xbox 360
|
||||
* -> Xbox One
|
||||
*
|
||||
* @return string the lowercase platform name
|
||||
*/
|
||||
public function getPlatform()
|
||||
{
|
||||
return strtolower($this->useragent['platform']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current full version identifier
|
||||
*
|
||||
* @return string the browser full version identifier
|
||||
*/
|
||||
public function getLongVersion()
|
||||
{
|
||||
return $this->useragent['version'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current major version identifier
|
||||
*
|
||||
* @return string the browser major version identifier
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
$version = explode('.', $this->getLongVersion());
|
||||
|
||||
return intval($version[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the request comes from a human, or from a bot/crawler
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isHuman()
|
||||
{
|
||||
$browser = $this->getBrowser();
|
||||
if (empty($browser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('~(bot|crawl)~i', $browser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
<?php
|
||||
namespace Grav\Common;
|
||||
|
||||
use \Doctrine\Common\Cache as DoctrineCache;
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
|
||||
/**
|
||||
* The GravCache object is used throughout Grav to store and retrieve cached data.
|
||||
* It uses DoctrineCache library and supports a variety of caching mechanisms. Those include:
|
||||
*
|
||||
* APC
|
||||
* XCache
|
||||
* RedisCache
|
||||
* MemCache
|
||||
* MemCacheD
|
||||
* FileSystem
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Cache extends Getters
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* @var string Cache key.
|
||||
*/
|
||||
protected $key;
|
||||
|
||||
protected $lifetime;
|
||||
protected $now;
|
||||
|
||||
/** @var Config $config */
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var DoctrineCache\CacheProvider
|
||||
*/
|
||||
protected $driver;
|
||||
|
||||
protected $driver_name;
|
||||
|
||||
protected $driver_setting;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $enabled;
|
||||
|
||||
protected $cache_dir;
|
||||
|
||||
protected static $standard_remove = [
|
||||
'cache://twig/',
|
||||
'cache://doctrine/',
|
||||
'cache://compiled/',
|
||||
'cache://validated-',
|
||||
'cache://images',
|
||||
'asset://',
|
||||
];
|
||||
|
||||
protected static $all_remove = [
|
||||
'cache://',
|
||||
'cache://images',
|
||||
'asset://'
|
||||
];
|
||||
|
||||
protected static $assets_remove = [
|
||||
'asset://'
|
||||
];
|
||||
|
||||
protected static $images_remove = [
|
||||
'cache://images'
|
||||
];
|
||||
|
||||
protected static $cache_remove = [
|
||||
'cache://'
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Grav $grav
|
||||
*/
|
||||
public function __construct(Grav $grav)
|
||||
{
|
||||
$this->init($grav);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization that sets a base key and the driver based on configuration settings
|
||||
*
|
||||
* @param Grav $grav
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init(Grav $grav)
|
||||
{
|
||||
/** @var Config $config */
|
||||
$this->config = $grav['config'];
|
||||
$this->now = time();
|
||||
|
||||
$this->cache_dir = $grav['locator']->findResource('cache://doctrine', true, true);
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = $grav['uri'];
|
||||
|
||||
$prefix = $this->config->get('system.cache.prefix');
|
||||
|
||||
$this->enabled = (bool)$this->config->get('system.cache.enabled');
|
||||
|
||||
// Cache key allows us to invalidate all cache on configuration changes.
|
||||
$this->key = ($prefix ? $prefix : 'g') . '-' . substr(md5($uri->rootUrl(true) . $this->config->key() . GRAV_VERSION),
|
||||
2, 8);
|
||||
|
||||
$this->driver_setting = $this->config->get('system.cache.driver');
|
||||
|
||||
$this->driver = $this->getCacheDriver();
|
||||
|
||||
// Set the cache namespace to our unique key
|
||||
$this->driver->setNamespace($this->key);
|
||||
|
||||
// Dump Cache state
|
||||
$grav['debugger']->addMessage('Cache: [' . ($this->enabled ? 'true' : 'false') . '] Setting: [' . $this->driver_setting . '] Driver: [' . $this->driver_name . ']');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically picks the cache mechanism to use. If you pick one manually it will use that
|
||||
* If there is no config option for $driver in the config, or it's set to 'auto', it will
|
||||
* pick the best option based on which cache extensions are installed.
|
||||
*
|
||||
* @return DoctrineCache\CacheProvider The cache driver to use
|
||||
*/
|
||||
public function getCacheDriver()
|
||||
{
|
||||
$setting = $this->driver_setting;
|
||||
$driver_name = 'file';
|
||||
|
||||
if (!$setting || $setting == 'auto') {
|
||||
if (extension_loaded('apcu')) {
|
||||
$driver_name = 'apcu';
|
||||
} elseif (extension_loaded('apc')) {
|
||||
$driver_name = 'apc';
|
||||
} elseif (extension_loaded('wincache')) {
|
||||
$driver_name = 'wincache';
|
||||
} elseif (extension_loaded('xcache')) {
|
||||
$driver_name = 'xcache';
|
||||
}
|
||||
} else {
|
||||
$driver_name = $setting;
|
||||
}
|
||||
|
||||
$this->driver_name = $driver_name;
|
||||
|
||||
switch ($driver_name) {
|
||||
case 'apc':
|
||||
$driver = new DoctrineCache\ApcCache();
|
||||
break;
|
||||
|
||||
case 'apcu':
|
||||
$driver = new DoctrineCache\ApcuCache();
|
||||
break;
|
||||
|
||||
case 'wincache':
|
||||
$driver = new DoctrineCache\WinCacheCache();
|
||||
break;
|
||||
|
||||
case 'xcache':
|
||||
$driver = new DoctrineCache\XcacheCache();
|
||||
break;
|
||||
|
||||
case 'memcache':
|
||||
$memcache = new \Memcache();
|
||||
$memcache->connect($this->config->get('system.cache.memcache.server', 'localhost'),
|
||||
$this->config->get('system.cache.memcache.port', 11211));
|
||||
$driver = new DoctrineCache\MemcacheCache();
|
||||
$driver->setMemcache($memcache);
|
||||
break;
|
||||
|
||||
case 'redis':
|
||||
$redis = new \Redis();
|
||||
$redis->connect($this->config->get('system.cache.redis.server', 'localhost'),
|
||||
$this->config->get('system.cache.redis.port', 6379));
|
||||
|
||||
$driver = new DoctrineCache\RedisCache();
|
||||
$driver->setRedis($redis);
|
||||
break;
|
||||
|
||||
default:
|
||||
$driver = new DoctrineCache\FilesystemCache($this->cache_dir);
|
||||
break;
|
||||
}
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a cached entry if it exists based on an id. If it does not exist, it returns false
|
||||
*
|
||||
* @param string $id the id of the cached entry
|
||||
*
|
||||
* @return object returns the cached entry, can be any type, or false if doesn't exist
|
||||
*/
|
||||
public function fetch($id)
|
||||
{
|
||||
if ($this->enabled) {
|
||||
return $this->driver->fetch($id);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a new cached entry.
|
||||
*
|
||||
* @param string $id the id of the cached entry
|
||||
* @param array|object $data the data for the cached entry to store
|
||||
* @param int $lifetime the lifetime to store the entry in seconds
|
||||
*/
|
||||
public function save($id, $data, $lifetime = null)
|
||||
{
|
||||
if ($this->enabled) {
|
||||
if ($lifetime === null) {
|
||||
$lifetime = $this->getLifetime();
|
||||
}
|
||||
$this->driver->save($id, $data, $lifetime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter method to get the cache key
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to clear all Grav caches
|
||||
*
|
||||
* @param string $remove standard|all|assets-only|images-only|cache-only
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function clearCache($remove = 'standard')
|
||||
{
|
||||
$locator = self::getGrav()['locator'];
|
||||
$output = [];
|
||||
$user_config = USER_DIR . 'config/system.yaml';
|
||||
|
||||
switch ($remove) {
|
||||
case 'all':
|
||||
$remove_paths = self::$all_remove;
|
||||
break;
|
||||
case 'assets-only':
|
||||
$remove_paths = self::$assets_remove;
|
||||
break;
|
||||
case 'images-only':
|
||||
$remove_paths = self::$images_remove;
|
||||
break;
|
||||
case 'cache-only':
|
||||
$remove_paths = self::$cache_remove;
|
||||
break;
|
||||
default:
|
||||
$remove_paths = self::$standard_remove;
|
||||
}
|
||||
|
||||
|
||||
foreach ($remove_paths as $stream) {
|
||||
|
||||
// Convert stream to a real path
|
||||
$path = $locator->findResource($stream, true, true);
|
||||
// Make sure path exists before proceeding, otherwise we would wipe ROOT_DIR
|
||||
if (!$path) {
|
||||
throw new \RuntimeException("Stream '{$stream}' not found", 500);
|
||||
}
|
||||
|
||||
$anything = false;
|
||||
$files = glob($path . '/*');
|
||||
|
||||
if (is_array($files)) {
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
if (@unlink($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
if (@Folder::delete($file)) {
|
||||
$anything = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($anything) {
|
||||
$output[] = '<red>Cleared: </red>' . $path . '/*';
|
||||
}
|
||||
}
|
||||
|
||||
$output[] = '';
|
||||
|
||||
if (($remove == 'all' || $remove == 'standard') && file_exists($user_config)) {
|
||||
touch($user_config);
|
||||
|
||||
$output[] = '<red>Touched: </red>' . $user_config;
|
||||
$output[] = '';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the cache lifetime programmatically
|
||||
*
|
||||
* @param int $future timestamp
|
||||
*/
|
||||
public function setLifetime($future)
|
||||
{
|
||||
if (!$future) {
|
||||
return;
|
||||
}
|
||||
|
||||
$interval = $future - $this->now;
|
||||
if ($interval > 0 && $interval < $this->getLifetime()) {
|
||||
$this->lifetime = $interval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the cache lifetime (in seconds)
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLifetime()
|
||||
{
|
||||
if ($this->lifetime === null) {
|
||||
$this->lifetime = $this->config->get('system.cache.lifetime') ?: 604800; // 1 week default
|
||||
}
|
||||
|
||||
return $this->lifetime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Grav\Common;
|
||||
|
||||
/**
|
||||
* Offers composer helper methods.
|
||||
*
|
||||
* @author eschmar
|
||||
* @license MIT
|
||||
*/
|
||||
class Composer
|
||||
{
|
||||
/** @const Default composer location */
|
||||
const DEFAULT_PATH = "bin/composer.phar";
|
||||
|
||||
/**
|
||||
* Returns the location of composer.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getComposerLocation()
|
||||
{
|
||||
if (!function_exists('shell_exec') || strtolower(substr(PHP_OS, 0, 3)) === 'win') {
|
||||
return self::DEFAULT_PATH;
|
||||
}
|
||||
|
||||
// check for global composer install
|
||||
$path = trim(shell_exec("command -v composer"));
|
||||
|
||||
// fall back to grav bundled composer
|
||||
if (!$path || !preg_match('/(composer|composer\.phar)$/', $path)) {
|
||||
$path = self::DEFAULT_PATH;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the composer executable file path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getComposerExecutor()
|
||||
{
|
||||
$executor = PHP_BINARY . ' ';
|
||||
$composer = static::getComposerLocation();
|
||||
|
||||
if ($composer !== static::DEFAULT_PATH && is_executable($composer)) {
|
||||
$file = fopen($composer, 'r');
|
||||
$firstLine = fgets($file);
|
||||
fclose($file);
|
||||
|
||||
if (!preg_match('/^#!.+php/i', $firstLine)) {
|
||||
$executor = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $executor . $composer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
|
||||
/**
|
||||
* The Compiled base class.
|
||||
*/
|
||||
abstract class CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var string Filename (base name) of the compiled configuration.
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string|bool Configuration checksum.
|
||||
*/
|
||||
public $checksum;
|
||||
|
||||
/**
|
||||
* @var string Cache folder to be used.
|
||||
*/
|
||||
protected $cacheFolder;
|
||||
|
||||
/**
|
||||
* @var array List of files to load.
|
||||
*/
|
||||
protected $files;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* @var mixed Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* @param string $cacheFolder Cache folder to be used.
|
||||
* @param array $files List of files as returned from ConfigFileFinder class.
|
||||
* @param string $path Base path for the file list.
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __construct($cacheFolder, array $files, $path)
|
||||
{
|
||||
if (!$cacheFolder) {
|
||||
throw new \BadMethodCallException('Cache folder not defined.');
|
||||
}
|
||||
|
||||
$this->cacheFolder = $cacheFolder;
|
||||
$this->files = $files;
|
||||
$this->path = $path ? rtrim($path, '\\/') . '/' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename for the compiled PHP file.
|
||||
*
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function name($name = null)
|
||||
{
|
||||
if (!$this->name) {
|
||||
$this->name = $name ?: md5(json_encode(array_keys($this->files)));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified() {}
|
||||
|
||||
/**
|
||||
* Load the configuration.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function load()
|
||||
{
|
||||
if ($this->object) {
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
$filename = $this->createFilename();
|
||||
if (!$this->loadCompiledFile($filename) && $this->loadFiles()) {
|
||||
$this->saveCompiledFile($filename);
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns checksum from the configuration files.
|
||||
*
|
||||
* You can set $this->checksum = false to disable this check.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function checksum()
|
||||
{
|
||||
if (!isset($this->checksum)) {
|
||||
$this->checksum = md5(json_encode($this->files) . $this->version);
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
protected function createFilename()
|
||||
{
|
||||
return "{$this->cacheFolder}/{$this->name()->name}.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
abstract protected function createObject(array $data = []);
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
abstract protected function finalizeObject();
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
abstract protected function loadFile($name, $filename);
|
||||
|
||||
/**
|
||||
* Load and join all configuration files.
|
||||
*
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected function loadFiles()
|
||||
{
|
||||
$this->createObject();
|
||||
|
||||
$list = array_reverse($this->files);
|
||||
foreach ($list as $files) {
|
||||
foreach ($files as $name => $item) {
|
||||
$this->loadFile($name, $this->path . $item['file']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->finalizeObject();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load compiled file.
|
||||
*
|
||||
* @param string $filename
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected function loadCompiledFile($filename)
|
||||
{
|
||||
if (!file_exists($filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache = include $filename;
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['data'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['@class'] != get_class($this)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if ($cache['checksum'] !== $this->checksum()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->createObject($cache['data']);
|
||||
|
||||
$this->finalizeObject();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save compiled file.
|
||||
*
|
||||
* @param string $filename
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function saveCompiledFile($filename)
|
||||
{
|
||||
$file = PhpFile::instance($filename);
|
||||
|
||||
// Attempt to lock the file for writing.
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
}
|
||||
|
||||
if ($file->locked() === false) {
|
||||
// File was already locked by another process.
|
||||
return;
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => get_class($this),
|
||||
'timestamp' => time(),
|
||||
'checksum' => $this->checksum(),
|
||||
'files' => $this->files,
|
||||
'data' => $this->object->toArray()
|
||||
];
|
||||
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
$file->free();
|
||||
|
||||
$this->modified();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
|
||||
/**
|
||||
* The Compiled Blueprints class.
|
||||
*/
|
||||
class CompiledBlueprints extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Blueprints Blueprints object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
$this->object = new Blueprints($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject() {}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$this->object->embed($name, $file->content(), '/');
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
|
||||
/**
|
||||
* The Compiled Configuration class.
|
||||
*/
|
||||
class CompiledConfig extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Config Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* @var callable Blueprints loader.
|
||||
*/
|
||||
protected $callable;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $withDefaults;
|
||||
|
||||
/**
|
||||
* Set blueprints for the configuration.
|
||||
*
|
||||
* @param callable $blueprints
|
||||
* @return $this
|
||||
*/
|
||||
public function setBlueprints(callable $blueprints)
|
||||
{
|
||||
$this->callable = $blueprints;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $withDefaults
|
||||
* @return mixed
|
||||
*/
|
||||
public function load($withDefaults = false)
|
||||
{
|
||||
$this->withDefaults = $withDefaults;
|
||||
|
||||
return parent::load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
if ($this->withDefaults && empty($data) && is_callable($this->callable)) {
|
||||
$blueprints = $this->callable;
|
||||
$data = $blueprints()->getDefaults();
|
||||
}
|
||||
|
||||
$this->object = new Config($data, $this->callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject()
|
||||
{
|
||||
$this->object->checksum($this->checksum());
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$this->object->modified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$this->object->join($name, $file->content(), '/');
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
|
||||
/**
|
||||
* The Compiled Languages class.
|
||||
*/
|
||||
class CompiledLanguages extends CompiledBase
|
||||
{
|
||||
/**
|
||||
* @var int Version number for the compiled file.
|
||||
*/
|
||||
public $version = 1;
|
||||
|
||||
/**
|
||||
* @var Languages Configuration object.
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* Create configuration object.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
protected function createObject(array $data = [])
|
||||
{
|
||||
$this->object = new Languages($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize configuration object.
|
||||
*/
|
||||
protected function finalizeObject()
|
||||
{
|
||||
$this->object->checksum($this->checksum());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function gets called when cached configuration is saved.
|
||||
*/
|
||||
public function modified()
|
||||
{
|
||||
$this->object->modified(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load single configuration file and append it to the correct position.
|
||||
*
|
||||
* @param string $name Name of the position.
|
||||
* @param string $filename File to be loaded.
|
||||
*/
|
||||
protected function loadFile($name, $filename)
|
||||
{
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
if (preg_match('|languages\.yaml$|', $filename)) {
|
||||
$this->object->mergeRecursive($file->content());
|
||||
} else {
|
||||
$this->object->join($name, $file->content(), '/');
|
||||
}
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Debugger;
|
||||
use Grav\Common\Grav;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Service\ConfigServiceProvider;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Config extends Data
|
||||
{
|
||||
protected $checksum;
|
||||
protected $modified = false;
|
||||
|
||||
public function key()
|
||||
{
|
||||
return $this->checksum();
|
||||
}
|
||||
|
||||
public function checksum($checksum = null)
|
||||
{
|
||||
if ($checksum !== null) {
|
||||
$this->checksum = $checksum;
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
public function modified($modified = null)
|
||||
{
|
||||
if ($modified !== null) {
|
||||
$this->modified = $modified;
|
||||
}
|
||||
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
public function reload()
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
|
||||
// Load new configuration.
|
||||
$config = ConfigServiceProvider::load($grav);
|
||||
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = $grav['debugger'];
|
||||
|
||||
if ($config->modified()) {
|
||||
// Update current configuration.
|
||||
$this->items = $config->toArray();
|
||||
$this->checksum($config->checksum());
|
||||
$this->modified(true);
|
||||
|
||||
$debugger->addMessage('Configuration was changed and saved.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function debug()
|
||||
{
|
||||
/** @var Debugger $debugger */
|
||||
$debugger = Grav::instance()['debugger'];
|
||||
|
||||
$debugger->addMessage('Environment Name: ' . $this->environment);
|
||||
if ($this->modified()) {
|
||||
$debugger->addMessage('Configuration reloaded and cached.');
|
||||
}
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
$setup = Grav::instance()['setup']->toArray();
|
||||
foreach ($setup as $key => $value) {
|
||||
if ($key === 'streams' || !is_array($value)) {
|
||||
// Optimized as streams and simple values are fully defined in setup.
|
||||
$this->items[$key] = $value;
|
||||
} else {
|
||||
$this->joinDefaults($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @deprecated
|
||||
*/
|
||||
public function getLanguages()
|
||||
{
|
||||
return Grav::instance()['languages'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Filesystem\Folder;
|
||||
|
||||
/**
|
||||
* The Configuration & Blueprints Finder class.
|
||||
*/
|
||||
class ConfigFileFinder
|
||||
{
|
||||
protected $base = '';
|
||||
|
||||
/**
|
||||
* @param string $base
|
||||
* @return $this
|
||||
*/
|
||||
public function setBase($base)
|
||||
{
|
||||
$this->base = $base ? "{$base}/" : '';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all locations for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function locateFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$list += $this->detectRecursive($folder, $pattern, $levels);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all locations for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function getFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
$files = $this->detectRecursive($folder, $pattern, $levels);
|
||||
|
||||
$list += $files[trim($path, '/')];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all paths for all the files with a timestamp.
|
||||
*
|
||||
* @param array $paths List of folders to look from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
*/
|
||||
public function listFiles(array $paths, $pattern = '|\.yaml$|', $levels = -1)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$list = array_merge_recursive($list, $this->detectAll($folder, $pattern, $levels));
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find filename from a list of folders.
|
||||
*
|
||||
* Note: Only finds the last override.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param array $folders
|
||||
* @return array
|
||||
*/
|
||||
public function locateFileInFolder($filename, array $folders)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$list += $this->detectInFolder($folder, $filename);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find filename from a list of folders.
|
||||
*
|
||||
* @param array $folders
|
||||
* @param string $filename
|
||||
* @return array
|
||||
*/
|
||||
public function locateInFolders(array $folders, $filename = null)
|
||||
{
|
||||
$list = [];
|
||||
foreach ($folders as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
$list[$path] = $this->detectInFolder($folder, $filename);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all existing locations for a single file with a timestamp.
|
||||
*
|
||||
* @param array $paths Filesystem paths to look up from.
|
||||
* @param string $name Configuration file to be located.
|
||||
* @param string $ext File extension (optional, defaults to .yaml).
|
||||
* @return array
|
||||
*/
|
||||
public function locateFile(array $paths, $name, $ext = '.yaml')
|
||||
{
|
||||
$filename = preg_replace('|[.\/]+|', '/', $name) . $ext;
|
||||
|
||||
$list = [];
|
||||
foreach ($paths as $folder) {
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_file("{$folder}/{$filename}")) {
|
||||
$modified = filemtime("{$folder}/{$filename}");
|
||||
} else {
|
||||
$modified = 0;
|
||||
}
|
||||
$basename = $this->base . $name;
|
||||
$list[$path] = [$basename => ['file' => "{$path}/{$filename}", 'modified' => $modified]];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all directories with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectRecursive($folder, $pattern, $levels)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'levels' => $levels,
|
||||
'compare' => 'Filename',
|
||||
'pattern' => $pattern,
|
||||
'filters' => [
|
||||
'pre-key' => $this->base,
|
||||
'key' => $pattern,
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ['file' => "{$path}/{$file->getSubPathname()}", 'modified' => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
|
||||
ksort($list);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all directories with the lookup file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $lookup Filename to be located (defaults to directory name).
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectInFolder($folder, $lookup = null)
|
||||
{
|
||||
$folder = rtrim($folder, '/');
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
$base = $path === $folder ? '' : ($path ? substr($folder, 0, -strlen($path)) : $folder . '/');
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \DirectoryIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$find = ($lookup ?: $name) . '.yaml';
|
||||
$filename = "{$path}/{$name}/{$find}";
|
||||
|
||||
if (file_exists($base . $filename)) {
|
||||
$basename = $this->base . $name;
|
||||
$list[$basename] = ['file' => $filename, 'modified' => filemtime($base . $filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
* @param string $folder Location to look up from.
|
||||
* @param string $pattern Pattern to match the file. Pattern will also be removed from the key.
|
||||
* @param int $levels Maximum number of recursive directories.
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function detectAll($folder, $pattern, $levels)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
if (is_dir($folder)) {
|
||||
// Find all system and user configuration files.
|
||||
$options = [
|
||||
'levels' => $levels,
|
||||
'compare' => 'Filename',
|
||||
'pattern' => $pattern,
|
||||
'filters' => [
|
||||
'pre-key' => $this->base,
|
||||
'key' => $pattern,
|
||||
'value' => function (\RecursiveDirectoryIterator $file) use ($path) {
|
||||
return ["{$path}/{$file->getSubPathname()}" => $file->getMTime()];
|
||||
}
|
||||
],
|
||||
'key' => 'SubPathname'
|
||||
];
|
||||
|
||||
$list = Folder::all($folder, $options);
|
||||
|
||||
ksort($list);
|
||||
} else {
|
||||
$list = [];
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
|
||||
/**
|
||||
* The Languages class contains configuration rules.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Languages extends Data
|
||||
{
|
||||
public function checksum($checksum = null)
|
||||
{
|
||||
if ($checksum !== null) {
|
||||
$this->checksum = $checksum;
|
||||
}
|
||||
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
public function modified($modified = null)
|
||||
{
|
||||
if ($modified !== null) {
|
||||
$this->modified = $modified;
|
||||
}
|
||||
|
||||
return $this->modified;
|
||||
}
|
||||
|
||||
public function reformat()
|
||||
{
|
||||
if (isset($this->items['plugins'])) {
|
||||
$this->items = array_merge_recursive($this->items, $this->items['plugins']);
|
||||
unset($this->items['plugins']);
|
||||
}
|
||||
}
|
||||
|
||||
public function mergeRecursive(array $data)
|
||||
{
|
||||
$this->items = array_merge_recursive($this->items, $data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\Data\Data;
|
||||
use Grav\Common\Utils;
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* The Config class contains configuration information.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Setup extends Data
|
||||
{
|
||||
protected $streams = [
|
||||
'system' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['system'],
|
||||
]
|
||||
],
|
||||
'user' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user'],
|
||||
]
|
||||
],
|
||||
'environment' => [
|
||||
'type' => 'ReadOnlyStream'
|
||||
// If not defined, environment will be set up in the constructor.
|
||||
],
|
||||
'asset' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['assets'],
|
||||
]
|
||||
],
|
||||
'blueprints' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://blueprints', 'user://blueprints', 'system/blueprints'],
|
||||
]
|
||||
],
|
||||
'config' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://config', 'user://config', 'system/config'],
|
||||
]
|
||||
],
|
||||
'plugins' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'plugin' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://plugins'],
|
||||
]
|
||||
],
|
||||
'themes' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://themes'],
|
||||
]
|
||||
],
|
||||
'languages' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['environment://languages', 'user://languages', 'system/languages'],
|
||||
]
|
||||
],
|
||||
'cache' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['cache'],
|
||||
'images' => ['images']
|
||||
]
|
||||
],
|
||||
'log' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['logs']
|
||||
]
|
||||
],
|
||||
'backup' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
'' => ['backup']
|
||||
]
|
||||
],
|
||||
'image' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://images', 'system://images']
|
||||
]
|
||||
],
|
||||
'page' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://pages']
|
||||
]
|
||||
],
|
||||
'account' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://accounts']
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$environment = $container['uri']->environment();
|
||||
if (!$environment) {
|
||||
$environment = 'localhost';
|
||||
}
|
||||
|
||||
// Pre-load setup.php which contains our initial configuration.
|
||||
// Configuration may contain dynamic parts, which is why we need to always load it.
|
||||
$file = GRAV_ROOT . '/setup.php';
|
||||
$setup = is_file($file) ? (array) include $file : [];
|
||||
|
||||
// Add default streams defined in beginning of the class.
|
||||
if (!isset($setup['streams']['schemes'])) {
|
||||
$setup['streams']['schemes'] = [];
|
||||
}
|
||||
$setup['streams']['schemes'] += $this->streams;
|
||||
|
||||
// Initialize class.
|
||||
parent::__construct($setup);
|
||||
|
||||
// Set up environment.
|
||||
$this->def('environment', $environment);
|
||||
$this->def('streams.schemes.environment.prefixes', ['' => ["user://{$this->environment}"]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$locator = new UniformResourceLocator(GRAV_ROOT);
|
||||
$files = [];
|
||||
|
||||
$guard = 5;
|
||||
do {
|
||||
$check = $files;
|
||||
$this->initializeLocator($locator);
|
||||
$files = $locator->findResources('config://streams.yaml');
|
||||
|
||||
if ($check === $files) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Update streams.
|
||||
foreach (array_reverse($files) as $path) {
|
||||
$file = CompiledYamlFile::instance($path);
|
||||
$content = $file->content();
|
||||
if (!empty($content['schemes'])) {
|
||||
$this->items['streams']['schemes'] = $content['schemes'] + $this->items['streams']['schemes'];
|
||||
}
|
||||
}
|
||||
} while (--$guard);
|
||||
|
||||
if (!$guard) {
|
||||
throw new \RuntimeException('Setup: Configuration reload loop detected!');
|
||||
}
|
||||
|
||||
// Make sure we have valid setup.
|
||||
$this->check($locator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
* @param UniformResourceLocator $locator
|
||||
*/
|
||||
public function initializeLocator(UniformResourceLocator $locator)
|
||||
{
|
||||
$locator->reset();
|
||||
|
||||
$schemes = (array) $this->get('streams.schemes', []);
|
||||
|
||||
foreach ($schemes as $scheme => $config) {
|
||||
if (isset($config['paths'])) {
|
||||
$locator->addPath($scheme, '', $config['paths']);
|
||||
}
|
||||
if (isset($config['prefixes'])) {
|
||||
foreach ($config['prefixes'] as $prefix => $paths) {
|
||||
$locator->addPath($scheme, $prefix, $paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available streams and their types from the configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getStreams()
|
||||
{
|
||||
$schemes = [];
|
||||
foreach ((array) $this->get('streams.schemes') as $scheme => $config) {
|
||||
$type = !empty($config['type']) ? $config['type'] : 'ReadOnlyStream';
|
||||
if ($type[0] != '\\') {
|
||||
$type = '\\RocketTheme\\Toolbox\\StreamWrapper\\' . $type;
|
||||
}
|
||||
|
||||
$schemes[$scheme] = $type;
|
||||
}
|
||||
|
||||
return $schemes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UniformResourceLocator $locator
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function check(UniformResourceLocator $locator)
|
||||
{
|
||||
$streams = isset($this->items['streams']['schemes']) ? $this->items['streams']['schemes'] : null;
|
||||
if (!is_array($streams)) {
|
||||
throw new \InvalidArgumentException('Configuration is missing streams.schemes!');
|
||||
}
|
||||
$diff = array_keys(array_diff_key($this->streams, $streams));
|
||||
if ($diff) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Configuration is missing keys %s from streams.schemes!', implode(', ', $diff))
|
||||
);
|
||||
}
|
||||
|
||||
if (!$locator->findResource('environment://config', true)) {
|
||||
// If environment does not have its own directory, remove it from the lookup.
|
||||
$this->set('streams.schemes.environment.prefixes', ['config' => []]);
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
// Create security.yaml if it doesn't exist.
|
||||
$filename = $locator->findResource('config://security.yaml', true, true);
|
||||
$file = YamlFile::instance($filename);
|
||||
if (!$file->exists()) {
|
||||
$file->save(['salt' => Utils::generateRandomString(14)]);
|
||||
$file->free();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,476 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
|
||||
/**
|
||||
* Blueprint handles the inside logic of blueprints.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Blueprint implements \ArrayAccess, ExportInterface
|
||||
{
|
||||
use Export, NestedArrayAccessWithGetters, GravTrait;
|
||||
|
||||
public $name;
|
||||
|
||||
public $initialized = false;
|
||||
|
||||
protected $items;
|
||||
protected $context;
|
||||
protected $fields;
|
||||
protected $rules = array();
|
||||
protected $nested = array();
|
||||
protected $filter = ['validation' => 1];
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
* @param Blueprints $context
|
||||
*/
|
||||
public function __construct($name, array $data = array(), Blueprints $context = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->items = $data;
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set filter for inherited properties.
|
||||
*
|
||||
* @param array $filter List of field names to be inherited.
|
||||
*/
|
||||
public function setFilter(array $filter)
|
||||
{
|
||||
$this->filter = array_flip($filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all form fields.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields()
|
||||
{
|
||||
if (!isset($this->fields)) {
|
||||
$this->fields = [];
|
||||
$this->embed('', $this->items);
|
||||
}
|
||||
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate data against blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function validate(array $data)
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
|
||||
try {
|
||||
$this->validateArray($data, $this->nested);
|
||||
} catch (\RuntimeException $e) {
|
||||
$language = self::getGrav()['language'];
|
||||
$message = sprintf($language->translate('FORM.VALIDATION_FAIL', null, true) . ' %s', $e->getMessage());
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge two arrays by using blueprints.
|
||||
*
|
||||
* @param array $data1
|
||||
* @param array $data2
|
||||
* @return array
|
||||
*/
|
||||
public function mergeData(array $data1, array $data2)
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
return $this->mergeArrays($data1, $data2, $this->nested);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter data by using blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function filter(array $data)
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
return $this->filterArray($data, $this->nested);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return data fields that do not exist in blueprints.
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $prefix
|
||||
* @return array
|
||||
*/
|
||||
public function extra(array $data, $prefix = '')
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
$rules = $this->nested;
|
||||
|
||||
// Drill down to prefix level
|
||||
if (!empty($prefix)) {
|
||||
$parts = explode('.', trim($prefix, '.'));
|
||||
foreach ($parts as $part) {
|
||||
$rules = isset($rules[$part]) ? $rules[$part] : [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->extraArray($data, $rules, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend blueprint with another blueprint.
|
||||
*
|
||||
* @param Blueprint $extends
|
||||
* @param bool $append
|
||||
*/
|
||||
public function extend(Blueprint $extends, $append = false)
|
||||
{
|
||||
$blueprints = $append ? $this->items : $extends->toArray();
|
||||
$appended = $append ? $extends->toArray() : $this->items;
|
||||
|
||||
$bref_stack = array(&$blueprints);
|
||||
$head_stack = array($appended);
|
||||
|
||||
do {
|
||||
end($bref_stack);
|
||||
|
||||
$bref = &$bref_stack[key($bref_stack)];
|
||||
$head = array_pop($head_stack);
|
||||
|
||||
unset($bref_stack[key($bref_stack)]);
|
||||
|
||||
foreach (array_keys($head) as $key) {
|
||||
if (isset($key, $bref[$key]) && is_array($bref[$key]) && is_array($head[$key])) {
|
||||
$bref_stack[] = &$bref[$key];
|
||||
$head_stack[] = $head[$key];
|
||||
} else {
|
||||
$bref = array_merge($bref, array($key => $head[$key]));
|
||||
}
|
||||
}
|
||||
} while (count($head_stack));
|
||||
|
||||
$this->items = $blueprints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object into an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return ['name' => $this->name, 'items' => $this->items, 'rules' => $this->rules, 'nested' => $this->nested];
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed an array to the blueprint.
|
||||
*
|
||||
* @param $name
|
||||
* @param array $value
|
||||
* @param string $separator
|
||||
*/
|
||||
public function embed($name, array $value, $separator = '.')
|
||||
{
|
||||
|
||||
if (!isset($value['form']['fields']) || !is_array($value['form']['fields'])) {
|
||||
return;
|
||||
}
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
$prefix = $name ? strtr($name, $separator, '.') . '.' : '';
|
||||
$params = array_intersect_key($this->filter, $value);
|
||||
$this->parseFormFields($value['form']['fields'], $params, $prefix, $this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function validateArray(array $data, array $rules)
|
||||
{
|
||||
$this->checkRequired($data, $rules);
|
||||
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
Validation::validate($field, $rule);
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$this->validateArray($field, $val);
|
||||
} elseif (isset($this->items['form']['validation']) && $this->items['form']['validation'] == 'strict') {
|
||||
// Undefined/extra item.
|
||||
throw new \RuntimeException(sprintf('%s is not defined in blueprints', $key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function filterArray(array $data, array $rules)
|
||||
{
|
||||
$results = array();
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
$field = Validation::filter($field, $rule);
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$field = $this->filterArray($field, $val);
|
||||
} elseif (isset($this->items['form']['validation']) && $this->items['form']['validation'] == 'strict') {
|
||||
$field = null;
|
||||
}
|
||||
|
||||
if (isset($field) && (!is_array($field) || !empty($field))) {
|
||||
$results[$key] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data1
|
||||
* @param array $data2
|
||||
* @param array $rules
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function mergeArrays(array $data1, array $data2, array $rules)
|
||||
{
|
||||
foreach ($data2 as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if (!$rule && array_key_exists($key, $data1) && is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$data1[$key] = $this->mergeArrays($data1[$key], $field, $val);
|
||||
} else {
|
||||
// Otherwise just take value from the data2.
|
||||
$data1[$key] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $data1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $rules
|
||||
* @param string $prefix
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function extraArray(array $data, array $rules, $prefix)
|
||||
{
|
||||
$array = array();
|
||||
foreach ($data as $key => $field) {
|
||||
$val = isset($rules[$key]) ? $rules[$key] : null;
|
||||
$rule = is_string($val) ? $this->rules[$val] : null;
|
||||
|
||||
if ($rule) {
|
||||
// Item has been defined in blueprints.
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$array += $this->ExtraArray($field, $val, $prefix . $key . '.');
|
||||
} else {
|
||||
// Undefined/extra item.
|
||||
$array[$prefix.$key] = $field;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all field definitions from the blueprints.
|
||||
*
|
||||
* @param array $fields
|
||||
* @param array $params
|
||||
* @param string $prefix
|
||||
* @param array $current
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormFields(array &$fields, $params, $prefix, array &$current)
|
||||
{
|
||||
// Go though all the fields in current level.
|
||||
foreach ($fields as $key => &$field) {
|
||||
$current[$key] = &$field;
|
||||
// Set name from the array key.
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
|
||||
if (isset($field['fields']) && (!isset($field['type']) || $field['type'] !== 'list')) {
|
||||
// Recursively get all the nested fields.
|
||||
$newParams = array_intersect_key($this->filter, $field);
|
||||
$this->parseFormFields($field['fields'], $newParams, $prefix, $current[$key]['fields']);
|
||||
} else if ($field['type'] !== 'ignore') {
|
||||
$this->rules[$prefix . $key] = &$field;
|
||||
$this->addProperty($prefix . $key);
|
||||
|
||||
if ($field['type'] === 'list') {
|
||||
// we loop through list to get the actual field
|
||||
if (isset($field['fields']) && $field['fields']) {
|
||||
foreach($field['fields'] as $subName => &$subField) {
|
||||
$this->parseFormField($subField);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->parseFormField($field);
|
||||
}
|
||||
|
||||
if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
|
||||
$field['validate'] += $this->getRule($field['validate']['rule']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Parses individual field definition
|
||||
*
|
||||
* @param array $field
|
||||
* @internal
|
||||
*/
|
||||
protected function parseFormField(&$field) {
|
||||
foreach ($field as $name => $value) {
|
||||
// Support nested blueprints.
|
||||
if ($this->context && $name == '@import') {
|
||||
$values = (array) $value;
|
||||
if (!isset($field['fields'])) {
|
||||
$field['fields'] = array();
|
||||
}
|
||||
foreach ($values as $bname) {
|
||||
$b = $this->context->get($bname);
|
||||
$field['fields'] = array_merge($field['fields'], $b->fields());
|
||||
}
|
||||
}
|
||||
|
||||
// Support for callable data values.
|
||||
elseif (substr($name, 0, 6) == '@data-') {
|
||||
$property = substr($name, 6);
|
||||
if (is_array($value)) {
|
||||
$func = array_shift($value);
|
||||
} else {
|
||||
$func = $value;
|
||||
$value = array();
|
||||
}
|
||||
list($o, $f) = preg_split('/::/', $func);
|
||||
if (!$f && function_exists($o)) {
|
||||
$data = call_user_func_array($o, $value);
|
||||
} elseif ($f && method_exists($o, $f)) {
|
||||
$data = call_user_func_array(array($o, $f), $value);
|
||||
}
|
||||
|
||||
// If function returns a value,
|
||||
if (isset($data)) {
|
||||
if (isset($field[$property]) && is_array($field[$property]) && is_array($data)) {
|
||||
// Combine field and @data-field together.
|
||||
$field[$property] += $data;
|
||||
} else {
|
||||
// Or create/replace field with @data-field.
|
||||
$field[$property] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elseif (substr($name, 0, 8) == '@config-') {
|
||||
$property = substr($name, 8);
|
||||
$default = isset($field[$property]) ? $field[$property] : null;
|
||||
$config = self::getGrav()['config']->get($value, $default);
|
||||
|
||||
if (!is_null($config)) {
|
||||
$field[$property] = $config;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add property to the definition.
|
||||
*
|
||||
* @param string $path Comma separated path to the property.
|
||||
* @internal
|
||||
*/
|
||||
protected function addProperty($path)
|
||||
{
|
||||
$parts = explode('.', $path);
|
||||
$item = array_pop($parts);
|
||||
|
||||
$nested = &$this->nested;
|
||||
foreach ($parts as $part) {
|
||||
if (!isset($nested[$part])) {
|
||||
$nested[$part] = array();
|
||||
}
|
||||
$nested = &$nested[$part];
|
||||
}
|
||||
|
||||
if (!isset($nested[$item])) {
|
||||
$nested[$item] = $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $rule
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
protected function getRule($rule)
|
||||
{
|
||||
if (isset($this->items['rules'][$rule]) && is_array($this->items['rules'][$rule])) {
|
||||
return $this->items['rules'][$rule];
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $fields
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
protected function checkRequired(array $data, array $fields)
|
||||
{
|
||||
foreach ($fields as $name => $field) {
|
||||
if (!is_string($field)) {
|
||||
continue;
|
||||
}
|
||||
$field = $this->rules[$field];
|
||||
if (isset($field['validate']['required'])
|
||||
&& $field['validate']['required'] === true
|
||||
&& empty($data[$name])) {
|
||||
$value = isset($field['label']) ? $field['label'] : $field['name'];
|
||||
$language = self::getGrav()['language'];
|
||||
$message = sprintf($language->translate('FORM.MISSING_REQUIRED_FIELD', null, true) . ' %s', $value);
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\GravTrait;
|
||||
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
|
||||
|
||||
/**
|
||||
* Blueprints class keeps track on blueprint instances.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Blueprints
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected $search;
|
||||
protected $types;
|
||||
protected $instances = array();
|
||||
|
||||
/**
|
||||
* @param string|array $search Search path.
|
||||
*/
|
||||
public function __construct($search)
|
||||
{
|
||||
$this->search = $search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blueprint.
|
||||
*
|
||||
* @param string $type Blueprint type.
|
||||
* @return Blueprint
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function get($type)
|
||||
{
|
||||
if (!isset($this->instances[$type])) {
|
||||
$parents = [];
|
||||
if (is_string($this->search)) {
|
||||
$filename = $this->search . $type . YAML_EXT;
|
||||
|
||||
// Check if search is a stream and resolve the path.
|
||||
if (strpos($filename, '://')) {
|
||||
$grav = static::getGrav();
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$parents = $locator->findResources($filename);
|
||||
$filename = array_shift($parents);
|
||||
}
|
||||
} else {
|
||||
$filename = isset($this->search[$type]) ? $this->search[$type] : '';
|
||||
}
|
||||
|
||||
if ($filename && is_file($filename)) {
|
||||
$file = CompiledYamlFile::instance($filename);
|
||||
$blueprints = $file->content();
|
||||
} else {
|
||||
$blueprints = [];
|
||||
}
|
||||
|
||||
$blueprint = new Blueprint($type, $blueprints, $this);
|
||||
|
||||
if (isset($blueprints['@extends'])) {
|
||||
// Extend blueprint by other blueprints.
|
||||
$extends = (array) $blueprints['@extends'];
|
||||
|
||||
if (is_string(key($extends))) {
|
||||
$extends = [ $extends ];
|
||||
}
|
||||
|
||||
foreach ($extends as $extendConfig) {
|
||||
$extendType = !is_string($extendConfig) ? empty($extendConfig['type']) ? false : $extendConfig['type'] : $extendConfig;
|
||||
|
||||
if (!$extendType) {
|
||||
continue;
|
||||
} elseif ($extendType === '@parent') {
|
||||
$parentFile = array_shift($parents);
|
||||
if (!$parentFile || !is_file($parentFile)) {
|
||||
continue;
|
||||
}
|
||||
$blueprints = CompiledYamlFile::instance($parentFile)->content();
|
||||
$parent = new Blueprint($type.'-parent', $blueprints, $this);
|
||||
$blueprint->extend($parent);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_string($extendConfig) || empty($extendConfig['context'])) {
|
||||
$context = $this;
|
||||
} else {
|
||||
// Load blueprints from external context.
|
||||
$array = explode('://', $extendConfig['context'], 2);
|
||||
$scheme = array_shift($array);
|
||||
$path = array_shift($array);
|
||||
if ($path) {
|
||||
$scheme .= '://';
|
||||
$extendType = $path ? "{$path}/{$extendType}" : $extendType;
|
||||
}
|
||||
$context = new self($scheme);
|
||||
}
|
||||
$blueprint->extend($context->get($extendType));
|
||||
}
|
||||
}
|
||||
|
||||
$this->instances[$type] = $blueprint;
|
||||
}
|
||||
|
||||
return $this->instances[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available blueprint types.
|
||||
*
|
||||
* @return array List of type=>name
|
||||
*/
|
||||
public function types()
|
||||
{
|
||||
if ($this->types === null) {
|
||||
$this->types = array();
|
||||
|
||||
// Check if search is a stream.
|
||||
if (strpos($this->search, '://')) {
|
||||
// Stream: use UniformResourceIterator.
|
||||
$grav = static::getGrav();
|
||||
/** @var UniformResourceLocator $locator */
|
||||
$locator = $grav['locator'];
|
||||
$iterator = $locator->getIterator($this->search, null);
|
||||
} else {
|
||||
// Not a stream: use DirectoryIterator.
|
||||
$iterator = new \DirectoryIterator($this->search);
|
||||
}
|
||||
|
||||
/** @var \DirectoryIterator $file */
|
||||
foreach ($iterator as $file) {
|
||||
if (!$file->isFile() || '.' . $file->getExtension() != YAML_EXT) {
|
||||
continue;
|
||||
}
|
||||
$name = $file->getBasename(YAML_EXT);
|
||||
$this->types[$name] = ucfirst(strtr($name, '_', ' '));
|
||||
}
|
||||
}
|
||||
return $this->types;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use RocketTheme\Toolbox\ArrayTraits\Countable;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
use RocketTheme\Toolbox\Blueprints\Blueprints;
|
||||
use RocketTheme\Toolbox\File\File;
|
||||
use RocketTheme\Toolbox\File\FileInterface;
|
||||
|
||||
/**
|
||||
* Recursive data object
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Data implements DataInterface, \ArrayAccess, \Countable, ExportInterface
|
||||
{
|
||||
use NestedArrayAccessWithGetters, Countable, Export;
|
||||
|
||||
protected $gettersVariable = 'items';
|
||||
protected $items;
|
||||
|
||||
/**
|
||||
* @var Blueprints
|
||||
*/
|
||||
protected $blueprints;
|
||||
|
||||
/**
|
||||
* @var File
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
* @param Blueprint|callable $blueprints
|
||||
*/
|
||||
public function __construct(array $items = array(), $blueprints = null)
|
||||
{
|
||||
$this->items = $items;
|
||||
$this->blueprints = $blueprints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $data->value('this.is.my.nested.variable');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return mixed Value.
|
||||
*/
|
||||
public function value($name, $default = null, $separator = '.')
|
||||
{
|
||||
return $this->get($name, $default, $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join nested values together by using blueprints.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function join($name, $value, $separator = '.')
|
||||
{
|
||||
$old = $this->get($name, null, $separator);
|
||||
if ($old !== null) {
|
||||
if (!is_array($old)) {
|
||||
throw new \RuntimeException('Value ' . $old);
|
||||
}
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
} elseif (!is_array($value)) {
|
||||
throw new \RuntimeException('Value ' . $value);
|
||||
}
|
||||
$value = $this->blueprints()->mergeData($old, $value, $name, $separator);
|
||||
}
|
||||
|
||||
$this->set($name, $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get nested structure containing default values defined in the blueprints.
|
||||
*
|
||||
* Fields without default value are ignored in the list.
|
||||
|
||||
* @return array
|
||||
*/
|
||||
public function getDefaults()
|
||||
{
|
||||
return $this->blueprints()->getDefaults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default values by using blueprints.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
*/
|
||||
public function joinDefaults($name, $value, $separator = '.')
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
}
|
||||
$old = $this->get($name, null, $separator);
|
||||
if ($old !== null) {
|
||||
$value = $this->blueprints()->mergeData($value, $old, $name, $separator);
|
||||
}
|
||||
|
||||
$this->set($name, $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value from the configuration and join it with given data.
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param array $value Value to be joined.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getJoined($name, $value, $separator = '.')
|
||||
{
|
||||
if (is_object($value)) {
|
||||
$value = (array) $value;
|
||||
} elseif (!is_array($value)) {
|
||||
throw new \RuntimeException('Value ' . $value);
|
||||
}
|
||||
|
||||
$old = $this->get($name, null, $separator);
|
||||
|
||||
if ($old === null) {
|
||||
// No value set; no need to join data.
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (!is_array($old)) {
|
||||
throw new \RuntimeException('Value ' . $old);
|
||||
}
|
||||
|
||||
// Return joined data.
|
||||
return $this->blueprints()->mergeData($old, $value, $name, $separator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge two configurations together.
|
||||
*
|
||||
* @param array $data
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(array $data)
|
||||
{
|
||||
$this->items = $this->blueprints()->mergeData($this->items, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default values to the configuration if variables were not set.
|
||||
*
|
||||
* @param array $data
|
||||
* @return $this
|
||||
*/
|
||||
public function setDefaults(array $data)
|
||||
{
|
||||
$this->items = $this->blueprints()->mergeData($data, $this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate by blueprints.
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$this->blueprints()->validate($this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
* Filter all items by using blueprints.
|
||||
*/
|
||||
public function filter()
|
||||
{
|
||||
$this->items = $this->blueprints()->filter($this->items);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extra items which haven't been defined in blueprints.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function extra()
|
||||
{
|
||||
return $this->blueprints ? $this->blueprints->extra($this->items) : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return blueprints.
|
||||
*
|
||||
* @return Blueprints
|
||||
*/
|
||||
public function blueprints()
|
||||
{
|
||||
if (!$this->blueprints){
|
||||
$this->blueprints = new Blueprints;
|
||||
} elseif (is_callable($this->blueprints)) {
|
||||
// Lazy load blueprints.
|
||||
$blueprints = $this->blueprints;
|
||||
$this->blueprints = $blueprints();
|
||||
}
|
||||
return $this->blueprints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data if storage has been defined.
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$file = $this->file();
|
||||
if ($file) {
|
||||
$file->save($this->items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the data already exists in the storage.
|
||||
*
|
||||
* NOTE: This method does not check if the data is current.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
{
|
||||
return $this->file()->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return unmodified data as raw string.
|
||||
*
|
||||
* NOTE: This function only returns data which has been saved to the storage.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function raw()
|
||||
{
|
||||
return $this->file()->raw();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or get the data storage.
|
||||
*
|
||||
* @param FileInterface $storage Optionally enter a new storage.
|
||||
* @return FileInterface
|
||||
*/
|
||||
public function file(FileInterface $storage = null)
|
||||
{
|
||||
if ($storage) {
|
||||
$this->storage = $storage;
|
||||
}
|
||||
return $this->storage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use RocketTheme\Toolbox\File\FileInterface;
|
||||
|
||||
/**
|
||||
* Data interface
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
interface DataInterface
|
||||
{
|
||||
/**
|
||||
* Get value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $data->value('this.is.my.nested.variable');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return mixed Value.
|
||||
*/
|
||||
public function value($name, $default = null, $separator = '.');
|
||||
|
||||
/**
|
||||
* Merge external data.
|
||||
*
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function merge(array $data);
|
||||
|
||||
/**
|
||||
* Return blueprints.
|
||||
*/
|
||||
public function blueprints();
|
||||
|
||||
/**
|
||||
* Validate by blueprints.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validate();
|
||||
|
||||
/**
|
||||
* Filter all items by using blueprints.
|
||||
*/
|
||||
public function filter();
|
||||
|
||||
/**
|
||||
* Get extra items which haven't been defined in blueprints.
|
||||
*/
|
||||
public function extra();
|
||||
|
||||
/**
|
||||
* Save data into the file.
|
||||
*/
|
||||
public function save();
|
||||
|
||||
/**
|
||||
* Set or get the data storage.
|
||||
*
|
||||
* @param FileInterface $storage Optionally enter a new storage.
|
||||
* @return FileInterface
|
||||
*/
|
||||
public function file(FileInterface $storage = null);
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
use Symfony\Component\Yaml\Parser;
|
||||
|
||||
/**
|
||||
* Data validation.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Validation
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* Validate value against a blueprint field definition.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param array $field
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function validate($value, array $field)
|
||||
{
|
||||
$validate = isset($field['validate']) ? (array) $field['validate'] : array();
|
||||
|
||||
// If value isn't required, we will stop validation if empty value is given.
|
||||
if (empty($validate['required']) && ($value === null || $value === '')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get language class
|
||||
$language = self::getGrav()['language'];
|
||||
|
||||
// Validate type with fallback type text.
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'type'.strtr($type, '-', '_');
|
||||
$name = ucfirst(isset($field['label']) ? $field['label'] : $field['name']);
|
||||
$message = (string) isset($field['validate']['message']) ? $language->translate($field['validate']['message']) : $language->translate('FORM.INVALID_INPUT', null, true) . ' "' . $language->translate($name) . '"';
|
||||
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $validate, $field);
|
||||
} else {
|
||||
$success = self::typeText($value, $validate, $field);
|
||||
}
|
||||
if (!$success) {
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
|
||||
// Check individual rules
|
||||
foreach ($validate as $rule => $params) {
|
||||
$method = 'validate'.strtr($rule, '-', '_');
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $params);
|
||||
|
||||
if (!$success) {
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter value against a blueprint field definition.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param array $field
|
||||
* @return mixed Filtered value.
|
||||
*/
|
||||
public static function filter($value, array $field)
|
||||
{
|
||||
$validate = isset($field['validate']) ? (array) $field['validate'] : array();
|
||||
|
||||
// If value isn't required, we will return null if empty value is given.
|
||||
if (empty($validate['required']) && ($value === null || $value === '')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// special case for files, value is never empty and errors with code 4 instead
|
||||
if (empty($validate['required']) && $field['type'] == 'file' && (isset($value['error']) && ($value['error'] == UPLOAD_ERR_NO_FILE || in_array(UPLOAD_ERR_NO_FILE, $value['error'])))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if this is a YAML field, simply parse it and return the value
|
||||
if (isset($field['yaml']) && $field['yaml'] === true) {
|
||||
try {
|
||||
$yaml = new Parser();
|
||||
return $yaml->parse($value);
|
||||
} catch (ParseException $e) {
|
||||
throw new \RuntimeException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Validate type with fallback type text.
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'filter'.strtr($type, '-', '_');
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$value = self::$method($value, $validate, $field);
|
||||
} else {
|
||||
$value = self::filterText($value, $validate, $field);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: text
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeText($value, array $params, array $field)
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($params['min']) && strlen($value) < $params['min']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($params['max']) && strlen($value) > $params['max']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$min = isset($params['min']) ? $params['min'] : 0;
|
||||
if (isset($params['step']) && (strlen($value) - $min) % $params['step'] == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!isset($params['multiline']) || !$params['multiline']) && preg_match('/\R/um', $value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function filterText($value, array $params, array $field)
|
||||
{
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
protected static function filterCommaList($value, array $params, array $field)
|
||||
{
|
||||
return is_array($value) ? $value : preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
protected static function typeCommaList($value, array $params, array $field)
|
||||
{
|
||||
return is_array($value) ? true : self::typeText($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: textarea
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeTextarea($value, array $params, array $field)
|
||||
{
|
||||
if (!isset($params['multiline'])) {
|
||||
$params['multiline'] = true;
|
||||
}
|
||||
|
||||
return self::typeText($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: password
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typePassword($value, array $params, array $field)
|
||||
{
|
||||
return self::typeText($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: hidden
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeHidden($value, array $params, array $field)
|
||||
{
|
||||
return self::typeText($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: checkbox list
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeCheckboxes($value, array $params, array $field)
|
||||
{
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
protected static function filterCheckboxes($value, array $params, array $field)
|
||||
{
|
||||
return self::filterArray($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: checkbox
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeCheckbox($value, array $params, array $field)
|
||||
{
|
||||
$value = (string) $value;
|
||||
|
||||
if (!isset($field['value'])) {
|
||||
$field['value'] = 1;
|
||||
}
|
||||
if ($value && $value != $field['value']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: radio
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeRadio($value, array $params, array $field)
|
||||
{
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: toggle
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeToggle($value, array $params, array $field)
|
||||
{
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: file
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeFile($value, array $params, array $field)
|
||||
{
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
protected static function filterFile($value, array $params, array $field)
|
||||
{
|
||||
if (isset($field['multiple']) && $field['multiple'] === true) {
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
if (is_array($value)) {
|
||||
return reset($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: select
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeSelect($value, array $params, array $field)
|
||||
{
|
||||
return self::typeArray((array) $value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: number
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
|
||||
public static function typeNumber($value, array $params, array $field)
|
||||
{
|
||||
if (!is_numeric($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($params['min']) && $value < $params['min']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($params['max']) && $value > $params['max']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$min = isset($params['min']) ? $params['min'] : 0;
|
||||
if (isset($params['step']) && fmod($value - $min, $params['step']) == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function filterNumber($value, array $params, array $field)
|
||||
{
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
protected static function filterDateTime($value, array $params, array $field)
|
||||
{
|
||||
$format = self::getGrav()['config']->get('system.pages.dateformat.default');
|
||||
if ($format) {
|
||||
$converted = new \DateTime($value);
|
||||
return $converted->format($format);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* HTML5 input: range
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeRange($value, array $params, array $field)
|
||||
{
|
||||
return self::typeNumber($value, $params, $field);
|
||||
}
|
||||
|
||||
protected static function filterRange($value, array $params, array $field)
|
||||
{
|
||||
return self::filterNumber($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: color
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeColor($value, array $params, array $field)
|
||||
{
|
||||
return preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: email
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeEmail($value, array $params, array $field)
|
||||
{
|
||||
return self::typeText($value, $params, $field) && filter_var($value, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: url
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
|
||||
public static function typeUrl($value, array $params, array $field)
|
||||
{
|
||||
return self::typeText($value, $params, $field) && filter_var($value, FILTER_VALIDATE_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: datetime
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeDatetime($value, array $params, array $field)
|
||||
{
|
||||
if ($value instanceof \DateTime) {
|
||||
return true;
|
||||
} elseif (!is_string($value)) {
|
||||
return false;
|
||||
} elseif (!isset($params['format'])) {
|
||||
return false !== strtotime($value);
|
||||
}
|
||||
|
||||
$dateFromFormat = \DateTime::createFromFormat($params['format'], $value);
|
||||
|
||||
return $dateFromFormat && $value === date($params['format'], $dateFromFormat->getTimestamp());
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: datetime-local
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeDatetimeLocal($value, array $params, array $field)
|
||||
{
|
||||
return self::typeDatetime($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: date
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeDate($value, array $params, array $field)
|
||||
{
|
||||
$params = array($params);
|
||||
if (!isset($params['format'])) {
|
||||
$params['format'] = 'Y-m-d';
|
||||
}
|
||||
return self::typeDatetime($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: time
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeTime($value, array $params, array $field)
|
||||
{
|
||||
$params = array($params);
|
||||
if (!isset($params['format'])) {
|
||||
$params['format'] = 'H:i';
|
||||
}
|
||||
return self::typeDatetime($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: month
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeMonth($value, array $params, array $field)
|
||||
{
|
||||
$params = array($params);
|
||||
if (!isset($params['format'])) {
|
||||
$params['format'] = 'Y-m';
|
||||
}
|
||||
return self::typeDatetime($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML5 input: week
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeWeek($value, array $params, array $field)
|
||||
{
|
||||
if (!isset($params['format']) && !preg_match('/^\d{4}-W\d{2}$/u', $value)) {
|
||||
return false;
|
||||
}
|
||||
return self::typeDatetime($value, $params, $field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: array
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeArray($value, array $params, array $field)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($field['multiple'])) {
|
||||
if (isset($params['min']) && count($value) < $params['min']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($params['max']) && count($value) > $params['max']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$min = isset($params['min']) ? $params['min'] : 0;
|
||||
if (isset($params['step']) && (count($value) - $min) % $params['step'] == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$options = isset($field['options']) ? array_keys($field['options']) : array();
|
||||
$values = isset($field['use']) && $field['use'] == 'keys' ? array_keys($value) : $value;
|
||||
if ($options && array_diff($values, $options)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function filterArray($value, $params, $field)
|
||||
{
|
||||
$values = (array) $value;
|
||||
$options = isset($field['options']) ? array_keys($field['options']) : array();
|
||||
$multi = isset($field['multiple']) ? $field['multiple'] : false;
|
||||
|
||||
if (count($values) == 1 && isset($values[0]) && $values[0] == '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($options) {
|
||||
$useKey = isset($field['use']) && $field['use'] == 'keys';
|
||||
foreach ($values as $key => $value) {
|
||||
$values[$key] = $useKey ? (bool) $value : $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($multi) {
|
||||
foreach ($values as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$value = implode(',', $value);
|
||||
}
|
||||
|
||||
$values[$key] = array_map('trim', explode(',', $value));
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function typeList($value, array $params, array $field)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
foreach ($value as $key => $item) {
|
||||
foreach ($field['fields'] as $subKey => $subField) {
|
||||
$subKey = trim($subKey, '.');
|
||||
$subValue = isset($item[$subKey]) ? $item[$subKey] : null;
|
||||
self::validate($subValue, $subField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function filterList($value, array $params, array $field)
|
||||
{
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: ignore (will not validate)
|
||||
*
|
||||
* @param mixed $value Value to be validated.
|
||||
* @param array $params Validation parameters.
|
||||
* @param array $field Blueprint for the field.
|
||||
* @return bool True if validation succeeded.
|
||||
*/
|
||||
public static function typeIgnore($value, array $params, array $field)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function filterIgnore($value, array $params, array $field)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
// HTML5 attributes (min, max and range are handled inside the types)
|
||||
|
||||
public static function validateRequired($value, $params)
|
||||
{
|
||||
if (is_string($value)) {
|
||||
$value = trim($value);
|
||||
}
|
||||
|
||||
return (bool) $params !== true || !empty($value);
|
||||
}
|
||||
|
||||
public static function validatePattern($value, $params)
|
||||
{
|
||||
return (bool) preg_match("`^{$params}$`u", $value);
|
||||
}
|
||||
|
||||
|
||||
// Internal types
|
||||
|
||||
public static function validateAlpha($value, $params)
|
||||
{
|
||||
return ctype_alpha($value);
|
||||
}
|
||||
|
||||
public static function validateAlnum($value, $params)
|
||||
{
|
||||
return ctype_alnum($value);
|
||||
}
|
||||
|
||||
public static function typeBool($value, $params)
|
||||
{
|
||||
return is_bool($value) || $value == 1 || $value == 0;
|
||||
}
|
||||
|
||||
public static function validateBool($value, $params)
|
||||
{
|
||||
return is_bool($value) || $value == 1 || $value == 0;
|
||||
}
|
||||
|
||||
protected static function filterBool($value, $params)
|
||||
{
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
public static function validateDigit($value, $params)
|
||||
{
|
||||
return ctype_digit($value);
|
||||
}
|
||||
|
||||
public static function validateFloat($value, $params)
|
||||
{
|
||||
return is_float(filter_var($value, FILTER_VALIDATE_FLOAT));
|
||||
}
|
||||
|
||||
protected static function filterFloat($value, $params)
|
||||
{
|
||||
return (float) $value;
|
||||
}
|
||||
|
||||
public static function validateHex($value, $params)
|
||||
{
|
||||
return ctype_xdigit($value);
|
||||
}
|
||||
|
||||
public static function validateInt($value, $params)
|
||||
{
|
||||
return is_numeric($value) && (int) $value == $value;
|
||||
}
|
||||
|
||||
protected static function filterInt($value, $params)
|
||||
{
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
public static function validateArray($value, $params)
|
||||
{
|
||||
return is_array($value) || ($value instanceof \ArrayAccess
|
||||
&& $value instanceof \Traversable
|
||||
&& $value instanceof \Countable);
|
||||
}
|
||||
|
||||
public static function validateJson($value, $params)
|
||||
{
|
||||
return (bool) (json_decode($value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
namespace Grav\Common;
|
||||
|
||||
use DebugBar\DataCollector\ConfigCollector;
|
||||
use DebugBar\JavascriptRenderer;
|
||||
use DebugBar\StandardDebugBar;
|
||||
use Grav\Common\Config\Config;
|
||||
|
||||
/**
|
||||
* Class Debugger
|
||||
* @package Grav\Common
|
||||
*/
|
||||
class Debugger
|
||||
{
|
||||
/** @var Grav $grav */
|
||||
protected $grav;
|
||||
|
||||
/** @var Config $config */
|
||||
protected $config;
|
||||
|
||||
/** @var JavascriptRenderer $renderer */
|
||||
protected $renderer;
|
||||
|
||||
/** @var StandardDebugBar $debugbar */
|
||||
protected $debugbar;
|
||||
|
||||
protected $enabled;
|
||||
|
||||
protected $timers = [];
|
||||
|
||||
/**
|
||||
* Debugger constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->debugbar = new StandardDebugBar();
|
||||
$this->debugbar['time']->addMeasure('Loading', $this->debugbar['time']->getRequestStartTime(), microtime(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the debugger
|
||||
*
|
||||
* @return $this
|
||||
* @throws \DebugBar\DebugBarException
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->grav = Grav::instance();
|
||||
$this->config = $this->grav['config'];
|
||||
|
||||
if ($this->enabled()) {
|
||||
$this->debugbar->addCollector(new ConfigCollector((array)$this->config->get('system'), 'Config'));
|
||||
$this->debugbar->addCollector(new ConfigCollector((array)$this->config->get('plugins'), 'Plugins'));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/get the enabled state of the debugger
|
||||
*
|
||||
* @param bool $state If null, the method returns the enabled value. If set, the method sets the enabled state
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function enabled($state = null)
|
||||
{
|
||||
if (isset($state)) {
|
||||
$this->enabled = $state;
|
||||
} else {
|
||||
if (!isset($this->enabled)) {
|
||||
$this->enabled = $this->config->get('system.debugger.enabled');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the debugger assets to the Grav Assets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addAssets()
|
||||
{
|
||||
if ($this->enabled()) {
|
||||
/** @var Assets $assets */
|
||||
$assets = $this->grav['assets'];
|
||||
|
||||
// Add jquery library
|
||||
$assets->add('jquery', 101);
|
||||
|
||||
$this->renderer = $this->debugbar->getJavascriptRenderer();
|
||||
$this->renderer->setIncludeVendors(false);
|
||||
|
||||
// Get the required CSS files
|
||||
list($css_files, $js_files) = $this->renderer->getAssets(null, JavascriptRenderer::RELATIVE_URL);
|
||||
foreach ($css_files as $css) {
|
||||
$assets->addCss($css);
|
||||
}
|
||||
|
||||
$assets->addCss('/system/assets/debugger.css');
|
||||
|
||||
foreach ($js_files as $js) {
|
||||
$assets->addJs($js);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a data collector
|
||||
*
|
||||
* @param $collector
|
||||
*
|
||||
* @return $this
|
||||
* @throws \DebugBar\DebugBarException
|
||||
*/
|
||||
public function addCollector($collector)
|
||||
{
|
||||
$this->debugbar->addCollector($collector);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a data collector
|
||||
*
|
||||
* @param $collector
|
||||
*
|
||||
* @return \DebugBar\DataCollector\DataCollectorInterface
|
||||
* @throws \DebugBar\DebugBarException
|
||||
*/
|
||||
public function getCollector($collector)
|
||||
{
|
||||
return $this->debugbar->getCollector($collector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the debug bar
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if ($this->enabled()) {
|
||||
echo $this->renderer->render();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the data through the HTTP headers
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function sendDataInHeaders()
|
||||
{
|
||||
$this->debugbar->sendDataInHeaders();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a timer with an associated name and description
|
||||
*
|
||||
* @param $name
|
||||
* @param string|null $description
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function startTimer($name, $description = null)
|
||||
{
|
||||
if ($name[0] == '_' || $this->config->get('system.debugger.enabled')) {
|
||||
$this->debugbar['time']->startMeasure($name, $description);
|
||||
$this->timers[] = $name;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the named timer
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function stopTimer($name)
|
||||
{
|
||||
if (in_array($name, $this->timers) && ($name[0] == '_' || $this->config->get('system.debugger.enabled'))) {
|
||||
$this->debugbar['time']->stopMeasure($name);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump variables into the Messages tab of the Debug Bar
|
||||
*
|
||||
* @param $message
|
||||
* @param string $label
|
||||
* @param bool $isString
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addMessage($message, $label = 'info', $isString = true)
|
||||
{
|
||||
if ($this->enabled()) {
|
||||
$this->debugbar['messages']->addMessage($message, $label, $isString);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Grav\Common\Errors;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
use Whoops;
|
||||
|
||||
/**
|
||||
* Class Debugger
|
||||
* @package Grav\Common
|
||||
*/
|
||||
class Errors
|
||||
{
|
||||
public function resetHandlers()
|
||||
{
|
||||
$grav = Grav::instance();
|
||||
$config = $grav['config']->get('system.errors');
|
||||
$jsonRequest = $_SERVER && $_SERVER['HTTP_ACCEPT'] && $_SERVER['HTTP_ACCEPT'] == 'application/json';
|
||||
|
||||
// Setup Whoops-based error handler
|
||||
$whoops = new \Whoops\Run;
|
||||
|
||||
if (isset($config['display'])) {
|
||||
if ($config['display']) {
|
||||
$error_page = new Whoops\Handler\PrettyPageHandler;
|
||||
$error_page->setPageTitle('Crikey! There was an error...');
|
||||
$error_page->addResourcePath(GRAV_ROOT . '/system/assets');
|
||||
$error_page->addCustomCss('whoops.css');
|
||||
$whoops->pushHandler($error_page);
|
||||
} else {
|
||||
$whoops->pushHandler(new SimplePageHandler);
|
||||
}
|
||||
}
|
||||
|
||||
if (method_exists('Whoops\Util\Misc', 'isAjaxRequest')) { //Whoops 2.0
|
||||
if (Whoops\Util\Misc::isAjaxRequest() || $jsonRequest) {
|
||||
$whoops->pushHandler(new Whoops\Handler\JsonResponseHandler);
|
||||
}
|
||||
} elseif (function_exists('Whoops\isAjaxRequest')) { //Whoops 2.0.0-alpha
|
||||
if (Whoops\isAjaxRequest() || $jsonRequest) {
|
||||
$whoops->pushHandler(new Whoops\Handler\JsonResponseHandler);
|
||||
}
|
||||
} else { //Whoops 1.x
|
||||
$json_page = new Whoops\Handler\JsonResponseHandler;
|
||||
$json_page->onlyForAjaxRequests(true);
|
||||
}
|
||||
|
||||
if (isset($config['log']) && $config['log']) {
|
||||
$logger = $grav['log'];
|
||||
$whoops->pushHandler(function($exception, $inspector, $run) use ($logger) {
|
||||
try {
|
||||
$logger->addCritical($exception->getMessage() . ' - Trace: ' . $exception->getTraceAsString());
|
||||
} catch (\Exception $e) {
|
||||
echo $e;
|
||||
}
|
||||
}, 'log');
|
||||
}
|
||||
|
||||
$whoops->register();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
html, body {
|
||||
height: 100%
|
||||
}
|
||||
body {
|
||||
margin:0 3rem;
|
||||
padding:0;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
|
||||
display: -ms-flexbox; /* TWEENER - IE 10 */
|
||||
display: -webkit-flex; /* NEW - Chrome */
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
-webkit-justify-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.container {
|
||||
margin: 0rem;
|
||||
max-width: 600px;
|
||||
padding-bottom:5rem;
|
||||
}
|
||||
|
||||
header {
|
||||
color: #000;
|
||||
font-size: 4rem;
|
||||
letter-spacing: 2px;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
p {
|
||||
font-family: Optima, Segoe, "Segoe UI", Candara, Calibri, Arial, sans-serif;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-weight: normal;
|
||||
color: #999;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-weight: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
code {
|
||||
font-weight: bold;
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Layout template file for Whoops's pretty error output.
|
||||
*/
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Whoops there was an error!</title>
|
||||
<style><?php echo $stylesheet ?></style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="details">
|
||||
<header>
|
||||
Server Error
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
<p>Sorry, something went terribly wrong!</p>
|
||||
|
||||
<h3><?php echo $code ?> - <?php echo $message ?></h3>
|
||||
|
||||
<h5>For further details please review your <code>logs/</code> folder, or enable displaying of errors in your system configuration.</h5>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
namespace Grav\Common\Errors;
|
||||
|
||||
use Whoops\Handler\Handler;
|
||||
use Whoops\Util\Misc;
|
||||
use Whoops\Util\TemplateHelper;
|
||||
|
||||
class SimplePageHandler extends Handler
|
||||
{
|
||||
private $searchPaths = array();
|
||||
private $resourceCache = array();
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// Add the default, local resource search path:
|
||||
$this->searchPaths[] = __DIR__ . "/Resources";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$inspector = $this->getInspector();
|
||||
|
||||
$helper = new TemplateHelper();
|
||||
$templateFile = $this->getResource("layout.html.php");
|
||||
$cssFile = $this->getResource("error.css");
|
||||
|
||||
$code = $inspector->getException()->getCode();
|
||||
$message = $inspector->getException()->getMessage();
|
||||
|
||||
if ($inspector->getException() instanceof \ErrorException) {
|
||||
$code = Misc::translateErrorCode($code);
|
||||
}
|
||||
|
||||
$vars = array(
|
||||
"stylesheet" => file_get_contents($cssFile),
|
||||
"code" => $code,
|
||||
"message" => $message,
|
||||
);
|
||||
|
||||
$helper->setVariables($vars);
|
||||
$helper->render($templateFile);
|
||||
|
||||
return Handler::QUIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $resource
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getResource($resource)
|
||||
{
|
||||
// If the resource was found before, we can speed things up
|
||||
// by caching its absolute, resolved path:
|
||||
if (isset($this->resourceCache[$resource])) {
|
||||
return $this->resourceCache[$resource];
|
||||
}
|
||||
|
||||
// Search through available search paths, until we find the
|
||||
// resource we're after:
|
||||
foreach ($this->searchPaths as $path) {
|
||||
$fullPath = $path . "/$resource";
|
||||
|
||||
if (is_file($fullPath)) {
|
||||
// Cache the result:
|
||||
$this->resourceCache[$resource] = $fullPath;
|
||||
return $fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got this far, nothing was found.
|
||||
throw new \RuntimeException(
|
||||
"Could not find resource '$resource' in any resource paths."
|
||||
. "(searched: " . join(", ", $this->searchPaths). ")"
|
||||
);
|
||||
}
|
||||
|
||||
public function addResourcePath($path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"'$path' is not a valid directory"
|
||||
);
|
||||
}
|
||||
|
||||
array_unshift($this->searchPaths, $path);
|
||||
}
|
||||
|
||||
public function getResourcePaths()
|
||||
{
|
||||
return $this->searchPaths;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace Grav\Common\File;
|
||||
|
||||
use RocketTheme\Toolbox\File\PhpFile;
|
||||
|
||||
/**
|
||||
* Class CompiledFile
|
||||
* @package Grav\Common\File
|
||||
*
|
||||
* @property string $filename
|
||||
* @property string $extension
|
||||
* @property string $raw
|
||||
* @property array|string $content
|
||||
*/
|
||||
trait CompiledFile
|
||||
{
|
||||
/**
|
||||
* Get/set parsed file contents.
|
||||
*
|
||||
* @param mixed $var
|
||||
* @return string
|
||||
*/
|
||||
public function content($var = null)
|
||||
{
|
||||
// Set some options
|
||||
$this->settings(['native' => true, 'compat' => true]);
|
||||
|
||||
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
|
||||
if ($var === null && $this->raw === null && $this->content === null) {
|
||||
$key = md5($this->filename);
|
||||
$file = PhpFile::instance(CACHE_DIR . "compiled/files/{$key}{$this->extension}.php");
|
||||
$modified = $this->modified();
|
||||
|
||||
if (!$modified) {
|
||||
return $this->decode($this->raw());
|
||||
}
|
||||
|
||||
$class = get_class($this);
|
||||
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!isset($cache['@class'])
|
||||
|| $cache['@class'] != $class
|
||||
|| $cache['modified'] != $modified
|
||||
|| $cache['filename'] != $this->filename
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
try {
|
||||
$file->lock(false);
|
||||
} catch (\Exception $e) {
|
||||
// Another process has locked the file; we will check this in a bit.
|
||||
}
|
||||
|
||||
// Decode RAW file into compiled array.
|
||||
$data = (array) $this->decode($this->raw());
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'filename' => $this->filename,
|
||||
'modified' => $modified,
|
||||
'data' => $data
|
||||
];
|
||||
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
}
|
||||
$file->free();
|
||||
|
||||
$this->content = $cache['data'];
|
||||
}
|
||||
|
||||
return parent::content($var);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace Grav\Common\File;
|
||||
|
||||
use RocketTheme\Toolbox\File\MarkdownFile;
|
||||
|
||||
class CompiledMarkdownFile extends MarkdownFile
|
||||
{
|
||||
use CompiledFile;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace Grav\Common\File;
|
||||
|
||||
use RocketTheme\Toolbox\File\YamlFile;
|
||||
|
||||
class CompiledYamlFile extends YamlFile
|
||||
{
|
||||
use CompiledFile;
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
<?php
|
||||
namespace Grav\Common\Filesystem;
|
||||
|
||||
/**
|
||||
* Folder helper class.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
abstract class Folder
|
||||
{
|
||||
/**
|
||||
* Recursively find the last modified time under given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return int
|
||||
*/
|
||||
public static function lastModifiedFolder($path)
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$filter = new RecursiveFolderFilterIterator($directory);
|
||||
$iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($iterator as $dir) {
|
||||
$dir_modified = $dir->getMTime();
|
||||
if ($dir_modified > $last_modified) {
|
||||
$last_modified = $dir_modified;
|
||||
}
|
||||
}
|
||||
|
||||
return $last_modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find the last modified time under given path by file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $extensions which files to search for specifically
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function lastModifiedFile($path, $extensions = 'md|yaml')
|
||||
{
|
||||
$last_modified = 0;
|
||||
|
||||
$directory = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$recursive = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator = new \RegexIterator($recursive, '/^.+\.'.$extensions.'$/i');
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($iterator as $filepath => $file) {
|
||||
$file_modified = $file->getMTime();
|
||||
if ($file_modified > $last_modified) {
|
||||
$last_modified = $file_modified;
|
||||
}
|
||||
}
|
||||
|
||||
return $last_modified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relative path between target and base path. If path isn't relative, return full path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param mixed|string $base
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativePath($path, $base = GRAV_ROOT)
|
||||
{
|
||||
if ($base) {
|
||||
$base = preg_replace('![\\\/]+!', '/', $base);
|
||||
$path = preg_replace('![\\\/]+!', '/', $path);
|
||||
if (strpos($path, $base) === 0) {
|
||||
$path = ltrim(substr($path, strlen($base)), '/');
|
||||
}
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get relative path between target and base path. If path isn't relative, return full path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $base
|
||||
* @return string
|
||||
*/
|
||||
public static function getRelativePathDotDot($path, $base)
|
||||
{
|
||||
$base = preg_replace('![\\\/]+!', '/', $base);
|
||||
$path = preg_replace('![\\\/]+!', '/', $path);
|
||||
|
||||
if ($path === $base) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$baseParts = explode('/', isset($base[0]) && '/' === $base[0] ? substr($base, 1) : $base);
|
||||
$pathParts = explode('/', isset($path[0]) && '/' === $path[0] ? substr($path, 1) : $path);
|
||||
|
||||
array_pop($baseParts);
|
||||
$lastPart = array_pop($pathParts);
|
||||
foreach ($baseParts as $i => $directory) {
|
||||
if (isset($pathParts[$i]) && $pathParts[$i] === $directory) {
|
||||
unset($baseParts[$i], $pathParts[$i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$pathParts[] = $lastPart;
|
||||
$path = str_repeat('../', count($baseParts)) . implode('/', $pathParts);
|
||||
|
||||
return '' === $path
|
||||
|| '/' === $path[0]
|
||||
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
|
||||
? "./$path" : $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift first directory out of the path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*/
|
||||
public static function shift(&$path)
|
||||
{
|
||||
$parts = explode('/', trim($path, '/'), 2);
|
||||
$result = array_shift($parts);
|
||||
$path = array_shift($parts);
|
||||
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return recursive list of all files and directories under given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $params
|
||||
* @return array
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function all($path, array $params = [])
|
||||
{
|
||||
if ($path === false) {
|
||||
throw new \RuntimeException("Path to {$path} doesn't exist.");
|
||||
}
|
||||
|
||||
$compare = isset($params['compare']) ? 'get' . $params['compare'] : null;
|
||||
$pattern = isset($params['pattern']) ? $params['pattern'] : null;
|
||||
$filters = isset($params['filters']) ? $params['filters'] : null;
|
||||
$recursive = isset($params['recursive']) ? $params['recursive'] : true;
|
||||
$levels = isset($params['levels']) ? $params['levels'] : -1;
|
||||
$key = isset($params['key']) ? 'get' . $params['key'] : null;
|
||||
$value = isset($params['value']) ? 'get' . $params['value'] : ($recursive ? 'getSubPathname' : 'getFilename');
|
||||
$folders = isset($params['folders']) ? $params['folders'] : true;
|
||||
$files = isset($params['files']) ? $params['files'] : true;
|
||||
|
||||
if ($recursive) {
|
||||
$directory = new \RecursiveDirectoryIterator($path,
|
||||
\RecursiveDirectoryIterator::SKIP_DOTS + \FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
|
||||
$iterator = new \RecursiveIteratorIterator($directory, \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$iterator->setMaxDepth(max($levels, -1));
|
||||
} else {
|
||||
$iterator = new \FilesystemIterator($path);
|
||||
}
|
||||
|
||||
$results = [];
|
||||
|
||||
/** @var \RecursiveDirectoryIterator $file */
|
||||
foreach ($iterator as $file) {
|
||||
// Ignore hidden files.
|
||||
if ($file->getFilename()[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
if (!$folders && $file->isDir()) {
|
||||
continue;
|
||||
}
|
||||
if (!$files && $file->isFile()) {
|
||||
continue;
|
||||
}
|
||||
if ($compare && $pattern && !preg_match($pattern, $file->{$compare}())) {
|
||||
continue;
|
||||
}
|
||||
$fileKey = $key ? $file->{$key}() : null;
|
||||
$filePath = $file->{$value}();
|
||||
if ($filters) {
|
||||
if (isset($filters['key'])) {
|
||||
$pre = !empty($filters['pre-key']) ? $filters['pre-key'] : '';
|
||||
$fileKey = $pre . preg_replace($filters['key'], '', $fileKey);
|
||||
}
|
||||
if (isset($filters['value'])) {
|
||||
$filter = $filters['value'];
|
||||
if (is_callable($filter)) {
|
||||
$filePath = call_user_func($filter, $file);
|
||||
} else {
|
||||
$filePath = preg_replace($filter, '', $filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($fileKey !== null) {
|
||||
$results[$fileKey] = $filePath;
|
||||
} else {
|
||||
$results[] = $filePath;
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively copy directory in filesystem.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $ignore Ignore files matching pattern (regular expression).
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function copy($source, $target, $ignore = null)
|
||||
{
|
||||
$source = rtrim($source, '\\/');
|
||||
$target = rtrim($target, '\\/');
|
||||
|
||||
if (!is_dir($source)) {
|
||||
throw new \RuntimeException('Cannot copy non-existing folder.');
|
||||
}
|
||||
|
||||
// Make sure that path to the target exists before copying.
|
||||
self::create($target);
|
||||
|
||||
$success = true;
|
||||
|
||||
// Go through all sub-directories and copy everything.
|
||||
$files = self::all($source);
|
||||
foreach ($files as $file) {
|
||||
if ($ignore && preg_match($ignore, $file)) {
|
||||
continue;
|
||||
}
|
||||
$src = $source .'/'. $file;
|
||||
$dst = $target .'/'. $file;
|
||||
|
||||
if (is_dir($src)) {
|
||||
// Create current directory (if it doesn't exist).
|
||||
if (!is_dir($dst)) {
|
||||
$success &= @mkdir($dst, 0777, true);
|
||||
}
|
||||
} else {
|
||||
// Or copy current file.
|
||||
$success &= @copy($src, $dst);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
$error = error_get_last();
|
||||
throw new \RuntimeException($error['message']);
|
||||
}
|
||||
|
||||
// Make sure that the change will be detected when caching.
|
||||
@touch(dirname($target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Move directory in filesystem.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function move($source, $target)
|
||||
{
|
||||
if (!is_dir($source)) {
|
||||
throw new \RuntimeException('Cannot move non-existing folder.');
|
||||
}
|
||||
|
||||
// Don't do anything if the source is the same as the new target
|
||||
if ($source == $target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure that path to the target exists before moving.
|
||||
self::create(dirname($target));
|
||||
|
||||
// Just rename the directory.
|
||||
$success = @rename($source, $target);
|
||||
|
||||
if (!$success) {
|
||||
$error = error_get_last();
|
||||
throw new \RuntimeException($error['message']);
|
||||
}
|
||||
|
||||
// Make sure that the change will be detected when caching.
|
||||
@touch(dirname($source));
|
||||
@touch(dirname($target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively delete directory from filesystem.
|
||||
*
|
||||
* @param string $target
|
||||
* @param bool $include_target
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($target, $include_target = true)
|
||||
{
|
||||
if (!is_dir($target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = self::doDelete($target, $include_target);
|
||||
|
||||
if (!$success) {
|
||||
$error = error_get_last();
|
||||
throw new \RuntimeException($error['message']);
|
||||
}
|
||||
|
||||
// Make sure that the change will be detected when caching.
|
||||
if ($include_target) {
|
||||
@touch(dirname($target));
|
||||
} else {
|
||||
@touch($target);
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function mkdir($folder)
|
||||
{
|
||||
self::create($folder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @throws \RuntimeException
|
||||
* @internal
|
||||
*/
|
||||
public static function create($folder)
|
||||
{
|
||||
if (is_dir($folder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$success = @mkdir($folder, 0777, true);
|
||||
|
||||
if (!$success) {
|
||||
$error = error_get_last();
|
||||
throw new \RuntimeException($error['message']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive copy of one directory to another
|
||||
*
|
||||
* @param $src
|
||||
* @param $dest
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function rcopy($src, $dest)
|
||||
{
|
||||
|
||||
// If the src is not a directory do a simple file copy
|
||||
if (!is_dir($src)) {
|
||||
copy($src, $dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the destination directory does not exist create it
|
||||
if (!is_dir($dest)) {
|
||||
if (!mkdir($dest)) {
|
||||
// If the destination directory could not be created stop processing
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Open the source directory to read in files
|
||||
$i = new \DirectoryIterator($src);
|
||||
/** @var \DirectoryIterator $f */
|
||||
foreach ($i as $f) {
|
||||
if ($f->isFile()) {
|
||||
copy($f->getRealPath(), "$dest/" . $f->getFilename());
|
||||
} else {
|
||||
if (!$f->isDot() && $f->isDir()) {
|
||||
static::rcopy($f->getRealPath(), "$dest/$f");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $folder
|
||||
* @param bool $include_target
|
||||
* @return bool
|
||||
* @internal
|
||||
*/
|
||||
protected static function doDelete($folder, $include_target = true)
|
||||
{
|
||||
// Special case for symbolic links.
|
||||
if (is_link($folder)) {
|
||||
return @unlink($folder);
|
||||
}
|
||||
|
||||
$files = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($folder, \RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
/** @var \DirectoryIterator $fileinfo */
|
||||
foreach ($files as $fileinfo) {
|
||||
if ($fileinfo->isDir()) {
|
||||
if (false === @rmdir($fileinfo->getRealPath())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (false === @unlink($fileinfo->getRealPath())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $include_target ? @rmdir($folder) : true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Grav\Common\Filesystem;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
|
||||
/**
|
||||
* Class RecursiveFolderFilterIterator
|
||||
* @package Grav\Common\Filesystem
|
||||
*/
|
||||
class RecursiveFolderFilterIterator extends \RecursiveFilterIterator
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected static $folder_ignores;
|
||||
|
||||
/**
|
||||
* Create a RecursiveFilterIterator from a RecursiveIterator
|
||||
*
|
||||
* @param RecursiveIterator $iterator
|
||||
*/
|
||||
public function __construct(\RecursiveIterator $iterator)
|
||||
{
|
||||
parent::__construct($iterator);
|
||||
if (empty($this::$folder_ignores)) {
|
||||
$this::$folder_ignores = self::getGrav()['config']->get('system.pages.ignore_folders');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current element of the iterator is acceptable
|
||||
*
|
||||
* @return bool true if the current element is acceptable, otherwise false.
|
||||
*/
|
||||
public function accept()
|
||||
{
|
||||
/** @var $current \SplFileInfo */
|
||||
$current = $this->current();
|
||||
|
||||
if ($current->isDir() && !in_array($current->getFilename(), $this::$folder_ignores)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Iterator;
|
||||
|
||||
abstract class AbstractCollection extends Iterator {
|
||||
|
||||
use GravTrait;
|
||||
|
||||
public function toJson()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return json_encode($items);
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace Grav\Common\GPM\Common;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Iterator;
|
||||
|
||||
abstract class AbstractPackageCollection extends Iterator {
|
||||
|
||||
use GravTrait;
|
||||
|
||||
protected $type;
|
||||
|
||||
public function toJson()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return json_encode($items);
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->items as $name => $package) {
|
||||
$items[$name] = $package->toArray();
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||