mirror of
https://github.com/getgrav/grav.git
synced 2026-03-05 20:11:50 +01:00
Merge branch 'release/0.9.34'
This commit is contained in:
20
CHANGELOG.md
20
CHANGELOG.md
@@ -1,3 +1,23 @@
|
||||
# v0.9.34
|
||||
## 08/04/2015
|
||||
|
||||
1. [](#new)
|
||||
* Added new `cache_all` system setting + media `cache()` method
|
||||
* Added base languages configuration
|
||||
* Added property language to page to help plugins identify page language
|
||||
* New `Utils::arrayFilterRecursive()` method
|
||||
2. [](#improved)
|
||||
* Improved Session handling to support site and admin independently
|
||||
* Allow Twig variables to be modified in other events
|
||||
* Blueprint updates in preparation for Admin plugin
|
||||
* Changed `Inflector` from static to object and added multi-language support
|
||||
* Support for admin override of a page's blueprints
|
||||
3. [](#bugfix)
|
||||
* Removed unused `use` in `VideoMedium` that was causing error
|
||||
* Array fix in `User.authorise()` method
|
||||
* Fix for typo in `translations_fallback`
|
||||
* Fixed moving page to the root
|
||||
|
||||
# v0.9.33
|
||||
## 07/21/2015
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"php": ">=5.4.0",
|
||||
"twig/twig": "~1.16",
|
||||
"erusev/parsedown-extra": "~0.7",
|
||||
"symfony/yaml": "2.7.*",
|
||||
"symfony/console": "2.7.*",
|
||||
"symfony/event-dispatcher": "2.7.*",
|
||||
"symfony/yaml": "2.7.3",
|
||||
"symfony/console": "2.7.3",
|
||||
"symfony/event-dispatcher": "2.7.3",
|
||||
"doctrine/cache": "~1.4",
|
||||
"maximebf/debugbar": "dev-master",
|
||||
"filp/whoops": "1.2.*@dev",
|
||||
|
||||
@@ -13,60 +13,101 @@ form:
|
||||
label: Site Title
|
||||
size: large
|
||||
placeholder: "Site wide title"
|
||||
help: Default title for your site
|
||||
help: "Default title for your site, often used in themes"
|
||||
|
||||
author.name:
|
||||
type: text
|
||||
size: large
|
||||
label: Default Author
|
||||
help: "A default author name, often used in themes or page content"
|
||||
|
||||
author.email:
|
||||
type: text
|
||||
size: large
|
||||
label: Default Email
|
||||
help: "A default email to reference in themes or pages"
|
||||
validate:
|
||||
type: email
|
||||
|
||||
taxonomies:
|
||||
type: text
|
||||
type: selectize
|
||||
size: large
|
||||
label: Taxonomy Types
|
||||
classes: fancy
|
||||
help: "Taxonomy types must be defined here if you wish to use them in pages"
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
metadata:
|
||||
type: array
|
||||
label: Metadata
|
||||
placeholder_key: Name
|
||||
placeholder_value: Content
|
||||
|
||||
blog:
|
||||
summary:
|
||||
type: section
|
||||
title: Blog
|
||||
title: Page Summary
|
||||
|
||||
fields:
|
||||
blog.route:
|
||||
type: text
|
||||
size: large
|
||||
label: Blog URL
|
||||
summary.enabled:
|
||||
type: toggle
|
||||
label: Enabled
|
||||
highlight: 1
|
||||
help: "Enable page summary (the summary returns the same as the page content)"
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
summary.size:
|
||||
type: text
|
||||
size: x-small
|
||||
label: Summary Size
|
||||
help: "The amount of characters of a page to use as a content summary"
|
||||
validate:
|
||||
type: int
|
||||
min: 0
|
||||
max: 65536
|
||||
|
||||
routes:
|
||||
summary.format:
|
||||
type: toggle
|
||||
label: Format
|
||||
classes: fancy
|
||||
help: "short = use the first occurrence of delimiter or size; long = summary delimiter will be ignored"
|
||||
highlight: short
|
||||
options:
|
||||
'short': 'Short'
|
||||
'long': 'Long'
|
||||
|
||||
summary.delimiter:
|
||||
type: text
|
||||
size: x-small
|
||||
label: Delimiter
|
||||
help: "The summary delimiter (default '===')"
|
||||
|
||||
metadata:
|
||||
type: section
|
||||
title: Routes
|
||||
title: Metadata
|
||||
|
||||
fields:
|
||||
metadata:
|
||||
type: array
|
||||
label: Metadata
|
||||
help: "Default metadata values that will be displayed on every page unless overridden by the page"
|
||||
placeholder_key: Name
|
||||
placeholder_value: Content
|
||||
|
||||
|
||||
routes:
|
||||
type: section
|
||||
title: Redirects & Routes
|
||||
|
||||
fields:
|
||||
redirects:
|
||||
type: array
|
||||
label: Custom Redirects
|
||||
help: "routes to redirect to other pages. Standard Regex replacement is valid"
|
||||
placeholder_key: /your/alias
|
||||
placeholder_value: /your/redirect
|
||||
|
||||
routes:
|
||||
type: array
|
||||
label: Custom
|
||||
label: Custom Routes
|
||||
help: "routes to alias to other pages. Standard Regex replacement is valid"
|
||||
placeholder_key: /your/alias
|
||||
placeholder_value: /your/route
|
||||
|
||||
@@ -14,7 +14,7 @@ form:
|
||||
type: pages
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Home Page
|
||||
label: Home page
|
||||
show_all: false
|
||||
show_modular: false
|
||||
show_root: false
|
||||
@@ -23,61 +23,65 @@ form:
|
||||
pages.theme:
|
||||
type: themeselect
|
||||
classes: fancy
|
||||
selectize: true
|
||||
size: medium
|
||||
label: Default Theme
|
||||
help: "Set the theme (defaults to 'default')"
|
||||
|
||||
pages.markdown.extra:
|
||||
type: toggle
|
||||
label: Markdown Extra
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
label: Default theme
|
||||
help: "Set the default theme for Grav to use (default is Antimatter)"
|
||||
|
||||
pages.process:
|
||||
type: checkboxes
|
||||
label: Process
|
||||
help: "Control how pages are processed. Can be set per-page rather than globally"
|
||||
default: [markdown: true, twig: true]
|
||||
options:
|
||||
markdown: Markdown
|
||||
twig: Twig
|
||||
use: keys
|
||||
|
||||
timezone:
|
||||
type: select
|
||||
label: Timezone
|
||||
size: medium
|
||||
classes: fancy
|
||||
help: "Override the default timezone the server"
|
||||
@data-options: '\Grav\Common\Utils::timezones'
|
||||
default: ''
|
||||
options:
|
||||
'': 'Default (Server Timezone)'
|
||||
|
||||
pages.dateformat.short:
|
||||
type: select
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Short Date Format
|
||||
help: "Set the short date format"
|
||||
default: 'jS M Y'
|
||||
label: Short date format
|
||||
help: "Set the short date format that can be used by themes"
|
||||
default: "jS M Y"
|
||||
options:
|
||||
'F jS \\a\\t g:ia': "January 1st at 11:59pm"
|
||||
'l jS of F g:i A': "Monday 1st of January at 11:59 PM"
|
||||
'D, m M Y G:i:s': "Mon, 01 Jan 2014 23:59:00"
|
||||
'd-m-y G:i': "01-01-14 23:59"
|
||||
'jS M Y': "10th Feb 2014"
|
||||
"F jS \\a\\t g:ia": "January 1st at 11:59pm"
|
||||
"l jS of F g:i A": "Monday 1st of January at 11:59 PM"
|
||||
"D, m M Y G:i:s": "Mon, 01 Jan 2014 23:59:00"
|
||||
"d-m-y G:i": "01-01-14 23:59"
|
||||
"jS M Y": "10th Feb 2014"
|
||||
|
||||
pages.dateformat.long:
|
||||
type: select
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Long Date Format
|
||||
help: "Set the long date format"
|
||||
label: Long date format
|
||||
help: "Set the long date format that can be used by themes"
|
||||
options:
|
||||
'F jS \a\t g:ia': "January 1st at 11:59pm"
|
||||
'l jS of F g:i A': "Monday 1st of January at 11:59 PM"
|
||||
'D, m M Y G:i:s': "Mon, 01 Jan 2014 23:59:00"
|
||||
'd-m-y G:i': "01-01-14 23:59"
|
||||
'jS M Y': "10th Feb 2014"
|
||||
"F jS \\a\\t g:ia": "January 1st at 11:59pm"
|
||||
"l jS of F g:i A": "Monday 1st of January at 11:59 PM"
|
||||
"D, m M Y G:i:s": "Mon, 01 Jan 2014 23:59:00"
|
||||
"d-m-y G:i": "01-01-14 23:59"
|
||||
"jS M Y": "10th Feb 2014"
|
||||
|
||||
pages.order.by:
|
||||
type: select
|
||||
size: medium
|
||||
classes: fancy
|
||||
label: Default Ordering
|
||||
label: Default ordering
|
||||
help: "Pages in a list will render using this order unless it is overridden"
|
||||
options:
|
||||
default: Default - based on folder name
|
||||
folder: Folder - based on prefix-less folder name
|
||||
@@ -86,9 +90,10 @@ form:
|
||||
|
||||
pages.order.dir:
|
||||
type: toggle
|
||||
label: Default Order Direction
|
||||
label: Default order direction
|
||||
highlight: asc
|
||||
default: desc
|
||||
help: "The direction of pages in a list"
|
||||
options:
|
||||
asc: Ascending
|
||||
desc: Descending
|
||||
@@ -96,15 +101,16 @@ form:
|
||||
pages.list.count:
|
||||
type: text
|
||||
size: x-small
|
||||
label: Default Item Count
|
||||
help: "Default max pages count"
|
||||
label: Default page count
|
||||
help: "Default maximum pages count in a list"
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
|
||||
pages.publish_dates:
|
||||
type: toggle
|
||||
label: Date-based publishing
|
||||
help: Automatically (un)publish posts based on their date
|
||||
help: "Automatically (un)publish posts based on their date"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -112,17 +118,47 @@ form:
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.events:
|
||||
type: checkboxes
|
||||
label: Events
|
||||
help: "Enable or Disable specific events. Disabling these can break plugins"
|
||||
default: [page: true, twig: true]
|
||||
options:
|
||||
page: Page Events
|
||||
twig: Twig Events
|
||||
use: keys
|
||||
|
||||
pages.redirect_default_route:
|
||||
type: toggle
|
||||
label: Redirect default route
|
||||
help: "Automatically redirect to a page's default route"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
events:
|
||||
languages:
|
||||
type: section
|
||||
title: Events
|
||||
title: Languages
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.events.page:
|
||||
|
||||
languages.supported:
|
||||
type: selectize
|
||||
size: large
|
||||
label: Supported
|
||||
help: "Comma separated list of 2 letter language codes (for example 'en,fr,de')"
|
||||
classes: fancy
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
languages.translations:
|
||||
type: toggle
|
||||
label: Page events
|
||||
label: Translations enabled
|
||||
help: "Support translations in Grav, plugins and extensions"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -130,9 +166,10 @@ form:
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
pages.events.twig:
|
||||
languages.translations_fallback:
|
||||
type: toggle
|
||||
label: Twig events
|
||||
label: Translations fallback
|
||||
help: "Fallback through supported translations if active language doesn't exist"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -140,6 +177,131 @@ form:
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.session_store_active:
|
||||
type: toggle
|
||||
label: Active language in session
|
||||
help: "Support translations in Grav, plugins and extensions"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.home_redirect.include_lang:
|
||||
type: toggle
|
||||
label: Home redirect include language
|
||||
help: "Include language in home redirect (/en)"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
languages.home_redirect.include_route:
|
||||
type: toggle
|
||||
label: Home redirect include route
|
||||
help: "Include route in home redirect (/blog)"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
http_headers:
|
||||
type: section
|
||||
title: HTTP Headers
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.expires:
|
||||
type: text
|
||||
size: small
|
||||
label: Expires
|
||||
help: "Sets the expires header. The value is in seconds."
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
pages.last_modified:
|
||||
type: toggle
|
||||
label: Last modified
|
||||
help: "Sets the last modified header that can help optimize proxy and browser caching"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
pages.etag:
|
||||
type: toggle
|
||||
label: ETag
|
||||
help: "Sets the etag header to help identify when a page has been modified"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
pages.vary_accept_encoding:
|
||||
type: toggle
|
||||
label: Vary accept encoding
|
||||
help: "Sets the `Vary: Accept Encoding` header to help with proxy and CDN caching"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
markdown:
|
||||
type: section
|
||||
title: Markdown
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
pages.markdown.extra:
|
||||
type: toggle
|
||||
label: Markdown extra
|
||||
help: "Enable default support for Markdown Extra - https://michelf.ca/projects/php-markdown/extra/"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.auto_line_breaks:
|
||||
type: toggle
|
||||
label: Auto line breaks
|
||||
help: "Enable support for automatic line breaks in markdown"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.auto_url_links:
|
||||
type: toggle
|
||||
label: Auto URL links
|
||||
help: "Enable automatic conversion of URLs into HTML hyperlinks"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
pages.markdown.escape_markup:
|
||||
type: toggle
|
||||
label: Escape markup
|
||||
help: "Escape markup tags into HTML entities"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
caching:
|
||||
type: section
|
||||
title: Caching
|
||||
@@ -149,6 +311,7 @@ form:
|
||||
cache.enabled:
|
||||
type: toggle
|
||||
label: Caching
|
||||
help: "Global ON/OFF switch to enable/disable Grav caching"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -160,7 +323,8 @@ form:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Cache Check Method
|
||||
label: Cache check method
|
||||
help: "Select the method that Grav uses to check if page files have been modified."
|
||||
options:
|
||||
file: File
|
||||
folder: Folder
|
||||
@@ -171,6 +335,7 @@ form:
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Cache driver
|
||||
help: "Choose which cache driver Grav should use. 'Auto Detect' attempts to find the best for you"
|
||||
options:
|
||||
auto: Auto detect
|
||||
file: File
|
||||
@@ -182,38 +347,29 @@ form:
|
||||
cache.prefix:
|
||||
type: text
|
||||
size: x-small
|
||||
label: Cache Prefix
|
||||
label: Cache prefix
|
||||
help: "An identifier for part of the Grav key. Don't change unless you know what your doing."
|
||||
placeholder: "Derived from base URL (override by entering random string)"
|
||||
|
||||
cache.lifetime:
|
||||
type: text
|
||||
size: small
|
||||
label: Lifetime
|
||||
help: "Sets the cache lifetime in seconds. 0 = infinite"
|
||||
validate:
|
||||
type: number
|
||||
|
||||
cache.gzip:
|
||||
type: toggle
|
||||
label: GZIP compression
|
||||
highlight: 1
|
||||
label: Gzip compression
|
||||
help: "Enable GZip compression of the Grav page for increased performance."
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.enable_asset_timestamp:
|
||||
type: toggle
|
||||
label: Enable timestamps on assets
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
media.enable_media_timestamp:
|
||||
type: toggle
|
||||
label: Enable timestamps on media
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
twig:
|
||||
type: section
|
||||
@@ -224,6 +380,7 @@ form:
|
||||
twig.cache:
|
||||
type: toggle
|
||||
label: Twig caching
|
||||
help: "Control the Twig caching mechanism. Leave this enabled for best performance."
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -234,7 +391,8 @@ form:
|
||||
twig.debug:
|
||||
type: toggle
|
||||
label: Twig debug
|
||||
highlight: 1
|
||||
help: "Allows the option of not loading the Twig Debugger extension"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
@@ -244,6 +402,7 @@ form:
|
||||
twig.auto_reload:
|
||||
type: toggle
|
||||
label: Detect changes
|
||||
help: "Twig will automatically recompile the Twig cache if it detects any changes in Twig templates"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -254,7 +413,8 @@ form:
|
||||
twig.autoescape:
|
||||
type: toggle
|
||||
label: Autoescape variables
|
||||
highlight: 1
|
||||
help: "Autoescapes all variables. This will break your site most likely"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
@@ -269,8 +429,9 @@ form:
|
||||
fields:
|
||||
assets.css_pipeline:
|
||||
type: toggle
|
||||
label: CSS Pipeline
|
||||
highlight: 1
|
||||
label: CSS pipeline
|
||||
help: "The CSS pipeline is the unification of multiple CSS resources into one file"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
@@ -279,7 +440,8 @@ form:
|
||||
|
||||
assets.css_minify:
|
||||
type: toggle
|
||||
label: CSS Minify
|
||||
label: CSS minify
|
||||
help: "Minify the CSS during pipelining"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -289,8 +451,9 @@ form:
|
||||
|
||||
assets.css_minify_windows:
|
||||
type: toggle
|
||||
label: CSS Minify Windows Override
|
||||
highlight: 1
|
||||
label: CSS minify Windows override
|
||||
help: "Minify Override for Windows platforms. False by default due to ThreadStackSize"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
@@ -299,7 +462,8 @@ form:
|
||||
|
||||
assets.css_rewrite:
|
||||
type: toggle
|
||||
label: CSS Rewrite
|
||||
label: CSS rewrite
|
||||
help: "Rewrite any CSS relative URLs during pipelining"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -309,8 +473,9 @@ form:
|
||||
|
||||
assets.js_pipeline:
|
||||
type: toggle
|
||||
label: JavaScript Pipeline
|
||||
highlight: 01
|
||||
label: JavaScript pipeline
|
||||
help: "The JS pipeline is the unification of multiple JS resources into one file"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
@@ -319,7 +484,8 @@ form:
|
||||
|
||||
assets.js_minify:
|
||||
type: toggle
|
||||
label: JavaScript Minify
|
||||
label: JavaScript minify
|
||||
help: "Minify the JS during pipelining"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -327,6 +493,23 @@ form:
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.enable_asset_timestamp:
|
||||
type: toggle
|
||||
label: Enable timestamps on assets
|
||||
help: "Enable asset timestamps"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
assets.collections:
|
||||
type: array
|
||||
label: Collections
|
||||
placeholder_key: collection_name
|
||||
placeholder_value: collection_path
|
||||
|
||||
errors:
|
||||
type: section
|
||||
title: Error handler
|
||||
@@ -336,6 +519,7 @@ form:
|
||||
errors.display:
|
||||
type: toggle
|
||||
label: Display errors
|
||||
help: "Display full backtrace-style error page"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -346,6 +530,7 @@ form:
|
||||
errors.log:
|
||||
type: toggle
|
||||
label: Log errors
|
||||
help: "Log errors to /logs folder"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -362,56 +547,18 @@ form:
|
||||
debugger.enabled:
|
||||
type: toggle
|
||||
label: Debugger
|
||||
highlight: 1
|
||||
help: "Enable Grav debugger and following settings"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger.mode:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Mode
|
||||
options:
|
||||
detect: Auto-Detect
|
||||
development: Development
|
||||
production: Production
|
||||
|
||||
debugger.strict:
|
||||
debugger.twig:
|
||||
type: toggle
|
||||
label: Strict
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
debugger.max_depth:
|
||||
type: select
|
||||
size: small
|
||||
classes: fancy
|
||||
label: Detail Level
|
||||
placeholder: "How many nested levels to display for objects or arrays"
|
||||
options:
|
||||
1: 1 level
|
||||
2: 2 levels
|
||||
3: 3 levels
|
||||
4: 4 levels
|
||||
5: 5 levels
|
||||
6: 6 levels
|
||||
7: 7 levels
|
||||
8: 8 levels
|
||||
9: 9 levels
|
||||
10: 10 levels
|
||||
validate:
|
||||
type: number
|
||||
|
||||
debugger.log.enabled:
|
||||
type: toggle
|
||||
label: Logging
|
||||
label: Debug Twig
|
||||
help: "Enable debugging of Twig templates"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -421,7 +568,8 @@ form:
|
||||
|
||||
debugger.shutdown.close_connection:
|
||||
type: toggle
|
||||
label: Shutdown Close Connection
|
||||
label: Shutdown close connection
|
||||
help: "Close the connection before calling onShutdown(). false for debugging"
|
||||
highlight: 1
|
||||
options:
|
||||
1: Yes
|
||||
@@ -438,16 +586,29 @@ form:
|
||||
images.default_image_quality:
|
||||
type: text
|
||||
label: Default image quality
|
||||
help: "Default image quality to use when resampling or caching images (85%)"
|
||||
classes: x-small
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
max: 100
|
||||
|
||||
images.cache_all:
|
||||
type: toggle
|
||||
label: Cache all images
|
||||
help: "Run all images through Grav's cache system even if they have no media manipulations"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
images.debug:
|
||||
type: toggle
|
||||
label: Image debug watermark
|
||||
highlight: 1
|
||||
help: "Show an overlay over images indicating the pixel depth of the image when working with retina for example"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
@@ -457,30 +618,80 @@ form:
|
||||
media.upload_limit:
|
||||
type: text
|
||||
label: File upload limit
|
||||
help: "Set maximum upload size in bytes (0 is unlimited)"
|
||||
classes: small
|
||||
validate:
|
||||
type: number
|
||||
|
||||
system:
|
||||
media.enable_media_timestamp:
|
||||
type: toggle
|
||||
label: Enable timestamps on media
|
||||
help: "Appends a timestamp based on last modified date to each media item"
|
||||
highlight: 0
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
session:
|
||||
type: section
|
||||
title: System
|
||||
title: Session
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
timezone:
|
||||
type: select
|
||||
label: Timezone
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Utils::timezones'
|
||||
default: ''
|
||||
session.enabled:
|
||||
type: toggle
|
||||
label: Enabled
|
||||
help: "Enable session support within Grav"
|
||||
highlight: 1
|
||||
options:
|
||||
'': '- None -'
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
session.timeout:
|
||||
type: text
|
||||
size: small
|
||||
label: Timeout
|
||||
help: "Sets the session timeout in seconds"
|
||||
validate:
|
||||
type: number
|
||||
min: 1
|
||||
|
||||
session.name:
|
||||
type: text
|
||||
size: small
|
||||
label: Name
|
||||
help: "An identifier used to form the name of the session cookie"
|
||||
|
||||
|
||||
advanced:
|
||||
type: section
|
||||
title: Advanced
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
absolute_urls:
|
||||
type: toggle
|
||||
label: Absolute URLs
|
||||
highlight: 0
|
||||
help: "Absolute or relative URLs for `base_url`"
|
||||
options:
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
|
||||
param_sep:
|
||||
type: select
|
||||
label: Parameter separator
|
||||
classes: fancy
|
||||
help: "Separater for passed parameters that can be changed for Apache on Windows"
|
||||
default: ''
|
||||
options:
|
||||
':': ': (default)'
|
||||
';': '; (use this for apache on Windows)'
|
||||
';': '; (for Apache running on Windows)'
|
||||
|
||||
278
system/blueprints/pages/default.yaml
Normal file
278
system/blueprints/pages/default.yaml
Normal file
@@ -0,0 +1,278 @@
|
||||
title: Default
|
||||
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
|
||||
fields:
|
||||
type:
|
||||
type: hidden
|
||||
label: Page Type
|
||||
default: default
|
||||
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
type: tab
|
||||
title: Content
|
||||
|
||||
fields:
|
||||
header.title:
|
||||
type: text
|
||||
style: vertical
|
||||
label: Title
|
||||
validate:
|
||||
required: true
|
||||
|
||||
content:
|
||||
type: markdown
|
||||
label: Content
|
||||
validate:
|
||||
type: textarea
|
||||
|
||||
uploads:
|
||||
type: uploads
|
||||
label: Page Media
|
||||
|
||||
options:
|
||||
type: tab
|
||||
title: Options
|
||||
|
||||
fields:
|
||||
|
||||
publishing:
|
||||
type: section
|
||||
title: Publishing
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.published:
|
||||
type: toggle
|
||||
label: Published
|
||||
help: "By default, a page is published unless you explicitly set published: false or via a publish_date being in the future, or unpublish_date in the past"
|
||||
highlight: 1
|
||||
size: medium
|
||||
options:
|
||||
'': Global
|
||||
1: Yes
|
||||
0: No
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.date:
|
||||
type: datetime
|
||||
label: Date
|
||||
toggleable: true
|
||||
help: "The date variable allows you to specifically set a date associated with this page."
|
||||
|
||||
|
||||
|
||||
header.published_date:
|
||||
type: datetime
|
||||
label: Published Date
|
||||
toggleable: true
|
||||
help: "Can provide a date to automatically trigger publication."
|
||||
|
||||
header.unpublished_date:
|
||||
type: datetime
|
||||
label: Unublished Date
|
||||
toggleable: true
|
||||
help: "can provide a date to automatically trigger un-publication."
|
||||
|
||||
|
||||
|
||||
meta:
|
||||
type: section
|
||||
title: Metadata
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.metadata.description:
|
||||
type: textarea
|
||||
toggleable: true
|
||||
label: Description
|
||||
default:
|
||||
validate:
|
||||
max: 155
|
||||
|
||||
header.metadata.keywords:
|
||||
type: text
|
||||
toggleable: true
|
||||
label: Keywords
|
||||
validate:
|
||||
max: 120
|
||||
|
||||
header.metadata.author:
|
||||
type: text
|
||||
toggleable: true
|
||||
label: Author
|
||||
validate:
|
||||
max: 120
|
||||
|
||||
header.metadata.robots:
|
||||
type: checkboxes
|
||||
toggleable: true
|
||||
label: Robots
|
||||
options:
|
||||
noindex: No index
|
||||
nofollow: No follow
|
||||
use: keys
|
||||
|
||||
taxonomies:
|
||||
type: section
|
||||
title: Taxonomies
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
header.taxonomy:
|
||||
type: taxonomy
|
||||
label: Taxonomy
|
||||
multiple: true
|
||||
validate:
|
||||
type: array
|
||||
|
||||
advanced:
|
||||
type: tab
|
||||
title: Advanced
|
||||
|
||||
fields:
|
||||
columns:
|
||||
type: columns
|
||||
fields:
|
||||
column1:
|
||||
type: column
|
||||
fields:
|
||||
folder:
|
||||
type: text
|
||||
label: Folder Name
|
||||
validate:
|
||||
type: slug
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
|
||||
type:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Display Template
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
|
||||
column2:
|
||||
type: column
|
||||
|
||||
fields:
|
||||
order:
|
||||
type: order
|
||||
label: Ordering
|
||||
sitemap:
|
||||
|
||||
overrides:
|
||||
type: section
|
||||
title: Overrides
|
||||
underline: true
|
||||
|
||||
fields:
|
||||
|
||||
header.menu:
|
||||
type: text
|
||||
label: Menu
|
||||
toggleable: true
|
||||
help: "The string to be used in a menu. If not set, <b>Title</b> will be used."
|
||||
|
||||
header.slug:
|
||||
type: text
|
||||
label: Slug
|
||||
toggleable: true
|
||||
help: "The slug variable allows you to specifically set the page's portion of the URL"
|
||||
validate:
|
||||
message: A slug must contain only lowercase alphanumeric characters and dashes
|
||||
rule: slug
|
||||
|
||||
|
||||
|
||||
header.process:
|
||||
type: checkboxes
|
||||
label: 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: Default Child Type
|
||||
default: default
|
||||
placeholder: Use Global
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
|
||||
header.visible:
|
||||
type: toggle
|
||||
label: Visible
|
||||
help: "Determines if a page is visible in the navigation."
|
||||
highlight: 1
|
||||
options:
|
||||
'': Global
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.routable:
|
||||
type: toggle
|
||||
label: Routable
|
||||
help: If this page is reachable by a URL
|
||||
highlight: 1
|
||||
default: ''
|
||||
options:
|
||||
'': Global
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
header.cache_enable:
|
||||
type: toggle
|
||||
label: Caching
|
||||
highlight: 1
|
||||
options:
|
||||
'': Global
|
||||
1: Enabled
|
||||
0: Disabled
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
header.order_by:
|
||||
type: hidden
|
||||
|
||||
header.order_manual:
|
||||
type: hidden
|
||||
validate:
|
||||
type: commalist
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
46
system/blueprints/pages/modular.yaml
Normal file
46
system/blueprints/pages/modular.yaml
Normal file
@@ -0,0 +1,46 @@
|
||||
title: Modular
|
||||
@extends:
|
||||
type: default
|
||||
context: blueprints://pages
|
||||
|
||||
form:
|
||||
fields:
|
||||
tabs:
|
||||
type: tabs
|
||||
active: 1
|
||||
|
||||
fields:
|
||||
content:
|
||||
fields:
|
||||
|
||||
header.content.items:
|
||||
type: select
|
||||
label: Items
|
||||
default: @self.modular
|
||||
options:
|
||||
@self.modular: Children
|
||||
|
||||
header.content.order.by:
|
||||
type: select
|
||||
label: Order By
|
||||
default: date
|
||||
options:
|
||||
folder: Folder
|
||||
title: Title
|
||||
date: Date
|
||||
default: Default
|
||||
|
||||
header.content.order.dir:
|
||||
type: select
|
||||
label: Order
|
||||
default: desc
|
||||
options:
|
||||
asc: Ascending
|
||||
desc: Descending
|
||||
|
||||
header.process:
|
||||
type: ignore
|
||||
content:
|
||||
type: ignore
|
||||
uploads:
|
||||
type: ignore
|
||||
@@ -52,3 +52,7 @@ form:
|
||||
default: 1
|
||||
validate:
|
||||
type: bool
|
||||
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
@@ -82,3 +82,5 @@ form:
|
||||
type: order
|
||||
label: Ordering
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
17
system/blueprints/pages/move.yaml
Normal file
17
system/blueprints/pages/move.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
@@ -46,3 +46,7 @@ form:
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
rules:
|
||||
slug:
|
||||
pattern: "[a-z][a-z0-9_\-]+"
|
||||
min: 2
|
||||
max: 80
|
||||
|
||||
form:
|
||||
validation: loose
|
||||
fields:
|
||||
|
||||
title:
|
||||
type: text
|
||||
label: Title
|
||||
validate:
|
||||
required: true
|
||||
|
||||
folder:
|
||||
type: text
|
||||
label: Folder
|
||||
validate:
|
||||
type: slug
|
||||
required: true
|
||||
|
||||
route:
|
||||
type: select
|
||||
label: Parent
|
||||
classes: fancy
|
||||
@data-options: '\Grav\Common\Page\Pages::parents'
|
||||
@data-default: '\Grav\Plugin\admin::route'
|
||||
options:
|
||||
'/': '- Root -'
|
||||
validate:
|
||||
required: true
|
||||
|
||||
type:
|
||||
type: select
|
||||
classes: fancy
|
||||
label: Display Template
|
||||
default: default
|
||||
@data-options: '\Grav\Common\Page\Pages::types'
|
||||
validate:
|
||||
required: true
|
||||
@@ -82,3 +82,5 @@ form:
|
||||
type: order
|
||||
label: Ordering
|
||||
|
||||
blueprint:
|
||||
type: blueprint
|
||||
|
||||
@@ -15,10 +15,12 @@ form:
|
||||
readonly: true
|
||||
|
||||
email:
|
||||
type: text
|
||||
type: email
|
||||
size: large
|
||||
label: Email
|
||||
validate:
|
||||
type: email
|
||||
message: Must be a valid email address
|
||||
required: true
|
||||
|
||||
password:
|
||||
@@ -27,6 +29,8 @@ form:
|
||||
label: Password
|
||||
validate:
|
||||
required: true
|
||||
message: Password must contain at least one number and one uppercase and lowercase letter, and at least 8 or more characters
|
||||
pattern: '(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}'
|
||||
|
||||
fullname:
|
||||
type: text
|
||||
|
||||
@@ -3,7 +3,14 @@ timezone: '' # Valid values: http://php.net/manual/en/
|
||||
param_sep: ':' # Parameter separator, use ';' for Apache on windows
|
||||
|
||||
languages:
|
||||
translations: true # Enable translations by default
|
||||
supported: [] # List of languages supported. eg: [en, fr, de]
|
||||
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
|
||||
home_redirect:
|
||||
include_lang: true # Include language in home redirect (/en)
|
||||
include_route: false # Include route in home redirect (/blog)
|
||||
|
||||
|
||||
home:
|
||||
alias: '/home' # Default path for home, ie /
|
||||
@@ -80,6 +87,7 @@ debugger:
|
||||
|
||||
images:
|
||||
default_image_quality: 85 # Default image quality to use when resampling images (85%)
|
||||
cache_all: false # Cache all image by default
|
||||
debug: false # Show an overlay over images indicating the pixel depth of the image when working with retina for example
|
||||
|
||||
media:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '0.9.33');
|
||||
define('GRAV_VERSION', '0.9.34');
|
||||
define('DS', '/');
|
||||
|
||||
// Directories and Paths
|
||||
|
||||
58
system/languages/en.yaml
Normal file
58
system/languages/en.yaml
Normal file
@@ -0,0 +1,58 @@
|
||||
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'
|
||||
|
||||
|
||||
@@ -120,7 +120,6 @@ class Config extends Data
|
||||
$setup['streams']['schemes'] += $this->streams;
|
||||
|
||||
$setup = $this->autoDetectEnvironmentConfig($setup);
|
||||
$this->messages[] = $setup['streams']['schemes']['config']['prefixes'][''];
|
||||
|
||||
$this->setup = $setup;
|
||||
parent::__construct($setup);
|
||||
@@ -202,24 +201,20 @@ class Config extends Data
|
||||
|
||||
// Generate checksum according to the configuration settings.
|
||||
if (!$checkConfig) {
|
||||
$this->messages[] = 'Check configuration timestamps from system.yaml files.';
|
||||
// Just check changes in system.yaml files and ignore all the other files.
|
||||
$cc = $checkSystem ? $this->finder->locateConfigFile($this->configLookup, 'system') : [];
|
||||
} else {
|
||||
$this->messages[] = 'Check configuration timestamps from all configuration files.';
|
||||
// Check changes in all configuration files.
|
||||
$cc = $this->finder->locateConfigFiles($this->configLookup, $this->pluginLookup);
|
||||
}
|
||||
|
||||
if ($checkBlueprints) {
|
||||
$this->messages[] = 'Check blueprint timestamps from all blueprint files.';
|
||||
$cb = $this->finder->locateBlueprintFiles($this->blueprintLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cb = [];
|
||||
}
|
||||
|
||||
if ($checkLanguages) {
|
||||
$this->messages[] = 'Check language timestamps from all language files.';
|
||||
$cl = $this->finder->locateLanguageFiles($this->languagesLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cl = [];
|
||||
@@ -341,6 +336,11 @@ class Config extends Data
|
||||
$this->items = $cache['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $languages
|
||||
* @param $plugins
|
||||
* @param null $filename
|
||||
*/
|
||||
protected function loadCompiledLanguages($languages, $plugins, $filename = null)
|
||||
{
|
||||
$checksum = md5(json_encode($languages));
|
||||
@@ -366,11 +366,24 @@ class Config extends Data
|
||||
|
||||
// Load languages.
|
||||
$this->languages = new Languages;
|
||||
foreach ($languageFiles as $files) {
|
||||
$this->loadLanguagesFiles($files);
|
||||
|
||||
if (isset($languageFiles['user/plugins'])) {
|
||||
foreach ((array) $languageFiles['user/plugins'] as $plugin => $item) {
|
||||
$lang_file = CompiledYamlFile::instance($item['file']);
|
||||
$content = $lang_file->content();
|
||||
foreach ((array) $content as $lang => $value) {
|
||||
$this->languages->join($lang, $value, '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->languages->reformat();
|
||||
if (isset($languageFiles['system/languages'])) {
|
||||
foreach ((array) $languageFiles['system/languages'] as $lang => $item) {
|
||||
$lang_file = CompiledYamlFile::instance($item['file']);
|
||||
$content = $lang_file->content();
|
||||
$this->languages->join($lang, $content, '/');
|
||||
}
|
||||
}
|
||||
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
@@ -415,14 +428,6 @@ class Config extends Data
|
||||
}
|
||||
}
|
||||
|
||||
public function loadLanguagesFiles(array $files)
|
||||
{
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->languages->join($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
|
||||
@@ -143,7 +143,7 @@ class ConfigFinder
|
||||
$filename = "{$path}/{$name}/$find";
|
||||
|
||||
if (file_exists($filename)) {
|
||||
$list["plugins"] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
$list[$name] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
|
||||
/**
|
||||
@@ -11,7 +12,7 @@ use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
*/
|
||||
class Blueprint
|
||||
{
|
||||
use Export, DataMutatorTrait;
|
||||
use Export, DataMutatorTrait, GravTrait;
|
||||
|
||||
public $name;
|
||||
|
||||
@@ -75,7 +76,7 @@ class Blueprint
|
||||
try {
|
||||
$this->validateArray($data, $this->nested);
|
||||
} catch (\RuntimeException $e) {
|
||||
throw new \RuntimeException(sprintf('Page validation failed: %s', $e->getMessage()));
|
||||
throw new \RuntimeException(sprintf('<b>Validation failed:</b> %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +118,17 @@ class Blueprint
|
||||
{
|
||||
// Initialize data
|
||||
$this->fields();
|
||||
return $this->extraArray($data, $this->nested, $prefix);
|
||||
$rules = $this->nested;
|
||||
|
||||
// Drill down to prefix level
|
||||
if (!empty($prefix)) {
|
||||
$parts = explode('.', trim($prefix, '.'));
|
||||
foreach ($parts as $part) {
|
||||
$rules = isset($rules[$part]) ? $rules[$part] : [];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->extraArray($data, $rules, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +297,7 @@ class Blueprint
|
||||
// Item has been defined in blueprints.
|
||||
} elseif (is_array($field) && is_array($val)) {
|
||||
// Array has been defined in blueprints.
|
||||
$array += $this->ExtraArray($field, $val, $prefix);
|
||||
$array += $this->ExtraArray($field, $val, $prefix . $key . '.');
|
||||
} else {
|
||||
// Undefined/extra item.
|
||||
$array[$prefix.$key] = $field;
|
||||
@@ -313,11 +324,11 @@ class Blueprint
|
||||
$field['name'] = $prefix . $key;
|
||||
$field += $params;
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
if (isset($field['fields']) && $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 {
|
||||
} else if ($field['type'] !== 'ignore') {
|
||||
// Add rule.
|
||||
$this->rules[$prefix . $key] = &$field;
|
||||
$this->addProperty($prefix . $key);
|
||||
@@ -362,10 +373,20 @@ class Blueprint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize predefined validation rule.
|
||||
if (isset($field['validate']['rule'])) {
|
||||
if (isset($field['validate']['rule']) && $field['type'] !== 'ignore') {
|
||||
$field['validate'] += $this->getRule($field['validate']['rule']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Grav\Common\Data;
|
||||
|
||||
use Grav\Common\File\CompiledYamlFile;
|
||||
use Grav\Common\GravTrait;
|
||||
|
||||
/**
|
||||
* Blueprints class keeps track on blueprint instances.
|
||||
@@ -11,6 +12,8 @@ use Grav\Common\File\CompiledYamlFile;
|
||||
*/
|
||||
class Blueprints
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected $search;
|
||||
protected $types;
|
||||
protected $instances = array();
|
||||
@@ -55,8 +58,20 @@ class Blueprints
|
||||
if (isset($blueprints['@extends'])) {
|
||||
// Extend blueprint by other blueprints.
|
||||
$extends = (array) $blueprints['@extends'];
|
||||
foreach ($extends as $extendType) {
|
||||
$blueprint->extend($this->get($extendType));
|
||||
|
||||
if (is_string(key($extends))) {
|
||||
$extends = [ $extends ];
|
||||
}
|
||||
|
||||
foreach ($extends as $extendConfig) {
|
||||
$extendType = !is_string($extendConfig) ? empty($extendConfig['type']) ? false : $extendConfig['type'] : $extendConfig;
|
||||
|
||||
if (!$extendType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$context = is_string($extendConfig) || empty($extendConfig['context']) ? $this : new self(self::getGrav()['locator']->findResource($extendConfig['context']));
|
||||
$blueprint->extend($context->get($extendType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,14 +28,16 @@ class Validation
|
||||
// Validate type with fallback type text.
|
||||
$type = (string) isset($field['validate']['type']) ? $field['validate']['type'] : $field['type'];
|
||||
$method = 'type'.strtr($type, '-', '_');
|
||||
$name = ucfirst($field['label'] ? $field['label'] : $field['name']);
|
||||
$message = (string) isset($field['validate']['message']) ? $field['validate']['message'] : 'Invalid input in ' . $name;
|
||||
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $validate, $field);
|
||||
} else {
|
||||
$success = self::typeText($value, $validate, $field);
|
||||
}
|
||||
if (!$success) {
|
||||
$name = $field['label'] ? $field['label'] : $field['name'];
|
||||
throw new \RuntimeException("invalid input in {$name}");
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
|
||||
// Check individual rules
|
||||
@@ -43,8 +45,9 @@ class Validation
|
||||
$method = 'validate'.strtr($rule, '-', '_');
|
||||
if (method_exists(__CLASS__, $method)) {
|
||||
$success = self::$method($value, $params);
|
||||
|
||||
if (!$success) {
|
||||
throw new \RuntimeException('Failed');
|
||||
throw new \RuntimeException($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,6 +492,7 @@ class Validation
|
||||
{
|
||||
$values = (array) $value;
|
||||
$options = isset($field['options']) ? array_keys($field['options']) : array();
|
||||
$multi = isset($field['multiple']) ? $field['multiple'] : false;
|
||||
|
||||
if ($options) {
|
||||
$useKey = isset($field['use']) && $field['use'] == 'keys';
|
||||
@@ -497,9 +501,39 @@ class Validation
|
||||
}
|
||||
}
|
||||
|
||||
if ($multi) {
|
||||
foreach ($values as $key => $value) {
|
||||
$values[$key] = explode(',', $value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
public static function typeList($value, array $params, array $field)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($field['fields'])) {
|
||||
foreach ($value as $key => $item) {
|
||||
foreach ($field['fields'] as $subKey => $subField) {
|
||||
$subKey = trim($subKey, '.');
|
||||
$subValue = isset($item[$subKey]) ? $item[$subKey] : null;
|
||||
self::validate($subValue, $subField);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function filterList($value, array $params, array $field)
|
||||
{
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom input: ignore (will not validate)
|
||||
*
|
||||
@@ -513,6 +547,11 @@ class Validation
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function filterIgnore($value, array $params, array $field)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
// HTML5 attributes (min, max and range are handled inside the types)
|
||||
|
||||
public static function validateRequired($value, $params)
|
||||
|
||||
@@ -25,7 +25,7 @@ trait CompiledFile
|
||||
// If nothing has been loaded, attempt to get pre-compiled version of the file first.
|
||||
if ($var === null && $this->raw === null && $this->content === null) {
|
||||
$key = md5($this->filename);
|
||||
$file = PhpFile::instance(CACHE_DIR . "/compiled/files/{$key}{$this->extension}.php");
|
||||
$file = PhpFile::instance(CACHE_DIR . "compiled/files/{$key}{$this->extension}.php");
|
||||
$modified = $this->modified();
|
||||
|
||||
if (!$modified) {
|
||||
|
||||
@@ -349,6 +349,7 @@ class GPM extends Iterator
|
||||
public function findPackages($searches = [])
|
||||
{
|
||||
$packages = ['total' => 0, 'not_found' => []];
|
||||
$inflector = new Inflector();
|
||||
|
||||
foreach ($searches as $search) {
|
||||
$repository = '';
|
||||
@@ -380,7 +381,7 @@ class GPM extends Iterator
|
||||
}
|
||||
|
||||
$not_found = new \stdClass();
|
||||
$not_found->name = Inflector::camelize($search);
|
||||
$not_found->name = $inflector->camelize($search);
|
||||
$not_found->slug = $search;
|
||||
$not_found->package_type = $type;
|
||||
$not_found->install_path = str_replace('%name%', $search, $this->install_paths[$type]);
|
||||
|
||||
@@ -159,6 +159,8 @@ class Grav extends Container
|
||||
$container->register(new StreamsServiceProvider);
|
||||
$container->register(new ConfigServiceProvider);
|
||||
|
||||
$container['inflector'] = new Inflector();
|
||||
|
||||
$container['debugger']->stopTimer('_init');
|
||||
|
||||
return $container;
|
||||
@@ -172,8 +174,8 @@ class Grav extends Container
|
||||
// Initialize configuration.
|
||||
$debugger->startTimer('_config', 'Configuration');
|
||||
$this['config']->init();
|
||||
$this['session']->init();
|
||||
$this['uri']->init();
|
||||
$this['session']->init();
|
||||
$this['errors']->resetHandlers();
|
||||
$debugger->init();
|
||||
$this['config']->debug();
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Grav\Common;
|
||||
/**
|
||||
* This file was originally part of the Akelos Framework
|
||||
*/
|
||||
use Grav\Common\Language\Language;
|
||||
|
||||
/**
|
||||
* Inflector for pluralize and singularize English nouns.
|
||||
@@ -20,65 +21,55 @@ namespace Grav\Common;
|
||||
|
||||
class Inflector
|
||||
{
|
||||
use GravTrait;
|
||||
|
||||
protected $plural;
|
||||
protected $singular;
|
||||
protected $uncountable;
|
||||
protected $irregular;
|
||||
protected $ordinals;
|
||||
|
||||
public function init()
|
||||
{
|
||||
if (empty($this->plural)) {
|
||||
$language = self::getGrav()['language'];
|
||||
$this->plural = $language->translate('INFLECTOR_PLURALS', null, true);
|
||||
$this->singular = $language->translate('INFLECTOR_SINGULAR', null, true);
|
||||
$this->uncountable = $language->translate('INFLECTOR_UNCOUNTABLE', null, true);
|
||||
$this->irregular = $language->translate('INFLECTOR_IRREGULAR', null, true);
|
||||
$this->ordinals = $language->translate('INFLECTOR_ORDINALS', null, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pluralizes English nouns.
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @param string $word English noun to pluralize
|
||||
* @return string Plural noun
|
||||
*/
|
||||
public static function pluralize($word, $count = 2)
|
||||
public function pluralize($word, $count = 2)
|
||||
{
|
||||
$this->init();
|
||||
|
||||
if ($count == 1) {
|
||||
return $word;
|
||||
}
|
||||
|
||||
$plural = array(
|
||||
'/(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');
|
||||
|
||||
$uncountable = array('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep');
|
||||
|
||||
$irregular = array(
|
||||
'person' => 'people',
|
||||
'man' => 'men',
|
||||
'child' => 'children',
|
||||
'sex' => 'sexes',
|
||||
'move' => 'moves');
|
||||
|
||||
$lowercased_word = strtolower($word);
|
||||
|
||||
foreach ($uncountable as $_uncountable) {
|
||||
foreach ($this->uncountable as $_uncountable) {
|
||||
if (substr($lowercased_word, (-1*strlen($_uncountable))) == $_uncountable) {
|
||||
return $word;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($irregular as $_plural => $_singular) {
|
||||
foreach ($this->irregular as $_plural => $_singular) {
|
||||
if (preg_match('/('.$_plural.')$/i', $word, $arr)) {
|
||||
return preg_replace('/('.$_plural.')$/i', substr($arr[0], 0, 1).substr($_singular, 1), $word);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($plural as $rule => $replacement) {
|
||||
foreach ($this->plural as $rule => $replacement) {
|
||||
if (preg_match($rule, $word)) {
|
||||
return preg_replace($rule, $replacement, $word);
|
||||
}
|
||||
@@ -94,62 +85,28 @@ class Inflector
|
||||
* @param int $count
|
||||
* @return string Singular noun.
|
||||
*/
|
||||
public static function singularize($word, $count = 1)
|
||||
public function singularize($word, $count = 1)
|
||||
{
|
||||
$this->init();
|
||||
|
||||
if ($count != 1) {
|
||||
return $word;
|
||||
}
|
||||
|
||||
$singular = array (
|
||||
'/(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' => '',
|
||||
);
|
||||
|
||||
$uncountable = array('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep');
|
||||
|
||||
$irregular = array(
|
||||
'person' => 'people',
|
||||
'man' => 'men',
|
||||
'child' => 'children',
|
||||
'sex' => 'sexes',
|
||||
'move' => 'moves');
|
||||
|
||||
$lowercased_word = strtolower($word);
|
||||
foreach ($uncountable as $_uncountable) {
|
||||
foreach ($this->uncountable as $_uncountable) {
|
||||
if (substr($lowercased_word, (-1*strlen($_uncountable))) == $_uncountable) {
|
||||
return $word;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($irregular as $_plural => $_singular) {
|
||||
foreach ($this->irregular as $_plural => $_singular) {
|
||||
if (preg_match('/('.$_singular.')$/i', $word, $arr)) {
|
||||
return preg_replace('/('.$_singular.')$/i', substr($arr[0], 0, 1).substr($_plural, 1), $word);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($singular as $rule => $replacement) {
|
||||
foreach ($this->singular as $rule => $replacement) {
|
||||
if (preg_match($rule, $word)) {
|
||||
return preg_replace($rule, $replacement, $word);
|
||||
}
|
||||
@@ -162,24 +119,22 @@ class Inflector
|
||||
* Converts an underscored or CamelCase word into a English
|
||||
* sentence.
|
||||
*
|
||||
* The titleize static public function converts text like "WelcomePage",
|
||||
* The titleize public function converts text like "WelcomePage",
|
||||
* "welcome_page" or "welcome page" to this "Welcome
|
||||
* Page".
|
||||
* If second parameter is set to 'first' it will only
|
||||
* capitalize the first character of the title.
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @param string $word Word to format as tile
|
||||
* @param string $uppercase If set to 'first' it will only uppercase the
|
||||
* first character. Otherwise it will uppercase all
|
||||
* the words in the title.
|
||||
* @return string Text formatted as title
|
||||
*/
|
||||
public static function titleize($word, $uppercase = '')
|
||||
public function titleize($word, $uppercase = '')
|
||||
{
|
||||
$uppercase = $uppercase == 'first' ? 'ucfirst' : 'ucwords';
|
||||
return $uppercase(static::humanize(static::underscorize($word)));
|
||||
return $uppercase($this->humanize($this->underscorize($word)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,13 +144,11 @@ class Inflector
|
||||
* will remove non alphanumeric character from the word, so
|
||||
* "who's online" will be converted to "WhoSOnline"
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @see variablize
|
||||
* @param string $word Word to convert to camel case
|
||||
* @return string UpperCamelCasedWord
|
||||
*/
|
||||
public static function camelize($word)
|
||||
public function camelize($word)
|
||||
{
|
||||
return str_replace(' ', '', ucwords(preg_replace('/[^A-Z^a-z^0-9]+/', ' ', $word)));
|
||||
}
|
||||
@@ -208,12 +161,10 @@ class Inflector
|
||||
*
|
||||
* This can be really useful for creating friendly URLs.
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @param string $word Word to underscore
|
||||
* @return string Underscored word
|
||||
*/
|
||||
public static function underscorize($word)
|
||||
public function underscorize($word)
|
||||
{
|
||||
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2', $word);
|
||||
$regex2 = preg_replace('/([a-zd])([A-Z])/', '\1_\2', $regex1);
|
||||
@@ -229,12 +180,10 @@ class Inflector
|
||||
*
|
||||
* This can be really useful for creating friendly URLs.
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @param string $word Word to hyphenate
|
||||
* @return string hyphenized word
|
||||
*/
|
||||
public static function hyphenize($word)
|
||||
public function hyphenize($word)
|
||||
{
|
||||
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1-\2', $word);
|
||||
$regex2 = preg_replace('/([a-zd])([A-Z])/', '\1-\2', $regex1);
|
||||
@@ -252,14 +201,12 @@ class Inflector
|
||||
* If you need to uppercase all the words you just have to
|
||||
* pass 'all' as a second parameter.
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @param string $word String to "humanize"
|
||||
* @param string $uppercase If set to 'all' it will uppercase all the words
|
||||
* instead of just the first one.
|
||||
* @return string Human-readable word
|
||||
*/
|
||||
public static function humanize($word, $uppercase = '')
|
||||
public function humanize($word, $uppercase = '')
|
||||
{
|
||||
$uppercase = $uppercase == 'all' ? 'ucwords' : 'ucfirst';
|
||||
return $uppercase(str_replace('_', ' ', preg_replace('/_id$/', '', $word)));
|
||||
@@ -272,15 +219,13 @@ class Inflector
|
||||
* will remove non alphanumeric character from the word, so
|
||||
* "who's online" will be converted to "whoSOnline"
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @see camelize
|
||||
* @param string $word Word to lowerCamelCase
|
||||
* @return string Returns a lowerCamelCasedWord
|
||||
*/
|
||||
public static function variablize($word)
|
||||
public function variablize($word)
|
||||
{
|
||||
$word = static::camelize($word);
|
||||
$word = $this->camelize($word);
|
||||
return strtolower($word[0]).substr($word, 1);
|
||||
}
|
||||
|
||||
@@ -290,15 +235,13 @@ class Inflector
|
||||
*
|
||||
* Converts "Person" to "people"
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @see classify
|
||||
* @param string $class_name Class name for getting related table_name.
|
||||
* @return string plural_table_name
|
||||
*/
|
||||
public static function tableize($class_name)
|
||||
public function tableize($class_name)
|
||||
{
|
||||
return static::pluralize(static::underscore($class_name));
|
||||
return $this->pluralize($this->underscore($class_name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,15 +250,13 @@ class Inflector
|
||||
*
|
||||
* Converts "people" to "Person"
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @see tableize
|
||||
* @param string $table_name Table name for getting related ClassName.
|
||||
* @return string SingularClassName
|
||||
*/
|
||||
public static function classify($table_name)
|
||||
public function classify($table_name)
|
||||
{
|
||||
return static::camelize(static::singularize($table_name));
|
||||
return $this->camelize($this->singularize($table_name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,34 +264,34 @@ class Inflector
|
||||
*
|
||||
* This method converts 13 to 13th, 2 to 2nd ...
|
||||
*
|
||||
* @access static public
|
||||
* @static
|
||||
* @param integer $number Number to get its ordinal value
|
||||
* @return string Ordinal representation of given string.
|
||||
*/
|
||||
public static function ordinalize($number)
|
||||
public function ordinalize($number)
|
||||
{
|
||||
$this->init();
|
||||
|
||||
if (in_array(($number % 100), range(11, 13))) {
|
||||
return $number.'th';
|
||||
return $number.$this->ordinals['default'];
|
||||
} else {
|
||||
switch (($number % 10)) {
|
||||
case 1:
|
||||
return $number.'st';
|
||||
return $number.$this->ordinals['first'];
|
||||
break;
|
||||
case 2:
|
||||
return $number.'nd';
|
||||
return $number.$this->ordinals['second'];
|
||||
break;
|
||||
case 3:
|
||||
return $number.'rd';
|
||||
return $number.$this->ordinals['third'];
|
||||
break;
|
||||
default:
|
||||
return $number.'th';
|
||||
return $number.$this->ordinals['default'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function monthize($days)
|
||||
public function monthize($days)
|
||||
{
|
||||
$now = new \DateTime();
|
||||
$end = new \DateTime();
|
||||
|
||||
@@ -276,13 +276,15 @@ class Language
|
||||
/**
|
||||
* Translate a key and possibly arguments into a string using current lang and fallbacks
|
||||
*
|
||||
* @param $args first argument is the lookup key value
|
||||
* other arguments can be passed and replaced in the translation with sprintf syntax
|
||||
* @param $args first argument is the lookup key value
|
||||
* other arguments can be passed and replaced in the translation with sprintf syntax
|
||||
* @param Array $languages
|
||||
* @param bool $array_support
|
||||
* @param bool $html_out
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function translate($args, Array $languages = null)
|
||||
public function translate($args, Array $languages = null, $array_support = false, $html_out = false)
|
||||
{
|
||||
if (is_array($args)) {
|
||||
$lookup = array_shift($args);
|
||||
@@ -293,9 +295,12 @@ class Language
|
||||
|
||||
|
||||
if ($this->config->get('system.languages.translations', true)) {
|
||||
if ($this->enabled() && $lookup) {
|
||||
|
||||
if (isset($this->grav['admin'])) {
|
||||
$languages = ['en'];
|
||||
} elseif ($this->enabled() && $lookup) {
|
||||
if (empty($languages)) {
|
||||
if ($this->config->get('system.languages.translations.fallback', true)) {
|
||||
if ($this->config->get('system.languages.translations_fallback', true)) {
|
||||
$languages = $this->getFallbackLanguages();
|
||||
} else {
|
||||
$languages = (array)$this->getDefault();
|
||||
@@ -306,7 +311,7 @@ class Language
|
||||
}
|
||||
|
||||
foreach ((array)$languages as $lang) {
|
||||
$translation = $this->getTranslation($lang, $lookup);
|
||||
$translation = $this->getTranslation($lang, $lookup, $array_support);
|
||||
|
||||
if ($translation) {
|
||||
if (count($args) >= 1) {
|
||||
@@ -318,7 +323,11 @@ class Language
|
||||
}
|
||||
}
|
||||
|
||||
return '<span class="untranslated">' . $lookup . '</span>';
|
||||
if ($html_out) {
|
||||
return '<span class="untranslated">' . $lookup . '</span>';
|
||||
} else {
|
||||
return $lookup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,15 +336,16 @@ class Language
|
||||
* @param $key
|
||||
* @param $index
|
||||
* @param null $languages
|
||||
* @param bool $html_out
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function translateArray($key, $index, $languages = null)
|
||||
public function translateArray($key, $index, $languages = null, $html_out = false)
|
||||
{
|
||||
if ($this->config->get('system.languages.translations', true)) {
|
||||
if ($this->enabled() && $key) {
|
||||
if (empty($languages)) {
|
||||
if ($this->config->get('system.languages.translations.fallback', true)) {
|
||||
if ($this->config->get('system.languages.translations_fallback', true)) {
|
||||
$languages = $this->getFallbackLanguages();
|
||||
} else {
|
||||
$languages = (array)$this->getDefault();
|
||||
@@ -353,21 +363,26 @@ class Language
|
||||
}
|
||||
}
|
||||
|
||||
return '<span class="untranslated">' . $key . '[' . $index . ']</span>';
|
||||
if ($html_out) {
|
||||
return '<span class="untranslated">' . $key . '[' . $index . ']</span>';
|
||||
} else {
|
||||
return $key . '[' . $index . ']';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the translation text for a given lang and key
|
||||
*
|
||||
* @param $lang lang code
|
||||
* @param $key key to lookup with
|
||||
* @param $lang lang code
|
||||
* @param $key key to lookup with
|
||||
* @param bool $array_support
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTranslation($lang, $key)
|
||||
public function getTranslation($lang, $key, $array_support = false)
|
||||
{
|
||||
$translation = $this->config->getLanguages()->get($lang . '.' . $key, null);
|
||||
if (is_array($translation)) {
|
||||
if (!$array_support && is_array($translation)) {
|
||||
return (string)array_shift($translation);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Grav\Common\Page\Medium;
|
||||
|
||||
use Grav\Common\GravTrait;
|
||||
use Gregwar\Image\Exceptions\GenerationError;
|
||||
use RocketTheme\Toolbox\Event\Event;
|
||||
|
||||
class ImageFile extends \Gregwar\Image\Image
|
||||
|
||||
@@ -66,17 +66,23 @@ class ImageMedium extends Medium
|
||||
{
|
||||
parent::__construct($items, $blueprint);
|
||||
|
||||
$config = self::$grav['config'];
|
||||
|
||||
$image_info = getimagesize($this->get('filepath'));
|
||||
$this->def('width', $image_info[0]);
|
||||
$this->def('height', $image_info[1]);
|
||||
$this->def('mime', $image_info['mime']);
|
||||
$this->def('debug', self::$grav['config']->get('system.images.debug'));
|
||||
$this->def('debug', $config->get('system.images.debug'));
|
||||
|
||||
$this->set('thumbnails.media', $this->get('filepath'));
|
||||
|
||||
$this->default_quality = self::$grav['config']->get('system.images.default_image_quality', 85);
|
||||
$this->default_quality = $config->get('system.images.default_image_quality', 85);
|
||||
|
||||
$this->reset();
|
||||
|
||||
if ($config->get('system.images.cache_all', false)) {
|
||||
$this->cache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,6 +135,19 @@ class ImageMedium extends Medium
|
||||
return self::$grav['base_url'] . $output . $this->querystring() . $this->urlHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply processes with no extra methods. Useful for triggering events.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function cache()
|
||||
{
|
||||
if (!$this->image) {
|
||||
$this->image();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return srcset string for this Medium and its alternatives.
|
||||
|
||||
@@ -7,7 +7,6 @@ use Grav\Common\Grav;
|
||||
use Grav\Common\GravTrait;
|
||||
use Grav\Common\Data\Blueprint;
|
||||
use Grav\Common\Data\Data;
|
||||
use Gregwar\Image\Image as ImageFile;
|
||||
|
||||
class VideoMedium extends Medium
|
||||
{
|
||||
|
||||
@@ -56,6 +56,7 @@ class Page
|
||||
protected $items;
|
||||
protected $header;
|
||||
protected $frontmatter;
|
||||
protected $language;
|
||||
protected $content;
|
||||
protected $summary;
|
||||
protected $raw_content;
|
||||
@@ -127,6 +128,10 @@ class Page
|
||||
} else {
|
||||
$this->extension($extension);
|
||||
}
|
||||
|
||||
// Exract page language from page extension
|
||||
$language = trim(basename($this->extension(), 'md'), '.') ?: null;
|
||||
$this->language($language);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,6 +222,9 @@ class Page
|
||||
if (isset($this->header->title)) {
|
||||
$this->title = trim($this->header->title);
|
||||
}
|
||||
if (isset($this->header->language)) {
|
||||
$this->language = trim($this->header->language);
|
||||
}
|
||||
if (isset($this->header->template)) {
|
||||
$this->template = trim($this->header->template);
|
||||
}
|
||||
@@ -281,6 +289,22 @@ class Page
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page language
|
||||
*
|
||||
* @param $var
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function language($var = null)
|
||||
{
|
||||
if ($var !== null) {
|
||||
$this->language = $var;
|
||||
}
|
||||
|
||||
return $this->language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a header value directly
|
||||
*
|
||||
@@ -539,7 +563,7 @@ class Page
|
||||
return preg_replace($regex, '', $this->folder);
|
||||
}
|
||||
if ($name == 'type') {
|
||||
return basename($this->name(), '.md');
|
||||
return $this->template();
|
||||
}
|
||||
if ($name == 'media') {
|
||||
return $this->media()->all();
|
||||
@@ -605,22 +629,6 @@ class Page
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page extension
|
||||
*
|
||||
* @param $var
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function extension($var = null)
|
||||
{
|
||||
if ($var !== null) {
|
||||
$this->extension = $var;
|
||||
}
|
||||
|
||||
return $this->extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save page if there's a file assigned to it.
|
||||
* @param bool $reorder Internal use.
|
||||
@@ -658,9 +666,12 @@ class Page
|
||||
if ($parent->path()) {
|
||||
$clone->path($parent->path() . '/' . $clone->folder());
|
||||
}
|
||||
|
||||
// TODO: make sure we always have the route.
|
||||
if ($parent->route()) {
|
||||
$clone->route($parent->route() . '/'. $clone->slug());
|
||||
} else {
|
||||
$clone->route(self::getGrav()['pages']->root()->route() . '/'. $clone->slug());
|
||||
}
|
||||
|
||||
return $clone;
|
||||
@@ -693,7 +704,33 @@ class Page
|
||||
/** @var Pages $pages */
|
||||
$pages = self::getGrav()['pages'];
|
||||
|
||||
return $pages->blueprints($this->template());
|
||||
$blueprint = $pages->blueprints($this->blueprintName());
|
||||
|
||||
$fields = $blueprint->fields();
|
||||
|
||||
// override if you only want 'normal' mode
|
||||
if (empty($fields) && self::getGrav()['admin'] && self::getGrav()['config']->get('plugins.admin.edit_mode', 'auto') == 'normal') {
|
||||
$blueprint = $pages->blueprints('default');
|
||||
}
|
||||
|
||||
// override if you only want 'expert' mode
|
||||
if (!empty($fields) && self::getGrav()['admin'] && self::getGrav()['config']->get('plugins.admin.edit_mode', 'auto') == 'expert') {
|
||||
$blueprint = $pages->blueprints('');
|
||||
}
|
||||
|
||||
return $blueprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the blueprint name for this page. Use the blueprint form field if set
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function blueprintName()
|
||||
{
|
||||
$blueprint_name = filter_input(INPUT_POST, 'blueprint', FILTER_SANITIZE_STRING) ?: $this->template();
|
||||
|
||||
return $blueprint_name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -725,7 +762,7 @@ class Page
|
||||
public function extra()
|
||||
{
|
||||
$blueprints = $this->blueprints();
|
||||
return $blueprints->extra($this->toArray(), 'header.');
|
||||
return $blueprints->extra($this->toArray()['header'], 'header.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -824,11 +861,28 @@ class Page
|
||||
$this->template = $var;
|
||||
}
|
||||
if (empty($this->template)) {
|
||||
$this->template = ($this->modular() ? 'modular/' : '') . str_replace($this->extension, '', $this->name());
|
||||
$this->template = ($this->modular() ? 'modular/' : '') . str_replace($this->extension(), '', $this->name());
|
||||
}
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and sets the extension field.
|
||||
*
|
||||
* @param null $var
|
||||
* @return null|string
|
||||
*/
|
||||
public function extension($var = null)
|
||||
{
|
||||
if ($var !== null) {
|
||||
$this->extension = $var;
|
||||
}
|
||||
if (empty($this->extension)) {
|
||||
$this->extension = '.' . pathinfo($this->name(), PATHINFO_EXTENSION);
|
||||
}
|
||||
return $this->extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and sets the expires field. If not set will return the default
|
||||
*
|
||||
@@ -1005,24 +1059,29 @@ class Page
|
||||
if (null === $this->metadata) {
|
||||
$header_tag_http_equivs = ['content-type', 'default-style', 'refresh'];
|
||||
$this->metadata = array();
|
||||
$page_header = $this->header;
|
||||
|
||||
// Set the Generator tag
|
||||
$this->metadata['generator'] = array('name'=>'generator', 'content'=>'GravCMS ' . GRAV_VERSION);
|
||||
|
||||
// Safety check to ensure we have a header
|
||||
if ($page_header) {
|
||||
|
||||
if (isset($this->header->metadata)) {
|
||||
$page_header = $this->header->metadata;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Merge any site.metadata settings in with page metadata
|
||||
$defaults = (array) self::getGrav()['config']->get('site.metadata');
|
||||
|
||||
if (isset($page_header->metadata)) {
|
||||
$page_header->metadata = array_merge($defaults, $page_header->metadata);
|
||||
if (isset($page_header)) {
|
||||
$page_header = array_merge($defaults, $page_header);
|
||||
} else {
|
||||
$page_header->metadata = $defaults;
|
||||
$page_header = $defaults;
|
||||
}
|
||||
|
||||
// Build an array of meta objects..
|
||||
foreach ((array)$page_header->metadata as $key => $value) {
|
||||
foreach ((array)$page_header as $key => $value) {
|
||||
// If this is a property type metadata: "og", "twitter", "facebook" etc
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $property => $prop_value) {
|
||||
|
||||
@@ -404,8 +404,8 @@ class Pages
|
||||
{
|
||||
if (!self::$types) {
|
||||
self::$types = new Types();
|
||||
self::$types->scanBlueprints('theme://blueprints/');
|
||||
self::$types->scanTemplates('theme://templates/');
|
||||
file_exists('theme://blueprints/') && self::$types->scanBlueprints('theme://blueprints/');
|
||||
file_exists('theme://templates/') && self::$types->scanTemplates('theme://templates/');
|
||||
|
||||
$event = new Event();
|
||||
$event->types = self::$types;
|
||||
|
||||
@@ -13,27 +13,24 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
use ArrayAccess, Constructor, Iterator, Countable, Export;
|
||||
|
||||
protected $items;
|
||||
protected $systemBlueprints;
|
||||
|
||||
public function register($type, $blueprint = null)
|
||||
{
|
||||
if (!$blueprint && $this->systemBlueprints && isset($this->systemBlueprints[$type])) {
|
||||
$useBlueprint = $this->systemBlueprints[$type];
|
||||
} else {
|
||||
$useBlueprint = $blueprint;
|
||||
}
|
||||
|
||||
if ($blueprint || empty($this->items[$type])) {
|
||||
$this->items[$type] = $blueprint;
|
||||
$this->items[$type] = $useBlueprint;
|
||||
}
|
||||
}
|
||||
|
||||
public function scanBlueprints($path)
|
||||
{
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|'
|
||||
],
|
||||
'key' => 'SubPathName',
|
||||
'value' => 'PathName',
|
||||
];
|
||||
|
||||
$this->items = Folder::all($path, $options) + $this->items;
|
||||
$this->items = $this->findBlueprints($path) + $this->items;
|
||||
}
|
||||
|
||||
public function scanTemplates($path)
|
||||
@@ -48,6 +45,10 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
'recursive' => false
|
||||
];
|
||||
|
||||
if (!$this->systemBlueprints) {
|
||||
$this->systemBlueprints = $this->findBlueprints('blueprints://pages');
|
||||
}
|
||||
|
||||
foreach (Folder::all($path, $options) as $type) {
|
||||
$this->register($type);
|
||||
}
|
||||
@@ -78,9 +79,24 @@ class Types implements \ArrayAccess, \Iterator, \Countable
|
||||
if (strpos($name, 'modular/') !== 0) {
|
||||
continue;
|
||||
}
|
||||
$list[basename($name)] = trim(ucfirst(strtr(basename($name), '_', ' ')));
|
||||
$list[$name] = trim(ucfirst(strtr(basename($name), '_', ' ')));
|
||||
}
|
||||
ksort($list);
|
||||
return $list;
|
||||
}
|
||||
|
||||
private function findBlueprints($path)
|
||||
{
|
||||
$options = [
|
||||
'compare' => 'Filename',
|
||||
'pattern' => '|\.yaml$|',
|
||||
'filters' => [
|
||||
'key' => '|\.yaml$|'
|
||||
],
|
||||
'key' => 'SubPathName',
|
||||
'value' => 'PathName',
|
||||
];
|
||||
|
||||
return Folder::all($path, $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ class Plugins extends Iterator
|
||||
$config = self::getGrav()['config'];
|
||||
$plugins = (array) $config->get('plugins');
|
||||
|
||||
$inflector = self::getGrav()['inflector'];
|
||||
|
||||
/** @var EventDispatcher $events */
|
||||
$events = self::getGrav()['events'];
|
||||
|
||||
@@ -52,7 +54,7 @@ class Plugins extends Iterator
|
||||
|
||||
$pluginClassFormat = [
|
||||
'Grav\\Plugin\\'.ucfirst($plugin).'Plugin',
|
||||
'Grav\\Plugin\\'.Inflector::camelize($plugin).'Plugin'
|
||||
'Grav\\Plugin\\'.$inflector->camelize($plugin).'Plugin'
|
||||
];
|
||||
$pluginClassName = false;
|
||||
|
||||
|
||||
@@ -21,15 +21,27 @@ class Session extends \RocketTheme\Toolbox\Session\Session
|
||||
$config = $this->grav['config'];
|
||||
|
||||
if ($config->get('system.session.enabled')) {
|
||||
// Only activate admin if we're inside the admin path.
|
||||
$is_admin = false;
|
||||
$route = $config->get('plugins.admin.route');
|
||||
$base = '/' . trim($route, '/');
|
||||
if (substr($uri->route(), 0, strlen($base)) == $base) {
|
||||
$is_admin = true;
|
||||
}
|
||||
|
||||
$session_timeout = $config->get('system.session.timeout', 1800);
|
||||
$session_path = $config->get('system.session.path', '/' . ltrim($uri->rootUrl(false), '/'));
|
||||
|
||||
// Define session service.
|
||||
parent::__construct(
|
||||
$config->get('system.session.timeout', 1800),
|
||||
$config->get('system.session.path', '/' . ltrim($uri->rootUrl(false), '/'))
|
||||
$session_timeout,
|
||||
$session_path
|
||||
);
|
||||
|
||||
$site_identifier = $config->get('site.title', 'unkown');
|
||||
$this->setName($config->get('system.session.name', 'grav_site') . '_' . substr(md5($site_identifier), 0, 7));
|
||||
$site_identifier = $config->get('site.title', 'unknown');
|
||||
$this->setName($config->get('system.session.name', 'grav_site') . '_' . substr(md5($site_identifier), 0, 7) . ($is_admin ? '_admin' : ''));
|
||||
$this->start();
|
||||
setcookie(session_name(), session_id(), time() + $session_timeout, $session_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,15 +141,16 @@ class Themes extends Iterator
|
||||
$locator = $grav['locator'];
|
||||
$file = $locator('theme://theme.php') ?: $locator("theme://{$name}.php");
|
||||
|
||||
$inflector = $grav['inflector'];
|
||||
|
||||
if ($file) {
|
||||
// Local variables available in the file: $grav, $config, $name, $file
|
||||
$class = include $file;
|
||||
|
||||
if (!is_object($class)) {
|
||||
|
||||
$themeClassFormat = [
|
||||
'Grav\\Theme\\'.ucfirst($name),
|
||||
'Grav\\Theme\\'.Inflector::camelize($name)
|
||||
'Grav\\Theme\\'.$inflector->camelize($name)
|
||||
];
|
||||
$themeClassName = false;
|
||||
|
||||
|
||||
@@ -301,13 +301,14 @@ class Twig
|
||||
$this->grav->fireEvent('onTwigSiteVariables');
|
||||
$pages = $this->grav['pages'];
|
||||
$page = $this->grav['page'];
|
||||
$content = $page->content();
|
||||
|
||||
$twig_vars = $this->twig_vars;
|
||||
|
||||
$twig_vars['pages'] = $pages->root();
|
||||
$twig_vars['page'] = $page;
|
||||
$twig_vars['header'] = $page->header();
|
||||
$twig_vars['content'] = $page->content();
|
||||
$twig_vars['content'] = $content;
|
||||
$ext = '.' . ($format ? $format : 'html') . TWIG_EXT;
|
||||
|
||||
// determine if params are set, if so disable twig cache
|
||||
|
||||
@@ -78,6 +78,7 @@ class TwigExtension extends \Twig_Extension
|
||||
new \Twig_SimpleFunction('debug', [$this, 'dump'], ['needs_context' => true, 'needs_environment' => true]),
|
||||
new \Twig_SimpleFunction('gist', [$this, 'gistFunc']),
|
||||
new \Twig_simpleFunction('random_string', [$this, 'randomStringFunc']),
|
||||
new \Twig_SimpleFunction('array', [$this, 'arrayFunc']),
|
||||
new \Twig_simpleFunction('t', [$this, 'translate']),
|
||||
new \Twig_simpleFunction('ta', [$this, 'translateArray'])
|
||||
];
|
||||
@@ -194,16 +195,18 @@ class TwigExtension extends \Twig_Extension
|
||||
// TODO: check this and fix the docblock if needed.
|
||||
$action = $action.'ize';
|
||||
|
||||
$inflector = $this->grav['inflector'];
|
||||
|
||||
if (in_array(
|
||||
$action,
|
||||
['titleize','camelize','underscorize','hyphenize', 'humanize','ordinalize','monthize']
|
||||
)) {
|
||||
return Inflector::$action($data);
|
||||
return $inflector->$action($data);
|
||||
} elseif (in_array($action, ['pluralize','singularize'])) {
|
||||
if ($count) {
|
||||
return Inflector::$action($data, $count);
|
||||
return $inflector->$action($data, $count);
|
||||
} else {
|
||||
return Inflector::$action($data);
|
||||
return $inflector->$action($data);
|
||||
}
|
||||
} else {
|
||||
return $data;
|
||||
@@ -479,6 +482,11 @@ class TwigExtension extends \Twig_Extension
|
||||
return Utils::generateRandomString($count);
|
||||
}
|
||||
|
||||
public function arrayFunc($value)
|
||||
{
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
public function translateFunc()
|
||||
{
|
||||
return $this->grav['language']->translate(func_get_args());
|
||||
|
||||
@@ -9,6 +9,9 @@ use Grav\Common\GravTrait;
|
||||
/**
|
||||
* User object
|
||||
*
|
||||
* @property mixed authenticated
|
||||
* @property mixed password
|
||||
* @property bool|string hashed_password
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
@@ -57,14 +60,13 @@ class User extends Data
|
||||
|
||||
// Plain-text is still stored
|
||||
if ($this->password) {
|
||||
|
||||
if ($password !== $this->password) {
|
||||
// Plain-text passwords do not match, we know we should fail but execute
|
||||
// verify to protect us from timing attacks and return false regardless of
|
||||
// the result
|
||||
Authentication::verify($password, self::getGrav()['config']->get('system.security.default_hash'));
|
||||
return false;
|
||||
} else {
|
||||
} else {
|
||||
// Plain-text does match, we can update the hash and proceed
|
||||
$save = true;
|
||||
|
||||
@@ -97,6 +99,10 @@ class User extends Data
|
||||
*/
|
||||
public function authorise($action)
|
||||
{
|
||||
if (empty($this->items)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->get("access.{$action}") === true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,9 @@ abstract class Utils
|
||||
use GravTrait;
|
||||
|
||||
/**
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function startsWith($haystack, $needle)
|
||||
@@ -27,14 +28,17 @@ abstract class Utils
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
return $needle === '' || strpos($haystack, $needle) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function endsWith($haystack, $needle)
|
||||
@@ -47,14 +51,17 @@ abstract class Utils
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
return $needle === '' || substr($haystack, -strlen($needle)) === $needle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
* @param string $haystack
|
||||
* @param string $needle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function contains($haystack, $needle)
|
||||
@@ -67,11 +74,12 @@ abstract class Utils
|
||||
*
|
||||
* @param object $obj1
|
||||
* @param object $obj2
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function mergeObjects($obj1, $obj2)
|
||||
{
|
||||
return (object) array_merge((array) $obj1, (array) $obj2);
|
||||
return (object)array_merge((array)$obj1, (array)$obj2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,6 +90,7 @@ abstract class Utils
|
||||
* @param string $ending
|
||||
* @param bool $exact
|
||||
* @param bool $considerHtml
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function truncateHtml($text, $length = 100, $ending = '...', $exact = false, $considerHtml = true)
|
||||
@@ -100,34 +109,41 @@ abstract class Utils
|
||||
// if there is any html-tag in this line, handle it and add it (uncounted) to the output
|
||||
if (!empty($line_matchings[1])) {
|
||||
// if it's an "empty element" with or without xhtml-conform closing slash
|
||||
if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {
|
||||
if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is',
|
||||
$line_matchings[1])) {
|
||||
// do nothing
|
||||
// if tag is a closing tag
|
||||
} else if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
|
||||
// delete tag from $open_tags list
|
||||
$pos = array_search($tag_matchings[1], $open_tags);
|
||||
if ($pos !== false) {
|
||||
unset($open_tags[$pos]);
|
||||
// if tag is a closing tag
|
||||
} else {
|
||||
if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
|
||||
// delete tag from $open_tags list
|
||||
$pos = array_search($tag_matchings[1], $open_tags);
|
||||
if ($pos !== false) {
|
||||
unset($open_tags[$pos]);
|
||||
}
|
||||
// if tag is an opening tag
|
||||
} else {
|
||||
if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {
|
||||
// add tag to the beginning of $open_tags list
|
||||
array_unshift($open_tags, strtolower($tag_matchings[1]));
|
||||
}
|
||||
}
|
||||
// if tag is an opening tag
|
||||
} else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {
|
||||
// add tag to the beginning of $open_tags list
|
||||
array_unshift($open_tags, strtolower($tag_matchings[1]));
|
||||
}
|
||||
// add html-tag to $truncate'd text
|
||||
$truncate .= $line_matchings[1];
|
||||
}
|
||||
// calculate the length of the plain text part of the line; handle entities as one character
|
||||
$content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
|
||||
if ($total_length+$content_length> $length) {
|
||||
$content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ',
|
||||
$line_matchings[2]));
|
||||
if ($total_length + $content_length > $length) {
|
||||
// the number of characters which are left
|
||||
$left = $length - $total_length;
|
||||
$entities_length = 0;
|
||||
// search for html entities
|
||||
if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, PREG_OFFSET_CAPTURE)) {
|
||||
if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities,
|
||||
PREG_OFFSET_CAPTURE)) {
|
||||
// calculate the real length of all entities in the legal range
|
||||
foreach ($entities[0] as $entity) {
|
||||
if ($entity[1]+1-$entities_length <= $left) {
|
||||
if ($entity[1] + 1 - $entities_length <= $left) {
|
||||
$left--;
|
||||
$entities_length += strlen($entity[0]);
|
||||
} else {
|
||||
@@ -136,7 +152,7 @@ abstract class Utils
|
||||
}
|
||||
}
|
||||
}
|
||||
$truncate .= substr($line_matchings[2], 0, $left+$entities_length);
|
||||
$truncate .= substr($line_matchings[2], 0, $left + $entities_length);
|
||||
// maximum length is reached, so get off the loop
|
||||
break;
|
||||
} else {
|
||||
@@ -172,6 +188,7 @@ abstract class Utils
|
||||
$truncate .= '</' . $tag . '>';
|
||||
}
|
||||
}
|
||||
|
||||
return $truncate;
|
||||
}
|
||||
|
||||
@@ -208,7 +225,7 @@ abstract class Utils
|
||||
if ($force_download) {
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename='.$file_parts['basename']);
|
||||
header('Content-Disposition: attachment; filename=' . $file_parts['basename']);
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
@@ -243,14 +260,14 @@ abstract class Utils
|
||||
* Return the mimetype based on filename
|
||||
*
|
||||
* @param $extension Extension of file (eg .txt)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getMimeType($extension)
|
||||
{
|
||||
$extension = strtolower($extension);
|
||||
|
||||
switch($extension)
|
||||
{
|
||||
switch ($extension) {
|
||||
case "js":
|
||||
return "application/x-javascript";
|
||||
|
||||
@@ -348,6 +365,7 @@ abstract class Utils
|
||||
* Normalize path by processing relative `.` and `..` syntax and merging path
|
||||
*
|
||||
* @param $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function normalizePath($path)
|
||||
@@ -366,6 +384,7 @@ abstract class Utils
|
||||
array_push($ret, $segment);
|
||||
}
|
||||
}
|
||||
|
||||
return $root . implode('/', $ret);
|
||||
}
|
||||
|
||||
@@ -383,10 +402,9 @@ abstract class Utils
|
||||
asort($offsets);
|
||||
|
||||
$timezone_list = array();
|
||||
foreach( $offsets as $timezone => $offset )
|
||||
{
|
||||
foreach ($offsets as $timezone => $offset) {
|
||||
$offset_prefix = $offset < 0 ? '-' : '+';
|
||||
$offset_formatted = gmdate( 'H:i', abs($offset) );
|
||||
$offset_formatted = gmdate('H:i', abs($offset));
|
||||
|
||||
$pretty_offset = "UTC${offset_prefix}${offset_formatted}";
|
||||
|
||||
@@ -396,4 +414,23 @@ abstract class Utils
|
||||
return $timezone_list;
|
||||
|
||||
}
|
||||
|
||||
public static function arrayFilterRecursive(Array $source, $fn)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($source as $key => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
$result[$key] = static::arrayFilterRecursive($value, $fn);
|
||||
continue;
|
||||
}
|
||||
if ($fn($key, $value))
|
||||
{
|
||||
$result[$key] = $value; // KEEP
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user