Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
|
@ -0,0 +1,6 @@
|
|||
id: fallback
|
||||
label: 'Fallback date format'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: 'D, m/d/Y - H:i'
|
|
@ -0,0 +1,6 @@
|
|||
id: html_date
|
||||
label: 'HTML Date'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: Y-m-d
|
|
@ -0,0 +1,6 @@
|
|||
id: html_datetime
|
||||
label: 'HTML Datetime'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: 'Y-m-d\TH:i:sO'
|
|
@ -0,0 +1,6 @@
|
|||
id: html_month
|
||||
label: 'HTML Month'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: Y-m
|
|
@ -0,0 +1,6 @@
|
|||
id: html_time
|
||||
label: 'HTML Time'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: 'H:i:s'
|
|
@ -0,0 +1,6 @@
|
|||
id: html_week
|
||||
label: 'HTML Week'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: Y-\WW
|
|
@ -0,0 +1,6 @@
|
|||
id: html_year
|
||||
label: 'HTML Year'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: Y
|
|
@ -0,0 +1,6 @@
|
|||
id: html_yearless_date
|
||||
label: 'HTML Yearless date'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: true
|
||||
pattern: m-d
|
|
@ -0,0 +1,6 @@
|
|||
id: long
|
||||
label: 'Default long date'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: false
|
||||
pattern: 'l, F j, Y - H:i'
|
|
@ -0,0 +1,6 @@
|
|||
id: medium
|
||||
label: 'Default medium date'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: false
|
||||
pattern: 'D, m/d/Y - H:i'
|
|
@ -0,0 +1,6 @@
|
|||
id: short
|
||||
label: 'Default short date'
|
||||
status: true
|
||||
langcode: en
|
||||
locked: false
|
||||
pattern: 'm/d/Y - H:i'
|
1
core/modules/system/config/install/system.authorize.yml
Normal file
1
core/modules/system/config/install/system.authorize.yml
Normal file
|
@ -0,0 +1 @@
|
|||
filetransfer_default:
|
4
core/modules/system/config/install/system.cron.yml
Normal file
4
core/modules/system/config/install/system.cron.yml
Normal file
|
@ -0,0 +1,4 @@
|
|||
threshold:
|
||||
autorun: 0
|
||||
requirements_warning: 172800
|
||||
requirements_error: 1209600
|
9
core/modules/system/config/install/system.date.yml
Normal file
9
core/modules/system/config/install/system.date.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
country:
|
||||
default: ''
|
||||
first_day: 0
|
||||
timezone:
|
||||
default: ''
|
||||
user:
|
||||
configurable: true
|
||||
warn: false
|
||||
default: 0
|
3
core/modules/system/config/install/system.diff.yml
Normal file
3
core/modules/system/config/install/system.diff.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
context:
|
||||
lines_leading: 2
|
||||
lines_trailing: 2
|
5
core/modules/system/config/install/system.file.yml
Normal file
5
core/modules/system/config/install/system.file.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
allow_insecure_uploads: false
|
||||
default_scheme: 'public'
|
||||
path:
|
||||
temporary: ''
|
||||
temporary_maximum_age: 21600
|
14
core/modules/system/config/install/system.filter.yml
Normal file
14
core/modules/system/config/install/system.filter.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
protocols:
|
||||
- http
|
||||
- https
|
||||
- ftp
|
||||
- news
|
||||
- nntp
|
||||
- tel
|
||||
- telnet
|
||||
- mailto
|
||||
- irc
|
||||
- ssh
|
||||
- sftp
|
||||
- webcal
|
||||
- rtsp
|
1
core/modules/system/config/install/system.image.gd.yml
Normal file
1
core/modules/system/config/install/system.image.gd.yml
Normal file
|
@ -0,0 +1 @@
|
|||
jpeg_quality: 75
|
1
core/modules/system/config/install/system.image.yml
Normal file
1
core/modules/system/config/install/system.image.yml
Normal file
|
@ -0,0 +1 @@
|
|||
toolkit: gd
|
1
core/modules/system/config/install/system.logging.yml
Normal file
1
core/modules/system/config/install/system.logging.yml
Normal file
|
@ -0,0 +1 @@
|
|||
error_level: hide
|
2
core/modules/system/config/install/system.mail.yml
Normal file
2
core/modules/system/config/install/system.mail.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
interface:
|
||||
default: 'php_mail'
|
|
@ -0,0 +1,2 @@
|
|||
message: '@site is currently under maintenance. We should be back shortly. Thank you for your patience.'
|
||||
langcode: en
|
|
@ -0,0 +1,5 @@
|
|||
id: account
|
||||
label: 'User account menu'
|
||||
description: 'Links related to the user account.'
|
||||
langcode: en
|
||||
locked: true
|
5
core/modules/system/config/install/system.menu.admin.yml
Normal file
5
core/modules/system/config/install/system.menu.admin.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
id: admin
|
||||
label: Administration
|
||||
description: 'Contains links to administrative tasks.'
|
||||
langcode: en
|
||||
locked: true
|
|
@ -0,0 +1,5 @@
|
|||
id: footer
|
||||
label: Footer
|
||||
description: 'Use this for linking to site information.'
|
||||
langcode: en
|
||||
locked: true
|
5
core/modules/system/config/install/system.menu.main.yml
Normal file
5
core/modules/system/config/install/system.menu.main.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
id: main
|
||||
label: 'Main navigation'
|
||||
description: 'Use this for linking to the main site sections.'
|
||||
langcode: en
|
||||
locked: true
|
5
core/modules/system/config/install/system.menu.tools.yml
Normal file
5
core/modules/system/config/install/system.menu.tools.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
id: tools
|
||||
label: Tools
|
||||
description: 'Contains links for site visitors. Some modules add their links here.'
|
||||
langcode: en
|
||||
locked: true
|
15
core/modules/system/config/install/system.performance.yml
Normal file
15
core/modules/system/config/install/system.performance.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
cache:
|
||||
page:
|
||||
max_age: 0
|
||||
css:
|
||||
preprocess: true
|
||||
gzip: true
|
||||
fast_404:
|
||||
enabled: true
|
||||
paths: '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'
|
||||
exclude_paths: '/\/(?:styles|imagecache)\//'
|
||||
html: '<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL "@path" was not found on this server.</p></body></html>'
|
||||
js:
|
||||
preprocess: true
|
||||
gzip: true
|
||||
stale_file_threshold: 2592000
|
6
core/modules/system/config/install/system.rss.yml
Normal file
6
core/modules/system/config/install/system.rss.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
channel:
|
||||
description: ''
|
||||
items:
|
||||
limit: 10
|
||||
view_mode: rss
|
||||
langcode: en
|
12
core/modules/system/config/install/system.site.yml
Normal file
12
core/modules/system/config/install/system.site.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
uuid: ''
|
||||
name: ''
|
||||
mail: ''
|
||||
slogan: ''
|
||||
page:
|
||||
403: ''
|
||||
404: ''
|
||||
front: /user/login
|
||||
admin_compact_mode: false
|
||||
weight_select_max: 100
|
||||
langcode: en
|
||||
default_langcode: en
|
17
core/modules/system/config/install/system.theme.global.yml
Normal file
17
core/modules/system/config/install/system.theme.global.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
favicon:
|
||||
mimetype: image/vnd.microsoft.icon
|
||||
path: ''
|
||||
url: ''
|
||||
use_default: true
|
||||
features:
|
||||
comment_user_picture: true
|
||||
comment_user_verification: true
|
||||
favicon: true
|
||||
logo: true
|
||||
name: true
|
||||
node_user_picture: true
|
||||
slogan: true
|
||||
logo:
|
||||
path: ''
|
||||
url: ''
|
||||
use_default: true
|
2
core/modules/system/config/install/system.theme.yml
Normal file
2
core/modules/system/config/install/system.theme.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
admin: ''
|
||||
default: stark
|
360
core/modules/system/config/schema/system.schema.yml
Normal file
360
core/modules/system/config/schema/system.schema.yml
Normal file
|
@ -0,0 +1,360 @@
|
|||
# Schema for the configuration files of the System module.
|
||||
|
||||
system.site:
|
||||
type: config_object
|
||||
label: 'Site information'
|
||||
mapping:
|
||||
uuid:
|
||||
type: string
|
||||
label: 'Site UUID'
|
||||
name:
|
||||
type: label
|
||||
label: 'Site name'
|
||||
mail:
|
||||
type: email
|
||||
label: 'Email address'
|
||||
slogan:
|
||||
type: label
|
||||
label: 'Slogan'
|
||||
page:
|
||||
type: mapping
|
||||
label: 'Pages'
|
||||
mapping:
|
||||
403:
|
||||
type: path
|
||||
label: 'Default 403 (access denied) page'
|
||||
404:
|
||||
type: path
|
||||
label: 'Default 404 (not found) page'
|
||||
front:
|
||||
type: path
|
||||
label: 'Default front page'
|
||||
admin_compact_mode:
|
||||
type: boolean
|
||||
label: 'Compact mode'
|
||||
weight_select_max:
|
||||
type: integer
|
||||
label: 'Weight element maximum value'
|
||||
default_langcode:
|
||||
type: string
|
||||
label: 'Site default language code'
|
||||
mail_notification:
|
||||
type: string
|
||||
label: 'Notification email address'
|
||||
|
||||
system.maintenance:
|
||||
type: config_object
|
||||
label: 'Maintenance mode'
|
||||
mapping:
|
||||
message:
|
||||
type: text
|
||||
label: 'Message to display when in maintenance mode'
|
||||
|
||||
system.authorize:
|
||||
type: config_object
|
||||
label: 'Authorize settings'
|
||||
mapping:
|
||||
filetransfer_default:
|
||||
type: string
|
||||
label: 'Default file transfer protocol'
|
||||
|
||||
system.cron:
|
||||
type: config_object
|
||||
label: 'Cron settings'
|
||||
mapping:
|
||||
threshold:
|
||||
type: mapping
|
||||
label: 'Thresholds'
|
||||
mapping:
|
||||
autorun:
|
||||
type: integer
|
||||
label: 'Run cron every'
|
||||
requirements_warning:
|
||||
type: integer
|
||||
label: 'Requirements warning period'
|
||||
requirements_error:
|
||||
type: integer
|
||||
label: 'Requirements error period'
|
||||
|
||||
system.date:
|
||||
type: config_object
|
||||
label: 'Date settings'
|
||||
mapping:
|
||||
first_day:
|
||||
type: integer
|
||||
label: 'First day of week'
|
||||
country:
|
||||
type: mapping
|
||||
label: 'Country'
|
||||
mapping:
|
||||
default:
|
||||
type: string
|
||||
label: 'Default country'
|
||||
timezone:
|
||||
type: mapping
|
||||
label: 'Time zone settings'
|
||||
mapping:
|
||||
default:
|
||||
type: string
|
||||
label: 'Default time zone'
|
||||
user:
|
||||
type: mapping
|
||||
label: 'User'
|
||||
mapping:
|
||||
configurable:
|
||||
type: boolean
|
||||
label: 'Users may set their own time zone'
|
||||
default:
|
||||
type: integer
|
||||
label: 'Time zone for new users'
|
||||
warn:
|
||||
type: boolean
|
||||
label: 'Remind users at login if their time zone is not set'
|
||||
|
||||
system.diff:
|
||||
type: config_object
|
||||
label: 'Diff settings'
|
||||
mapping:
|
||||
context:
|
||||
type: mapping
|
||||
label: 'Context'
|
||||
mapping:
|
||||
lines_leading:
|
||||
type: integer
|
||||
label: 'Number of leading lines in a diff'
|
||||
lines_trailing:
|
||||
type: integer
|
||||
label: 'Number of trailing lines in a diff'
|
||||
|
||||
system.filter:
|
||||
type: config_object
|
||||
label: 'Filter settings'
|
||||
mapping:
|
||||
protocols:
|
||||
type: sequence
|
||||
label: 'Allowed protocols'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Protocol'
|
||||
|
||||
system.logging:
|
||||
type: config_object
|
||||
label: 'Logging settings'
|
||||
mapping:
|
||||
error_level:
|
||||
type: string
|
||||
label: 'Error messages to display'
|
||||
|
||||
system.performance:
|
||||
type: config_object
|
||||
label: 'Performance settings'
|
||||
mapping:
|
||||
cache:
|
||||
type: mapping
|
||||
label: 'Caching'
|
||||
mapping:
|
||||
page:
|
||||
type: mapping
|
||||
label: 'Page caching'
|
||||
mapping:
|
||||
max_age:
|
||||
type: integer
|
||||
label: 'Max age'
|
||||
css:
|
||||
type: mapping
|
||||
label: 'CSS performance settings'
|
||||
mapping:
|
||||
preprocess:
|
||||
type: boolean
|
||||
label: 'Aggregate CSS files'
|
||||
gzip:
|
||||
type: boolean
|
||||
label: 'Compress CSS files'
|
||||
fast_404:
|
||||
type: mapping
|
||||
label: 'Fast 404 settings'
|
||||
mapping:
|
||||
enabled:
|
||||
type: boolean
|
||||
label: 'Fast 404 enabled'
|
||||
paths:
|
||||
type: string
|
||||
label: 'Regular expression to match'
|
||||
exclude_paths:
|
||||
type: string
|
||||
label: 'Regular expression to not match'
|
||||
html:
|
||||
type: string
|
||||
label: 'Fast 404 page html'
|
||||
js:
|
||||
type: mapping
|
||||
label: 'JavaScript performance settings'
|
||||
mapping:
|
||||
preprocess:
|
||||
type: boolean
|
||||
label: 'JavaScript preprocess'
|
||||
gzip:
|
||||
type: boolean
|
||||
label: 'Compress JavaScript files.'
|
||||
response:
|
||||
type: mapping
|
||||
label: 'Response performance settings'
|
||||
mapping:
|
||||
gzip:
|
||||
type: boolean
|
||||
label: 'Compress cached pages'
|
||||
stale_file_threshold:
|
||||
type: integer
|
||||
label: 'Stale file threshold'
|
||||
|
||||
system.rss:
|
||||
type: config_object
|
||||
label: 'Feed settings'
|
||||
mapping:
|
||||
channel:
|
||||
type: mapping
|
||||
label: 'Feed channel'
|
||||
mapping:
|
||||
description:
|
||||
type: text
|
||||
label: 'Feed description'
|
||||
items:
|
||||
type: mapping
|
||||
label: 'Feed items'
|
||||
mapping:
|
||||
limit:
|
||||
type: integer
|
||||
label: 'Feed item limit'
|
||||
view_mode:
|
||||
type: string
|
||||
label: 'Feed content'
|
||||
|
||||
system.theme:
|
||||
type: config_object
|
||||
label: 'Theme settings'
|
||||
mapping:
|
||||
admin:
|
||||
type: string
|
||||
label: 'Administration theme'
|
||||
default:
|
||||
type: string
|
||||
label: 'Default theme'
|
||||
|
||||
system.menu.*:
|
||||
type: config_entity
|
||||
label: 'Menu'
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'ID'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
description:
|
||||
type: label
|
||||
label: 'Menu description'
|
||||
locked:
|
||||
type: boolean
|
||||
label: ''
|
||||
|
||||
system.action.*:
|
||||
type: config_entity
|
||||
label: 'System action'
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'ID'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
type:
|
||||
type: string
|
||||
label: 'Type'
|
||||
plugin:
|
||||
type: string
|
||||
label: 'Plugin'
|
||||
configuration:
|
||||
type: action.configuration.[%parent.plugin]
|
||||
|
||||
system.file:
|
||||
type: config_object
|
||||
label: 'File system'
|
||||
mapping:
|
||||
allow_insecure_uploads:
|
||||
type: boolean
|
||||
label: 'Allow insecure uploads'
|
||||
default_scheme:
|
||||
type: string
|
||||
label: 'Default download method'
|
||||
path:
|
||||
type: mapping
|
||||
label: 'Path settings'
|
||||
mapping:
|
||||
temporary:
|
||||
type: string
|
||||
label: 'Temporary directory'
|
||||
temporary_maximum_age:
|
||||
type: integer
|
||||
label: 'Maximum age for temporary files'
|
||||
|
||||
system.image:
|
||||
type: config_object
|
||||
label: 'Image settings'
|
||||
mapping:
|
||||
toolkit:
|
||||
type: string
|
||||
label: 'Toolkit'
|
||||
|
||||
system.image.gd:
|
||||
type: config_object
|
||||
label: 'Image settings'
|
||||
mapping:
|
||||
jpeg_quality:
|
||||
type: integer
|
||||
label: 'JPEG quality'
|
||||
|
||||
system.mail:
|
||||
type: config_object
|
||||
label: 'Mail system'
|
||||
mapping:
|
||||
interface:
|
||||
type: sequence
|
||||
label: 'Interfaces'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Interface'
|
||||
|
||||
system.theme.global:
|
||||
type: theme_settings
|
||||
label: 'Theme global settings'
|
||||
|
||||
block.settings.system_branding_block:
|
||||
type: block_settings
|
||||
label: 'Branding block'
|
||||
mapping:
|
||||
use_site_logo:
|
||||
type: boolean
|
||||
label: 'Use site logo'
|
||||
use_site_name:
|
||||
type: boolean
|
||||
label: 'Use site name'
|
||||
use_site_slogan:
|
||||
type: boolean
|
||||
label: 'Use site slogan'
|
||||
|
||||
block.settings.system_menu_block:*:
|
||||
type: block_settings
|
||||
label: 'Menu block'
|
||||
mapping:
|
||||
level:
|
||||
type: integer
|
||||
label: 'Starting level'
|
||||
depth:
|
||||
type: integer
|
||||
label: 'Maximum number of levels'
|
||||
|
||||
condition.plugin.request_path:
|
||||
type: condition.plugin
|
||||
mapping:
|
||||
pages:
|
||||
type: string
|
370
core/modules/system/css/system.admin.css
Normal file
370
core/modules/system/css/system.admin.css
Normal file
|
@ -0,0 +1,370 @@
|
|||
/**
|
||||
* @file
|
||||
* Styles for administration pages.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reusable layout styles.
|
||||
*/
|
||||
.layout-container {
|
||||
margin: 0 1.5em;
|
||||
}
|
||||
.layout-container:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 38em) {
|
||||
.layout-container {
|
||||
margin: 0 2.5em;
|
||||
}
|
||||
.layout-column {
|
||||
float: left; /* LTR */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
[dir="rtl"] .layout-column {
|
||||
float: right;
|
||||
}
|
||||
.layout-column + .layout-column {
|
||||
padding-left: 10px; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .layout-column + .layout-column {
|
||||
padding-right: 10px;
|
||||
padding-left: 0;
|
||||
}
|
||||
.layout-column.half {
|
||||
width: 50%;
|
||||
}
|
||||
.layout-column.quarter {
|
||||
width: 25%;
|
||||
}
|
||||
.layout-column.three-quarter {
|
||||
width: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Panel.
|
||||
* Used to visually group items together.
|
||||
*/
|
||||
.panel {
|
||||
padding: 5px 5px 15px;
|
||||
}
|
||||
.panel__description {
|
||||
margin: 0 0 3px;
|
||||
padding: 2px 0 3px 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* System compact link: to toggle the display of description text.
|
||||
*/
|
||||
.compact-link {
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick inline admin links.
|
||||
*/
|
||||
small .admin-link:before {
|
||||
content: ' [';
|
||||
}
|
||||
small .admin-link:after {
|
||||
content: ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Modules page.
|
||||
*/
|
||||
.system-modules thead > tr {
|
||||
border: 0;
|
||||
}
|
||||
.system-modules div.incompatible {
|
||||
font-weight: bold;
|
||||
}
|
||||
.system-modules td.checkbox {
|
||||
min-width: 25px;
|
||||
width: 4%;
|
||||
}
|
||||
.system-modules td.module {
|
||||
width: 25%;
|
||||
}
|
||||
.system-modules td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.system-modules label,
|
||||
.system-modules-uninstall label {
|
||||
color: #1d1d1d;
|
||||
font-size: 1.15em;
|
||||
}
|
||||
.system-modules details {
|
||||
color: #5c5c5b;
|
||||
line-height: 20px;
|
||||
overflow: hidden; /* truncates descriptions if too long */
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.system-modules details[open] {
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
white-space: normal;
|
||||
}
|
||||
.system-modules details[open] summary .text {
|
||||
-webkit-hyphens: auto;
|
||||
-moz-hyphens: auto;
|
||||
-ms-hyphens: auto;
|
||||
hyphens: auto;
|
||||
text-transform: none;
|
||||
}
|
||||
.system-modules td details a {
|
||||
color: #5C5C5B;
|
||||
border: 0px;
|
||||
}
|
||||
.system-modules td details {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
height: 20px;
|
||||
}
|
||||
.system-modules td details summary {
|
||||
padding: 0;
|
||||
text-transform: none;
|
||||
font-weight: normal;
|
||||
cursor: default;
|
||||
}
|
||||
.system-modules td {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 40em) {
|
||||
.system-modules td.name {
|
||||
width: 20%;
|
||||
}
|
||||
.system-modules td.description {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
.system-modules .requirements {
|
||||
padding: 5px 0;
|
||||
max-width: 490px;
|
||||
}
|
||||
.system-modules .links {
|
||||
overflow: hidden; /* prevents collapse */
|
||||
}
|
||||
.system-modules .checkbox {
|
||||
margin: 0 5px;
|
||||
}
|
||||
.system-modules .checkbox .form-item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.admin-requirements,
|
||||
.admin-required {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
}
|
||||
.admin-enabled {
|
||||
color: #080;
|
||||
}
|
||||
.admin-missing {
|
||||
color: #f00;
|
||||
}
|
||||
.module-link {
|
||||
display: block;
|
||||
padding: 2px 20px;
|
||||
white-space: nowrap;
|
||||
margin-top: 2px;
|
||||
float: left; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .module-link {
|
||||
float: right;
|
||||
}
|
||||
.module-link-help {
|
||||
background: url(../../../misc/icons/787878/questionmark-disc.svg) 0 50% no-repeat;
|
||||
}
|
||||
.module-link-permissions {
|
||||
background: url(../../../misc/icons/787878/key.svg) 0 50% no-repeat;
|
||||
}
|
||||
.module-link-configure {
|
||||
background: url(../../../misc/icons/787878/cog.svg) 0 50% no-repeat;
|
||||
}
|
||||
|
||||
/* Status report. */
|
||||
.system-status-report td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.system-status-report__status-icon {
|
||||
width: 16px;
|
||||
padding-right: 0; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .system-status-report__status-icon {
|
||||
padding-left: 0;
|
||||
padding-right: 6px;
|
||||
}
|
||||
.system-status-report__status-icon:before {
|
||||
content: "";
|
||||
background-repeat: no-repeat;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-top: 2px;
|
||||
display: block;
|
||||
}
|
||||
.system-status-report__status-icon--error:before {
|
||||
background-image: url(../../../misc/icons/ea2800/error.svg);
|
||||
}
|
||||
.system-status-report__status-icon--warning:before {
|
||||
background-image: url(../../../misc/icons/e29700/warning.svg);
|
||||
}
|
||||
.system-status-report__status-title {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appearance page.
|
||||
*/
|
||||
.theme-info__header {
|
||||
margin-bottom: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
.theme-default .theme-info__header {
|
||||
font-weight: bold;
|
||||
}
|
||||
.theme-info__description {
|
||||
margin-top: 0;
|
||||
}
|
||||
.system-themes-list {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.system-themes-list-uninstalled {
|
||||
border-top: 1px solid #cdcdcd;
|
||||
padding-top: 20px;
|
||||
}
|
||||
.system-themes-list__header {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.theme-selector {
|
||||
padding-top: 20px;
|
||||
}
|
||||
.theme-selector .screenshot,
|
||||
.theme-selector .no-screenshot {
|
||||
border: 1px solid #e0e0d8;
|
||||
padding: 2px;
|
||||
vertical-align: bottom;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
text-align: center;
|
||||
}
|
||||
.theme-default .screenshot {
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
.system-themes-list-uninstalled .screenshot,
|
||||
.system-themes-list-uninstalled .no-screenshot {
|
||||
max-width: 194px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme display without vertical toolbar.
|
||||
*/
|
||||
@media screen and (min-width: 45em) {
|
||||
body:not(.toolbar-vertical) .system-themes-list-installed .screenshot,
|
||||
body:not(.toolbar-vertical) .system-themes-list-installed .no-screenshot {
|
||||
float: left; /* LTR */
|
||||
margin: 0 20px 0 0; /* LTR */
|
||||
width: 294px;
|
||||
}
|
||||
[dir="rtl"] body:not(.toolbar-vertical) .system-themes-list-installed .screenshot,
|
||||
[dir="rtl"] body:not(.toolbar-vertical) .system-themes-list-installed .no-screenshot {
|
||||
float: right;
|
||||
margin: 0 0 0 20px;
|
||||
}
|
||||
body:not(.toolbar-vertical) .system-themes-list-installed .system-themes-list__header {
|
||||
margin-top: 0;
|
||||
}
|
||||
body:not(.toolbar-vertical) .system-themes-list-uninstalled .theme-selector {
|
||||
box-sizing: border-box;
|
||||
width: 31.25%;
|
||||
float: left; /* LTR */
|
||||
padding: 20px 20px 20px 0; /* LTR */
|
||||
}
|
||||
[dir="rtl"] body:not(.toolbar-vertical) .system-themes-list-uninstalled .theme-selector {
|
||||
float: right;
|
||||
padding: 20px 0 20px 20px;
|
||||
}
|
||||
body:not(.toolbar-vertical) .system-themes-list-uninstalled .theme-info {
|
||||
min-height: 170px;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme display with vertical toolbar.
|
||||
*/
|
||||
@media screen and (min-width: 60em) {
|
||||
.toolbar-vertical .system-themes-list-installed .screenshot,
|
||||
.toolbar-vertical .system-themes-list-installed .no-screenshot {
|
||||
float: left; /* LTR */
|
||||
margin: 0 20px 0 0; /* LTR */
|
||||
width: 294px;
|
||||
}
|
||||
[dir="rtl"] .toolbar-vertical .system-themes-list-installed .screenshot,
|
||||
[dir="rtl"] .toolbar-vertical .system-themes-list-installed .no-screenshot {
|
||||
float: right;
|
||||
margin: 0 0 0 20px;
|
||||
}
|
||||
.toolbar-vertical .system-themes-list-installed .theme-info__header {
|
||||
margin-top: 0;
|
||||
}
|
||||
.toolbar-vertical .system-themes-list-uninstalled .theme-selector {
|
||||
box-sizing: border-box;
|
||||
width: 31.25%;
|
||||
float: left; /* LTR */
|
||||
padding: 20px 20px 20px 0; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .toolbar-vertical .system-themes-list-uninstalled .theme-selector {
|
||||
float: right;
|
||||
padding: 20px 0 20px 20px;
|
||||
}
|
||||
.toolbar-vertical .system-themes-list-uninstalled .theme-info {
|
||||
min-height: 170px;
|
||||
}
|
||||
}
|
||||
.system-themes-list-installed .theme-info {
|
||||
max-width: 940px;
|
||||
}
|
||||
|
||||
.theme-selector .incompatible {
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.theme-selector .operations {
|
||||
margin: 10px 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
.theme-selector .operations li {
|
||||
float: left; /* LTR */
|
||||
margin: 0;
|
||||
padding: 0 0.7em;
|
||||
list-style-type: none;
|
||||
border-right: 1px solid #cdcdcd; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .theme-selector .operations li {
|
||||
float: right;
|
||||
border-left: 1px solid #cdcdcd;
|
||||
border-right: none;
|
||||
}
|
||||
.theme-selector .operations li:last-child {
|
||||
padding: 0 0 0 0.7em; /* LTR */
|
||||
border-right: none; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .theme-selector .operations li:last-child {
|
||||
padding: 0 0.7em 0 0;
|
||||
border-left: none;
|
||||
}
|
||||
.theme-selector .operations li:first-child {
|
||||
padding: 0 0.7em 0 0; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .theme-selector .operations li:first-child {
|
||||
padding: 0 0 0 0.7em;
|
||||
}
|
||||
.system-themes-admin-form {
|
||||
clear: left;
|
||||
}
|
100
core/modules/system/css/system.diff.css
Normal file
100
core/modules/system/css/system.diff.css
Normal file
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* Inline diff metadata
|
||||
*/
|
||||
.diff-inline-metadata {
|
||||
padding:4px;
|
||||
border:1px solid #ddd;
|
||||
background:#fff;
|
||||
margin:0 0 10px;
|
||||
}
|
||||
|
||||
.diff-inline-legend {
|
||||
font-size:11px;
|
||||
}
|
||||
|
||||
.diff-inline-legend span,
|
||||
.diff-inline-legend label {
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline diff markup
|
||||
*/
|
||||
span.diff-deleted {
|
||||
color:#ccc;
|
||||
}
|
||||
span.diff-deleted img {
|
||||
border: solid 2px #ccc;
|
||||
}
|
||||
span.diff-changed {
|
||||
background:#ffb;
|
||||
}
|
||||
span.diff-changed img {
|
||||
border:solid 2px #ffb;
|
||||
}
|
||||
span.diff-added {
|
||||
background:#cfc;
|
||||
}
|
||||
span.diff-added img {
|
||||
border: solid 2px #cfc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traditional split diff theming
|
||||
*/
|
||||
table.diff {
|
||||
border-spacing: 4px;
|
||||
margin-bottom: 20px;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
table.diff .even, table.diff .odd {
|
||||
background-color: inherit;
|
||||
border: none;
|
||||
}
|
||||
table.diff .diff-prevlink {
|
||||
text-align: left;
|
||||
}
|
||||
table.diff .diff-nextlink {
|
||||
text-align: right;
|
||||
}
|
||||
table.diff .diff-section-title,
|
||||
table.diff .diff-section-title {
|
||||
background-color: #f0f0ff;
|
||||
font-size: 0.83em;
|
||||
font-weight: bold;
|
||||
padding: 0.1em 1em;
|
||||
}
|
||||
table.diff .diff-context {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
table.diff .diff-deletedline {
|
||||
background-color: #ffa;
|
||||
width: 50%;
|
||||
}
|
||||
table.diff .diff-addedline {
|
||||
background-color: #afa;
|
||||
width: 50%;
|
||||
}
|
||||
table.diff .diffchange {
|
||||
color: #f00;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.diff .diff-marker {
|
||||
width: 1.4em;
|
||||
}
|
||||
table.diff .diff-content {
|
||||
width: 50%;
|
||||
}
|
||||
table.diff th {
|
||||
padding-right: inherit;
|
||||
}
|
||||
table.diff td div {
|
||||
overflow: auto;
|
||||
padding: 0.1ex 0.5em;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
table.diff td {
|
||||
padding: 0.1ex 0.4em;
|
||||
}
|
52
core/modules/system/css/system.maintenance.css
Normal file
52
core/modules/system/css/system.maintenance.css
Normal file
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* Update styles
|
||||
*/
|
||||
.update-results {
|
||||
margin-top: 3em;
|
||||
padding: 0.25em;
|
||||
border: 1px solid #ccc;
|
||||
background: #eee;
|
||||
font-size: smaller;
|
||||
}
|
||||
.update-results h2 {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
.update-results h4 {
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
.update-results .none {
|
||||
color: #888;
|
||||
font-style: italic;
|
||||
}
|
||||
.update-results .failure strong {
|
||||
color: #b63300;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize.php styles
|
||||
*/
|
||||
#edit-submit-connection {
|
||||
clear: both;
|
||||
}
|
||||
#edit-submit-process,
|
||||
.filetransfer {
|
||||
display: none;
|
||||
clear: both;
|
||||
}
|
||||
.js #edit-submit-connection {
|
||||
display: none;
|
||||
}
|
||||
.js #edit-submit-process {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#edit-connection-settings-change-connection-type {
|
||||
margin: 2.6em 0.5em 0 1em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Theme maintenance styles
|
||||
*/
|
||||
.authorize-results__failure {
|
||||
font-weight: bold;
|
||||
}
|
448
core/modules/system/css/system.module.css
Normal file
448
core/modules/system/css/system.module.css
Normal file
|
@ -0,0 +1,448 @@
|
|||
/**
|
||||
* @file
|
||||
* Generic theme-independent base styles.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Autocomplete.
|
||||
*
|
||||
* @see autocomplete.js
|
||||
*/
|
||||
|
||||
/* Animated throbber */
|
||||
.js input.form-autocomplete {
|
||||
background-image: url(../../../misc/throbber-inactive.png);
|
||||
background-position: 100% center; /* LTR */
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.js[dir="rtl"] input.form-autocomplete {
|
||||
background-position: 0% center;
|
||||
}
|
||||
.js input.form-autocomplete.ui-autocomplete-loading {
|
||||
background-image: url(../../../misc/throbber-active.gif);
|
||||
background-position: 100% center; /* LTR */
|
||||
}
|
||||
.js[dir="rtl"] input.form-autocomplete.ui-autocomplete-loading {
|
||||
background-position: 0% center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unboxed fieldsets for grouping form elements.
|
||||
*/
|
||||
.fieldgroup {
|
||||
border-width: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsible details.
|
||||
*
|
||||
* @see collapse.js
|
||||
*/
|
||||
.js details:not([open]) .details-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizable textareas.
|
||||
*/
|
||||
.form-textarea-wrapper textarea {
|
||||
display: block;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.resize-none {
|
||||
resize: none;
|
||||
}
|
||||
.resize-vertical {
|
||||
resize: vertical;
|
||||
min-height: 2em;
|
||||
}
|
||||
.resize-horizontal {
|
||||
resize: horizontal;
|
||||
max-width: 100%;
|
||||
}
|
||||
.resize-both {
|
||||
resize: both;
|
||||
max-width: 100%;
|
||||
min-height: 2em;
|
||||
}
|
||||
|
||||
/**
|
||||
* TableDrag behavior.
|
||||
*
|
||||
* @see tabledrag.js
|
||||
*/
|
||||
body.drag {
|
||||
cursor: move;
|
||||
}
|
||||
tr.region-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
tr.region-message {
|
||||
color: #999;
|
||||
}
|
||||
tr.region-populated {
|
||||
display: none;
|
||||
}
|
||||
tr.add-new .tabledrag-changed {
|
||||
display: none;
|
||||
}
|
||||
.draggable a.tabledrag-handle {
|
||||
cursor: move;
|
||||
float: left; /* LTR */
|
||||
height: 1.7em;
|
||||
margin-left: -1em; /* LTR */
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
[dir="rtl"] .draggable a.tabledrag-handle {
|
||||
float: right;
|
||||
margin-right: -1em;
|
||||
margin-left: 0;
|
||||
}
|
||||
a.tabledrag-handle:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
a.tabledrag-handle .handle {
|
||||
background: url(../../../misc/icons/787878/move.svg) no-repeat 6px 7px;
|
||||
height: 14px;
|
||||
margin: -0.4em 0.5em 0;
|
||||
padding: 0.42em 0.5em;
|
||||
width: 14px;
|
||||
}
|
||||
a.tabledrag-handle:hover .handle,
|
||||
a.tabledrag-handle:focus .handle {
|
||||
background-image: url(../../../misc/icons/000000/move.svg);
|
||||
}
|
||||
.touch .draggable td {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.touch .draggable .menu-item__link {
|
||||
display: inline-block;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.touch a.tabledrag-handle {
|
||||
height: 44px;
|
||||
width: 40px;
|
||||
}
|
||||
.touch a.tabledrag-handle .handle {
|
||||
background-position: 40% 19px;
|
||||
height: 21px;
|
||||
}
|
||||
.touch .draggable.drag a.tabledrag-handle .handle {
|
||||
background-position: 50% -32px;
|
||||
}
|
||||
.indentation {
|
||||
float: left; /* LTR */
|
||||
height: 1.7em;
|
||||
margin: -0.4em 0.2em -0.4em -0.4em; /* LTR */
|
||||
padding: 0.42em 0 0.42em 0.6em; /* LTR */
|
||||
width: 20px;
|
||||
}
|
||||
[dir="rtl"] .indentation {
|
||||
float: right;
|
||||
margin: -0.4em -0.4em -0.4em 0.2em;
|
||||
padding: 0.42em 0.6em 0.42em 0;
|
||||
}
|
||||
div.tree-child {
|
||||
background: url(../../../misc/tree.png) no-repeat 11px center; /* LTR */
|
||||
}
|
||||
div.tree-child-last {
|
||||
background: url(../../../misc/tree-bottom.png) no-repeat 11px center; /* LTR */
|
||||
}
|
||||
[dir="rtl"] div.tree-child,
|
||||
[dir="rtl"] div.tree-child-last {
|
||||
background-position: -65px center;
|
||||
}
|
||||
div.tree-child-horizontal {
|
||||
background: url(../../../misc/tree.png) no-repeat -11px center;
|
||||
}
|
||||
.tabledrag-toggle-weight-wrapper {
|
||||
text-align: right; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .tabledrag-toggle-weight-wrapper {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/**
|
||||
* TableHeader behavior.
|
||||
*
|
||||
* @see tableheader.js
|
||||
*/
|
||||
table.sticky-header {
|
||||
background-color: #fff;
|
||||
margin-top: 0;
|
||||
z-index: 500;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress behavior.
|
||||
*
|
||||
* @see progress.js
|
||||
*/
|
||||
.progress {
|
||||
position: relative;
|
||||
}
|
||||
.progress__track {
|
||||
background-color: #fff;
|
||||
border: 1px solid;
|
||||
margin-top: 5px;
|
||||
max-width: 100%;
|
||||
min-width: 100px;
|
||||
height: 16px;
|
||||
}
|
||||
.progress__bar {
|
||||
background-color: #000;
|
||||
height: 1.5em;
|
||||
min-width: 3%;
|
||||
max-width: 100%;
|
||||
}
|
||||
.progress__description,
|
||||
.progress__percentage {
|
||||
color: #555;
|
||||
overflow: hidden;
|
||||
font-size: .875em;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
.progress__description {
|
||||
float: left; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .progress__description {
|
||||
float: right;
|
||||
}
|
||||
.progress__percentage {
|
||||
float: right; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .progress__percentage {
|
||||
float: left;
|
||||
}
|
||||
.progress--small .progress__track {
|
||||
height: 7px;
|
||||
}
|
||||
.progress--small .progress__bar {
|
||||
height: 7px;
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
|
||||
/* Throbber */
|
||||
.ajax-progress {
|
||||
display: inline-block;
|
||||
padding: 1px 5px 2px 5px;
|
||||
}
|
||||
[dir="rtl"] .ajax-progress {
|
||||
float: right;
|
||||
}
|
||||
.ajax-progress-throbber .throbber {
|
||||
background: transparent url(../../../misc/throbber-active.gif) no-repeat 0px center;
|
||||
display: inline;
|
||||
padding: 1px 5px 2px;
|
||||
}
|
||||
.ajax-progress-throbber .message {
|
||||
display: inline;
|
||||
padding: 1px 5px 2px;
|
||||
}
|
||||
tr .ajax-progress-throbber .throbber {
|
||||
margin: 0 2px;
|
||||
}
|
||||
.ajax-progress-bar {
|
||||
width: 16em;
|
||||
}
|
||||
|
||||
/* Full screen throbber */
|
||||
.ajax-progress-fullscreen {
|
||||
/* Can't do center:50% middle: 50%, so approximate it for a typical window size. */
|
||||
left: 49%;
|
||||
position: fixed;
|
||||
top: 48.5%;
|
||||
z-index: 1000;
|
||||
background-color: #232323;
|
||||
background-image: url("../../../misc/loading-small.gif");
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 7px;
|
||||
height: 24px;
|
||||
opacity: 0.9;
|
||||
padding: 4px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline items.
|
||||
*/
|
||||
.container-inline div,
|
||||
.container-inline label {
|
||||
display: inline;
|
||||
}
|
||||
/* Details contents always need to be rendered as block. */
|
||||
.container-inline .details-wrapper {
|
||||
display: block;
|
||||
}
|
||||
/* Display form elements horizontally. */
|
||||
.form--inline .form-item {
|
||||
float: left; /* LTR */
|
||||
margin-right: 0.5em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .form--inline .form-item {
|
||||
float: right;
|
||||
margin-right: 0;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.form--inline .form-item-separator {
|
||||
margin-top: 2.3em;
|
||||
margin-right: 1em; /* LTR */
|
||||
margin-left: 0.5em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .form--inline .form-item-separator {
|
||||
margin-right: 0.5em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.form--inline .form-actions {
|
||||
clear: left; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .form--inline .form-actions {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prevent text wrapping.
|
||||
*/
|
||||
.nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* For anything you want to hide on page load when JS is enabled, so
|
||||
* that you can use the JS to control visibility and avoid flicker.
|
||||
*/
|
||||
.js .js-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* For anything you want to show on page load only when JS is enabled.
|
||||
*/
|
||||
.js-show {
|
||||
display: none;
|
||||
}
|
||||
.js .js-show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide elements from all users.
|
||||
*
|
||||
* Used for elements which should not be immediately displayed to any user. An
|
||||
* example would be collapsible details that will be expanded with a click
|
||||
* from a user. The effect of this class can be toggled with the jQuery show()
|
||||
* and hide() functions.
|
||||
*/
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide elements visually, but keep them available for screen readers.
|
||||
*
|
||||
* Used for information required for screen reader users to understand and use
|
||||
* the site where visual display is undesirable. Information provided in this
|
||||
* manner should be kept concise, to avoid unnecessary burden on the user.
|
||||
* "!important" is used to prevent unintentional overrides.
|
||||
*/
|
||||
.visually-hidden {
|
||||
position: absolute !important;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
overflow: hidden;
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* The .focusable class extends the .visually-hidden class to allow
|
||||
* the element to be focusable when navigated to via the keyboard.
|
||||
*/
|
||||
.visually-hidden.focusable:active,
|
||||
.visually-hidden.focusable:focus {
|
||||
position: static !important;
|
||||
clip: auto;
|
||||
overflow: visible;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide visually and from screen readers, but maintain layout.
|
||||
*/
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Float clearing.
|
||||
*
|
||||
* Based on the micro clearfix hack by Nicolas Gallagher, with the :before
|
||||
* pseudo selector removed to allow normal top margin collapse.
|
||||
*
|
||||
* @see http://nicolasgallagher.com/micro-clearfix-hack
|
||||
*/
|
||||
.clearfix:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text alignment classes.
|
||||
*/
|
||||
.text-align-left {
|
||||
text-align: left;
|
||||
}
|
||||
.text-align-right {
|
||||
text-align: right;
|
||||
}
|
||||
.text-align-center {
|
||||
text-align: center;
|
||||
}
|
||||
.text-align-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alignment classes (images, videos, blockquotes …).
|
||||
*/
|
||||
.align-left {
|
||||
float: left;
|
||||
}
|
||||
.align-right {
|
||||
float: right;
|
||||
}
|
||||
.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove browser styles, especially for <buttons> and so on.
|
||||
*/
|
||||
.reset-appearance {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
border: 0 none;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Contain positioned elements.
|
||||
*/
|
||||
.position-container {
|
||||
position: relative;
|
||||
}
|
603
core/modules/system/css/system.theme.css
Normal file
603
core/modules/system/css/system.theme.css
Normal file
|
@ -0,0 +1,603 @@
|
|||
/**
|
||||
* @file
|
||||
* Basic styling for common markup.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Publishing status.
|
||||
*/
|
||||
.node--unpublished {
|
||||
background-color: #fff4f4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by tablesort-indicator.html.twig.
|
||||
*/
|
||||
th.is-active img {
|
||||
display: inline;
|
||||
}
|
||||
td.is-active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by item-list.html.twig.
|
||||
*/
|
||||
.item-list .title {
|
||||
font-weight: bold;
|
||||
}
|
||||
.item-list ul {
|
||||
margin: 0 0 0.75em 0;
|
||||
padding: 0;
|
||||
}
|
||||
.item-list ul li {
|
||||
margin: 0 0 0.25em 1.5em; /* LTR */
|
||||
padding: 0;
|
||||
}
|
||||
[dir="rtl"] .item-list ul li {
|
||||
margin: 0 1.5em 0.25em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by Form API.
|
||||
*/
|
||||
.form-item,
|
||||
.form-actions {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
tr.odd .form-item,
|
||||
tr.even .form-item {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.form-composite > .fieldset-wrapper > .description,
|
||||
.form-item .description {
|
||||
font-size: 0.85em;
|
||||
}
|
||||
label.option {
|
||||
display: inline;
|
||||
font-weight: normal;
|
||||
}
|
||||
.form-composite > legend,
|
||||
.label {
|
||||
display:inline;
|
||||
font-size: inherit;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.form-checkboxes .form-item,
|
||||
.form-radios .form-item {
|
||||
margin-top: 0.4em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
.form-type-radio .description,
|
||||
.form-type-checkbox .description {
|
||||
margin-left: 2.4em;
|
||||
}
|
||||
.marker {
|
||||
color: #e00;
|
||||
}
|
||||
|
||||
.form-required:after {
|
||||
content: '';
|
||||
vertical-align: super;
|
||||
display: inline-block;
|
||||
/* Use a background image to prevent screen readers from announcing the text. */
|
||||
background-image: url(../../../misc/icons/ee0000/required.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 6px 6px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin: 0 0.3em;
|
||||
}
|
||||
|
||||
abbr.tabledrag-changed,
|
||||
abbr.ajax-changed {
|
||||
border-bottom: none;
|
||||
}
|
||||
.form-item input.error,
|
||||
.form-item textarea.error,
|
||||
.form-item select.error {
|
||||
border: 2px solid red;
|
||||
}
|
||||
.button,
|
||||
.image-button {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.button:first-child,
|
||||
.image-button:first-child {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* Inline error messages. */
|
||||
.form-error-message:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
vertical-align: sub;
|
||||
background: url(../../../misc/icons/ea2800/error.svg) no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline items.
|
||||
*/
|
||||
.container-inline label:after,
|
||||
.container-inline .label:after {
|
||||
content: ':';
|
||||
}
|
||||
.form-type-radios .container-inline label:after {
|
||||
content: '';
|
||||
}
|
||||
.form-type-radios .container-inline .form-type-radio {
|
||||
margin: 0 1em;
|
||||
}
|
||||
.container-inline .form-actions,
|
||||
.container-inline.form-actions {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by #type 'more_link'.
|
||||
*/
|
||||
.more-link {
|
||||
display: block;
|
||||
text-align: right; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .more-link {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Style for the help icon. */
|
||||
.icon-help {
|
||||
background: url(../../../misc/help.png) 0 50% no-repeat; /* LTR */
|
||||
padding: 1px 0 1px 20px; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .icon-help {
|
||||
background-position: 100% 50%;
|
||||
padding: 1px 20px 1px 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by pager.html.twig.
|
||||
*/
|
||||
.pager__items {
|
||||
clear: both;
|
||||
text-align: center;
|
||||
}
|
||||
.pager__item {
|
||||
display: inline;
|
||||
padding: 0.5em;
|
||||
}
|
||||
.pager__item.is-active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show buttons as links.
|
||||
*/
|
||||
button.link {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
label button.link {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapsible details.
|
||||
*
|
||||
* @see collapse.js
|
||||
* @thanks http://nicolasgallagher.com/css-background-image-hacks/
|
||||
*/
|
||||
details {
|
||||
border: 1px solid #ccc;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
details > .details-wrapper {
|
||||
padding: 0.5em 1.5em;
|
||||
}
|
||||
/* @todo Regression: The summary of uncollapsible details are no longer
|
||||
vertically aligned with the .details-wrapper in browsers without native
|
||||
details support. */
|
||||
summary {
|
||||
cursor: pointer;
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
.collapse-processed > summary {
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
.collapse-processed > summary:before {
|
||||
background: url(../../../misc/menu-expanded.png) 0px 100% no-repeat; /* LTR */
|
||||
content: "";
|
||||
float: left;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
}
|
||||
[dir="rtl"] .collapse-processed > summary:before {
|
||||
background-position: 100% 100%;
|
||||
float: right;
|
||||
}
|
||||
.collapse-processed:not([open]) > summary:before {
|
||||
background-position: 25% 35%; /* LTR */
|
||||
-ms-transform: rotate(-90deg);
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
[dir="rtl"] .collapse-processed:not([open]) > summary:before {
|
||||
background-position: 75% 35%;
|
||||
-ms-transform: rotate(90deg);
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/**
|
||||
* TableDrag behavior.
|
||||
*
|
||||
* @see tabledrag.js
|
||||
*/
|
||||
tr.drag {
|
||||
background-color: #fffff0;
|
||||
}
|
||||
tr.drag-previous {
|
||||
background-color: #ffd;
|
||||
}
|
||||
body div.tabledrag-changed-warning {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/**
|
||||
* TableSelect behavior.
|
||||
*
|
||||
* @see tableselect.js
|
||||
*/
|
||||
tr.selected td {
|
||||
background: #ffc;
|
||||
}
|
||||
td.checkbox,
|
||||
th.checkbox {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress bar.
|
||||
*
|
||||
* @see progress.js
|
||||
*/
|
||||
.progress__track {
|
||||
border-color: #b3b3b3;
|
||||
border-radius: 10em;
|
||||
background-color: #f2f1eb;
|
||||
background-image: -webkit-linear-gradient(#e7e7df, #f0f0f0);
|
||||
background-image: linear-gradient(#e7e7df, #f0f0f0);
|
||||
box-shadow: inset 0 1px 3px hsla(0, 0%, 0%, 0.16);
|
||||
}
|
||||
.progress__bar {
|
||||
border: 1px #07629a solid;
|
||||
background: #057ec9;
|
||||
background-image:
|
||||
-webkit-linear-gradient( top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15) ),
|
||||
-webkit-linear-gradient( left top,
|
||||
#0094f0 0%,
|
||||
#0094f0 25%,
|
||||
#007ecc 25%,
|
||||
#007ecc 50%,
|
||||
#0094f0 50%,
|
||||
#0094f0 75%,
|
||||
#0094f0 100% );
|
||||
background-image:
|
||||
-webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)), -webkit-linear-gradient(left top, #0094f0 0%, #0094f0 25%, #007ecc 25%, #007ecc 50%, #0094f0 50%, #0094f0 75%, #0094f0 100%);
|
||||
background-image:
|
||||
linear-gradient( to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15) ),
|
||||
linear-gradient( to right bottom,
|
||||
#0094f0 0%,
|
||||
#0094f0 25%,
|
||||
#007ecc 25%,
|
||||
#007ecc 50%,
|
||||
#0094f0 50%,
|
||||
#0094f0 75%,
|
||||
#0094f0 100% );
|
||||
background-size: 40px 40px;
|
||||
margin-top: -1px;
|
||||
margin-left: -1px;
|
||||
padding: 0 1px;
|
||||
width: 3%;
|
||||
height: 16px;
|
||||
border-radius: 10em;
|
||||
-webkit-animation: animate-stripes 3s linear infinite;
|
||||
-moz-animation: animate-stripes 3s linear infinite;
|
||||
-webkit-transition: width 0.5s ease-out;
|
||||
transition: width 0.5s ease-out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress bar animations.
|
||||
*/
|
||||
@-webkit-keyframes animate-stripes {
|
||||
0% {background-position: 0 0, 0 0;} 100% {background-position: 0 0, -80px 0;}
|
||||
}
|
||||
@-ms-keyframes animate-stripes {
|
||||
0% {background-position: 0 0, 0 0;} 100% {background-position: 0 0, -80px 0;}
|
||||
}
|
||||
@keyframes animate-stripes {
|
||||
0% {background-position: 0 0, 0 0;} 100% {background-position: 0 0, -80px 0;}
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by menu.html.twig.
|
||||
*/
|
||||
ul.menu {
|
||||
list-style: none outside;
|
||||
margin-left: 1em; /* LTR */
|
||||
padding: 0;
|
||||
text-align: left; /* LTR */
|
||||
}
|
||||
[dir="rtl"] ul.menu {
|
||||
margin-left: 0;
|
||||
margin-right: 1em;
|
||||
text-align: right;
|
||||
}
|
||||
.menu-item--expanded {
|
||||
list-style-image: url(../../../misc/menu-expanded.png);
|
||||
list-style-type: circle;
|
||||
}
|
||||
.menu-item--collapsed {
|
||||
list-style-image: url(../../../misc/menu-collapsed.png); /* LTR */
|
||||
list-style-type: disc;
|
||||
}
|
||||
[dir="rtl"] .menu-item--collapsed {
|
||||
list-style-image: url(../../../misc/menu-collapsed-rtl.png);
|
||||
}
|
||||
.menu-item {
|
||||
padding-top: 0.2em;
|
||||
margin: 0;
|
||||
}
|
||||
ul.menu a.is-active {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by links.html.twig.
|
||||
*/
|
||||
ul.inline,
|
||||
ul.links.inline {
|
||||
display: inline;
|
||||
padding-left: 0;
|
||||
}
|
||||
ul.inline li {
|
||||
display: inline;
|
||||
list-style-type: none;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
ul.links a.is-active {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by breadcrumb.html.twig.
|
||||
*/
|
||||
.breadcrumb {
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
.breadcrumb ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
[dir="rtl"] .breadcrumb ol {
|
||||
/* This is required to win over specifity of [dir="rtl"] ol */
|
||||
margin-right: 0;
|
||||
}
|
||||
.breadcrumb li {
|
||||
display: inline;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
/* IE8 does not support :not() and :last-child. */
|
||||
.breadcrumb li:before {
|
||||
content: ' \BB ';
|
||||
}
|
||||
.breadcrumb li:first-child:before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Markup generated by menu-local-tasks.html.twig.
|
||||
*/
|
||||
div.tabs {
|
||||
margin: 1em 0;
|
||||
}
|
||||
ul.tabs {
|
||||
list-style: none;
|
||||
margin: 0 0 0.5em;
|
||||
padding: 0;
|
||||
}
|
||||
.tabs > li {
|
||||
display: inline-block;
|
||||
margin-right: 0.3em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .tabs > li {
|
||||
margin-left: 0.3em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.tabs a {
|
||||
display: block;
|
||||
padding: 0.2em 1em;
|
||||
text-decoration: none;
|
||||
}
|
||||
.tabs a.is-active {
|
||||
background-color: #eee;
|
||||
}
|
||||
.tabs a:focus,
|
||||
.tabs a:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Styles for link buttons and action links.
|
||||
*/
|
||||
.action-links {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 1em 0;
|
||||
}
|
||||
[dir="rtl"] .action-links {
|
||||
/* This is required to win over specifity of [dir="rtl"] ul */
|
||||
margin-right: 0;
|
||||
}
|
||||
.action-links li {
|
||||
display: inline-block;
|
||||
margin: 0 0.3em;
|
||||
}
|
||||
.action-links li:first-child {
|
||||
margin-left: 0; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .action-links li:first-child {
|
||||
margin-left: 0.3em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.button-action {
|
||||
display: inline-block;
|
||||
line-height: 160%;
|
||||
padding: 0.2em 0.5em 0.3em;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button-action:before {
|
||||
content: '+';
|
||||
font-weight: 900;
|
||||
margin-left: -0.1em; /* LTR */
|
||||
padding-right: 0.2em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .button-action:before {
|
||||
margin-left: 0;
|
||||
margin-right: -0.1em;
|
||||
padding-left: 0.2em;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Styles for system messages.
|
||||
*/
|
||||
.messages {
|
||||
background: no-repeat 10px 17px; /* LTR */
|
||||
border: 1px solid;
|
||||
border-width: 1px 1px 1px 0; /* LTR */
|
||||
border-radius: 2px;
|
||||
padding: 15px 20px 15px 35px; /* LTR */
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
[dir="rtl"] .messages {
|
||||
border-width: 1px 0 1px 1px;
|
||||
background-position: right 10px top 17px;
|
||||
padding-left: 20px;
|
||||
padding-right: 35px;
|
||||
text-align: right;
|
||||
}
|
||||
.messages + .messages {
|
||||
margin-top: 1.538em;
|
||||
}
|
||||
.messages__list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.messages__item + .messages__item {
|
||||
margin-top: 0.769em;
|
||||
}
|
||||
|
||||
/* See .color-success in Seven's colors.css */
|
||||
.messages--status {
|
||||
color: #325e1c;
|
||||
background-color: #f3faef;
|
||||
border-color: #c9e1bd #c9e1bd #c9e1bd transparent; /* LTR */
|
||||
background-image: url(../../../misc/icons/73b355/check.svg);
|
||||
box-shadow: -8px 0 0 #77b259; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .messages--status {
|
||||
border-color: #c9e1bd transparent #c9e1bd #c9e1bd;
|
||||
box-shadow: 8px 0 0 #77b259;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* See .color-warning in Seven's colors.css */
|
||||
.messages--warning {
|
||||
background-color: #fdf8ed;
|
||||
background-image: url(../../../misc/icons/e29700/warning.svg);
|
||||
border-color: #f4daa6 #f4daa6 #f4daa6 transparent; /* LTR */
|
||||
color: #734c00;
|
||||
box-shadow: -8px 0 0 #e09600; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .messages--warning {
|
||||
border-color: #f4daa6 transparent #f4daa6 #f4daa6;
|
||||
box-shadow: 8px 0 0 #e09600;
|
||||
}
|
||||
|
||||
/* See .color-error in Seven's colors.css */
|
||||
.messages--error {
|
||||
background-color: #fcf4f2;
|
||||
color: #a51b00;
|
||||
background-image: url(../../../misc/icons/ea2800/error.svg);
|
||||
border-color: #f9c9bf #f9c9bf #f9c9bf transparent; /* LTR */
|
||||
box-shadow: -8px 0 0 #e62600; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .messages--error {
|
||||
border-color: #f9c9bf transparent #f9c9bf #f9c9bf;
|
||||
box-shadow: 8px 0 0 #e62600;
|
||||
}
|
||||
.messages--error p.error {
|
||||
color: #a51b00;
|
||||
}
|
||||
|
||||
/* Field display */
|
||||
.field .field-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
.field-label-inline .field-label,
|
||||
.field-label-inline .field-items {
|
||||
float:left; /*LTR*/
|
||||
margin-right: 0.5em; /*LTR*/
|
||||
}
|
||||
[dir="rtl"] .field-label-inline .field-label,
|
||||
[dir="rtl"] .field-label-inline .field-items {
|
||||
float: right;
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.field-label-inline .field-label::after {
|
||||
content: ':';
|
||||
}
|
||||
|
||||
/* Form display */
|
||||
form .field-multiple-table {
|
||||
margin: 0;
|
||||
}
|
||||
form .field-multiple-table .field-multiple-drag {
|
||||
width: 30px;
|
||||
padding-right: 0; /*LTR*/
|
||||
}
|
||||
[dir="rtl"] form .field-multiple-table .field-multiple-drag {
|
||||
padding-left: 0;
|
||||
}
|
||||
form .field-multiple-table .field-multiple-drag .tabledrag-handle {
|
||||
padding-right: .5em; /*LTR*/
|
||||
}
|
||||
[dir="rtl"] form .field-multiple-table .field-multiple-drag .tabledrag-handle {
|
||||
padding-left: .5em;
|
||||
}
|
||||
form .field-add-more-submit {
|
||||
margin: .5em 0 0;
|
||||
}
|
BIN
core/modules/system/images/no_screenshot.png
Normal file
BIN
core/modules/system/images/no_screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
53
core/modules/system/js/system.date.js
Normal file
53
core/modules/system/js/system.date.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @file
|
||||
* Provides date format preview feature.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var dateFormats = drupalSettings.dateFormats;
|
||||
|
||||
/**
|
||||
* Display the preview for date format entered.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.dateFormat = {
|
||||
attach: function (context) {
|
||||
var $context = $(context);
|
||||
var $source = $context.find('[data-drupal-date-formatter="source"]').once('dateFormat');
|
||||
var $target = $context.find('[data-drupal-date-formatter="preview"]').once('dateFormat');
|
||||
var $preview = $target.find('em');
|
||||
|
||||
// All elements have to exist.
|
||||
if (!$source.length || !$target.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler that replaces date characters with value.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
*/
|
||||
function dateFormatHandler(e) {
|
||||
var baseValue = $(e.target).val() || '';
|
||||
var dateString = baseValue.replace(/\\?(.?)/gi, function (key, value) {
|
||||
return dateFormats[key] ? dateFormats[key] : value;
|
||||
});
|
||||
|
||||
$preview.html(dateString);
|
||||
$target.toggleClass('js-hide', !dateString.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* On given event triggers the date character replacement.
|
||||
*/
|
||||
$source.on('keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler)
|
||||
// Initialize preview.
|
||||
.trigger('keyup');
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
74
core/modules/system/js/system.js
Normal file
74
core/modules/system/js/system.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* @file
|
||||
* System behaviors.
|
||||
*/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
"use strict";
|
||||
|
||||
// Cache IDs in an array for ease of use.
|
||||
var ids = [];
|
||||
|
||||
/**
|
||||
* When a field is filled out, apply its value to other fields that will likely
|
||||
* use the same value. In the installer this is used to populate the
|
||||
* administrator email address with the same value as the site email address.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.copyFieldValue = {
|
||||
attach: function (context) {
|
||||
// List of fields IDs on which to bind the event listener.
|
||||
// Create an array of IDs to use with jQuery.
|
||||
for (var sourceId in drupalSettings.copyFieldValue) {
|
||||
if (drupalSettings.copyFieldValue.hasOwnProperty(sourceId)) {
|
||||
ids.push(sourceId);
|
||||
}
|
||||
}
|
||||
if (ids.length) {
|
||||
// Listen to value:copy events on all dependent fields.
|
||||
// We have to use body and not document because of the way jQuery events
|
||||
// bubble up the DOM tree.
|
||||
$('body').once('copy-field-values').on('value:copy', this.valueTargetCopyHandler);
|
||||
// Listen on all source elements.
|
||||
$('#' + ids.join(', #')).once('copy-field-values').on('blur', this.valueSourceBlurHandler);
|
||||
}
|
||||
},
|
||||
detach: function (context, settings, trigger) {
|
||||
if (trigger === 'unload' && ids.length) {
|
||||
$('body').removeOnce('copy-field-values').off('value:copy');
|
||||
$('#' + ids.join(', #')).removeOnce('copy-field-values').off('blur');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler that fill the target element with the specified value.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
* Event object.
|
||||
* @param {string} value
|
||||
* Custom value from jQuery trigger.
|
||||
*/
|
||||
valueTargetCopyHandler: function (e, value) {
|
||||
var $target = $(e.target);
|
||||
if ($target.val() === '') {
|
||||
$target.val(value);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for a Blur event on a source field.
|
||||
*
|
||||
* This event handler will trigger a 'value:copy' event on all dependent fields.
|
||||
*
|
||||
* @param {jQuery.Event} e
|
||||
*/
|
||||
valueSourceBlurHandler: function (e) {
|
||||
var value = $(e.target).val();
|
||||
var targetIds = drupalSettings.copyFieldValue[e.target.id];
|
||||
$('#' + targetIds.join(', #')).trigger('value:copy', value);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
84
core/modules/system/js/system.modules.js
Normal file
84
core/modules/system/js/system.modules.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @file
|
||||
* Module page behaviors.
|
||||
*/
|
||||
|
||||
(function ($, Drupal) {
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Filters the module list table by a text input search string.
|
||||
*
|
||||
* Additionally accounts for multiple tables being wrapped in "package" details
|
||||
* elements.
|
||||
*
|
||||
* Text search input: input.table-filter-text
|
||||
* Target table: input.table-filter-text[data-table]
|
||||
* Source text: .table-filter-text-source
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.tableFilterByText = {
|
||||
attach: function (context, settings) {
|
||||
var $input = $('input.table-filter-text').once('table-filter-text');
|
||||
var $table = $($input.attr('data-table'));
|
||||
var $rowsAndDetails;
|
||||
var $rows;
|
||||
var $details;
|
||||
var searching = false;
|
||||
|
||||
function hidePackageDetails(index, element) {
|
||||
var $packDetails = $(element);
|
||||
var $visibleRows = $packDetails.find('table:not(.sticky-header)').find('tbody tr:visible');
|
||||
$packDetails.toggle($visibleRows.length > 0);
|
||||
}
|
||||
|
||||
function filterModuleList(e) {
|
||||
var query = $(e.target).val().toLowerCase();
|
||||
|
||||
function showModuleRow(index, row) {
|
||||
var $row = $(row);
|
||||
var $sources = $row.find('.table-filter-text-source');
|
||||
var textMatch = $sources.text().toLowerCase().indexOf(query) !== -1;
|
||||
$row.closest('tr').toggle(textMatch);
|
||||
}
|
||||
// Search over all rows and packages.
|
||||
$rowsAndDetails.show();
|
||||
|
||||
// Filter if the length of the query is at least 2 characters.
|
||||
if (query.length >= 2) {
|
||||
searching = true;
|
||||
$rows.each(showModuleRow);
|
||||
|
||||
// Note that we first open all <details> to be able to use ':visible'.
|
||||
// Mark the <details> elements that were closed before filtering, so
|
||||
// they can be reclosed when filtering is removed.
|
||||
$details.not('[open]').attr('data-drupal-system-state', 'forced-open');
|
||||
|
||||
// Hide the package <details> if they don't have any visible rows.
|
||||
// Note that we first show() all <details> to be able to use ':visible'.
|
||||
$details.attr('open', true).each(hidePackageDetails);
|
||||
}
|
||||
else if (searching) {
|
||||
searching = false;
|
||||
$rowsAndDetails.show();
|
||||
// Return <details> elements that had been closed before filtering
|
||||
// to a closed state.
|
||||
$details.filter('[data-drupal-system-state="forced-open"]')
|
||||
.removeAttr('data-drupal-system-state')
|
||||
.attr('open', false);
|
||||
}
|
||||
}
|
||||
|
||||
if ($table.length) {
|
||||
$rowsAndDetails = $table.find('tr, details');
|
||||
$rows = $table.find('tbody tr');
|
||||
$details = $rowsAndDetails.filter('.package-listing');
|
||||
|
||||
$input.on('keyup', filterModuleList);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}(jQuery, Drupal));
|
38
core/modules/system/src/Access/CronAccessCheck.php
Normal file
38
core/modules/system/src/Access/CronAccessCheck.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Access\CronAccessCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
|
||||
/**
|
||||
* Access check for cron routes.
|
||||
*/
|
||||
class CronAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks access.
|
||||
*
|
||||
* @param string $key
|
||||
* The cron key.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access($key) {
|
||||
if ($key != \Drupal::state()->get('system.cron_key')) {
|
||||
\Drupal::logger('cron')->notice('Cron could not run because an invalid key was used.');
|
||||
return AccessResult::forbidden()->setCacheMaxAge(0);
|
||||
}
|
||||
elseif (\Drupal::state()->get('system.maintenance_mode')) {
|
||||
\Drupal::logger('cron')->notice('Cron could not run because the site is in maintenance mode.');
|
||||
return AccessResult::forbidden()->setCacheMaxAge(0);
|
||||
}
|
||||
return AccessResult::allowed()->setCacheMaxAge(0);
|
||||
}
|
||||
}
|
42
core/modules/system/src/Access/DbUpdateAccessCheck.php
Normal file
42
core/modules/system/src/Access/DbUpdateAccessCheck.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Access\DbUpdateAccessCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Access;
|
||||
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
|
||||
/**
|
||||
* Access check for database update routes.
|
||||
*/
|
||||
class DbUpdateAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks access for update routes.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
*
|
||||
* @return string
|
||||
* A \Drupal\Core\Access\AccessInterface constant value.
|
||||
*/
|
||||
public function access(AccountInterface $account) {
|
||||
// Allow the global variable in settings.php to override the access check.
|
||||
if (Settings::get('update_free_access')) {
|
||||
return AccessResult::allowed()->setCacheMaxAge(0);
|
||||
}
|
||||
|
||||
if ($account->hasPermission('administer software updates')) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
else {
|
||||
return AccessResult::forbidden()->cachePerPermissions();
|
||||
}
|
||||
}
|
||||
}
|
38
core/modules/system/src/ActionConfigEntityInterface.php
Normal file
38
core/modules/system/src/ActionConfigEntityInterface.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\ActionConfigEntityInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a action entity.
|
||||
*/
|
||||
interface ActionConfigEntityInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Returns whether or not this action is configurable.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isConfigurable();
|
||||
|
||||
/**
|
||||
* Returns the operation type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* Returns the operation plugin.
|
||||
*
|
||||
* @return \Drupal\Core\Action\ActionInterface
|
||||
*/
|
||||
public function getPlugin();
|
||||
|
||||
}
|
58
core/modules/system/src/Controller/AdminController.php
Normal file
58
core/modules/system/src/Controller/AdminController.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\AdminController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
|
||||
/**
|
||||
* Controller for admin section.
|
||||
*/
|
||||
class AdminController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Prints a listing of admin tasks, organized by module.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing the listing.
|
||||
*/
|
||||
public function index() {
|
||||
$module_info = system_get_info('module');
|
||||
foreach ($module_info as $module => $info) {
|
||||
$module_info[$module] = new \stdClass();
|
||||
$module_info[$module]->info = $info;
|
||||
}
|
||||
|
||||
uasort($module_info, 'system_sort_modules_by_info_name');
|
||||
$menu_items = array();
|
||||
|
||||
foreach ($module_info as $module => $info) {
|
||||
// Only display a section if there are any available tasks.
|
||||
if ($admin_tasks = system_get_module_admin_tasks($module, $info->info)) {
|
||||
// Sort links by title.
|
||||
uasort($admin_tasks, array('\Drupal\Component\Utility\SortArray', 'sortByTitleElement'));
|
||||
// Move 'Configure permissions' links to the bottom of each section.
|
||||
$permission_key = "user.admin_permissions.$module";
|
||||
if (isset($admin_tasks[$permission_key])) {
|
||||
$permission_task = $admin_tasks[$permission_key];
|
||||
unset($admin_tasks[$permission_key]);
|
||||
$admin_tasks[$permission_key] = $permission_task;
|
||||
}
|
||||
|
||||
$menu_items[$info->info['name']] = array($info->info['description'], $admin_tasks);
|
||||
}
|
||||
}
|
||||
|
||||
$output = array(
|
||||
'#theme' => 'system_admin_index',
|
||||
'#menu_items' => $menu_items,
|
||||
);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
89
core/modules/system/src/Controller/BatchController.php
Normal file
89
core/modules/system/src/Controller/BatchController.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\BatchController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* Controller routines for batch routes.
|
||||
*/
|
||||
class BatchController implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The app root.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* Constructs a new BatchController.
|
||||
*
|
||||
* @param string $root
|
||||
* The app root.
|
||||
*/
|
||||
public function __construct($root) {
|
||||
$this->root = $root;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('app.root')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a system batch page.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request object.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response|array
|
||||
* A \Symfony\Component\HttpFoundation\Response object or render array.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
*/
|
||||
public function batchPage(Request $request) {
|
||||
require_once $this->root . '/core/includes/batch.inc';
|
||||
$output = _batch_page($request);
|
||||
|
||||
if ($output === FALSE) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
elseif ($output instanceof Response) {
|
||||
return $output;
|
||||
}
|
||||
elseif (isset($output)) {
|
||||
$page = [
|
||||
'#type' => 'page',
|
||||
'#show_messages' => FALSE,
|
||||
'content' => $output,
|
||||
];
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The _title_callback for the system.batch_page.normal route.
|
||||
*
|
||||
* @return string
|
||||
* The page title.
|
||||
*/
|
||||
public function batchPageTitle() {
|
||||
$current_set = _batch_current_set();
|
||||
return !empty($current_set['title']) ? $current_set['title'] : '';
|
||||
}
|
||||
|
||||
}
|
674
core/modules/system/src/Controller/DbUpdateController.php
Normal file
674
core/modules/system/src/Controller/DbUpdateController.php
Normal file
|
@ -0,0 +1,674 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\DbUpdateController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
|
||||
use Drupal\Core\Render\BareHtmlPageRendererInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Controller routines for database update routes.
|
||||
*/
|
||||
class DbUpdateController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The keyvalue expirable factory.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface
|
||||
*/
|
||||
protected $keyValueExpirableFactory;
|
||||
|
||||
/**
|
||||
* A cache backend interface.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* The state service.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* The entity definition update manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
|
||||
*/
|
||||
protected $entityDefinitionUpdateManager;
|
||||
|
||||
/**
|
||||
* The bare HTML page renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\BareHtmlPageRendererInterface
|
||||
*/
|
||||
protected $bareHtmlPageRenderer;
|
||||
|
||||
/**
|
||||
* The app root.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $root;
|
||||
|
||||
/**
|
||||
* Constructs a new UpdateController.
|
||||
*
|
||||
* @param string $root
|
||||
* The app root.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $key_value_expirable_factory
|
||||
* The keyvalue expirable factory.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache
|
||||
* A cache backend interface.
|
||||
* @param \Drupal\Core\State\StateInterface $state
|
||||
* The state service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user.
|
||||
* @param \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface $entity_definition_update_manager
|
||||
* The entity definition update manager.
|
||||
* @param \Drupal\Core\Render\BareHtmlPageRendererInterface $bare_html_page_renderer
|
||||
* The bare HTML page renderer.
|
||||
*/
|
||||
public function __construct($root, KeyValueExpirableFactoryInterface $key_value_expirable_factory, CacheBackendInterface $cache, StateInterface $state, ModuleHandlerInterface $module_handler, AccountInterface $account, EntityDefinitionUpdateManagerInterface $entity_definition_update_manager, BareHtmlPageRendererInterface $bare_html_page_renderer) {
|
||||
$this->root = $root;
|
||||
$this->keyValueExpirableFactory = $key_value_expirable_factory;
|
||||
$this->cache = $cache;
|
||||
$this->state = $state;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->account = $account;
|
||||
$this->entityDefinitionUpdateManager = $entity_definition_update_manager;
|
||||
$this->bareHtmlPageRenderer = $bare_html_page_renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('app.root'),
|
||||
$container->get('keyvalue.expirable'),
|
||||
$container->get('cache.default'),
|
||||
$container->get('state'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('current_user'),
|
||||
$container->get('entity.definition_update_manager'),
|
||||
$container->get('bare_html_page_renderer')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a database update page.
|
||||
*
|
||||
* @param string $op
|
||||
* The update operation to perform. Can be any of the below:
|
||||
* - info
|
||||
* - selection
|
||||
* - run
|
||||
* - results
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request object.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* A response object object.
|
||||
*/
|
||||
public function handle($op, Request $request) {
|
||||
require_once $this->root . '/core/includes/install.inc';
|
||||
require_once $this->root . '/core/includes/update.inc';
|
||||
|
||||
drupal_load_updates();
|
||||
update_fix_compatibility();
|
||||
|
||||
if ($request->query->get('continue')) {
|
||||
$_SESSION['update_ignore_warnings'] = TRUE;
|
||||
}
|
||||
|
||||
$regions = array();
|
||||
$requirements = update_check_requirements();
|
||||
$severity = drupal_requirements_severity($requirements);
|
||||
if ($severity == REQUIREMENT_ERROR || ($severity == REQUIREMENT_WARNING && empty($_SESSION['update_ignore_warnings']))) {
|
||||
$regions['sidebar_first'] = $this->updateTasksList('requirements');
|
||||
$output = $this->requirements($severity, $requirements);
|
||||
}
|
||||
else {
|
||||
switch ($op) {
|
||||
case 'selection':
|
||||
$regions['sidebar_first'] = $this->updateTasksList('selection');
|
||||
$output = $this->selection();
|
||||
break;
|
||||
|
||||
case 'run':
|
||||
$regions['sidebar_first'] = $this->updateTasksList('run');
|
||||
$output = $this->triggerBatch($request);
|
||||
break;
|
||||
|
||||
case 'info':
|
||||
$regions['sidebar_first'] = $this->updateTasksList('info');
|
||||
$output = $this->info();
|
||||
break;
|
||||
|
||||
case 'results':
|
||||
$regions['sidebar_first'] = $this->updateTasksList('results');
|
||||
$output = $this->results();
|
||||
break;
|
||||
|
||||
// Regular batch ops : defer to batch processing API.
|
||||
default:
|
||||
require_once $this->root . '/core/includes/batch.inc';
|
||||
$regions['sidebar_first'] = $this->updateTasksList('run');
|
||||
$output = _batch_page($request);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($output instanceof Response) {
|
||||
return $output;
|
||||
}
|
||||
$title = isset($output['#title']) ? $output['#title'] : $this->t('Drupal database update');
|
||||
|
||||
return $this->bareHtmlPageRenderer->renderBarePage($output, $title, 'maintenance_page', $regions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the info database update page.
|
||||
*
|
||||
* @return array
|
||||
* A render array.
|
||||
*/
|
||||
protected function info() {
|
||||
// Change query-strings on css/js files to enforce reload for all users.
|
||||
_drupal_flush_css_js();
|
||||
// Flush the cache of all data for the update status module.
|
||||
$this->keyValueExpirableFactory->get('update')->deleteAll();
|
||||
$this->keyValueExpirableFactory->get('update_available_release')->deleteAll();
|
||||
|
||||
$build['info_header'] = array(
|
||||
'#markup' => '<p>' . $this->t('Use this utility to update your database whenever a new release of Drupal or a module is installed.') . '</p><p>' . $this->t('For more detailed information, see the <a href="https://www.drupal.org/upgrade">upgrading handbook</a>. If you are unsure what these terms mean you should probably contact your hosting provider.') . '</p>',
|
||||
);
|
||||
|
||||
$info[] = $this->t("<strong>Back up your code</strong>. Hint: when backing up module code, do not leave that backup in the 'modules' or 'sites/*/modules' directories as this may confuse Drupal's auto-discovery mechanism.");
|
||||
$info[] = $this->t('Put your site into <a href="@url">maintenance mode</a>.', array(
|
||||
'@url' => $this->url('system.site_maintenance_mode'),
|
||||
));
|
||||
$info[] = $this->t('<strong>Back up your database</strong>. This process will change your database values and in case of emergency you may need to revert to a backup.');
|
||||
$info[] = $this->t('Install your new files in the appropriate location, as described in the handbook.');
|
||||
$build['info'] = array(
|
||||
'#theme' => 'item_list',
|
||||
'#list_type' => 'ol',
|
||||
'#items' => $info,
|
||||
);
|
||||
$build['info_footer'] = array(
|
||||
'#markup' => '<p>' . $this->t('When you have performed the steps above, you may proceed.') . '</p>',
|
||||
);
|
||||
|
||||
$url = new Url('system.db_update', array('op' => 'selection'));
|
||||
$build['link'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Continue'),
|
||||
'#attributes' => array('class' => array('button', 'button--primary')),
|
||||
'#url' => $url,
|
||||
);
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a list of available database updates.
|
||||
*
|
||||
* @return array
|
||||
* A render array.
|
||||
*/
|
||||
protected function selection() {
|
||||
// Make sure there is no stale theme registry.
|
||||
$this->cache->deleteAll();
|
||||
|
||||
$count = 0;
|
||||
$incompatible_count = 0;
|
||||
$build['start'] = array(
|
||||
'#tree' => TRUE,
|
||||
'#type' => 'details',
|
||||
);
|
||||
|
||||
// Ensure system.module's updates appear first.
|
||||
$build['start']['system'] = array();
|
||||
|
||||
$updates = update_get_update_list();
|
||||
$starting_updates = array();
|
||||
$incompatible_updates_exist = FALSE;
|
||||
foreach ($updates as $module => $update) {
|
||||
if (!isset($update['start'])) {
|
||||
$build['start'][$module] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => $module . ' module',
|
||||
'#markup' => $update['warning'],
|
||||
'#prefix' => '<div class="messages messages--warning">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
$incompatible_updates_exist = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (!empty($update['pending'])) {
|
||||
$starting_updates[$module] = $update['start'];
|
||||
$build['start'][$module] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $update['start'],
|
||||
);
|
||||
$build['start'][$module . '_updates'] = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $update['pending'],
|
||||
'#title' => $module . ' module',
|
||||
);
|
||||
}
|
||||
if (isset($update['pending'])) {
|
||||
$count = $count + count($update['pending']);
|
||||
}
|
||||
}
|
||||
|
||||
// Find and label any incompatible updates.
|
||||
foreach (update_resolve_dependencies($starting_updates) as $data) {
|
||||
if (!$data['allowed']) {
|
||||
$incompatible_updates_exist = TRUE;
|
||||
$incompatible_count++;
|
||||
$module_update_key = $data['module'] . '_updates';
|
||||
if (isset($build['start'][$module_update_key]['#items'][$data['number']])) {
|
||||
if ($data['missing_dependencies']) {
|
||||
$text = $this->t('This update will been skipped due to the following missing dependencies:') . '<em>' . implode(', ', $data['missing_dependencies']) . '</em>';
|
||||
}
|
||||
else {
|
||||
$text = $this->t("This update will be skipped due to an error in the module's code.");
|
||||
}
|
||||
$build['start'][$module_update_key]['#items'][$data['number']] .= '<div class="warning">' . $text . '</div>';
|
||||
}
|
||||
// Move the module containing this update to the top of the list.
|
||||
$build['start'] = array($module_update_key => $build['start'][$module_update_key]) + $build['start'];
|
||||
}
|
||||
}
|
||||
|
||||
// Warn the user if any updates were incompatible.
|
||||
if ($incompatible_updates_exist) {
|
||||
drupal_set_message($this->t('Some of the pending updates cannot be applied because their dependencies were not met.'), 'warning');
|
||||
}
|
||||
|
||||
// If there are entity definition updates, display their summary.
|
||||
if ($this->entityDefinitionUpdateManager->needsUpdates()) {
|
||||
$entity_build = array();
|
||||
$summary = $this->entityDefinitionUpdateManager->getChangeSummary();
|
||||
foreach ($summary as $entity_type_id => $items) {
|
||||
$entity_update_key = 'entity_type_updates_' . $entity_type_id;
|
||||
$entity_build[$entity_update_key] = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
'#title' => $entity_type_id . ' entity type',
|
||||
);
|
||||
$count++;
|
||||
}
|
||||
// Display these above the module updates, since they will be run first.
|
||||
$build['start'] = $entity_build + $build['start'];
|
||||
}
|
||||
|
||||
if (empty($count)) {
|
||||
drupal_set_message($this->t('No pending updates.'));
|
||||
unset($build);
|
||||
$build['links'] = array(
|
||||
'#theme' => 'links',
|
||||
'#links' => $this->helpfulLinks(),
|
||||
);
|
||||
|
||||
// No updates to run, so caches won't get flushed later. Clear them now.
|
||||
drupal_flush_all_caches();
|
||||
}
|
||||
else {
|
||||
$build['help'] = array(
|
||||
'#markup' => '<p>' . $this->t('The version of Drupal you are updating from has been automatically detected.') . '</p>',
|
||||
'#weight' => -5,
|
||||
);
|
||||
if ($incompatible_count) {
|
||||
$build['start']['#title'] = $this->formatPlural(
|
||||
$count,
|
||||
'1 pending update (@number_applied to be applied, @number_incompatible skipped)',
|
||||
'@count pending updates (@number_applied to be applied, @number_incompatible skipped)',
|
||||
array('@number_applied' => $count - $incompatible_count, '@number_incompatible' => $incompatible_count)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$build['start']['#title'] = $this->formatPlural($count, '1 pending update', '@count pending updates');
|
||||
}
|
||||
$url = new Url('system.db_update', array('op' => 'run'));
|
||||
$build['link'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Apply pending updates'),
|
||||
'#attributes' => array('class' => array('button', 'button--primary')),
|
||||
'#weight' => 5,
|
||||
'#url' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays results of the update script with any accompanying errors.
|
||||
*
|
||||
* @return array
|
||||
* A render array.
|
||||
*/
|
||||
protected function results() {
|
||||
// Report end result.
|
||||
$dblog_exists = $this->moduleHandler->moduleExists('dblog');
|
||||
if ($dblog_exists && $this->account->hasPermission('access site reports')) {
|
||||
$log_message = $this->t('All errors have been <a href="@url">logged</a>.', array(
|
||||
'@url' => $this->url('dblog.overview'),
|
||||
));
|
||||
}
|
||||
else {
|
||||
$log_message = $this->t('All errors have been logged.');
|
||||
}
|
||||
|
||||
if (!empty($_SESSION['update_success'])) {
|
||||
$message = '<p>' . $this->t('Updates were attempted. If you see no failures below, you may proceed happily back to your <a href="@url">site</a>. Otherwise, you may need to update your database manually.', array('@url' => $this->url('<front>'))) . ' ' . $log_message . '</p>';
|
||||
}
|
||||
else {
|
||||
$last = reset($_SESSION['updates_remaining']);
|
||||
list($module, $version) = array_pop($last);
|
||||
$message = '<p class="error">' . $this->t('The update process was aborted prematurely while running <strong>update #@version in @module.module</strong>.', array(
|
||||
'@version' => $version,
|
||||
'@module' => $module,
|
||||
)) . ' ' . $log_message;
|
||||
if ($dblog_exists) {
|
||||
$message .= ' ' . $this->t('You may need to check the <code>watchdog</code> database table manually.');
|
||||
}
|
||||
$message .= '</p>';
|
||||
}
|
||||
|
||||
if (Settings::get('update_free_access')) {
|
||||
$message .= '<p>' . $this->t("<strong>Reminder: don't forget to set the <code>\$settings['update_free_access']</code> value in your <code>settings.php</code> file back to <code>FALSE</code>.</strong>") . '</p>';
|
||||
}
|
||||
|
||||
$build['message'] = array(
|
||||
'#markup' => $message,
|
||||
);
|
||||
$build['links'] = array(
|
||||
'#theme' => 'links',
|
||||
'#links' => $this->helpfulLinks(),
|
||||
);
|
||||
|
||||
// Output a list of info messages.
|
||||
if (!empty($_SESSION['update_results'])) {
|
||||
$all_messages = array();
|
||||
foreach ($_SESSION['update_results'] as $module => $updates) {
|
||||
if ($module != '#abort') {
|
||||
$module_has_message = FALSE;
|
||||
$info_messages = array();
|
||||
foreach ($updates as $number => $queries) {
|
||||
$messages = array();
|
||||
foreach ($queries as $query) {
|
||||
// If there is no message for this update, don't show anything.
|
||||
if (empty($query['query'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($query['success']) {
|
||||
$messages[] = array(
|
||||
'#wrapper_attributes' => array('class' => array('success')),
|
||||
'#markup' => $query['query'],
|
||||
);
|
||||
}
|
||||
else {
|
||||
$messages[] = array(
|
||||
'#wrapper_attributes' => array('class' => array('failure')),
|
||||
'#markup' => '<strong>' . $this->t('Failed:') . '</strong> ' . $query['query'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($messages) {
|
||||
$module_has_message = TRUE;
|
||||
$info_messages[] = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $messages,
|
||||
'#title' => $this->t('Update #@count', array('@count' => $number)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If there were any messages then prefix them with the module name
|
||||
// and add it to the global message list.
|
||||
if ($module_has_message) {
|
||||
$all_messages[] = array(
|
||||
'#type' => 'container',
|
||||
'#prefix' => '<h3>' . $this->t('@module module', array('@module' => $module)) . '</h3>',
|
||||
'#children' => $info_messages,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($all_messages) {
|
||||
$build['query_messages'] = array(
|
||||
'#type' => 'container',
|
||||
'#children' => $all_messages,
|
||||
'#attributes' => array('class' => array('update-results')),
|
||||
'#prefix' => '<h2>' . $this->t('The following updates returned messages:') . '</h2>',
|
||||
);
|
||||
}
|
||||
}
|
||||
unset($_SESSION['update_results']);
|
||||
unset($_SESSION['update_success']);
|
||||
unset($_SESSION['update_ignore_warnings']);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a list of requirement errors or warnings.
|
||||
*
|
||||
* @return array
|
||||
* A render array.
|
||||
*/
|
||||
public function requirements($severity, array $requirements) {
|
||||
$options = $severity == REQUIREMENT_WARNING ? array('continue' => 1) : array();
|
||||
$try_again_url = $this->url('system.db_update', $options);
|
||||
|
||||
$build['status_report'] = array(
|
||||
'#theme' => 'status_report',
|
||||
'#requirements' => $requirements,
|
||||
'#suffix' => $this->t('Check the messages and <a href="@url">try again</a>.', array('@url' => $try_again_url))
|
||||
);
|
||||
|
||||
$build['#title'] = $this->t('Requirements problem');
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the update task list render array.
|
||||
*
|
||||
* @param string $active
|
||||
* The active task.
|
||||
* Can be one of 'requirements', 'info', 'selection', 'run', 'results'.
|
||||
*
|
||||
* @return array
|
||||
* A render array.
|
||||
*/
|
||||
protected function updateTasksList($active = NULL) {
|
||||
// Default list of tasks.
|
||||
$tasks = array(
|
||||
'requirements' => $this->t('Verify requirements'),
|
||||
'info' => $this->t('Overview'),
|
||||
'selection' => $this->t('Review updates'),
|
||||
'run' => $this->t('Run updates'),
|
||||
'results' => $this->t('Review log'),
|
||||
);
|
||||
|
||||
$task_list = array(
|
||||
'#theme' => 'maintenance_task_list',
|
||||
'#items' => $tasks,
|
||||
'#active' => $active,
|
||||
);
|
||||
return $task_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the database update batch process.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request object.
|
||||
*/
|
||||
protected function triggerBatch(Request $request) {
|
||||
// During the update, bring the site offline so that schema changes do not
|
||||
// affect visiting users.
|
||||
$maintenance_mode = $this->config('system.maintenance')->get('enabled');
|
||||
if (isset($maintenance_mode)) {
|
||||
$_SESSION['maintenance_mode'] = $maintenance_mode;
|
||||
}
|
||||
if (empty($_SESSION['maintenance_mode'])) {
|
||||
$this->state->set('system.maintenance_mode', TRUE);
|
||||
}
|
||||
|
||||
$operations = array();
|
||||
|
||||
// First of all perform entity definition updates, which will update
|
||||
// storage schema if needed, so that module update functions work with
|
||||
// the correct entity schema.
|
||||
if ($this->entityDefinitionUpdateManager->needsUpdates()) {
|
||||
$operations[] = array('update_entity_definitions', array('system', '0 - Update entity definitions'));
|
||||
}
|
||||
|
||||
// Resolve any update dependencies to determine the actual updates that will
|
||||
// be run and the order they will be run in.
|
||||
$start = $this->getModuleUpdates();
|
||||
$updates = update_resolve_dependencies($start);
|
||||
|
||||
// Store the dependencies for each update function in an array which the
|
||||
// batch API can pass in to the batch operation each time it is called. (We
|
||||
// do not store the entire update dependency array here because it is
|
||||
// potentially very large.)
|
||||
$dependency_map = array();
|
||||
foreach ($updates as $function => $update) {
|
||||
$dependency_map[$function] = !empty($update['reverse_paths']) ? array_keys($update['reverse_paths']) : array();
|
||||
}
|
||||
|
||||
// Determine updates to be performed.
|
||||
foreach ($updates as $update) {
|
||||
if ($update['allowed']) {
|
||||
// Set the installed version of each module so updates will start at the
|
||||
// correct place. (The updates are already sorted, so we can simply base
|
||||
// this on the first one we come across in the above foreach loop.)
|
||||
if (isset($start[$update['module']])) {
|
||||
drupal_set_installed_schema_version($update['module'], $update['number'] - 1);
|
||||
unset($start[$update['module']]);
|
||||
}
|
||||
// Add this update function to the batch.
|
||||
$function = $update['module'] . '_update_' . $update['number'];
|
||||
$operations[] = array('update_do_one', array($update['module'], $update['number'], $dependency_map[$function]));
|
||||
}
|
||||
}
|
||||
$batch['operations'] = $operations;
|
||||
$batch += array(
|
||||
'title' => $this->t('Updating'),
|
||||
'init_message' => $this->t('Starting updates'),
|
||||
'error_message' => $this->t('An unrecoverable error has occurred. You can find the error message below. It is advised to copy it to the clipboard for reference.'),
|
||||
'finished' => array('\Drupal\system\Controller\DbUpdateController', 'batchFinished'),
|
||||
);
|
||||
batch_set($batch);
|
||||
|
||||
return batch_process('update.php/results', Url::fromRoute('system.db_update', array('op' => 'start')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finishes the update process and stores the results for eventual display.
|
||||
*
|
||||
* After the updates run, all caches are flushed. The update results are
|
||||
* stored into the session (for example, to be displayed on the update results
|
||||
* page in update.php). Additionally, if the site was off-line, now that the
|
||||
* update process is completed, the site is set back online.
|
||||
*
|
||||
* @param $success
|
||||
* Indicate that the batch API tasks were all completed successfully.
|
||||
* @param array $results
|
||||
* An array of all the results that were updated in update_do_one().
|
||||
* @param array $operations
|
||||
* A list of all the operations that had not been completed by the batch API.
|
||||
*/
|
||||
public static function batchFinished($success, $results, $operations) {
|
||||
// No updates to run, so caches won't get flushed later. Clear them now.
|
||||
drupal_flush_all_caches();
|
||||
|
||||
$_SESSION['update_results'] = $results;
|
||||
$_SESSION['update_success'] = $success;
|
||||
$_SESSION['updates_remaining'] = $operations;
|
||||
|
||||
// Now that the update is done, we can put the site back online if it was
|
||||
// previously in maintenance mode.
|
||||
if (isset($_SESSION['maintenance_mode'])) {
|
||||
\Drupal::state()->set('system.maintenance_mode', FALSE);
|
||||
unset($_SESSION['maintenance_mode']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides links to the homepage and administration pages.
|
||||
*
|
||||
* @return array
|
||||
* An array of links.
|
||||
*/
|
||||
protected function helpfulLinks() {
|
||||
$links['front'] = array(
|
||||
'title' => $this->t('Front page'),
|
||||
'url' => Url::fromRoute('<front>'),
|
||||
);
|
||||
if ($this->account->hasPermission('access administration pages')) {
|
||||
$links['admin-pages'] = array(
|
||||
'title' => $this->t('Administration pages'),
|
||||
'url' => Url::fromRoute('system.admin'),
|
||||
);
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves module updates.
|
||||
*
|
||||
* @return array
|
||||
* The module updates that can be performed.
|
||||
*/
|
||||
protected function getModuleUpdates() {
|
||||
$return = array();
|
||||
$updates = update_get_update_list();
|
||||
foreach ($updates as $module => $update) {
|
||||
$return[$module] = $update['start'];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\EntityAutocompleteController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Component\Utility\Tags;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Entity\EntityAutocompleteMatcher;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* Defines a route controller for entity autocomplete form elements.
|
||||
*/
|
||||
class EntityAutocompleteController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The autocomplete matcher for entity references.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityAutocompleteMatcher
|
||||
*/
|
||||
protected $matcher;
|
||||
|
||||
/**
|
||||
* The key value store.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
|
||||
*/
|
||||
protected $keyValue;
|
||||
|
||||
/**
|
||||
* Constructs a EntityAutocompleteController object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityAutocompleteMatcher $matcher
|
||||
* The autocomplete matcher for entity references.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $key_value
|
||||
* The key value factory.
|
||||
*/
|
||||
public function __construct(EntityAutocompleteMatcher $matcher, KeyValueStoreInterface $key_value) {
|
||||
$this->matcher = $matcher;
|
||||
$this->keyValue = $key_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.autocomplete_matcher'),
|
||||
$container->get('keyvalue')->get('entity_autocomplete')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocomplete the label of an entity.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object that contains the typed tags.
|
||||
* @param string $target_type
|
||||
* The ID of the target entity type.
|
||||
* @param string $selection_handler
|
||||
* The plugin ID of the entity reference selection handler.
|
||||
* @param string $selection_settings_key
|
||||
* The hashed key of the key/value entry that holds the selection handler
|
||||
* settings.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* The matched entity labels as a JSON response.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Thrown if the selection settings key is not found in the key/value store
|
||||
* or if it does not match the stored data.
|
||||
*/
|
||||
public function handleAutocomplete(Request $request, $target_type, $selection_handler, $selection_settings_key) {
|
||||
$matches = array();
|
||||
// Get the typed string from the URL, if it exists.
|
||||
if ($input = $request->query->get('q')) {
|
||||
$typed_string = Tags::explode($input);
|
||||
$typed_string = Unicode::strtolower(array_pop($typed_string));
|
||||
|
||||
// Selection settings are passed in as a hashed key of a serialized array
|
||||
// stored in the key/value store.
|
||||
$selection_settings = $this->keyValue->get($selection_settings_key, FALSE);
|
||||
if ($selection_settings !== FALSE) {
|
||||
$selection_settings_hash = Crypt::hmacBase64(serialize($selection_settings) . $target_type . $selection_handler, Settings::getHashSalt());
|
||||
if ($selection_settings_hash !== $selection_settings_key) {
|
||||
// Disallow access when the selection settings hash does not match the
|
||||
// passed-in key.
|
||||
throw new AccessDeniedHttpException('Invalid selection settings key.');
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Disallow access when the selection settings key is not found in the
|
||||
// key/value store.
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
$matches = $this->matcher->getMatches($target_type, $selection_handler, $selection_settings, $typed_string);
|
||||
}
|
||||
|
||||
return new JsonResponse($matches);
|
||||
}
|
||||
|
||||
}
|
186
core/modules/system/src/Controller/FormAjaxController.php
Normal file
186
core/modules/system/src/Controller/FormAjaxController.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\FormAjaxController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Form\FormAjaxResponseBuilderInterface;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Render\MainContent\MainContentRendererInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\system\FileAjaxForm;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
/**
|
||||
* Defines a controller to respond to form Ajax requests.
|
||||
*/
|
||||
class FormAjaxController implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* A logger instance.
|
||||
*
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* The form builder.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormBuilderInterface|\Drupal\Core\Form\FormCacheInterface
|
||||
*/
|
||||
protected $formBuilder;
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* The main content to AJAX Response renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\MainContent\MainContentRendererInterface
|
||||
*/
|
||||
protected $ajaxRenderer;
|
||||
|
||||
/**
|
||||
* The current route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* The form AJAX response builder.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormAjaxResponseBuilderInterface
|
||||
*/
|
||||
protected $formAjaxResponseBuilder;
|
||||
|
||||
/**
|
||||
* Constructs a FormAjaxController object.
|
||||
*
|
||||
* @param \Psr\Log\LoggerInterface $logger
|
||||
* A logger instance.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
|
||||
* The form builder.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer.
|
||||
* @param \Drupal\Core\Render\MainContent\MainContentRendererInterface $ajax_renderer
|
||||
* The main content to AJAX Response renderer.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The current route match.
|
||||
* @param \Drupal\Core\Form\FormAjaxResponseBuilderInterface $form_ajax_response_builder
|
||||
* The form AJAX response builder.
|
||||
*/
|
||||
public function __construct(LoggerInterface $logger, FormBuilderInterface $form_builder, RendererInterface $renderer, MainContentRendererInterface $ajax_renderer, RouteMatchInterface $route_match, FormAjaxResponseBuilderInterface $form_ajax_response_builder) {
|
||||
$this->logger = $logger;
|
||||
$this->formBuilder = $form_builder;
|
||||
$this->renderer = $renderer;
|
||||
$this->ajaxRenderer = $ajax_renderer;
|
||||
$this->routeMatch = $route_match;
|
||||
$this->formAjaxResponseBuilder = $form_ajax_response_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('logger.factory')->get('ajax'),
|
||||
$container->get('form_builder'),
|
||||
$container->get('renderer'),
|
||||
$container->get('main_content_renderer.ajax'),
|
||||
$container->get('current_route_match'),
|
||||
$container->get('form_ajax_response_builder')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an Ajax form submission.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request object.
|
||||
*
|
||||
* @return mixed
|
||||
* Whatever is returned by the triggering element's #ajax['callback']
|
||||
* function. One of:
|
||||
* - A render array containing the new or updated content to return to the
|
||||
* browser. This is commonly an element within the rebuilt form.
|
||||
* - A \Drupal\Core\Ajax\AjaxResponse object containing commands for the
|
||||
* browser to process.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface
|
||||
*/
|
||||
public function content(Request $request) {
|
||||
$ajax_form = $this->getForm($request);
|
||||
$form = $ajax_form->getForm();
|
||||
$form_state = $ajax_form->getFormState();
|
||||
$commands = $ajax_form->getCommands();
|
||||
|
||||
$this->formBuilder->processForm($form['#form_id'], $form, $form_state);
|
||||
|
||||
return $this->formAjaxResponseBuilder->buildResponse($request, $form, $form_state, $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a form submitted via #ajax during an Ajax callback.
|
||||
*
|
||||
* This will load a form from the form cache used during Ajax operations. It
|
||||
* pulls the form info from the request body.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request object.
|
||||
*
|
||||
* @return \Drupal\system\FileAjaxForm
|
||||
* A wrapper object containing the $form, $form_state, $form_id,
|
||||
* $form_build_id and an initial list of Ajax $commands.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface
|
||||
*/
|
||||
protected function getForm(Request $request) {
|
||||
$form_state = new FormState();
|
||||
$form_build_id = $request->request->get('form_build_id');
|
||||
|
||||
// Get the form from the cache.
|
||||
$form = $this->formBuilder->getCache($form_build_id, $form_state);
|
||||
if (!$form) {
|
||||
// If $form cannot be loaded from the cache, the form_build_id must be
|
||||
// invalid, which means that someone performed a POST request onto
|
||||
// system/ajax without actually viewing the concerned form in the browser.
|
||||
// This is likely a hacking attempt as it never happens under normal
|
||||
// circumstances.
|
||||
$this->logger->warning('Invalid form POST data.');
|
||||
throw new BadRequestHttpException();
|
||||
}
|
||||
|
||||
// Since some of the submit handlers are run, redirects need to be disabled.
|
||||
$form_state->disableRedirect();
|
||||
|
||||
// When a form is rebuilt after Ajax processing, its #build_id and #action
|
||||
// should not change.
|
||||
// @see \Drupal\Core\Form\FormBuilderInterface::rebuildForm()
|
||||
$form_state->addRebuildInfo('copy', [
|
||||
'#build_id' => TRUE,
|
||||
'#action' => TRUE,
|
||||
]);
|
||||
|
||||
// The form needs to be processed; prepare for that by setting a few
|
||||
// internal variables.
|
||||
$form_state->setUserInput($request->request->all());
|
||||
$form_id = $form['#form_id'];
|
||||
|
||||
return new FileAjaxForm($form, $form_state, $form_id, $form['#build_id'], []);
|
||||
}
|
||||
|
||||
}
|
53
core/modules/system/src/Controller/Http4xxController.php
Normal file
53
core/modules/system/src/Controller/Http4xxController.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\Http4xxController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
|
||||
/**
|
||||
* Controller for default HTTP 4xx responses.
|
||||
*/
|
||||
class Http4xxController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The default 401 content.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing the message to display for 401 pages.
|
||||
*/
|
||||
public function on401() {
|
||||
return [
|
||||
'#markup' => $this->t('Please log in to access this page.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default 403 content.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing the message to display for 404 pages.
|
||||
*/
|
||||
public function on403() {
|
||||
return [
|
||||
'#markup' => $this->t('You are not authorized to access this page.'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default 404 content.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing the message to display for 404 pages.
|
||||
*/
|
||||
public function on404() {
|
||||
return [
|
||||
'#markup' => $this->t('The requested page could not be found.'),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
344
core/modules/system/src/Controller/SystemController.php
Normal file
344
core/modules/system/src/Controller/SystemController.php
Normal file
|
@ -0,0 +1,344 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\SystemController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Menu\MenuLinkTreeInterface;
|
||||
use Drupal\Core\Menu\MenuTreeParameters;
|
||||
use Drupal\Core\Theme\ThemeAccessCheck;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\system\SystemManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Returns responses for System routes.
|
||||
*/
|
||||
class SystemController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The entity query factory object.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Query\QueryFactory
|
||||
*/
|
||||
protected $queryFactory;
|
||||
|
||||
/**
|
||||
* System Manager Service.
|
||||
*
|
||||
* @var \Drupal\system\SystemManager
|
||||
*/
|
||||
protected $systemManager;
|
||||
|
||||
/**
|
||||
* The theme access checker service.
|
||||
*
|
||||
* @var \Drupal\Core\Theme\ThemeAccessCheck
|
||||
*/
|
||||
protected $themeAccess;
|
||||
|
||||
/**
|
||||
* The form builder service.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormBuilderInterface
|
||||
*/
|
||||
protected $formBuilder;
|
||||
|
||||
/**
|
||||
* The theme handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* The menu link tree service.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||
*/
|
||||
protected $menuLinkTree;
|
||||
|
||||
/**
|
||||
* Constructs a new SystemController.
|
||||
*
|
||||
* @param \Drupal\system\SystemManager $systemManager
|
||||
* System manager service.
|
||||
* @param \Drupal\Core\Entity\Query\QueryFactory $queryFactory
|
||||
* The entity query object.
|
||||
* @param \Drupal\Core\Theme\ThemeAccessCheck $theme_access
|
||||
* The theme access checker service.
|
||||
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
|
||||
* The form builder.
|
||||
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
||||
* The theme handler.
|
||||
* @param \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||
* The menu link tree service.
|
||||
*/
|
||||
public function __construct(SystemManager $systemManager, QueryFactory $queryFactory, ThemeAccessCheck $theme_access, FormBuilderInterface $form_builder, ThemeHandlerInterface $theme_handler, MenuLinkTreeInterface $menu_link_tree) {
|
||||
$this->systemManager = $systemManager;
|
||||
$this->queryFactory = $queryFactory;
|
||||
$this->themeAccess = $theme_access;
|
||||
$this->formBuilder = $form_builder;
|
||||
$this->themeHandler = $theme_handler;
|
||||
$this->menuLinkTree = $menu_link_tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('system.manager'),
|
||||
$container->get('entity.query'),
|
||||
$container->get('access_check.theme'),
|
||||
$container->get('form_builder'),
|
||||
$container->get('theme_handler'),
|
||||
$container->get('menu.link_tree')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the administration overview page.
|
||||
*
|
||||
* @param string $link_id
|
||||
* The ID of the administrative path link for which to display child links.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array of the administration overview page.
|
||||
*/
|
||||
public function overview($link_id) {
|
||||
// Check for status report errors.
|
||||
if ($this->systemManager->checkRequirements() && $this->currentUser()->hasPermission('administer site configuration')) {
|
||||
drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => $this->url('system.status'))), 'error');
|
||||
}
|
||||
// Load all menu links below it.
|
||||
$parameters = new MenuTreeParameters();
|
||||
$parameters->setRoot($link_id)->excludeRoot()->setTopLevelOnly()->onlyEnabledLinks();
|
||||
$tree = $this->menuLinkTree->load(NULL, $parameters);
|
||||
$manipulators = array(
|
||||
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||
);
|
||||
$tree = $this->menuLinkTree->transform($tree, $manipulators);
|
||||
$tree_access_cacheability = new CacheableMetadata();
|
||||
$blocks = array();
|
||||
foreach ($tree as $key => $element) {
|
||||
$tree_access_cacheability = $tree_access_cacheability->merge(CacheableMetadata::createFromObject($element->access));
|
||||
|
||||
// Only render accessible links.
|
||||
if (!$element->access->isAllowed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$link = $element->link;
|
||||
$block['title'] = $link->getTitle();
|
||||
$block['description'] = $link->getDescription();
|
||||
$block['content'] = array(
|
||||
'#theme' => 'admin_block_content',
|
||||
'#content' => $this->systemManager->getAdminBlock($link),
|
||||
);
|
||||
|
||||
if (!empty($block['content']['#content'])) {
|
||||
$blocks[$key] = $block;
|
||||
}
|
||||
}
|
||||
|
||||
if ($blocks) {
|
||||
ksort($blocks);
|
||||
$build = [
|
||||
'#theme' => 'admin_page',
|
||||
'#blocks' => $blocks,
|
||||
];
|
||||
$tree_access_cacheability->applyTo($build);
|
||||
return $build;
|
||||
}
|
||||
else {
|
||||
$build = [
|
||||
'#markup' => $this->t('You do not have any administrative items.'),
|
||||
];
|
||||
$tree_access_cacheability->applyTo($build);
|
||||
return $build;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the admin menu is in compact mode or not.
|
||||
*
|
||||
* @param string $mode
|
||||
* Valid values are 'on' and 'off'.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
*/
|
||||
public function compactPage($mode) {
|
||||
user_cookie_save(array('admin_compact_mode' => ($mode == 'on')));
|
||||
return $this->redirect('<front>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a single block from the administration menu as a page.
|
||||
*/
|
||||
public function systemAdminMenuBlockPage() {
|
||||
return $this->systemManager->getBlockContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a theme listing.
|
||||
*
|
||||
* @return string
|
||||
* An HTML string of the theme listing page.
|
||||
*
|
||||
* @todo Move into ThemeController.
|
||||
*/
|
||||
public function themesPage() {
|
||||
$config = $this->config('system.theme');
|
||||
// Get all available themes.
|
||||
$themes = $this->themeHandler->rebuildThemeData();
|
||||
uasort($themes, 'system_sort_modules_by_info_name');
|
||||
|
||||
$theme_default = $config->get('default');
|
||||
$theme_groups = array('installed' => array(), 'uninstalled' => array());
|
||||
$admin_theme = $config->get('admin');
|
||||
$admin_theme_options = array();
|
||||
|
||||
foreach ($themes as &$theme) {
|
||||
if (!empty($theme->info['hidden'])) {
|
||||
continue;
|
||||
}
|
||||
$theme->is_default = ($theme->getName() == $theme_default);
|
||||
$theme->is_admin = ($theme->getName() == $admin_theme || ($theme->is_default && $admin_theme == '0'));
|
||||
|
||||
// Identify theme screenshot.
|
||||
$theme->screenshot = NULL;
|
||||
// Create a list which includes the current theme and all its base themes.
|
||||
if (isset($themes[$theme->getName()]->base_themes)) {
|
||||
$theme_keys = array_keys($themes[$theme->getName()]->base_themes);
|
||||
$theme_keys[] = $theme->getName();
|
||||
}
|
||||
else {
|
||||
$theme_keys = array($theme->getName());
|
||||
}
|
||||
// Look for a screenshot in the current theme or in its closest ancestor.
|
||||
foreach (array_reverse($theme_keys) as $theme_key) {
|
||||
if (isset($themes[$theme_key]) && file_exists($themes[$theme_key]->info['screenshot'])) {
|
||||
$theme->screenshot = array(
|
||||
'uri' => $themes[$theme_key]->info['screenshot'],
|
||||
'alt' => $this->t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])),
|
||||
'title' => $this->t('Screenshot for !theme theme', array('!theme' => $theme->info['name'])),
|
||||
'attributes' => array('class' => array('screenshot')),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($theme->status)) {
|
||||
// Ensure this theme is compatible with this version of core.
|
||||
// Require the 'content' region to make sure the main page
|
||||
// content has a common place in all themes.
|
||||
$theme->incompatible_core = !isset($theme->info['core']) || ($theme->info['core'] != \DRUPAL::CORE_COMPATIBILITY) || !isset($theme->info['regions']['content']);
|
||||
$theme->incompatible_php = version_compare(phpversion(), $theme->info['php']) < 0;
|
||||
// Confirmed that the base theme is available.
|
||||
$theme->incompatible_base = isset($theme->info['base theme']) && !isset($themes[$theme->info['base theme']]);
|
||||
// Confirm that the theme engine is available.
|
||||
$theme->incompatible_engine = isset($theme->info['engine']) && !isset($theme->owner);
|
||||
}
|
||||
$theme->operations = array();
|
||||
if (!empty($theme->status) || !$theme->incompatible_core && !$theme->incompatible_php && !$theme->incompatible_base && !$theme->incompatible_engine) {
|
||||
// Create the operations links.
|
||||
$query['theme'] = $theme->getName();
|
||||
if ($this->themeAccess->checkAccess($theme->getName())) {
|
||||
$theme->operations[] = array(
|
||||
'title' => $this->t('Settings'),
|
||||
'url' => Url::fromRoute('system.theme_settings_theme', ['theme' => $theme->getName()]),
|
||||
'attributes' => array('title' => $this->t('Settings for !theme theme', array('!theme' => $theme->info['name']))),
|
||||
);
|
||||
}
|
||||
if (!empty($theme->status)) {
|
||||
if (!$theme->is_default) {
|
||||
$theme_uninstallable = TRUE;
|
||||
if ($theme->getName() == $admin_theme) {
|
||||
$theme_uninstallable = FALSE;
|
||||
}
|
||||
// Check it isn't the base of theme of an installed theme.
|
||||
foreach ($theme->required_by as $themename => $dependency) {
|
||||
if (!empty($themes[$themename]->status)) {
|
||||
$theme_uninstallable = FALSE;
|
||||
}
|
||||
}
|
||||
if ($theme_uninstallable) {
|
||||
$theme->operations[] = array(
|
||||
'title' => $this->t('Uninstall'),
|
||||
'url' => Url::fromRoute('system.theme_uninstall'),
|
||||
'query' => $query,
|
||||
'attributes' => array('title' => $this->t('Uninstall !theme theme', array('!theme' => $theme->info['name']))),
|
||||
);
|
||||
}
|
||||
$theme->operations[] = array(
|
||||
'title' => $this->t('Set as default'),
|
||||
'url' => Url::fromRoute('system.theme_set_default'),
|
||||
'query' => $query,
|
||||
'attributes' => array('title' => $this->t('Set !theme as default theme', array('!theme' => $theme->info['name']))),
|
||||
);
|
||||
}
|
||||
$admin_theme_options[$theme->getName()] = $theme->info['name'];
|
||||
}
|
||||
else {
|
||||
$theme->operations[] = array(
|
||||
'title' => $this->t('Install'),
|
||||
'url' => Url::fromRoute('system.theme_install'),
|
||||
'query' => $query,
|
||||
'attributes' => array('title' => $this->t('Install !theme theme', array('!theme' => $theme->info['name']))),
|
||||
);
|
||||
$theme->operations[] = array(
|
||||
'title' => $this->t('Install and set as default'),
|
||||
'url' => Url::fromRoute('system.theme_set_default'),
|
||||
'query' => $query,
|
||||
'attributes' => array('title' => $this->t('Install !theme as default theme', array('!theme' => $theme->info['name']))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add notes to default and administration theme.
|
||||
$theme->notes = array();
|
||||
if ($theme->is_default) {
|
||||
$theme->notes[] = $this->t('default theme');
|
||||
}
|
||||
if ($theme->is_admin) {
|
||||
$theme->notes[] = $this->t('admin theme');
|
||||
}
|
||||
|
||||
// Sort installed and uninstalled themes into their own groups.
|
||||
$theme_groups[$theme->status ? 'installed' : 'uninstalled'][] = $theme;
|
||||
}
|
||||
|
||||
// There are two possible theme groups.
|
||||
$theme_group_titles = array(
|
||||
'installed' => $this->formatPlural(count($theme_groups['installed']), 'Installed theme', 'Installed themes'),
|
||||
);
|
||||
if (!empty($theme_groups['uninstalled'])) {
|
||||
$theme_group_titles['uninstalled'] = $this->formatPlural(count($theme_groups['uninstalled']), 'Uninstalled theme', 'Uninstalled themes');
|
||||
}
|
||||
|
||||
uasort($theme_groups['installed'], 'system_sort_themes');
|
||||
$this->moduleHandler()->alter('system_themes_page', $theme_groups);
|
||||
|
||||
$build = array();
|
||||
$build[] = array(
|
||||
'#theme' => 'system_themes_page',
|
||||
'#theme_groups' => $theme_groups,
|
||||
'#theme_group_titles' => $theme_group_titles,
|
||||
);
|
||||
$build[] = $this->formBuilder->getForm('Drupal\system\Form\ThemeAdminForm', $admin_theme_options);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
75
core/modules/system/src/Controller/SystemInfoController.php
Normal file
75
core/modules/system/src/Controller/SystemInfoController.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\SystemInfoController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\system\SystemManager;
|
||||
|
||||
/**
|
||||
* Returns responses for System Info routes.
|
||||
*/
|
||||
class SystemInfoController implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* System Manager Service.
|
||||
*
|
||||
* @var \Drupal\system\SystemManager
|
||||
*/
|
||||
protected $systemManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('system.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a SystemInfoController object.
|
||||
*
|
||||
* @param \Drupal\system\SystemManager $systemManager
|
||||
* System manager service.
|
||||
*/
|
||||
public function __construct(SystemManager $systemManager) {
|
||||
$this->systemManager = $systemManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the site status report.
|
||||
*
|
||||
* @return string
|
||||
* The current status of the Drupal installation.
|
||||
*/
|
||||
public function status() {
|
||||
$requirements = $this->systemManager->listRequirements();
|
||||
return array('#theme' => 'status_report', '#requirements' => $requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contents of phpinfo().
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* A response object to be sent to the client.
|
||||
*/
|
||||
public function php() {
|
||||
if (function_exists('phpinfo')) {
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$output = ob_get_clean();
|
||||
}
|
||||
else {
|
||||
$output = t('The phpinfo() function has been disabled for security reasons. For more information, visit <a href="@phpinfo">Enabling and disabling phpinfo()</a> handbook page.', array('@phpinfo' => 'https://www.drupal.org/node/243993'));
|
||||
}
|
||||
return new Response($output);
|
||||
}
|
||||
|
||||
}
|
212
core/modules/system/src/Controller/ThemeController.php
Normal file
212
core/modules/system/src/Controller/ThemeController.php
Normal file
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\ThemeController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Config\PreExistingConfigException;
|
||||
use Drupal\Core\Config\UnmetDependenciesException;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||
use Drupal\Core\Routing\RouteBuilderInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* Controller for theme handling.
|
||||
*/
|
||||
class ThemeController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The theme handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* The route builder service.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteBuilderInterface
|
||||
*/
|
||||
protected $routeBuilder;
|
||||
|
||||
/**
|
||||
* Constructs a new ThemeController.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
||||
* The theme handler.
|
||||
* @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
|
||||
* The route builder.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
*/
|
||||
public function __construct(ThemeHandlerInterface $theme_handler, RouteBuilderInterface $route_builder, ConfigFactoryInterface $config_factory) {
|
||||
$this->themeHandler = $theme_handler;
|
||||
$this->configFactory = $config_factory;
|
||||
$this->routeBuilder = $route_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('theme_handler'),
|
||||
$container->get('router.builder'),
|
||||
$container->get('config.factory')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls a theme.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* A request object containing a theme name and a valid token.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* Redirects back to the appearance admin page.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Throws access denied when no theme or token is set in the request or when
|
||||
* the token is invalid.
|
||||
*/
|
||||
public function uninstall(Request $request) {
|
||||
$theme = $request->get('theme');
|
||||
$config = $this->config('system.theme');
|
||||
|
||||
if (isset($theme)) {
|
||||
// Get current list of themes.
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
|
||||
// Check if the specified theme is one recognized by the system.
|
||||
if (!empty($themes[$theme])) {
|
||||
// Do not uninstall the default or admin theme.
|
||||
if ($theme === $config->get('default') || $theme === $config->get('admin')) {
|
||||
drupal_set_message($this->t('%theme is the default theme and cannot be uninstalled.', array('%theme' => $themes[$theme]->info['name'])), 'error');
|
||||
}
|
||||
else {
|
||||
$this->themeHandler->uninstall(array($theme));
|
||||
drupal_set_message($this->t('The %theme theme has been uninstalled.', array('%theme' => $themes[$theme]->info['name'])));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
}
|
||||
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a theme.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* A request object containing a theme name and a valid token.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* Redirects back to the appearance admin page.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Throws access denied when no theme or token is set in the request or when
|
||||
* the token is invalid.
|
||||
*/
|
||||
public function install(Request $request) {
|
||||
$theme = $request->get('theme');
|
||||
|
||||
if (isset($theme)) {
|
||||
try {
|
||||
if ($this->themeHandler->install(array($theme))) {
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
drupal_set_message($this->t('The %theme theme has been installed.', array('%theme' => $themes[$theme]->info['name'])));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
|
||||
}
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->formatPlural(
|
||||
count($config_objects),
|
||||
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||
array(
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $theme,
|
||||
)),
|
||||
'error'
|
||||
);
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message($e->getTranslatedMessage($this->getStringTranslation(), $theme), 'error');
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
}
|
||||
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default theme.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* A request object containing a theme name.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* Redirects back to the appearance admin page.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Throws access denied when no theme is set in the request.
|
||||
*/
|
||||
public function setDefaultTheme(Request $request) {
|
||||
$config = $this->configFactory->getEditable('system.theme');
|
||||
$theme = $request->query->get('theme');
|
||||
|
||||
if (isset($theme)) {
|
||||
// Get current list of themes.
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
|
||||
// Check if the specified theme is one recognized by the system.
|
||||
// Or try to install the theme.
|
||||
if (isset($themes[$theme]) || $this->themeHandler->install(array($theme))) {
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
|
||||
// Set the default theme.
|
||||
$config->set('default', $theme)->save();
|
||||
|
||||
$this->routeBuilder->setRebuildNeeded();
|
||||
|
||||
// The status message depends on whether an admin theme is currently in
|
||||
// use: a value of 0 means the admin theme is set to be the default
|
||||
// theme.
|
||||
$admin_theme = $config->get('admin');
|
||||
if ($admin_theme != 0 && $admin_theme != $theme) {
|
||||
drupal_set_message($this->t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', array(
|
||||
'%admin_theme' => $themes[$admin_theme]->info['name'],
|
||||
'%selected_theme' => $themes[$theme]->info['name'],
|
||||
)));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('%theme is now the default theme.', array('%theme' => $themes[$theme]->info['name'])));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
|
||||
}
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
}
|
43
core/modules/system/src/Controller/TimezoneController.php
Normal file
43
core/modules/system/src/Controller/TimezoneController.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Controller\TimezoneController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
||||
/**
|
||||
* Provides a callback for finding out a timezone name.
|
||||
*/
|
||||
class TimezoneController {
|
||||
|
||||
/**
|
||||
* Retrieve a JSON object containing a time zone name given a timezone
|
||||
* abbreviation.
|
||||
*
|
||||
* @param string $abbreviation
|
||||
* Time zone abbreviation.
|
||||
* @param int $offset
|
||||
* Offset from GMT in seconds. Defaults to -1 which means that first found
|
||||
* time zone corresponding to abbr is returned. Otherwise exact offset is
|
||||
* searched and only if not found then the first time zone with any offset
|
||||
* is returned.
|
||||
* @param null|bool $is_daylight_saving_time
|
||||
* Daylight saving time indicator. If abbr does not exist then the time
|
||||
* zone is searched solely by offset and isdst.
|
||||
*
|
||||
* @return JsonResponse
|
||||
* The timezone name in JsonResponse object.
|
||||
*/
|
||||
public function getTimezone($abbreviation = '', $offset = -1, $is_daylight_saving_time = NULL) {
|
||||
// An abbreviation of "0" passed in the callback arguments should be
|
||||
// interpreted as the empty string.
|
||||
$abbreviation = $abbreviation ? $abbreviation : '';
|
||||
$timezone = timezone_name_from_abbr($abbreviation, intval($offset), $is_daylight_saving_time);
|
||||
return new JsonResponse($timezone);
|
||||
}
|
||||
|
||||
}
|
75
core/modules/system/src/CronController.php
Normal file
75
core/modules/system/src/CronController.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\CronController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\CronInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* Controller for Cron handling.
|
||||
*/
|
||||
class CronController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The cron service.
|
||||
*
|
||||
* @var \Drupal\Core\CronInterface
|
||||
*/
|
||||
protected $cron;
|
||||
|
||||
/**
|
||||
* Constructs a CronController object.
|
||||
*
|
||||
* @param \Drupal\Core\CronInterface $cron
|
||||
* The cron service.
|
||||
*/
|
||||
public function __construct(CronInterface $cron) {
|
||||
$this->cron = $cron;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('cron'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run Cron once.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* A Symfony response object.
|
||||
*/
|
||||
public function run() {
|
||||
$this->cron->run();
|
||||
|
||||
// HTTP 204 is "No content", meaning "I did what you asked and we're done."
|
||||
return new Response('', 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run cron manually.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* A Symfony direct response object.
|
||||
*/
|
||||
public function runManually() {
|
||||
if ($this->cron->run()) {
|
||||
drupal_set_message($this->t('Cron ran successfully.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('Cron run failed.'), 'error');
|
||||
}
|
||||
|
||||
return $this->redirect('system.status');
|
||||
}
|
||||
|
||||
}
|
43
core/modules/system/src/DateFormatAccessControlHandler.php
Normal file
43
core/modules/system/src/DateFormatAccessControlHandler.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\DateFormatAccessControlHandler.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the date format entity type.
|
||||
*
|
||||
* @see \Drupal\system\Entity\DateFormat
|
||||
*/
|
||||
class DateFormatAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
|
||||
// There are no restrictions on viewing a date format.
|
||||
if ($operation == 'view') {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
// Locked date formats cannot be updated or deleted.
|
||||
elseif (in_array($operation, array('update', 'delete'))) {
|
||||
if ($entity->isLocked()) {
|
||||
return AccessResult::forbidden()->cacheUntilEntityChanges($entity);
|
||||
}
|
||||
else {
|
||||
return parent::checkAccess($entity, $operation, $langcode, $account)->cacheUntilEntityChanges($entity);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::checkAccess($entity, $operation, $langcode, $account);
|
||||
}
|
||||
|
||||
}
|
83
core/modules/system/src/DateFormatListBuilder.php
Normal file
83
core/modules/system/src/DateFormatListBuilder.php
Normal file
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\DateFormatListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of date format entities.
|
||||
*
|
||||
* @see \Drupal\system\Entity\DateFormat
|
||||
*/
|
||||
class DateFormatListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* Constructs a new DateFormatListBuilder object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type definition.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The entity storage class.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter service.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage, DateFormatter $date_formatter) {
|
||||
parent::__construct($entity_type, $storage);
|
||||
|
||||
$this->dateFormatter = $date_formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
|
||||
return new static(
|
||||
$entity_type,
|
||||
$container->get('entity.manager')->getStorage($entity_type->id()),
|
||||
$container->get('date.formatter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['id'] = t('Machine name');
|
||||
$header['label'] = t('Name');
|
||||
$header['pattern'] = t('Pattern');
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
if ($entity->isLocked()) {
|
||||
$row['id'] = $this->t('@entity_id (locked)', array('@entity_id' => $entity->id()));
|
||||
}
|
||||
else {
|
||||
$row['id'] = $entity->id();
|
||||
}
|
||||
$row['label'] = $this->getLabel($entity);
|
||||
$row['pattern'] = $this->dateFormatter->format(REQUEST_TIME, $entity->id());
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
}
|
158
core/modules/system/src/Entity/Action.php
Normal file
158
core/modules/system/src/Entity/Action.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Entity\Action.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
|
||||
use Drupal\system\ActionConfigEntityInterface;
|
||||
use Drupal\Core\Action\ActionPluginCollection;
|
||||
use Drupal\Component\Plugin\ConfigurablePluginInterface;
|
||||
|
||||
/**
|
||||
* Defines the configured action entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "action",
|
||||
* label = @Translation("Action"),
|
||||
* admin_permission = "administer actions",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label"
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "label",
|
||||
* "type",
|
||||
* "plugin",
|
||||
* "configuration",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Action extends ConfigEntityBase implements ActionConfigEntityInterface, EntityWithPluginCollectionInterface {
|
||||
|
||||
/**
|
||||
* The name (plugin ID) of the action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The label of the action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The action type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* The configuration of the action.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $configuration = array();
|
||||
|
||||
/**
|
||||
* The plugin ID of the action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $plugin;
|
||||
|
||||
/**
|
||||
* The plugin collection that stores action plugins.
|
||||
*
|
||||
* @var \Drupal\Core\Action\ActionPluginCollection
|
||||
*/
|
||||
protected $pluginCollection;
|
||||
|
||||
/**
|
||||
* Encapsulates the creation of the action's LazyPluginCollection.
|
||||
*
|
||||
* @return \Drupal\Component\Plugin\LazyPluginCollection
|
||||
* The action's plugin collection.
|
||||
*/
|
||||
protected function getPluginCollection() {
|
||||
if (!$this->pluginCollection) {
|
||||
$this->pluginCollection = new ActionPluginCollection(\Drupal::service('plugin.manager.action'), $this->plugin, $this->configuration);
|
||||
}
|
||||
return $this->pluginCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPluginCollections() {
|
||||
return array('configuration' => $this->getPluginCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPlugin() {
|
||||
return $this->getPluginCollection()->get($this->plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPlugin($plugin_id) {
|
||||
$this->plugin = $plugin_id;
|
||||
$this->getPluginCollection()->addInstanceId($plugin_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPluginDefinition() {
|
||||
return $this->getPlugin()->getPluginDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(array $entities) {
|
||||
return $this->getPlugin()->executeMultiple($entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isConfigurable() {
|
||||
return $this->getPlugin() instanceof ConfigurablePluginInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function sort(ConfigEntityInterface $a, ConfigEntityInterface $b) {
|
||||
/** @var \Drupal\system\ActionConfigEntityInterface $a */
|
||||
/** @var \Drupal\system\ActionConfigEntityInterface $b */
|
||||
$a_type = $a->getType();
|
||||
$b_type = $b->getType();
|
||||
if ($a_type != $b_type) {
|
||||
return strnatcasecmp($a_type, $b_type);
|
||||
}
|
||||
return parent::sort($a, $b);
|
||||
}
|
||||
|
||||
}
|
80
core/modules/system/src/Entity/Menu.php
Normal file
80
core/modules/system/src/Entity/Menu.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Entity\Menu.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\system\MenuInterface;
|
||||
|
||||
/**
|
||||
* Defines the Menu configuration entity class.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "menu",
|
||||
* label = @Translation("Menu"),
|
||||
* handlers = {
|
||||
* "access" = "Drupal\system\MenuAccessControlHandler"
|
||||
* },
|
||||
* admin_permission = "administer menu",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label"
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "label",
|
||||
* "description",
|
||||
* "locked",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Menu extends ConfigEntityBase implements MenuInterface {
|
||||
|
||||
/**
|
||||
* The menu machine name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The human-readable name of the menu entity.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The menu description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* The locked status of this menu.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $locked = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isLocked() {
|
||||
return (bool) $this->locked;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\EventSubscriber\AdminRouteSubscriber.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Routing\RouteSubscriberBase;
|
||||
use Drupal\Core\Routing\RoutingEvents;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* Adds the _admin_route option to each admin route.
|
||||
*/
|
||||
class AdminRouteSubscriber extends RouteSubscriberBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function alterRoutes(RouteCollection $collection) {
|
||||
foreach ($collection->all() as $route) {
|
||||
if (strpos($route->getPath(), '/admin') === 0 && !$route->hasOption('_admin_route')) {
|
||||
$route->setOption('_admin_route', TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events = parent::getSubscribedEvents();
|
||||
|
||||
// Use a higher priority than \Drupal\field_ui\Routing\RouteSubscriber or
|
||||
// \Drupal\views\EventSubscriber\RouteSubscriber to ensure we add the
|
||||
// option to their routes.
|
||||
// @todo https://www.drupal.org/node/2158571
|
||||
$events[RoutingEvents::ALTER] = array('onAlterRoutes', -200);
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
92
core/modules/system/src/EventSubscriber/AutomaticCron.php
Normal file
92
core/modules/system/src/EventSubscriber/AutomaticCron.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\EventSubscriber\AutomaticCron.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\CronInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* A subscriber running cron when a request terminates.
|
||||
*/
|
||||
class AutomaticCron implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The cron service.
|
||||
*
|
||||
* @var \Drupal\Core\CronInterface
|
||||
*/
|
||||
protected $cron;
|
||||
|
||||
/**
|
||||
* The cron configuration.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The state key value store.
|
||||
*
|
||||
* Drupal\Core\State\StateInterface;
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Construct a new automatic cron runner.
|
||||
*
|
||||
* @param \Drupal\Core\CronInterface $cron
|
||||
* The cron service.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Drupal\Core\State\StateInterface $state
|
||||
* The state key value store.
|
||||
*/
|
||||
public function __construct(CronInterface $cron, ConfigFactoryInterface $config_factory, StateInterface $state) {
|
||||
$this->cron = $cron;
|
||||
$this->config = $config_factory->get('system.cron');
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the automated cron if enabled.
|
||||
*
|
||||
* @param Symfony\Component\HttpKernel\Event\PostResponseEvent $event
|
||||
* The Event to process.
|
||||
*/
|
||||
public function onTerminate(PostResponseEvent $event) {
|
||||
// If the site is not fully installed, suppress the automated cron run.
|
||||
// Otherwise it could be triggered prematurely by Ajax requests during
|
||||
// installation.
|
||||
if ($this->state->get('install_task') == 'done') {
|
||||
$threshold = $this->config->get('threshold.autorun');
|
||||
if ($threshold > 0) {
|
||||
$cron_next = $this->state->get('system.cron_last', 0) + $threshold;
|
||||
if (REQUEST_TIME > $cron_next) {
|
||||
$this->cron->run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the methods in this class that should be listeners.
|
||||
*
|
||||
* @return array
|
||||
* An array of event listener definitions.
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[KernelEvents::TERMINATE][] = array('onTerminate', 100);
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
86
core/modules/system/src/EventSubscriber/ConfigCacheTag.php
Normal file
86
core/modules/system/src/EventSubscriber/ConfigCacheTag.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\EventSubscriber\ConfigCacheTag.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
|
||||
use Drupal\Core\Config\ConfigCrudEvent;
|
||||
use Drupal\Core\Config\ConfigEvents;
|
||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* A subscriber invalidating cache tags when system config objects are saved.
|
||||
*/
|
||||
class ConfigCacheTag implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The theme handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* The cache tags invalidator.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
|
||||
*/
|
||||
protected $cacheTagsInvalidator;
|
||||
|
||||
/**
|
||||
* Constructs a ConfigCacheTag object.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
||||
* The theme handler.
|
||||
* @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
|
||||
* The cache tags invalidator.
|
||||
*/
|
||||
public function __construct(ThemeHandlerInterface $theme_handler, CacheTagsInvalidatorInterface $cache_tags_invalidator) {
|
||||
$this->themeHandler = $theme_handler;
|
||||
$this->cacheTagsInvalidator = $cache_tags_invalidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate cache tags when particular system config objects are saved.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigCrudEvent $event
|
||||
* The Event to process.
|
||||
*/
|
||||
public function onSave(ConfigCrudEvent $event) {
|
||||
// Changing the site settings may mean a different route is selected for the
|
||||
// front page. Additionally a change to the site name or similar must
|
||||
// invalidate the render cache since this could be used anywhere.
|
||||
if ($event->getConfig()->getName() === 'system.site') {
|
||||
$this->cacheTagsInvalidator->invalidateTags(['route_match', 'rendered']);
|
||||
}
|
||||
|
||||
// Global theme settings.
|
||||
if ($event->getConfig()->getName() === 'system.theme.global') {
|
||||
$this->cacheTagsInvalidator->invalidateTags(['rendered']);
|
||||
}
|
||||
|
||||
// Theme-specific settings, check if this matches a theme settings
|
||||
// configuration object, in that case, clear the rendered cache tag.
|
||||
foreach (array_keys($this->themeHandler->listInfo()) as $theme_name) {
|
||||
if ($theme_name == $event->getConfig()->getName()) {
|
||||
$this->cacheTagsInvalidator->invalidateTags(['rendered']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[ConfigEvents::SAVE][] = ['onSave'];
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
122
core/modules/system/src/FileAjaxForm.php
Normal file
122
core/modules/system/src/FileAjaxForm.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\FileAjaxForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Wrapper for Ajax forms data and commands, avoiding a multi-return-value tuple.
|
||||
*
|
||||
* @ingroup ajax
|
||||
*/
|
||||
class FileAjaxForm {
|
||||
|
||||
/**
|
||||
* The form to cache.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
/**
|
||||
* The form state.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormStateInterface
|
||||
*/
|
||||
protected $formState;
|
||||
|
||||
/**
|
||||
* The unique form ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $formId;
|
||||
|
||||
/**
|
||||
* The unique form build ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $formBuildId;
|
||||
|
||||
/**
|
||||
* The array of ajax commands.
|
||||
*
|
||||
* @var \Drupal\Core\Ajax\CommandInterface[]
|
||||
*/
|
||||
protected $commands;
|
||||
|
||||
/**
|
||||
* Constructs a FileAjaxForm object.
|
||||
*
|
||||
* @param array $form
|
||||
* The form definition.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The form state.
|
||||
* @param \Drupal\Core\Ajax\string|string $form_id
|
||||
* The unique form ID.
|
||||
* @param \Drupal\Core\Ajax\string|string $form_build_id
|
||||
* The unique form build ID.
|
||||
* @param \Drupal\Core\Ajax\CommandInterface[] $commands
|
||||
* The ajax commands.
|
||||
*/
|
||||
public function __construct(array $form, FormStateInterface $form_state, $form_id, $form_build_id, array $commands) {
|
||||
$this->form = $form;
|
||||
$this->formState = $form_state;
|
||||
$this->formId = $form_id;
|
||||
$this->formBuildId = $form_build_id;
|
||||
$this->commands = $commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all AJAX commands.
|
||||
*
|
||||
* @return \Drupal\Core\Ajax\CommandInterface[]
|
||||
* Returns all previously added AJAX commands.
|
||||
*/
|
||||
public function getCommands() {
|
||||
return $this->commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form definition.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getForm() {
|
||||
return $this->form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique form build ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFormBuildId() {
|
||||
return $this->formBuildId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the unique form ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFormId() {
|
||||
return $this->formId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the form state.
|
||||
*
|
||||
* @return \Drupal\Core\Form\FormStateInterface
|
||||
*/
|
||||
public function getFormState() {
|
||||
return $this->formState;
|
||||
}
|
||||
|
||||
}
|
71
core/modules/system/src/FileDownloadController.php
Normal file
71
core/modules/system/src/FileDownloadController.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\FileDownloadController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
/**
|
||||
* System file controller.
|
||||
*/
|
||||
class FileDownloadController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Handles private file transfers.
|
||||
*
|
||||
* Call modules that implement hook_file_download() to find out if a file is
|
||||
* accessible and what headers it should be transferred with. If one or more
|
||||
* modules returned headers the download will start with the returned headers.
|
||||
* If a module returns -1 an AccessDeniedHttpException will be thrown. If the
|
||||
* file exists but no modules responded an AccessDeniedHttpException will be
|
||||
* thrown. If the file does not exist a NotFoundHttpException will be thrown.
|
||||
*
|
||||
* @see hook_file_download()
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object.
|
||||
* @param string $scheme
|
||||
* The file scheme, defaults to 'private'.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
* Thrown when the requested file does not exist.
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Thrown when the user does not have access to the file.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
* The transferred file as response.
|
||||
*/
|
||||
public function download(Request $request, $scheme = 'private') {
|
||||
$target = $request->query->get('file');
|
||||
// Merge remaining path arguments into relative file path.
|
||||
$uri = $scheme . '://' . $target;
|
||||
|
||||
if (file_stream_wrapper_valid_scheme($scheme) && file_exists($uri)) {
|
||||
// Let other modules provide headers and controls access to the file.
|
||||
$headers = $this->moduleHandler()->invokeAll('file_download', array($uri));
|
||||
|
||||
foreach ($headers as $result) {
|
||||
if ($result == -1) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
}
|
||||
|
||||
if (count($headers)) {
|
||||
return new BinaryFileResponse($uri, 200, $headers);
|
||||
}
|
||||
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
}
|
156
core/modules/system/src/Form/CronForm.php
Normal file
156
core/modules/system/src/Form/CronForm.php
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\CronForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\CronInterface;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
|
||||
/**
|
||||
* Configure cron settings for this site.
|
||||
*/
|
||||
class CronForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* Stores the state storage service.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* The cron service.
|
||||
*
|
||||
* @var \Drupal\Core\CronInterface
|
||||
*/
|
||||
protected $cron;
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* Constructs a CronForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\State\StateInterface $state
|
||||
* The state key value store.
|
||||
* @param \Drupal\Core\CronInterface $cron
|
||||
* The cron service.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter service.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state, CronInterface $cron, DateFormatter $date_formatter) {
|
||||
parent::__construct($config_factory);
|
||||
$this->state = $state;
|
||||
$this->cron = $cron;
|
||||
$this->dateFormatter = $date_formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('state'),
|
||||
$container->get('cron'),
|
||||
$container->get('date.formatter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_cron_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.cron'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('system.cron');
|
||||
|
||||
$form['description'] = array(
|
||||
'#markup' => '<p>' . t('Cron takes care of running periodic tasks like checking for updates and indexing content for search.') . '</p>',
|
||||
);
|
||||
$form['run'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Run cron'),
|
||||
'#submit' => array('::submitCron'),
|
||||
);
|
||||
$status = '<p>' . $this->t('Last run: %time ago.', array('%time' => $this->dateFormatter->formatTimeDiffSince($this->state->get('system.cron_last')))) . '</p>';
|
||||
$form['status'] = array(
|
||||
'#markup' => $status,
|
||||
);
|
||||
|
||||
$form['cron_url'] = array(
|
||||
'#markup' => '<p>' . t('To run cron from outside the site, go to <a href="!cron">!cron</a>', array('!cron' => $this->url('system.cron', array('key' => $this->state->get('system.cron_key')), array('absolute' => TRUE)))) . '</p>',
|
||||
);
|
||||
|
||||
$form['cron'] = array(
|
||||
'#title' => t('Cron settings'),
|
||||
'#type' => 'details',
|
||||
'#open' => TRUE,
|
||||
);
|
||||
$options = array(3600, 10800, 21600, 43200, 86400, 604800);
|
||||
$form['cron']['cron_safe_threshold'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Run cron every'),
|
||||
'#description' => t('More information about setting up scheduled tasks can be found by <a href="@url">reading the cron tutorial on drupal.org</a>.', array('@url' => 'https://www.drupal.org/cron')),
|
||||
'#default_value' => $config->get('threshold.autorun'),
|
||||
'#options' => array(0 => t('Never')) + array_map(array($this->dateFormatter, 'formatInterval'), array_combine($options, $options)),
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.cron')
|
||||
->set('threshold.autorun', $form_state->getValue('cron_safe_threshold'))
|
||||
->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs cron and reloads the page.
|
||||
*/
|
||||
public function submitCron(array &$form, FormStateInterface $form_state) {
|
||||
// Run cron manually from Cron form.
|
||||
if ($this->cron->run()) {
|
||||
drupal_set_message(t('Cron run successfully.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Cron run failed.'), 'error');
|
||||
}
|
||||
|
||||
return new RedirectResponse($this->url('system.cron_settings', array(), array('absolute' => TRUE)));
|
||||
}
|
||||
|
||||
}
|
26
core/modules/system/src/Form/DateFormatAddForm.php
Normal file
26
core/modules/system/src/Form/DateFormatAddForm.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\DateFormatAddForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for adding a date format.
|
||||
*/
|
||||
class DateFormatAddForm extends DateFormatFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$actions = parent::actions($form, $form_state);
|
||||
$actions['submit']['#value'] = t('Add format');
|
||||
return $actions;
|
||||
}
|
||||
|
||||
}
|
55
core/modules/system/src/Form/DateFormatDeleteForm.php
Normal file
55
core/modules/system/src/Form/DateFormatDeleteForm.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\DateFormatDeleteForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Entity\EntityDeleteForm;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Builds a form to delete a date format.
|
||||
*/
|
||||
class DateFormatDeleteForm extends EntityDeleteForm {
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* Constructs an DateFormatDeleteForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter service.
|
||||
*/
|
||||
public function __construct(DateFormatter $date_formatter) {
|
||||
$this->dateFormatter = $date_formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('date.formatter')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return t('Are you sure you want to delete the format %name : %format?', array(
|
||||
'%name' => $this->entity->label(),
|
||||
'%format' => $this->dateFormatter->format(REQUEST_TIME, $this->entity->id()))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
40
core/modules/system/src/Form/DateFormatEditForm.php
Normal file
40
core/modules/system/src/Form/DateFormatEditForm.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\DateFormatEditForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for editing a date format.
|
||||
*/
|
||||
class DateFormatEditForm extends DateFormatFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::form($form, $form_state);
|
||||
|
||||
$now = t('Displayed as %date', array('%date' => $this->dateFormatter->format(REQUEST_TIME, $this->entity->id())));
|
||||
$form['date_format_pattern']['#field_suffix'] = ' <small data-drupal-date-formatter="preview">' . $now . '</small>';
|
||||
$form['date_format_pattern']['#default_value'] = $this->entity->getPattern();
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$actions = parent::actions($form, $form_state);
|
||||
$actions['submit']['#value'] = t('Save format');
|
||||
unset($actions['delete']);
|
||||
return $actions;
|
||||
}
|
||||
|
||||
}
|
166
core/modules/system/src/Form/DateFormatFormBase.php
Normal file
166
core/modules/system/src/Form/DateFormatFormBase.php
Normal file
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\DateFormatFormBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\Datetime\DrupalDateTime;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
|
||||
/**
|
||||
* Provides a base form for date formats.
|
||||
*/
|
||||
abstract class DateFormatFormBase extends EntityForm {
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* The date format storage.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
|
||||
*/
|
||||
protected $dateFormatStorage;
|
||||
|
||||
/**
|
||||
* Constructs a new date format form.
|
||||
*
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date service.
|
||||
* @param \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $date_format_storage
|
||||
* The date format storage.
|
||||
*/
|
||||
public function __construct(DateFormatter $date_formatter, ConfigEntityStorageInterface $date_format_storage) {
|
||||
$date = new DrupalDateTime();
|
||||
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->dateFormatStorage = $date_format_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('date.formatter'),
|
||||
$container->get('entity.manager')->getStorage('date_format')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for an existing date format.
|
||||
*
|
||||
* @param string|int $entity_id
|
||||
* The entity ID.
|
||||
* @param array $element
|
||||
* The form element.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if this format already exists, FALSE otherwise.
|
||||
*/
|
||||
public function exists($entity_id, array $element) {
|
||||
return (bool) $this->dateFormatStorage
|
||||
->getQuery()
|
||||
->condition('id', $element['#field_prefix'] . $entity_id)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => 'Name',
|
||||
'#maxlength' => 100,
|
||||
'#description' => t('Name of the date format'),
|
||||
'#default_value' => $this->entity->label(),
|
||||
);
|
||||
|
||||
$form['id'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
|
||||
'#disabled' => !$this->entity->isNew(),
|
||||
'#default_value' => $this->entity->id(),
|
||||
'#machine_name' => array(
|
||||
'exists' => array($this, 'exists'),
|
||||
'replace_pattern' =>'([^a-z0-9_]+)|(^custom$)',
|
||||
'error' => $this->t('The machine-readable name must be unique, and can only contain lowercase letters, numbers, and underscores. Additionally, it can not be the reserved word "custom".'),
|
||||
),
|
||||
);
|
||||
$form['date_format_pattern'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Format string'),
|
||||
'#maxlength' => 100,
|
||||
'#description' => $this->t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://php.net/manual/function.date.php')),
|
||||
'#required' => TRUE,
|
||||
'#attributes' => [
|
||||
'data-drupal-date-formatter' => 'source',
|
||||
],
|
||||
'#field_suffix' => ' <small class="js-hide" data-drupal-date-formatter="preview">' . $this->t('Displayed as %date_format', ['%date_format' => '']) . '</small>',
|
||||
);
|
||||
|
||||
$form['langcode'] = array(
|
||||
'#type' => 'language_select',
|
||||
'#title' => t('Language'),
|
||||
'#languages' => LanguageInterface::STATE_ALL,
|
||||
'#default_value' => $this->entity->language()->getId(),
|
||||
);
|
||||
$form['#attached']['drupalSettings']['dateFormats'] = $this->dateFormatter->getSampleDateFormats();
|
||||
$form['#attached']['library'][] = 'system/drupal.system.date';
|
||||
return parent::form($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(array $form, FormStateInterface $form_state) {
|
||||
parent::validate($form, $form_state);
|
||||
|
||||
// The machine name field should already check to see if the requested
|
||||
// machine name is available. Regardless of machine_name or human readable
|
||||
// name, check to see if the provided pattern exists.
|
||||
$pattern = trim($form_state->getValue('date_format_pattern'));
|
||||
foreach ($this->dateFormatStorage->loadMultiple() as $format) {
|
||||
if ($format->getPattern() == $pattern && ($this->entity->isNew() || $format->id() != $this->entity->id())) {
|
||||
$form_state->setErrorByName('date_format_pattern', $this->t('This format already exists. Enter a unique format string.'));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$form_state->setValue('pattern', trim($form_state->getValue('date_format_pattern')));
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$status = $this->entity->save();
|
||||
if ($status == SAVED_UPDATED) {
|
||||
drupal_set_message(t('Custom date format updated.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Custom date format added.'));
|
||||
}
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('collection'));
|
||||
}
|
||||
|
||||
}
|
151
core/modules/system/src/Form/FileSystemForm.php
Normal file
151
core/modules/system/src/Form/FileSystemForm.php
Normal file
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\FileSystemForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\StreamWrapper\PrivateStream;
|
||||
use Drupal\Core\StreamWrapper\PublicStream;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
|
||||
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure file system settings for this site.
|
||||
*/
|
||||
class FileSystemForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* The stream wrapper manager.
|
||||
*
|
||||
* @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
|
||||
*/
|
||||
protected $streamWrapperManager;
|
||||
|
||||
/**
|
||||
* Constructs a FileSystemForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter service.
|
||||
* @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
|
||||
* The stream wrapper manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, DateFormatter $date_formatter, StreamWrapperManagerInterface $stream_wrapper_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->streamWrapperManager = $stream_wrapper_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static (
|
||||
$container->get('config.factory'),
|
||||
$container->get('date.formatter'),
|
||||
$container->get('stream_wrapper_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_file_system_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.file'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('system.file');
|
||||
$form['file_public_path'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Public file system path'),
|
||||
'#markup' => PublicStream::basePath(),
|
||||
'#description' => t('A local file system path where public files will be stored. This directory must exist and be writable by Drupal. This directory must be relative to the Drupal installation directory and be accessible over the web. This must be changed in settings.php'),
|
||||
);
|
||||
|
||||
$form['file_private_path'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Private file system path'),
|
||||
'#markup' => (PrivateStream::basePath() ? PrivateStream::basePath() : t('Not set')),
|
||||
'#description' => t('An existing local file system path for storing private files. It should be writable by Drupal and not accessible over the web. This must be changed in settings.php'),
|
||||
);
|
||||
|
||||
$form['file_temporary_path'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Temporary directory'),
|
||||
'#default_value' => $config->get('path.temporary'),
|
||||
'#maxlength' => 255,
|
||||
'#description' => t('A local file system path where temporary files will be stored. This directory should not be accessible over the web.'),
|
||||
'#after_build' => array('system_check_directory'),
|
||||
);
|
||||
// Any visible, writeable wrapper can potentially be used for the files
|
||||
// directory, including a remote file system that integrates with a CDN.
|
||||
$options = $this->streamWrapperManager->getDescriptions(StreamWrapperInterface::WRITE_VISIBLE);
|
||||
|
||||
if (!empty($options)) {
|
||||
$form['file_default_scheme'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Default download method'),
|
||||
'#default_value' => $config->get('default_scheme'),
|
||||
'#options' => $options,
|
||||
'#description' => t('This setting is used as the preferred download method. The use of public files is more efficient, but does not provide any access control.'),
|
||||
);
|
||||
}
|
||||
|
||||
$intervals = array(0, 21600, 43200, 86400, 604800, 2419200, 7776000);
|
||||
$period = array_combine($intervals, array_map(array($this->dateFormatter, 'formatInterval'), $intervals));
|
||||
$period[0] = t('Never');
|
||||
$form['temporary_maximum_age'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Delete orphaned files after'),
|
||||
'#default_value' => $config->get('temporary_maximum_age'),
|
||||
'#options' => $period,
|
||||
'#description' => t('Orphaned files are not referenced from any content but remain in the file system and may appear in administrative listings. <strong>Warning:</strong> If enabled, orphaned files will be permanently deleted and may not be recoverable.'),
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$config = $this->config('system.file')
|
||||
->set('path.temporary', $form_state->getValue('file_temporary_path'))
|
||||
->set('temporary_maximum_age', $form_state->getValue('temporary_maximum_age'));
|
||||
|
||||
if ($form_state->hasValue('file_default_scheme')) {
|
||||
$config->set('default_scheme', $form_state->getValue('file_default_scheme'));
|
||||
}
|
||||
$config->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
131
core/modules/system/src/Form/ImageToolkitForm.php
Normal file
131
core/modules/system/src/Form/ImageToolkitForm.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\ImageToolkitForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\ImageToolkit\ImageToolkitManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configures image toolkit settings for this site.
|
||||
*/
|
||||
class ImageToolkitForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* An array containing currently available toolkits.
|
||||
*
|
||||
* @var \Drupal\Core\ImageToolkit\ImageToolkitInterface[]
|
||||
*/
|
||||
protected $availableToolkits = array();
|
||||
|
||||
/**
|
||||
* Constructs a ImageToolkitForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\ImageToolkit\ImageToolkitManager $manager
|
||||
* The image toolkit plugin manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ImageToolkitManager $manager) {
|
||||
parent::__construct($config_factory);
|
||||
|
||||
foreach ($manager->getAvailableToolkits() as $id => $definition) {
|
||||
$this->availableToolkits[$id] = $manager->createInstance($id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('image.toolkit.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_image_toolkit_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.image'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$current_toolkit = $this->config('system.image')->get('toolkit');
|
||||
|
||||
$form['image_toolkit'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Select an image processing toolkit'),
|
||||
'#default_value' => $current_toolkit,
|
||||
'#options' => array(),
|
||||
);
|
||||
|
||||
// If we have more than one image toolkit, allow the user to select the one
|
||||
// to use, and load each of the toolkits' settings form.
|
||||
foreach ($this->availableToolkits as $id => $toolkit) {
|
||||
$definition = $toolkit->getPluginDefinition();
|
||||
$form['image_toolkit']['#options'][$id] = $definition['title'];
|
||||
$form['image_toolkit_settings'][$id] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('@toolkit settings', array('@toolkit' => $definition['title'])),
|
||||
'#open' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':radio[name="image_toolkit"]' => array('value' => $id),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['image_toolkit_settings'][$id] += $toolkit->buildConfigurationForm(array(), $form_state);
|
||||
}
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::validateForm($form, $form_state);
|
||||
|
||||
// Call the form validation handler for each of the toolkits.
|
||||
foreach ($this->availableToolkits as $toolkit) {
|
||||
$toolkit->validateConfigurationForm($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.image')
|
||||
->set('toolkit', $form_state->getValue('image_toolkit'))
|
||||
->save();
|
||||
|
||||
// Call the form submit handler for each of the toolkits.
|
||||
foreach ($this->availableToolkits as $toolkit) {
|
||||
$toolkit->submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
64
core/modules/system/src/Form/LoggingForm.php
Normal file
64
core/modules/system/src/Form/LoggingForm.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\LoggingForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Configure logging settings for this site.
|
||||
*/
|
||||
class LoggingForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_logging_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.logging'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('system.logging');
|
||||
$form['error_level'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Error messages to display'),
|
||||
'#default_value' => $config->get('error_level'),
|
||||
'#options' => array(
|
||||
ERROR_REPORTING_HIDE => t('None'),
|
||||
ERROR_REPORTING_DISPLAY_SOME => t('Errors and warnings'),
|
||||
ERROR_REPORTING_DISPLAY_ALL => t('All messages'),
|
||||
ERROR_REPORTING_DISPLAY_VERBOSE => t('All messages, with backtrace information'),
|
||||
),
|
||||
'#description' => t('It is recommended that sites running on production environments do not display any errors.'),
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.logging')
|
||||
->set('error_level', $form_state->getValue('error_level'))
|
||||
->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
198
core/modules/system/src/Form/ModulesListConfirmForm.php
Normal file
198
core/modules/system/src/Form/ModulesListConfirmForm.php
Normal file
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\ModulesListConfirmForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\PreExistingConfigException;
|
||||
use Drupal\Core\Config\UnmetDependenciesException;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Builds a confirmation form for enabling modules with dependencies.
|
||||
*/
|
||||
class ModulesListConfirmForm extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The expirable key value store.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||
*/
|
||||
protected $keyValueExpirable;
|
||||
|
||||
/**
|
||||
* An associative list of modules to enable or disable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $modules = array();
|
||||
|
||||
/**
|
||||
* The module installer.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleInstallerInterface
|
||||
*/
|
||||
protected $moduleInstaller;
|
||||
|
||||
/**
|
||||
* Constructs a ModulesListConfirmForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer
|
||||
* The module installer.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
|
||||
* The key value expirable factory.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, KeyValueStoreExpirableInterface $key_value_expirable) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->moduleInstaller = $module_installer;
|
||||
$this->keyValueExpirable = $key_value_expirable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('module_handler'),
|
||||
$container->get('module_installer'),
|
||||
$container->get('keyvalue.expirable')->get('module_list')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Some required modules must be enabled');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('system.modules_list');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Continue');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->t('Would you like to continue with the above?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_modules_confirm_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$account = $this->currentUser()->id();
|
||||
$this->modules = $this->keyValueExpirable->get($account);
|
||||
|
||||
// Redirect to the modules list page if the key value store is empty.
|
||||
if (!$this->modules) {
|
||||
return $this->redirect('system.modules_list');
|
||||
}
|
||||
|
||||
$items = array();
|
||||
// Display a list of required modules that have to be installed as well but
|
||||
// were not manually selected.
|
||||
foreach ($this->modules['dependencies'] as $module => $dependencies) {
|
||||
$items[] = $this->formatPlural(count($dependencies), 'You must enable the @required module to install @module.', 'You must enable the @required modules to install @module.', array(
|
||||
'@module' => $this->modules['install'][$module],
|
||||
'@required' => implode(', ', $dependencies),
|
||||
));
|
||||
}
|
||||
|
||||
$form['message'] = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Remove the key value store entry.
|
||||
$account = $this->currentUser()->id();
|
||||
$this->keyValueExpirable->delete($account);
|
||||
|
||||
// Gets list of modules prior to install process.
|
||||
$before = $this->moduleHandler->getModuleList();
|
||||
|
||||
// Install the given modules.
|
||||
if (!empty($this->modules['install'])) {
|
||||
// Don't catch the exception that this can throw for missing dependencies:
|
||||
// the form doesn't allow modules with unmet dependencies, so the only way
|
||||
// this can happen is if the filesystem changed between form display and
|
||||
// submit, in which case the user has bigger problems.
|
||||
try {
|
||||
$this->moduleInstaller->install(array_keys($this->modules['install']));
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->formatPlural(
|
||||
count($config_objects),
|
||||
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||
array(
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $this->modules['install'][$e->getExtension()]
|
||||
)),
|
||||
'error'
|
||||
);
|
||||
return;
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $this->modules['install'][$e->getExtension()]),
|
||||
'error'
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets module list after install process, flushes caches and displays a
|
||||
// message if there are changes.
|
||||
if ($before != $this->moduleHandler->getModuleList()) {
|
||||
drupal_set_message($this->t('The configuration options have been saved.'));
|
||||
}
|
||||
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
}
|
545
core/modules/system/src/Form/ModulesListForm.php
Normal file
545
core/modules/system/src/Form/ModulesListForm.php
Normal file
|
@ -0,0 +1,545 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\ModulesListForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Config\PreExistingConfigException;
|
||||
use Drupal\Core\Config\UnmetDependenciesException;
|
||||
use Drupal\Core\Controller\TitleResolverInterface;
|
||||
use Drupal\Core\Access\AccessManagerInterface;
|
||||
use Drupal\Core\Extension\Extension;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
use Drupal\Core\Menu\MenuLinkManagerInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Provides module installation interface.
|
||||
*
|
||||
* The list of modules gets populated by module.info.yml files, which contain
|
||||
* each module's name, description, and information about which modules it
|
||||
* requires. See \Drupal\Core\Extension\InfoParser for info on module.info.yml
|
||||
* descriptors.
|
||||
*/
|
||||
class ModulesListForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The expirable key value store.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||
*/
|
||||
protected $keyValueExpirable;
|
||||
|
||||
/**
|
||||
* The title resolver.
|
||||
*
|
||||
* @var \Drupal\Core\Controller\TitleResolverInterface
|
||||
*/
|
||||
protected $titleResolver;
|
||||
|
||||
/**
|
||||
* The route provider.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteProviderInterface
|
||||
*/
|
||||
protected $routeProvider;
|
||||
|
||||
/**
|
||||
* The current route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* The menu link manager.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuLinkManagerInterface
|
||||
*/
|
||||
protected $menuLinkManager;
|
||||
|
||||
/**
|
||||
* The module installer.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleInstallerInterface
|
||||
*/
|
||||
protected $moduleInstaller;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('module_handler'),
|
||||
$container->get('module_installer'),
|
||||
$container->get('keyvalue.expirable')->get('module_list'),
|
||||
$container->get('access_manager'),
|
||||
$container->get('current_user'),
|
||||
$container->get('current_route_match'),
|
||||
$container->get('title_resolver'),
|
||||
$container->get('router.route_provider'),
|
||||
$container->get('plugin.manager.menu.link')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ModulesListForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer
|
||||
* The module installer.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
|
||||
* The key value expirable factory.
|
||||
* @param \Drupal\Core\Access\AccessManagerInterface $access_manager
|
||||
* Access manager.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The current route match.
|
||||
* @param \Drupal\Core\Controller\TitleResolverInterface $title_resolver
|
||||
* The title resolver.
|
||||
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider.
|
||||
* @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
|
||||
* The menu link manager.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, KeyValueStoreExpirableInterface $key_value_expirable, AccessManagerInterface $access_manager, AccountInterface $current_user, RouteMatchInterface $route_match, TitleResolverInterface $title_resolver, RouteProviderInterface $route_provider, MenuLinkManagerInterface $menu_link_manager) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->moduleInstaller = $module_installer;
|
||||
$this->keyValueExpirable = $key_value_expirable;
|
||||
$this->accessManager = $access_manager;
|
||||
$this->currentUser = $current_user;
|
||||
$this->routeMatch = $route_match;
|
||||
$this->titleResolver = $title_resolver;
|
||||
$this->routeProvider = $route_provider;
|
||||
$this->menuLinkManager = $menu_link_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_modules';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
require_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
$distribution = SafeMarkup::checkPlain(drupal_install_profile_distribution_name());
|
||||
|
||||
// Include system.admin.inc so we can use the sort callbacks.
|
||||
$this->moduleHandler->loadInclude('system', 'inc', 'system.admin');
|
||||
|
||||
$form['filters'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array(
|
||||
'class' => array('table-filter', 'js-show'),
|
||||
),
|
||||
);
|
||||
|
||||
$form['filters']['text'] = array(
|
||||
'#type' => 'search',
|
||||
'#title' => $this->t('Search'),
|
||||
'#size' => 30,
|
||||
'#placeholder' => $this->t('Enter module name'),
|
||||
'#attributes' => array(
|
||||
'class' => array('table-filter-text'),
|
||||
'data-table' => '#system-modules',
|
||||
'autocomplete' => 'off',
|
||||
'title' => $this->t('Enter a part of the module name or description to filter by.'),
|
||||
),
|
||||
);
|
||||
|
||||
// Sort all modules by their names.
|
||||
$modules = system_rebuild_module_data();
|
||||
uasort($modules, 'system_sort_modules_by_info_name');
|
||||
|
||||
// Iterate over each of the modules.
|
||||
$form['modules']['#tree'] = TRUE;
|
||||
foreach ($modules as $filename => $module) {
|
||||
if (empty($module->info['hidden'])) {
|
||||
$package = $module->info['package'];
|
||||
$form['modules'][$package][$filename] = $this->buildRow($modules, $module, $distribution);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a wrapper around every package.
|
||||
foreach (Element::children($form['modules']) as $package) {
|
||||
$form['modules'][$package] += array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t($package),
|
||||
'#open' => TRUE,
|
||||
'#theme' => 'system_modules_details',
|
||||
'#header' => array(
|
||||
array('data' => $this->t('Installed'), 'class' => array('checkbox', 'visually-hidden')),
|
||||
array('data' => $this->t('Name'), 'class' => array('name', 'visually-hidden')),
|
||||
array('data' => $this->t('Description'), 'class' => array('description', 'visually-hidden', RESPONSIVE_PRIORITY_LOW)),
|
||||
),
|
||||
'#attributes' => array('class' => array('package-listing')),
|
||||
// Ensure that the "Core" package comes first.
|
||||
'#weight' => $package == 'Core' ? -10 : NULL,
|
||||
);
|
||||
}
|
||||
|
||||
// If testing modules are shown, collapse the corresponding package by
|
||||
// default.
|
||||
if (isset($form['modules']['Testing'])) {
|
||||
$form['modules']['Testing']['#open'] = FALSE;
|
||||
}
|
||||
|
||||
// Lastly, sort all packages by title.
|
||||
uasort($form['modules'], array('\Drupal\Component\Utility\SortArray', 'sortByTitleProperty'));
|
||||
|
||||
$form['#attached']['library'][] = 'system/drupal.system.modules';
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save configuration'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a table row for the system modules page.
|
||||
*
|
||||
* @param array $modules
|
||||
* The list existing modules.
|
||||
* @param \Drupal\Core\Extension\Extension $module
|
||||
* The module for which to build the form row.
|
||||
* @param $distribution
|
||||
*
|
||||
* @return array
|
||||
* The form row for the given module.
|
||||
*/
|
||||
protected function buildRow(array $modules, Extension $module, $distribution) {
|
||||
// Set the basic properties.
|
||||
$row['#required'] = array();
|
||||
$row['#requires'] = array();
|
||||
$row['#required_by'] = array();
|
||||
|
||||
$row['name']['#markup'] = $module->info['name'];
|
||||
$row['description']['#markup'] = $this->t($module->info['description']);
|
||||
$row['version']['#markup'] = $module->info['version'];
|
||||
|
||||
// Generate link for module's help page. Assume that if a hook_help()
|
||||
// implementation exists then the module provides an overview page, rather
|
||||
// than checking to see if the page exists, which is costly.
|
||||
$row['links']['help'] = array();
|
||||
if ($this->moduleHandler->moduleExists('help') && $module->status && in_array($module->getName(), $this->moduleHandler->getImplementations('help'))) {
|
||||
$row['links']['help'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Help'),
|
||||
'#url' => Url::fromRoute('help.page', ['name' => $module->getName()]),
|
||||
'#options' => array('attributes' => array('class' => array('module-link', 'module-link-help'), 'title' => $this->t('Help'))),
|
||||
);
|
||||
}
|
||||
|
||||
// Generate link for module's permission, if the user has access to it.
|
||||
$row['links']['permissions'] = array();
|
||||
if ($module->status && \Drupal::currentUser()->hasPermission('administer permissions') && in_array($module->getName(), $this->moduleHandler->getImplementations('permission'))) {
|
||||
$row['links']['permissions'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Permissions'),
|
||||
'#url' => Url::fromRoute('user.admin_permissions'),
|
||||
'#options' => array('fragment' => 'module-' . $module->getName(), 'attributes' => array('class' => array('module-link', 'module-link-permissions'), 'title' => $this->t('Configure permissions'))),
|
||||
);
|
||||
}
|
||||
|
||||
// Generate link for module's configuration page, if it has one.
|
||||
$row['links']['configure'] = array();
|
||||
if ($module->status && isset($module->info['configure'])) {
|
||||
$route_parameters = isset($module->info['configure_parameters']) ? $module->info['configure_parameters'] : array();
|
||||
if ($this->accessManager->checkNamedRoute($module->info['configure'], $route_parameters, $this->currentUser)) {
|
||||
|
||||
$links = $this->menuLinkManager->loadLinksByRoute($module->info['configure']);
|
||||
/** @var \Drupal\Core\Menu\MenuLinkInterface $link */
|
||||
$link = reset($links);
|
||||
// Most configure links have a corresponding menu link, though some just
|
||||
// have a route.
|
||||
if ($link) {
|
||||
$description = $link->getDescription();
|
||||
}
|
||||
else {
|
||||
$request = new Request();
|
||||
$request->attributes->set('_route_name', $module->info['configure']);
|
||||
$route_object = $this->routeProvider->getRouteByName($module->info['configure']);
|
||||
$request->attributes->set('_route', $route_object);
|
||||
$request->attributes->add($route_parameters);
|
||||
$description = $this->titleResolver->getTitle($request, $route_object);
|
||||
}
|
||||
|
||||
$row['links']['configure'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => $this->t('Configure'),
|
||||
'#url' => Url::fromRoute($module->info['configure'], $route_parameters),
|
||||
'#options' => array(
|
||||
'attributes' => array(
|
||||
'class' => array('module-link', 'module-link-configure'),
|
||||
'title' => $description,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Present a checkbox for installing and indicating the status of a module.
|
||||
$row['enable'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Install'),
|
||||
'#default_value' => (bool) $module->status,
|
||||
'#disabled' => (bool) $module->status,
|
||||
);
|
||||
|
||||
// Disable the checkbox for required modules.
|
||||
if (!empty($module->info['required'])) {
|
||||
// Used when displaying modules that are required by the installation profile
|
||||
$row['enable']['#disabled'] = TRUE;
|
||||
$row['#required_by'][] = $distribution . (!empty($module->info['explanation']) ? ' ('. $module->info['explanation'] .')' : '');
|
||||
}
|
||||
|
||||
// Check the compatibilities.
|
||||
$compatible = TRUE;
|
||||
|
||||
// Initialize an empty array of reasons why the module is incompatible. Add
|
||||
// each reason as a separate element of the array.
|
||||
$reasons = array();
|
||||
|
||||
// Check the core compatibility.
|
||||
if ($module->info['core'] != \Drupal::CORE_COMPATIBILITY) {
|
||||
$compatible = FALSE;
|
||||
$reasons[] = $this->t('This version is not compatible with Drupal !core_version and should be replaced.', array(
|
||||
'!core_version' => \Drupal::CORE_COMPATIBILITY,
|
||||
));
|
||||
}
|
||||
|
||||
// Ensure this module is compatible with the currently installed version of PHP.
|
||||
if (version_compare(phpversion(), $module->info['php']) < 0) {
|
||||
$compatible = FALSE;
|
||||
$required = $module->info['php'] . (substr_count($module->info['php'], '.') < 2 ? '.*' : '');
|
||||
$reasons[] = $this->t('This module requires PHP version @php_required and is incompatible with PHP version !php_version.', array(
|
||||
'@php_required' => $required,
|
||||
'!php_version' => phpversion(),
|
||||
));
|
||||
}
|
||||
|
||||
// If this module is not compatible, disable the checkbox.
|
||||
if (!$compatible) {
|
||||
$status = implode(' ', $reasons);
|
||||
$row['enable']['#disabled'] = TRUE;
|
||||
$row['description']['#markup'] = $status;
|
||||
$row['#attributes']['class'][] = 'incompatible';
|
||||
}
|
||||
|
||||
// If this module requires other modules, add them to the array.
|
||||
foreach ($module->requires as $dependency => $version) {
|
||||
if (!isset($modules[$dependency])) {
|
||||
$row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">missing</span>)', array('@module' => Unicode::ucfirst($dependency)));
|
||||
$row['enable']['#disabled'] = TRUE;
|
||||
}
|
||||
// Only display visible modules.
|
||||
elseif (empty($modules[$dependency]->hidden)) {
|
||||
$name = $modules[$dependency]->info['name'];
|
||||
// Disable the module's checkbox if it is incompatible with the
|
||||
// dependency's version.
|
||||
if ($incompatible_version = drupal_check_incompatibility($version, str_replace(\Drupal::CORE_COMPATIBILITY . '-', '', $modules[$dependency]->info['version']))) {
|
||||
$row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> version @version)', array(
|
||||
'@module' => $name . $incompatible_version,
|
||||
'@version' => $modules[$dependency]->info['version'],
|
||||
));
|
||||
$row['enable']['#disabled'] = TRUE;
|
||||
}
|
||||
// Disable the checkbox if the dependency is incompatible with this
|
||||
// version of Drupal core.
|
||||
elseif ($modules[$dependency]->info['core'] != \Drupal::CORE_COMPATIBILITY) {
|
||||
$row['#requires'][$dependency] = $this->t('@module (<span class="admin-missing">incompatible with</span> this version of Drupal core)', array(
|
||||
'@module' => $name,
|
||||
));
|
||||
$row['enable']['#disabled'] = TRUE;
|
||||
}
|
||||
elseif ($modules[$dependency]->status) {
|
||||
$row['#requires'][$dependency] = $this->t('@module', array('@module' => $name));
|
||||
}
|
||||
else {
|
||||
$row['#requires'][$dependency] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this module is required by other modules, list those, and then make it
|
||||
// impossible to disable this one.
|
||||
foreach ($module->required_by as $dependent => $version) {
|
||||
if (isset($modules[$dependent]) && empty($modules[$dependent]->info['hidden'])) {
|
||||
if ($modules[$dependent]->status == 1 && $module->status == 1) {
|
||||
$row['#required_by'][$dependent] = $this->t('@module', array('@module' => $modules[$dependent]->info['name']));
|
||||
$row['enable']['#disabled'] = TRUE;
|
||||
}
|
||||
else {
|
||||
$row['#required_by'][$dependent] = $this->t('@module (<span class="admin-disabled">disabled</span>)', array('@module' => $modules[$dependent]->info['name']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for building a list of modules to install.
|
||||
*
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @return array
|
||||
* An array of modules to install and their dependencies.
|
||||
*/
|
||||
protected function buildModuleList(FormStateInterface $form_state) {
|
||||
$packages = $form_state->getValue('modules');
|
||||
|
||||
// Build a list of modules to install.
|
||||
$modules = array(
|
||||
'install' => array(),
|
||||
'dependencies' => array(),
|
||||
);
|
||||
|
||||
// Required modules have to be installed.
|
||||
// @todo This should really not be handled here.
|
||||
$data = system_rebuild_module_data();
|
||||
foreach ($data as $name => $module) {
|
||||
if (!empty($module->required) && !$this->moduleHandler->moduleExists($name)) {
|
||||
$modules['install'][$name] = $module->info['name'];
|
||||
}
|
||||
}
|
||||
|
||||
// First, build a list of all modules that were selected.
|
||||
foreach ($packages as $items) {
|
||||
foreach ($items as $name => $checkbox) {
|
||||
if ($checkbox['enable'] && !$this->moduleHandler->moduleExists($name)) {
|
||||
$modules['install'][$name] = $data[$name]->info['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all dependencies to a list.
|
||||
while (list($module) = each($modules['install'])) {
|
||||
foreach (array_keys($data[$module]->requires) as $dependency) {
|
||||
if (!isset($modules['install'][$dependency]) && !$this->moduleHandler->moduleExists($dependency)) {
|
||||
$modules['dependencies'][$module][$dependency] = $data[$dependency]->info['name'];
|
||||
$modules['install'][$dependency] = $data[$dependency]->info['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the install API is available.
|
||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
|
||||
// Invoke hook_requirements('install'). If failures are detected, make
|
||||
// sure the dependent modules aren't installed either.
|
||||
foreach (array_keys($modules['install']) as $module) {
|
||||
if (!drupal_check_module($module)) {
|
||||
unset($modules['install'][$module]);
|
||||
foreach (array_keys($data[$module]->required_by) as $dependent) {
|
||||
unset($modules['install'][$dependent]);
|
||||
unset($modules['dependencies'][$dependent]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Retrieve a list of modules to install and their dependencies.
|
||||
$modules = $this->buildModuleList($form_state);
|
||||
|
||||
// Check if we have to install any dependencies. If there is one or more
|
||||
// dependencies that are not installed yet, redirect to the confirmation
|
||||
// form.
|
||||
if (!empty($modules['dependencies']) || !empty($modules['missing'])) {
|
||||
// Write the list of changed module states into a key value store.
|
||||
$account = $this->currentUser()->id();
|
||||
$this->keyValueExpirable->setWithExpire($account, $modules, 60);
|
||||
|
||||
// Redirect to the confirmation form.
|
||||
$form_state->setRedirect('system.modules_list_confirm');
|
||||
|
||||
// We can exit here because at least one modules has dependencies
|
||||
// which we have to prompt the user for in a confirmation form.
|
||||
return;
|
||||
}
|
||||
|
||||
// Gets list of modules prior to install process.
|
||||
$before = $this->moduleHandler->getModuleList();
|
||||
|
||||
// There seem to be no dependencies that would need approval.
|
||||
if (!empty($modules['install'])) {
|
||||
try {
|
||||
$this->moduleInstaller->install(array_keys($modules['install']));
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->formatPlural(
|
||||
count($config_objects),
|
||||
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||
array(
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $modules['install'][$e->getExtension()]
|
||||
)),
|
||||
'error'
|
||||
);
|
||||
return;
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()]),
|
||||
'error'
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets module list after install process, flushes caches and displays a
|
||||
// message if there are changes.
|
||||
if ($before != $this->moduleHandler->getModuleList()) {
|
||||
drupal_set_message(t('The configuration options have been saved.'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
172
core/modules/system/src/Form/ModulesUninstallConfirmForm.php
Normal file
172
core/modules/system/src/Form/ModulesUninstallConfirmForm.php
Normal file
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\ModulesUninstallConfirmForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigManagerInterface;
|
||||
use Drupal\Core\Config\Entity\ConfigDependencyDeleteFormTrait;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
|
||||
/**
|
||||
* Builds a confirmation form to uninstall selected modules.
|
||||
*/
|
||||
class ModulesUninstallConfirmForm extends ConfirmFormBase {
|
||||
use ConfigDependencyDeleteFormTrait;
|
||||
|
||||
/**
|
||||
* The module installer service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleInstallerInterface
|
||||
*/
|
||||
protected $moduleInstaller;
|
||||
|
||||
/**
|
||||
* The expirable key value store.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||
*/
|
||||
protected $keyValueExpirable;
|
||||
|
||||
/**
|
||||
* The configuration manager.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigManagerInterface
|
||||
*/
|
||||
protected $configManager;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* An array of modules to uninstall.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $modules = array();
|
||||
|
||||
/**
|
||||
* Constructs a ModulesUninstallConfirmForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer
|
||||
* The module installer.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
|
||||
* The key value expirable factory.
|
||||
* @param \Drupal\Core\Config\ConfigManagerInterface $config_manager
|
||||
* The configuration manager.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(ModuleInstallerInterface $module_installer, KeyValueStoreExpirableInterface $key_value_expirable, ConfigManagerInterface $config_manager, EntityManagerInterface $entity_manager) {
|
||||
$this->moduleInstaller = $module_installer;
|
||||
$this->keyValueExpirable = $key_value_expirable;
|
||||
$this->configManager = $config_manager;
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('module_installer'),
|
||||
$container->get('keyvalue.expirable')->get('modules_uninstall'),
|
||||
$container->get('config.manager'),
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Confirm uninstall');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Uninstall');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('system.modules_uninstall');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->t('Would you like to continue with uninstalling the above?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_modules_uninstall_confirm_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
// Retrieve the list of modules from the key value store.
|
||||
$account = $this->currentUser()->id();
|
||||
$this->modules = $this->keyValueExpirable->get($account);
|
||||
|
||||
// Prevent this page from showing when the module list is empty.
|
||||
if (empty($this->modules)) {
|
||||
drupal_set_message($this->t('The selected modules could not be uninstalled, either due to a website problem or due to the uninstall confirmation form timing out. Please try again.'), 'error');
|
||||
return $this->redirect('system.modules_uninstall');
|
||||
}
|
||||
|
||||
$data = system_rebuild_module_data();
|
||||
$form['text']['#markup'] = '<p>' . $this->t('The following modules will be completely uninstalled from your site, and <em>all data from these modules will be lost</em>!') . '</p>';
|
||||
$form['modules'] = array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => array_map(function ($module) use ($data) {
|
||||
return $data[$module]->info['name'];
|
||||
}, $this->modules),
|
||||
);
|
||||
|
||||
// List the dependent entities.
|
||||
$this->addDependencyListsToForm($form, 'module', $this->modules ,$this->configManager, $this->entityManager);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Clear the key value store entry.
|
||||
$account = $this->currentUser()->id();
|
||||
$this->keyValueExpirable->delete($account);
|
||||
|
||||
// Uninstall the modules.
|
||||
$this->moduleInstaller->uninstall($this->modules);
|
||||
|
||||
drupal_set_message($this->t('The selected modules have been uninstalled.'));
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
}
|
194
core/modules/system/src/Form/ModulesUninstallForm.php
Normal file
194
core/modules/system/src/Form/ModulesUninstallForm.php
Normal file
|
@ -0,0 +1,194 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\ModulesUninstallForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a form for uninstalling modules.
|
||||
*/
|
||||
class ModulesUninstallForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The module installer service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleInstallerInterface
|
||||
*/
|
||||
protected $moduleInstaller;
|
||||
|
||||
/**
|
||||
* The expirable key value store.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||
*/
|
||||
protected $keyValueExpirable;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('module_handler'),
|
||||
$container->get('module_installer'),
|
||||
$container->get('keyvalue.expirable')->get('modules_uninstall')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ModulesUninstallForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Extension\ModuleInstallerInterface $module_installer
|
||||
* The module installer.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable
|
||||
* The key value expirable factory.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, ModuleInstallerInterface $module_installer, KeyValueStoreExpirableInterface $key_value_expirable) {
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->moduleInstaller = $module_installer;
|
||||
$this->keyValueExpirable = $key_value_expirable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_modules_uninstall';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
// Make sure the install API is available.
|
||||
include_once DRUPAL_ROOT . '/core/includes/install.inc';
|
||||
|
||||
// Get a list of all available modules.
|
||||
$modules = system_rebuild_module_data();
|
||||
$uninstallable = array_filter($modules, function ($module) use ($modules) {
|
||||
return empty($modules[$module->getName()]->info['required']) && drupal_get_installed_schema_version($module->getName()) > SCHEMA_UNINSTALLED;
|
||||
});
|
||||
|
||||
// Include system.admin.inc so we can use the sort callbacks.
|
||||
$this->moduleHandler->loadInclude('system', 'inc', 'system.admin');
|
||||
|
||||
$form['filters'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array(
|
||||
'class' => array('table-filter', 'js-show'),
|
||||
),
|
||||
);
|
||||
|
||||
$form['filters']['text'] = array(
|
||||
'#type' => 'search',
|
||||
'#title' => $this->t('Search'),
|
||||
'#size' => 30,
|
||||
'#placeholder' => $this->t('Enter module name'),
|
||||
'#attributes' => array(
|
||||
'class' => array('table-filter-text'),
|
||||
'data-table' => '#system-modules-uninstall',
|
||||
'autocomplete' => 'off',
|
||||
'title' => $this->t('Enter a part of the module name or description to filter by.'),
|
||||
),
|
||||
);
|
||||
|
||||
$form['modules'] = array();
|
||||
|
||||
// Only build the rest of the form if there are any modules available to
|
||||
// uninstall;
|
||||
if (empty($uninstallable)) {
|
||||
return $form;
|
||||
}
|
||||
|
||||
$profile = drupal_get_profile();
|
||||
|
||||
// Sort all modules by their name.
|
||||
uasort($uninstallable, 'system_sort_modules_by_info_name');
|
||||
$validation_reasons = $this->moduleInstaller->validateUninstall(array_keys($uninstallable));
|
||||
|
||||
$form['uninstall'] = array('#tree' => TRUE);
|
||||
foreach ($uninstallable as $module_key => $module) {
|
||||
$name = $module->info['name'] ?: $module->getName();
|
||||
$form['modules'][$module->getName()]['#module_name'] = $name;
|
||||
$form['modules'][$module->getName()]['name']['#markup'] = $name;
|
||||
$form['modules'][$module->getName()]['description']['#markup'] = $this->t($module->info['description']);
|
||||
|
||||
$form['uninstall'][$module->getName()] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Uninstall @module module', array('@module' => $name)),
|
||||
'#title_display' => 'invisible',
|
||||
);
|
||||
|
||||
// If a validator returns reasons not to uninstall a module,
|
||||
// list the reasons and disable the check box.
|
||||
if (isset($validation_reasons[$module_key])) {
|
||||
$form['modules'][$module->getName()]['#validation_reasons'] = $validation_reasons[$module_key];
|
||||
$form['uninstall'][$module->getName()]['#disabled'] = TRUE;
|
||||
}
|
||||
// All modules which depend on this one must be uninstalled first, before
|
||||
// we can allow this module to be uninstalled. (The installation profile
|
||||
// is excluded from this list.)
|
||||
foreach (array_keys($module->required_by) as $dependent) {
|
||||
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
|
||||
$name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent;
|
||||
$form['modules'][$module->getName()]['#required_by'][] = $name;
|
||||
$form['uninstall'][$module->getName()]['#disabled'] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['#attached']['library'][] = 'system/drupal.system.modules';
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Uninstall'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
// Form submitted, but no modules selected.
|
||||
if (!array_filter($form_state->getValue('uninstall'))) {
|
||||
$form_state->setErrorByName('uninstall', $this->t('No modules selected.'));
|
||||
$form_state->setRedirect('system.modules_uninstall');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Save all the values in an expirable key value store.
|
||||
$modules = $form_state->getValue('uninstall');
|
||||
$uninstall = array_keys(array_filter($modules));
|
||||
$account = $this->currentUser()->id();
|
||||
// Store the values for 6 hours. This expiration time is also used in
|
||||
// the form cache.
|
||||
$this->keyValueExpirable->setWithExpire($account, $uninstall, 6*60*60);
|
||||
|
||||
// Redirect to the confirm form.
|
||||
$form_state->setRedirect('system.modules_uninstall_confirm');
|
||||
}
|
||||
}
|
198
core/modules/system/src/Form/PerformanceForm.php
Normal file
198
core/modules/system/src/Form/PerformanceForm.php
Normal file
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\PerformanceForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure performance settings for this site.
|
||||
*/
|
||||
class PerformanceForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The render cache bin.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $renderCache;
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* The CSS asset collection optimizer service.
|
||||
*
|
||||
* @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface
|
||||
*/
|
||||
protected $cssCollectionOptimizer;
|
||||
|
||||
/**
|
||||
* The JavaScript asset collection optimizer service.
|
||||
*
|
||||
* @var \Drupal\Core\Asset\AssetCollectionOptimizerInterface
|
||||
*/
|
||||
protected $jsCollectionOptimizer;
|
||||
|
||||
/**
|
||||
* Constructs a PerformanceForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $render_cache
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter service.
|
||||
* @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $css_collection_optimizer
|
||||
* The CSS asset collection optimizer service.
|
||||
* @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $js_collection_optimizer
|
||||
* The JavaScript asset collection optimizer service.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, CacheBackendInterface $render_cache, DateFormatter $date_formatter, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer) {
|
||||
parent::__construct($config_factory);
|
||||
|
||||
$this->renderCache = $render_cache;
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->cssCollectionOptimizer = $css_collection_optimizer;
|
||||
$this->jsCollectionOptimizer = $js_collection_optimizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('cache.render'),
|
||||
$container->get('date.formatter'),
|
||||
$container->get('asset.css.collection_optimizer'),
|
||||
$container->get('asset.js.collection_optimizer')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_performance_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.performance'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['#attached']['library'][] = 'system/drupal.system';
|
||||
|
||||
$config = $this->config('system.performance');
|
||||
|
||||
$form['clear_cache'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Clear cache'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
|
||||
$form['clear_cache']['clear'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Clear all caches'),
|
||||
'#submit' => array('::submitCacheClear'),
|
||||
);
|
||||
|
||||
$form['caching'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Caching'),
|
||||
'#open' => TRUE,
|
||||
'#description' => $this->t('Note: Drupal provides an internal page cache module that is recommended for small to medium-sized websites.'),
|
||||
);
|
||||
// Identical options to the ones for block caching.
|
||||
// @see \Drupal\Core\Block\BlockBase::buildConfigurationForm()
|
||||
$period = array(0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 86400);
|
||||
$period = array_map(array($this->dateFormatter, 'formatInterval'), array_combine($period, $period));
|
||||
$period[0] = '<' . t('no caching') . '>';
|
||||
$form['caching']['page_cache_maximum_age'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Page cache maximum age'),
|
||||
'#default_value' => $config->get('cache.page.max_age'),
|
||||
'#options' => $period,
|
||||
'#description' => t('The maximum time a page can be cached by browsers and proxies. This is used as the value for max-age in Cache-Control headers.'),
|
||||
);
|
||||
|
||||
$directory = 'public://';
|
||||
$is_writable = is_dir($directory) && is_writable($directory);
|
||||
$disabled = !$is_writable;
|
||||
$disabled_message = '';
|
||||
if (!$is_writable) {
|
||||
$disabled_message = ' ' . t('<strong class="error">Set up the <a href="!file-system">public files directory</a> to make these optimizations available.</strong>', array('!file-system' => $this->url('system.file_system_settings')));
|
||||
}
|
||||
|
||||
$form['bandwidth_optimization'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Bandwidth optimization'),
|
||||
'#open' => TRUE,
|
||||
'#description' => t('External resources can be optimized automatically, which can reduce both the size and number of requests made to your website.') . $disabled_message,
|
||||
);
|
||||
|
||||
$form['bandwidth_optimization']['preprocess_css'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Aggregate CSS files'),
|
||||
'#default_value' => $config->get('css.preprocess'),
|
||||
'#disabled' => $disabled,
|
||||
);
|
||||
$form['bandwidth_optimization']['preprocess_js'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Aggregate JavaScript files'),
|
||||
'#default_value' => $config->get('js.preprocess'),
|
||||
'#disabled' => $disabled,
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->cssCollectionOptimizer->deleteAll();
|
||||
$this->jsCollectionOptimizer->deleteAll();
|
||||
// This form allows page compression settings to be changed, which can
|
||||
// invalidate cached pages in the render cache, so it needs to be cleared on
|
||||
// form submit.
|
||||
$this->renderCache->deleteAll();
|
||||
|
||||
$this->config('system.performance')
|
||||
->set('cache.page.max_age', $form_state->getValue('page_cache_maximum_age'))
|
||||
->set('css.preprocess', $form_state->getValue('preprocess_css'))
|
||||
->set('js.preprocess', $form_state->getValue('preprocess_js'))
|
||||
->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the caches.
|
||||
*/
|
||||
public function submitCacheClear(array &$form, FormStateInterface $form_state) {
|
||||
drupal_flush_all_caches();
|
||||
drupal_set_message(t('Caches cleared.'));
|
||||
}
|
||||
|
||||
}
|
165
core/modules/system/src/Form/RegionalForm.php
Normal file
165
core/modules/system/src/Form/RegionalForm.php
Normal file
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\RegionalForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Locale\CountryManagerInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure regional settings for this site.
|
||||
*/
|
||||
class RegionalForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The country manager.
|
||||
*
|
||||
* @var \Drupal\Core\Locale\CountryManagerInterface
|
||||
*/
|
||||
protected $countryManager;
|
||||
|
||||
/**
|
||||
* Constructs a RegionalForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Locale\CountryManagerInterface $country_manager
|
||||
* The country manager.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, CountryManagerInterface $country_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->countryManager = $country_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('country_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_regional_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.date'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$countries = $this->countryManager->getList();
|
||||
$system_date = $this->config('system.date');
|
||||
|
||||
// Date settings:
|
||||
$zones = system_time_zones();
|
||||
|
||||
$form['locale'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Locale'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
|
||||
$form['locale']['site_default_country'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Default country'),
|
||||
'#empty_value' => '',
|
||||
'#default_value' => $system_date->get('country.default'),
|
||||
'#options' => $countries,
|
||||
'#attributes' => array('class' => array('country-detect')),
|
||||
);
|
||||
|
||||
$form['locale']['date_first_day'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('First day of week'),
|
||||
'#default_value' => $system_date->get('first_day'),
|
||||
'#options' => array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday')),
|
||||
);
|
||||
|
||||
$form['timezone'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Time zones'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
|
||||
$form['timezone']['date_default_timezone'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Default time zone'),
|
||||
'#default_value' => $system_date->get('timezone.default') ?: date_default_timezone_get(),
|
||||
'#options' => $zones,
|
||||
);
|
||||
|
||||
$configurable_timezones = $system_date->get('timezone.user.configurable');
|
||||
$form['timezone']['configurable_timezones'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Users may set their own time zone'),
|
||||
'#default_value' => $configurable_timezones,
|
||||
);
|
||||
|
||||
$form['timezone']['configurable_timezones_wrapper'] = array(
|
||||
'#type' => 'container',
|
||||
'#states' => array(
|
||||
// Hide the user configured timezone settings when users are forced to use
|
||||
// the default setting.
|
||||
'invisible' => array(
|
||||
'input[name="configurable_timezones"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['timezone']['configurable_timezones_wrapper']['empty_timezone_message'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Remind users at login if their time zone is not set'),
|
||||
'#default_value' => $system_date->get('timezone.user.warn'),
|
||||
'#description' => t('Only applied if users may set their own time zone.')
|
||||
);
|
||||
|
||||
$form['timezone']['configurable_timezones_wrapper']['user_default_timezone'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Time zone for new users'),
|
||||
'#default_value' => $system_date->get('timezone.user.default'),
|
||||
'#options' => array(
|
||||
DRUPAL_USER_TIMEZONE_DEFAULT => t('Default time zone'),
|
||||
DRUPAL_USER_TIMEZONE_EMPTY => t('Empty time zone'),
|
||||
DRUPAL_USER_TIMEZONE_SELECT => t('Users may set their own time zone at registration'),
|
||||
),
|
||||
'#description' => t('Only applied if users may set their own time zone.')
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.date')
|
||||
->set('country.default', $form_state->getValue('site_default_country'))
|
||||
->set('first_day', $form_state->getValue('date_first_day'))
|
||||
->set('timezone.default', $form_state->getValue('date_default_timezone'))
|
||||
->set('timezone.user.configurable', $form_state->getValue('configurable_timezones'))
|
||||
->set('timezone.user.warn', $form_state->getValue('empty_timezone_message'))
|
||||
->set('timezone.user.default', $form_state->getValue('user_default_timezone'))
|
||||
->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
79
core/modules/system/src/Form/RssFeedsForm.php
Normal file
79
core/modules/system/src/Form/RssFeedsForm.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\RssFeedsForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Configure RSS settings for this site.
|
||||
*/
|
||||
class RssFeedsForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_rss_feeds_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.rss'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$rss_config = $this->config('system.rss');
|
||||
$form['feed_description'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Feed description'),
|
||||
'#default_value' => $rss_config->get('channel.description'),
|
||||
'#description' => t('Description of your site, included in each feed.')
|
||||
);
|
||||
$options = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30);
|
||||
$form['feed_default_items'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Number of items in each feed'),
|
||||
'#default_value' => $rss_config->get('items.limit'),
|
||||
'#options' => array_combine($options, $options),
|
||||
'#description' => t('Default number of items to include in each feed.')
|
||||
);
|
||||
$form['feed_view_mode'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Feed content'),
|
||||
'#default_value' => $rss_config->get('items.view_mode'),
|
||||
'#options' => array(
|
||||
'title' => t('Titles only'),
|
||||
'teaser' => t('Titles plus teaser'),
|
||||
'fulltext' => t('Full text'),
|
||||
),
|
||||
'#description' => t('Global setting for the default display of content items in each feed.')
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.rss')
|
||||
->set('channel.description', $form_state->getValue('feed_description'))
|
||||
->set('items.limit', $form_state->getValue('feed_default_items'))
|
||||
->set('items.view_mode', $form_state->getValue('feed_view_mode'))
|
||||
->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
223
core/modules/system/src/Form/SiteInformationForm.php
Normal file
223
core/modules/system/src/Form/SiteInformationForm.php
Normal file
|
@ -0,0 +1,223 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\SiteInformationForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Path\PathValidatorInterface;
|
||||
use Drupal\Core\Routing\RequestContext;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure site information settings for this site.
|
||||
*/
|
||||
class SiteInformationForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The path alias manager.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasManagerInterface
|
||||
*/
|
||||
protected $aliasManager;
|
||||
|
||||
/**
|
||||
* The path validator.
|
||||
*
|
||||
* @var \Drupal\Core\Path\PathValidatorInterface
|
||||
*/
|
||||
protected $pathValidator;
|
||||
|
||||
/**
|
||||
* The request context.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RequestContext
|
||||
*/
|
||||
protected $requestContext;
|
||||
|
||||
/**
|
||||
* Constructs a SiteInformationForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
|
||||
* The path alias manager.
|
||||
* @param \Drupal\Core\Path\PathValidatorInterface $path_validator
|
||||
* The path validator.
|
||||
* @param \Drupal\Core\Routing\RequestContext $request_context
|
||||
* The request context.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, AliasManagerInterface $alias_manager, PathValidatorInterface $path_validator, RequestContext $request_context) {
|
||||
parent::__construct($config_factory);
|
||||
|
||||
$this->aliasManager = $alias_manager;
|
||||
$this->pathValidator = $path_validator;
|
||||
$this->requestContext = $request_context;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('path.alias_manager'),
|
||||
$container->get('path.validator'),
|
||||
$container->get('router.request_context')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_site_information_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.site'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$site_config = $this->config('system.site');
|
||||
$site_mail = $site_config->get('mail');
|
||||
if (empty($site_mail)) {
|
||||
$site_mail = ini_get('sendmail_from');
|
||||
}
|
||||
|
||||
$form['site_information'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Site details'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
$form['site_information']['site_name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Site name'),
|
||||
'#default_value' => $site_config->get('name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['site_information']['site_slogan'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Slogan'),
|
||||
'#default_value' => $site_config->get('slogan'),
|
||||
'#description' => t("How this is used depends on your site's theme."),
|
||||
);
|
||||
$form['site_information']['site_mail'] = array(
|
||||
'#type' => 'email',
|
||||
'#title' => t('Email address'),
|
||||
'#default_value' => $site_mail,
|
||||
'#description' => t("The <em>From</em> address in automated emails sent during registration and new password requests, and other notifications. (Use an address ending in your site's domain to help prevent this email being flagged as spam.)"),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['front_page'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Front page'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
$front_page = $site_config->get('page.front') != '/user/login' ? $this->aliasManager->getAliasByPath($site_config->get('page.front')) : '';
|
||||
$form['front_page']['site_frontpage'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Default front page'),
|
||||
'#default_value' => $front_page,
|
||||
'#size' => 40,
|
||||
'#description' => t('Optionally, specify a relative URL to display as the front page. Leave blank to display the default front page.'),
|
||||
'#field_prefix' => $this->requestContext->getCompleteBaseUrl(),
|
||||
);
|
||||
$form['error_page'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Error pages'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
$form['error_page']['site_403'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Default 403 (access denied) page'),
|
||||
'#default_value' => $site_config->get('page.403'),
|
||||
'#size' => 40,
|
||||
'#description' => t('This page is displayed when the requested document is denied to the current user. Leave blank to display a generic "access denied" page.'),
|
||||
);
|
||||
$form['error_page']['site_404'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Default 404 (not found) page'),
|
||||
'#default_value' => $site_config->get('page.404'),
|
||||
'#size' => 40,
|
||||
'#description' => t('This page is displayed when no other content matches the requested document. Leave blank to display a generic "page not found" page.'),
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
// Check for empty front page path.
|
||||
if ($form_state->isValueEmpty('site_frontpage')) {
|
||||
// Set to default "user/login".
|
||||
$form_state->setValueForElement($form['front_page']['site_frontpage'], '/user/login');
|
||||
}
|
||||
else {
|
||||
// Get the normal path of the front page.
|
||||
$form_state->setValueForElement($form['front_page']['site_frontpage'], $this->aliasManager->getPathByAlias($form_state->getValue('site_frontpage')));
|
||||
}
|
||||
// Validate front page path.
|
||||
if (($value = $form_state->getValue('site_frontpage')) && $value[0] !== '/') {
|
||||
$form_state->setErrorByName('site_frontpage', $this->t("The path '%path' has to start with a slash.", ['%path' => $form_state->getValue('site_frontpage')]));
|
||||
|
||||
}
|
||||
if (!$this->pathValidator->isValid($form_state->getValue('site_frontpage'))) {
|
||||
$form_state->setErrorByName('site_frontpage', $this->t("The path '%path' is either invalid or you do not have access to it.", array('%path' => $form_state->getValue('site_frontpage'))));
|
||||
}
|
||||
// Get the normal paths of both error pages.
|
||||
if (!$form_state->isValueEmpty('site_403')) {
|
||||
$form_state->setValueForElement($form['error_page']['site_403'], $this->aliasManager->getPathByAlias($form_state->getValue('site_403')));
|
||||
}
|
||||
if (!$form_state->isValueEmpty('site_404')) {
|
||||
$form_state->setValueForElement($form['error_page']['site_404'], $this->aliasManager->getPathByAlias($form_state->getValue('site_404')));
|
||||
}
|
||||
if (($value = $form_state->getValue('site_403')) && $value[0] !== '/') {
|
||||
$form_state->setErrorByName('site_403', $this->t("The path '%path' has to start with a slash.", ['%path' => $form_state->getValue('site_403')]));
|
||||
}
|
||||
if (($value = $form_state->getValue('site_404')) && $value[0] !== '/') {
|
||||
$form_state->setErrorByName('site_404', $this->t("The path '%path' has to start with a slash.", ['%path' => $form_state->getValue('site_404')]));
|
||||
}
|
||||
// Validate 403 error path.
|
||||
if (!$form_state->isValueEmpty('site_403') && !$this->pathValidator->isValid($form_state->getValue('site_403'))) {
|
||||
$form_state->setErrorByName('site_403', $this->t("The path '%path' is either invalid or you do not have access to it.", array('%path' => $form_state->getValue('site_403'))));
|
||||
}
|
||||
// Validate 404 error path.
|
||||
if (!$form_state->isValueEmpty('site_404') && !$this->pathValidator->isValid($form_state->getValue('site_404'))) {
|
||||
$form_state->setErrorByName('site_404', $this->t("The path '%path' is either invalid or you do not have access to it.", array('%path' => $form_state->getValue('site_404'))));
|
||||
}
|
||||
|
||||
parent::validateForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.site')
|
||||
->set('name', $form_state->getValue('site_name'))
|
||||
->set('mail', $form_state->getValue('site_mail'))
|
||||
->set('slogan', $form_state->getValue('site_slogan'))
|
||||
->set('page.front', $form_state->getValue('site_frontpage'))
|
||||
->set('page.403', $form_state->getValue('site_403'))
|
||||
->set('page.404', $form_state->getValue('site_404'))
|
||||
->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
96
core/modules/system/src/Form/SiteMaintenanceModeForm.php
Normal file
96
core/modules/system/src/Form/SiteMaintenanceModeForm.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\SiteMaintenanceModeForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\State\StateInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure maintenance settings for this site.
|
||||
*/
|
||||
class SiteMaintenanceModeForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The state keyvalue collection.
|
||||
*
|
||||
* @var \Drupal\Core\State\StateInterface
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Constructs a new SiteMaintenanceModeForm.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\State\StateInterface $state
|
||||
* The state keyvalue collection to use.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state) {
|
||||
parent::__construct($config_factory);
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('state')
|
||||
);
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_site_maintenance_mode';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.maintenance'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('system.maintenance');
|
||||
$form['maintenance_mode'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Put site into maintenance mode'),
|
||||
'#default_value' => $this->state->get('system.maintenance_mode'),
|
||||
'#description' => t('Visitors will only see the maintenance mode message. Only users with the "Access site in maintenance mode" <a href="@permissions-url">permission</a> will be able to access the site. Authorized users can log in directly via the <a href="@user-login">user login</a> page.', array('@permissions-url' => $this->url('user.admin_permissions'), '@user-login' => $this->url('user.login'))),
|
||||
);
|
||||
$form['maintenance_mode_message'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Message to display when in maintenance mode'),
|
||||
'#default_value' => $config->get('message'),
|
||||
);
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.maintenance')
|
||||
->set('message', $form_state->getValue('maintenance_mode_message'))
|
||||
->save();
|
||||
|
||||
$this->state->set('system.maintenance_mode', $form_state->getValue('maintenance_mode'));
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
65
core/modules/system/src/Form/ThemeAdminForm.php
Normal file
65
core/modules/system/src/Form/ThemeAdminForm.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\ThemeAdminForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form to select the administration theme.
|
||||
*/
|
||||
class ThemeAdminForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_themes_admin_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['system.theme'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, array $theme_options = NULL) {
|
||||
// Administration theme settings.
|
||||
$form['admin_theme'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Administration theme'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
$form['admin_theme']['admin_theme'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => array(0 => $this->t('Default theme')) + $theme_options,
|
||||
'#title' => $this->t('Administration theme'),
|
||||
'#description' => $this->t('Choose "Default theme" to always use the same theme as the rest of the site.'),
|
||||
'#default_value' => $this->config('system.theme')->get('admin'),
|
||||
);
|
||||
$form['admin_theme']['actions'] = array('#type' => 'actions');
|
||||
$form['admin_theme']['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save configuration'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
$this->config('system.theme')->set('admin', $form_state->getValue('admin_theme'))->save();
|
||||
}
|
||||
|
||||
}
|
501
core/modules/system/src/Form/ThemeSettingsForm.php
Normal file
501
core/modules/system/src/Form/ThemeSettingsForm.php
Normal file
|
@ -0,0 +1,501 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Form\ThemeSettingsForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\StreamWrapper\PublicStream;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
|
||||
/**
|
||||
* Displays theme configuration for entire site and individual themes.
|
||||
*/
|
||||
class ThemeSettingsForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The theme handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* The MIME type guesser.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface
|
||||
*/
|
||||
protected $mimeTypeGuesser;
|
||||
|
||||
/**
|
||||
* An array of configuration names that should be editable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $editableConfig = [];
|
||||
|
||||
/**
|
||||
* Constructs a ThemeSettingsForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler instance to use.
|
||||
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
||||
* The theme handler.
|
||||
* @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser
|
||||
* The MIME type guesser instance to use.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, MimeTypeGuesserInterface $mime_type_guesser) {
|
||||
parent::__construct($config_factory);
|
||||
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->themeHandler = $theme_handler;
|
||||
$this->mimeTypeGuesser = $mime_type_guesser;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('theme_handler'),
|
||||
$container->get('file.mime_type.guesser')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'system_theme_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return $this->editableConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $theme
|
||||
* The theme name.
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $theme = '') {
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
|
||||
// Deny access if the theme is not installed or not found.
|
||||
if (!empty($theme) && (empty($themes[$theme]) || !$themes[$theme]->status)) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
// Default settings are defined in theme_get_setting() in includes/theme.inc
|
||||
if ($theme) {
|
||||
$var = 'theme_' . $theme . '_settings';
|
||||
$config_key = $theme . '.settings';
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
$features = $themes[$theme]->info['features'];
|
||||
}
|
||||
else {
|
||||
$var = 'theme_settings';
|
||||
$config_key = 'system.theme.global';
|
||||
}
|
||||
// @todo this is pretty meaningless since we're using theme_get_settings
|
||||
// which means overrides can bleed into active config here. Will be fixed
|
||||
// by https://www.drupal.org/node/2402467.
|
||||
$this->editableConfig = [$config_key];
|
||||
|
||||
$form['var'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $var
|
||||
);
|
||||
$form['config_key'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $config_key
|
||||
);
|
||||
|
||||
// Toggle settings
|
||||
$toggles = array(
|
||||
'logo' => t('Logo'),
|
||||
'name' => t('Site name'),
|
||||
'slogan' => t('Site slogan'),
|
||||
'node_user_picture' => t('User pictures in posts'),
|
||||
'comment_user_picture' => t('User pictures in comments'),
|
||||
'comment_user_verification' => t('User verification status in comments'),
|
||||
'favicon' => t('Shortcut icon'),
|
||||
);
|
||||
|
||||
// Some features are not always available
|
||||
$disabled = array();
|
||||
if (!user_picture_enabled()) {
|
||||
$disabled['toggle_node_user_picture'] = TRUE;
|
||||
$disabled['toggle_comment_user_picture'] = TRUE;
|
||||
}
|
||||
if (!$this->moduleHandler->moduleExists('comment')) {
|
||||
$disabled['toggle_comment_user_picture'] = TRUE;
|
||||
$disabled['toggle_comment_user_verification'] = TRUE;
|
||||
}
|
||||
|
||||
$form['theme_settings'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Toggle display'),
|
||||
'#open' => TRUE,
|
||||
'#description' => t('Enable or disable the display of certain page elements.'),
|
||||
);
|
||||
foreach ($toggles as $name => $title) {
|
||||
if ((!$theme) || in_array($name, $features)) {
|
||||
$form['theme_settings']['toggle_' . $name] = array('#type' => 'checkbox', '#title' => $title, '#default_value' => theme_get_setting('features.' . $name, $theme));
|
||||
// Disable checkboxes for features not supported in the current configuration.
|
||||
if (isset($disabled['toggle_' . $name])) {
|
||||
$form['theme_settings']['toggle_' . $name]['#disabled'] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Element::children($form['theme_settings'])) {
|
||||
// If there is no element in the theme settings details then do not show
|
||||
// it -- but keep it in the form if another module wants to alter.
|
||||
$form['theme_settings']['#access'] = FALSE;
|
||||
}
|
||||
|
||||
// Logo settings, only available when file.module is enabled.
|
||||
if ((!$theme) || in_array('logo', $features) && $this->moduleHandler->moduleExists('file')) {
|
||||
$form['logo'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Logo image settings'),
|
||||
'#open' => TRUE,
|
||||
'#states' => array(
|
||||
// Hide the logo image settings fieldset when logo display is disabled.
|
||||
'invisible' => array(
|
||||
'input[name="toggle_logo"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['logo']['default_logo'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Use the default logo supplied by the theme'),
|
||||
'#default_value' => theme_get_setting('logo.use_default', $theme),
|
||||
'#tree' => FALSE,
|
||||
);
|
||||
$form['logo']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#states' => array(
|
||||
// Hide the logo settings when using the default logo.
|
||||
'invisible' => array(
|
||||
'input[name="default_logo"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['logo']['settings']['logo_path'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Path to custom logo'),
|
||||
'#default_value' => theme_get_setting('logo.path', $theme),
|
||||
);
|
||||
$form['logo']['settings']['logo_upload'] = array(
|
||||
'#type' => 'file',
|
||||
'#title' => t('Upload logo image'),
|
||||
'#maxlength' => 40,
|
||||
'#description' => t("If you don't have direct file access to the server, use this field to upload your logo.")
|
||||
);
|
||||
}
|
||||
|
||||
if (((!$theme) || in_array('favicon', $features)) && $this->moduleHandler->moduleExists('file')) {
|
||||
$form['favicon'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Shortcut icon settings'),
|
||||
'#open' => TRUE,
|
||||
'#description' => t("Your shortcut icon, or 'favicon', is displayed in the address bar and bookmarks of most browsers."),
|
||||
'#states' => array(
|
||||
// Hide the shortcut icon settings fieldset when shortcut icon display
|
||||
// is disabled.
|
||||
'invisible' => array(
|
||||
'input[name="toggle_favicon"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['favicon']['default_favicon'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Use the default shortcut icon supplied by the theme'),
|
||||
'#default_value' => theme_get_setting('favicon.use_default', $theme),
|
||||
);
|
||||
$form['favicon']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#states' => array(
|
||||
// Hide the favicon settings when using the default favicon.
|
||||
'invisible' => array(
|
||||
'input[name="default_favicon"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['favicon']['settings']['favicon_path'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Path to custom icon'),
|
||||
'#default_value' => theme_get_setting('favicon.path', $theme),
|
||||
);
|
||||
$form['favicon']['settings']['favicon_upload'] = array(
|
||||
'#type' => 'file',
|
||||
'#title' => t('Upload icon image'),
|
||||
'#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.")
|
||||
);
|
||||
}
|
||||
|
||||
// Inject human-friendly values and form element descriptions for logo and
|
||||
// favicon.
|
||||
foreach (array('logo' => 'logo.svg', 'favicon' => 'favicon.ico') as $type => $default) {
|
||||
if (isset($form[$type]['settings'][$type . '_path'])) {
|
||||
$element = &$form[$type]['settings'][$type . '_path'];
|
||||
|
||||
// If path is a public:// URI, display the path relative to the files
|
||||
// directory; stream wrappers are not end-user friendly.
|
||||
$original_path = $element['#default_value'];
|
||||
$friendly_path = NULL;
|
||||
if (file_uri_scheme($original_path) == 'public') {
|
||||
$friendly_path = file_uri_target($original_path);
|
||||
$element['#default_value'] = $friendly_path;
|
||||
}
|
||||
|
||||
// Prepare local file path for description.
|
||||
if ($original_path && isset($friendly_path)) {
|
||||
$local_file = strtr($original_path, array('public:/' => PublicStream::basePath()));
|
||||
}
|
||||
elseif ($theme) {
|
||||
$local_file = drupal_get_path('theme', $theme) . '/' . $default;
|
||||
}
|
||||
else {
|
||||
$local_file = \Drupal::theme()->getActiveTheme()->getPath() . '/' . $default;
|
||||
}
|
||||
|
||||
$element['#description'] = t('Examples: <code>@implicit-public-file</code> (for a file in the public filesystem), <code>@explicit-file</code>, or <code>@local-file</code>.', array(
|
||||
'@implicit-public-file' => isset($friendly_path) ? $friendly_path : $default,
|
||||
'@explicit-file' => file_uri_scheme($original_path) !== FALSE ? $original_path : 'public://' . $default,
|
||||
'@local-file' => $local_file,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if ($theme) {
|
||||
// Call engine-specific settings.
|
||||
$function = $themes[$theme]->prefix . '_engine_settings';
|
||||
if (function_exists($function)) {
|
||||
$form['engine_specific'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => t('Theme-engine-specific settings'),
|
||||
'#open' => TRUE,
|
||||
'#description' => t('These settings only exist for the themes based on the %engine theme engine.', array('%engine' => $themes[$theme]->prefix)),
|
||||
);
|
||||
$function($form, $form_state);
|
||||
}
|
||||
|
||||
// Create a list which includes the current theme and all its base themes.
|
||||
if (isset($themes[$theme]->base_themes)) {
|
||||
$theme_keys = array_keys($themes[$theme]->base_themes);
|
||||
$theme_keys[] = $theme;
|
||||
}
|
||||
else {
|
||||
$theme_keys = array($theme);
|
||||
}
|
||||
|
||||
// Save the name of the current theme (if any), so that we can temporarily
|
||||
// override the current theme and allow theme_get_setting() to work
|
||||
// without having to pass the theme name to it.
|
||||
$default_active_theme = \Drupal::theme()->getActiveTheme();
|
||||
$default_theme = $default_active_theme->getName();
|
||||
/** @var \Drupal\Core\Theme\ThemeInitialization $theme_initialization */
|
||||
$theme_initialization = \Drupal::service('theme.initialization');
|
||||
\Drupal::theme()->setActiveTheme($theme_initialization->getActiveThemeByName($theme));
|
||||
|
||||
// Process the theme and all its base themes.
|
||||
foreach ($theme_keys as $theme) {
|
||||
// Include the theme-settings.php file.
|
||||
$filename = DRUPAL_ROOT . '/' . $themes[$theme]->getPath() . '/theme-settings.php';
|
||||
if (file_exists($filename)) {
|
||||
require_once $filename;
|
||||
}
|
||||
|
||||
// Call theme-specific settings.
|
||||
$function = $theme . '_form_system_theme_settings_alter';
|
||||
if (function_exists($function)) {
|
||||
$function($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the original current theme.
|
||||
if (isset($default_theme)) {
|
||||
\Drupal::theme()->setActiveTheme($default_active_theme);
|
||||
}
|
||||
else {
|
||||
\Drupal::theme()->resetActiveTheme();
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::validateForm($form, $form_state);
|
||||
|
||||
if ($this->moduleHandler->moduleExists('file')) {
|
||||
// Handle file uploads.
|
||||
$validators = array('file_validate_is_image' => array());
|
||||
|
||||
// Check for a new uploaded logo.
|
||||
$file = file_save_upload('logo_upload', $validators, FALSE, 0);
|
||||
if (isset($file)) {
|
||||
// File upload was attempted.
|
||||
if ($file) {
|
||||
// Put the temporary file in form_values so we can save it on submit.
|
||||
$form_state->setValue('logo_upload', $file);
|
||||
}
|
||||
else {
|
||||
// File upload failed.
|
||||
$form_state->setErrorByName('logo_upload', $this->t('The logo could not be uploaded.'));
|
||||
}
|
||||
}
|
||||
|
||||
$validators = array('file_validate_extensions' => array('ico png gif jpg jpeg apng svg'));
|
||||
|
||||
// Check for a new uploaded favicon.
|
||||
$file = file_save_upload('favicon_upload', $validators, FALSE, 0);
|
||||
if (isset($file)) {
|
||||
// File upload was attempted.
|
||||
if ($file) {
|
||||
// Put the temporary file in form_values so we can save it on submit.
|
||||
$form_state->setValue('favicon_upload', $file);
|
||||
}
|
||||
else {
|
||||
// File upload failed.
|
||||
$form_state->setErrorByName('favicon_upload', $this->t('The favicon could not be uploaded.'));
|
||||
}
|
||||
}
|
||||
|
||||
// If the user provided a path for a logo or favicon file, make sure a file
|
||||
// exists at that path.
|
||||
if ($form_state->getValue('logo_path')) {
|
||||
$path = $this->validatePath($form_state->getValue('logo_path'));
|
||||
if (!$path) {
|
||||
$form_state->setErrorByName('logo_path', $this->t('The custom logo path is invalid.'));
|
||||
}
|
||||
}
|
||||
if ($form_state->getValue('favicon_path')) {
|
||||
$path = $this->validatePath($form_state->getValue('favicon_path'));
|
||||
if (!$path) {
|
||||
$form_state->setErrorByName('favicon_path', $this->t('The custom favicon path is invalid.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
$config_key = $form_state->getValue('config_key');
|
||||
$this->editableConfig = [$config_key];
|
||||
$config = $this->config($config_key);
|
||||
|
||||
// Exclude unnecessary elements before saving.
|
||||
$form_state->cleanValues();
|
||||
$form_state->unsetValue('var');
|
||||
$form_state->unsetValue('config_key');
|
||||
|
||||
$values = $form_state->getValues();
|
||||
|
||||
// If the user uploaded a new logo or favicon, save it to a permanent location
|
||||
// and use it in place of the default theme-provided file.
|
||||
if ($this->moduleHandler->moduleExists('file')) {
|
||||
if ($file = $values['logo_upload']) {
|
||||
$filename = file_unmanaged_copy($file->getFileUri());
|
||||
$values['default_logo'] = 0;
|
||||
$values['logo_path'] = $filename;
|
||||
$values['toggle_logo'] = 1;
|
||||
}
|
||||
if ($file = $values['favicon_upload']) {
|
||||
$filename = file_unmanaged_copy($file->getFileUri());
|
||||
$values['default_favicon'] = 0;
|
||||
$values['favicon_path'] = $filename;
|
||||
$values['toggle_favicon'] = 1;
|
||||
}
|
||||
unset($values['logo_upload']);
|
||||
unset($values['favicon_upload']);
|
||||
|
||||
// If the user entered a path relative to the system files directory for
|
||||
// a logo or favicon, store a public:// URI so the theme system can handle it.
|
||||
if (!empty($values['logo_path'])) {
|
||||
$values['logo_path'] = $this->validatePath($values['logo_path']);
|
||||
}
|
||||
if (!empty($values['favicon_path'])) {
|
||||
$values['favicon_path'] = $this->validatePath($values['favicon_path']);
|
||||
}
|
||||
|
||||
if (empty($values['default_favicon']) && !empty($values['favicon_path'])) {
|
||||
$values['favicon_mimetype'] = $this->mimeTypeGuesser->guess($values['favicon_path']);
|
||||
}
|
||||
}
|
||||
|
||||
theme_settings_convert_to_config($values, $config)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for the system_theme_settings form.
|
||||
*
|
||||
* Attempts to validate normal system paths, paths relative to the public files
|
||||
* directory, or stream wrapper URIs. If the given path is any of the above,
|
||||
* returns a valid path or URI that the theme system can display.
|
||||
*
|
||||
* @param string $path
|
||||
* A path relative to the Drupal root or to the public files directory, or
|
||||
* a stream wrapper URI.
|
||||
* @return mixed
|
||||
* A valid path that can be displayed through the theme system, or FALSE if
|
||||
* the path could not be validated.
|
||||
*/
|
||||
protected function validatePath($path) {
|
||||
// Absolute local file paths are invalid.
|
||||
if (drupal_realpath($path) == $path) {
|
||||
return FALSE;
|
||||
}
|
||||
// A path relative to the Drupal root or a fully qualified URI is valid.
|
||||
if (is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
// Prepend 'public://' for relative file paths within public filesystem.
|
||||
if (file_uri_scheme($path) === FALSE) {
|
||||
$path = 'public://' . $path;
|
||||
}
|
||||
if (is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
75
core/modules/system/src/MachineNameController.php
Normal file
75
core/modules/system/src/MachineNameController.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\MachineNameController.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Controller routines for machine name transliteration routes.
|
||||
*/
|
||||
class MachineNameController implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The transliteration helper.
|
||||
*
|
||||
* @var \Drupal\Component\Transliteration\TransliterationInterface
|
||||
*/
|
||||
protected $transliteration;
|
||||
|
||||
/**
|
||||
* Constructs a MachineNameController object.
|
||||
*
|
||||
* @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
|
||||
* The transliteration helper.
|
||||
*/
|
||||
public function __construct(TransliterationInterface $transliteration) {
|
||||
$this->transliteration = $transliteration;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('transliteration')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transliterates a string in given language. Various postprocessing possible.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The input string and language for the transliteration.
|
||||
* Optionally may contain the replace_pattern, replace, lowercase parameters.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* The transliterated string.
|
||||
*/
|
||||
public function transliterate(Request $request) {
|
||||
$text = $request->query->get('text');
|
||||
$langcode = $request->query->get('langcode');
|
||||
$replace_pattern = $request->query->get('replace_pattern');
|
||||
$replace = $request->query->get('replace');
|
||||
$lowercase = $request->query->get('lowercase');
|
||||
|
||||
$transliterated = $this->transliteration->transliterate($text, $langcode, '_');
|
||||
if($lowercase) {
|
||||
$transliterated = Unicode::strtolower($transliterated);
|
||||
}
|
||||
if(isset($replace_pattern) && isset($replace)) {
|
||||
$transliterated = preg_replace('@' . $replace_pattern . '@', $replace, $transliterated);
|
||||
}
|
||||
return new JsonResponse($transliterated);
|
||||
}
|
||||
|
||||
}
|
42
core/modules/system/src/MenuAccessControlHandler.php
Normal file
42
core/modules/system/src/MenuAccessControlHandler.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\MenuAccessControlHandler.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the menu entity type.
|
||||
*
|
||||
* @see \Drupal\system\Entity\Menu
|
||||
*/
|
||||
class MenuAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
|
||||
if ($operation === 'view') {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
// Locked menus could not be deleted.
|
||||
elseif ($operation == 'delete') {
|
||||
if ($entity->isLocked()) {
|
||||
return AccessResult::forbidden()->cacheUntilEntityChanges($entity);
|
||||
}
|
||||
else {
|
||||
return parent::checkAccess($entity, $operation, $langcode, $account)->cacheUntilEntityChanges($entity);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::checkAccess($entity, $operation, $langcode, $account);
|
||||
}
|
||||
|
||||
}
|
33
core/modules/system/src/MenuInterface.php
Normal file
33
core/modules/system/src/MenuInterface.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\MenuInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a menu entity.
|
||||
*/
|
||||
interface MenuInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Returns the description of the menu.
|
||||
*
|
||||
* @return string
|
||||
* Description of the menu.
|
||||
*/
|
||||
public function getDescription();
|
||||
|
||||
/**
|
||||
* Determines if this menu is locked.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the menu is locked, FALSE otherwise.
|
||||
*/
|
||||
public function isLocked();
|
||||
|
||||
}
|
218
core/modules/system/src/PathBasedBreadcrumbBuilder.php
Normal file
218
core/modules/system/src/PathBasedBreadcrumbBuilder.php
Normal file
|
@ -0,0 +1,218 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\PathBasedBreadcrumbBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Access\AccessManagerInterface;
|
||||
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Controller\TitleResolverInterface;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\ParamConverter\ParamNotConvertedException;
|
||||
use Drupal\Core\Path\CurrentPathStack;
|
||||
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
|
||||
use Drupal\Core\Routing\RequestContext;
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
|
||||
|
||||
/**
|
||||
* Class to define the menu_link breadcrumb builder.
|
||||
*/
|
||||
class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The router request context.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RequestContext
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* The menu link access service.
|
||||
*
|
||||
* @var \Drupal\Core\Access\AccessManagerInterface
|
||||
*/
|
||||
protected $accessManager;
|
||||
|
||||
/**
|
||||
* The dynamic router service.
|
||||
*
|
||||
* @var \Symfony\Component\Routing\Matcher\RequestMatcherInterface
|
||||
*/
|
||||
protected $router;
|
||||
|
||||
/**
|
||||
* The dynamic router service.
|
||||
*
|
||||
* @var \Drupal\Core\PathProcessor\InboundPathProcessorInterface
|
||||
*/
|
||||
protected $pathProcessor;
|
||||
|
||||
/**
|
||||
* Site config object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The title resolver.
|
||||
*
|
||||
* @var \Drupal\Core\Controller\TitleResolverInterface
|
||||
*/
|
||||
protected $titleResolver;
|
||||
|
||||
/**
|
||||
* The current user object.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs the PathBasedBreadcrumbBuilder.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RequestContext $context
|
||||
* The router request context.
|
||||
* @param \Drupal\Core\Access\AccessManagerInterface $access_manager
|
||||
* The menu link access service.
|
||||
* @param \Symfony\Component\Routing\Matcher\RequestMatcherInterface $router
|
||||
* The dynamic router service.
|
||||
* @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor
|
||||
* The inbound path processor.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
* @param \Drupal\Core\Controller\TitleResolverInterface $title_resolver
|
||||
* The title resolver service.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user object.
|
||||
* @param \Drupal\Core\Path\CurrentPathStack $current_path
|
||||
* The current path.
|
||||
*/
|
||||
public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPathStack $current_path) {
|
||||
$this->context = $context;
|
||||
$this->accessManager = $access_manager;
|
||||
$this->router = $router;
|
||||
$this->pathProcessor = $path_processor;
|
||||
$this->config = $config_factory->get('system.site');
|
||||
$this->titleResolver = $title_resolver;
|
||||
$this->currentUser = $current_user;
|
||||
$this->currentPath = $current_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies(RouteMatchInterface $route_match) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build(RouteMatchInterface $route_match) {
|
||||
$links = array();
|
||||
|
||||
// General path-based breadcrumbs. Use the actual request path, prior to
|
||||
// resolving path aliases, so the breadcrumb can be defined by simply
|
||||
// creating a hierarchy of path aliases.
|
||||
$path = trim($this->context->getPathInfo(), '/');
|
||||
$path_elements = explode('/', $path);
|
||||
$exclude = array();
|
||||
// Don't show a link to the front-page path.
|
||||
$front = $this->config->get('page.front');
|
||||
$exclude[$front] = TRUE;
|
||||
// /user is just a redirect, so skip it.
|
||||
// @todo Find a better way to deal with /user.
|
||||
$exclude['/user'] = TRUE;
|
||||
while (count($path_elements) > 1) {
|
||||
array_pop($path_elements);
|
||||
// Copy the path elements for up-casting.
|
||||
$route_request = $this->getRequestForPath('/' . implode('/', $path_elements), $exclude);
|
||||
if ($route_request) {
|
||||
$route_match = RouteMatch::createFromRequest($route_request);
|
||||
$access = $this->accessManager->check($route_match, $this->currentUser);
|
||||
if ($access) {
|
||||
$title = $this->titleResolver->getTitle($route_request, $route_match->getRouteObject());
|
||||
}
|
||||
if ($access) {
|
||||
if (!isset($title)) {
|
||||
// Fallback to using the raw path component as the title if the
|
||||
// route is missing a _title or _title_callback attribute.
|
||||
$title = str_replace(array('-', '_'), ' ', Unicode::ucfirst(end($path_elements)));
|
||||
}
|
||||
$url = Url::fromRouteMatch($route_match);
|
||||
$links[] = new Link($title, $url);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if ($path && '/' . $path != $front) {
|
||||
// Add the Home link, except for the front page.
|
||||
$links[] = Link::createFromRoute($this->t('Home'), '<front>');
|
||||
}
|
||||
return array_reverse($links);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a path in the router.
|
||||
*
|
||||
* @param string $path
|
||||
* The request path with a leading slash.
|
||||
* @param array $exclude
|
||||
* An array of paths or system paths to skip.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
* A populated request object or NULL if the path couldn't be matched.
|
||||
*/
|
||||
protected function getRequestForPath($path, array $exclude) {
|
||||
if (!empty($exclude[$path])) {
|
||||
return NULL;
|
||||
}
|
||||
// @todo Use the RequestHelper once https://www.drupal.org/node/2090293 is
|
||||
// fixed.
|
||||
$request = Request::create($path);
|
||||
// Performance optimization: set a short accept header to reduce overhead in
|
||||
// AcceptHeaderMatcher when matching the request.
|
||||
$request->headers->set('Accept', 'text/html');
|
||||
// Find the system path by resolving aliases, language prefix, etc.
|
||||
$processed = $this->pathProcessor->processInbound($path, $request);
|
||||
if (empty($processed) || !empty($exclude[$processed])) {
|
||||
// This resolves to the front page, which we already add.
|
||||
return NULL;
|
||||
}
|
||||
$this->currentPath->setPath($processed, $request);
|
||||
// Attempt to match this path to provide a fully built request.
|
||||
try {
|
||||
$request->attributes->add($this->router->matchRequest($request));
|
||||
return $request;
|
||||
}
|
||||
catch (ParamNotConvertedException $e) {
|
||||
return NULL;
|
||||
}
|
||||
catch (ResourceNotFoundException $e) {
|
||||
return NULL;
|
||||
}
|
||||
catch (MethodNotAllowedException $e) {
|
||||
return NULL;
|
||||
}
|
||||
catch (AccessDeniedHttpException $e) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
33
core/modules/system/src/PathProcessor/PathProcessorFiles.php
Normal file
33
core/modules/system/src/PathProcessor/PathProcessorFiles.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\PathProcessor\PathProcessorFiles.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\PathProcessor;
|
||||
|
||||
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Defines a path processor to rewrite file URLs.
|
||||
*
|
||||
* As the route system does not allow arbitrary amount of parameters convert
|
||||
* the file path to a query parameter on the request.
|
||||
*/
|
||||
class PathProcessorFiles implements InboundPathProcessorInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processInbound($path, Request $request) {
|
||||
if (strpos($path, '/system/files/') === 0 && !$request->query->has('file')) {
|
||||
$file_path = preg_replace('|^\/system\/files\/|', '', $path);
|
||||
$request->query->set('file', $file_path);
|
||||
return '/system/files';
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
}
|
45
core/modules/system/src/PhpStorage/MockPhpStorage.php
Normal file
45
core/modules/system/src/PhpStorage/MockPhpStorage.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\PhpStorage\MockPhpStorage.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\PhpStorage;
|
||||
|
||||
/**
|
||||
* Mock PHP storage class used for testing.
|
||||
*/
|
||||
class MockPhpStorage {
|
||||
|
||||
/**
|
||||
* The storage configuration.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $configuration;
|
||||
|
||||
/**
|
||||
* Constructs a MockPhpStorage object.
|
||||
*
|
||||
* @param array $configuration
|
||||
*/
|
||||
public function __construct(array $configuration) {
|
||||
$this->configuration = $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configuration data.
|
||||
*/
|
||||
public function getConfiguration() {
|
||||
return $this->configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single configuration key.
|
||||
*/
|
||||
public function getConfigurationValue($key) {
|
||||
return isset($this->configuration[$key]) ? $this->configuration[$key] : NULL;
|
||||
}
|
||||
|
||||
}
|
23
core/modules/system/src/Plugin/Archiver/Tar.php
Normal file
23
core/modules/system/src/Plugin/Archiver/Tar.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Archiver\Tar.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Archiver;
|
||||
|
||||
use Drupal\Core\Archiver\Tar as BaseTar;
|
||||
|
||||
/**
|
||||
* Defines an archiver implementation for .tar files.
|
||||
*
|
||||
* @Archiver(
|
||||
* id = "Tar",
|
||||
* title = @Translation("Tar"),
|
||||
* description = @Translation("Handles .tar files."),
|
||||
* extensions = {"tar", "tgz", "tar.gz", "tar.bz2"}
|
||||
* )
|
||||
*/
|
||||
class Tar extends BaseTar {
|
||||
}
|
25
core/modules/system/src/Plugin/Archiver/Zip.php
Normal file
25
core/modules/system/src/Plugin/Archiver/Zip.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Archiver\Zip.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Archiver;
|
||||
|
||||
use Drupal\Core\Archiver\Zip as BaseZip;
|
||||
|
||||
/**
|
||||
* Defines an archiver implementation for .zip files.
|
||||
*
|
||||
* @link http://php.net/zip
|
||||
*
|
||||
* @Archiver(
|
||||
* id = "Zip",
|
||||
* title = @Translation("Zip"),
|
||||
* description = @Translation("Handles zip files."),
|
||||
* extensions = {"zip"}
|
||||
* )
|
||||
*/
|
||||
class Zip extends BaseZip {
|
||||
}
|
193
core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
Normal file
193
core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
Normal file
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Block\SystemBrandingBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a block to display 'Site branding' elements.
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_branding_block",
|
||||
* admin_label = @Translation("Site branding")
|
||||
* )
|
||||
*/
|
||||
class SystemBrandingBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* Stores the configuration factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* Creates a SystemBrandingBlock instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->configFactory = $config_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('config.factory')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array(
|
||||
'use_site_logo' => TRUE,
|
||||
'use_site_name' => TRUE,
|
||||
'use_site_slogan' => TRUE,
|
||||
'label_display' => FALSE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
// Get the theme.
|
||||
$theme = $form_state->get('block_theme');
|
||||
|
||||
// Get permissions.
|
||||
$url_system_theme_settings = new Url('system.theme_settings');
|
||||
$url_system_theme_settings_theme = new Url('system.theme_settings_theme', array('theme' => $theme));
|
||||
|
||||
if ($url_system_theme_settings->access() && $url_system_theme_settings_theme->access()) {
|
||||
// Provide links to the Appearance Settings and Theme Settings pages
|
||||
// if the user has access to administer themes.
|
||||
$site_logo_description = $this->t('Defined on the <a href="@appearance">Appearance Settings</a> or <a href="@theme">Theme Settings</a> page.', array(
|
||||
'@appearance' => $url_system_theme_settings->toString(),
|
||||
'@theme' => $url_system_theme_settings_theme->toString(),
|
||||
));
|
||||
}
|
||||
else {
|
||||
// Explain that the user does not have access to the Appearance and Theme
|
||||
// Settings pages.
|
||||
$site_logo_description = $this->t('Defined on the Appearance or Theme Settings page. You do not have the appropriate permissions to change the site logo.');
|
||||
}
|
||||
$url_system_site_information_settings = new Url('system.site_information_settings');
|
||||
if ($url_system_site_information_settings->access()) {
|
||||
// Get paths to settings pages.
|
||||
$site_information_url = $url_system_site_information_settings->toString();
|
||||
|
||||
// Provide link to Site Information page if the user has access to
|
||||
// administer site configuration.
|
||||
$site_name_description = $this->t('Defined on the <a href="@information">Site Information</a> page.', array('@information' => $site_information_url));
|
||||
$site_slogan_description = $this->t('Defined on the <a href="@information">Site Information</a> page.', array('@information' => $site_information_url));
|
||||
}
|
||||
else {
|
||||
// Explain that the user does not have access to the Site Information
|
||||
// page.
|
||||
$site_name_description = $this->t('Defined on the Site Information page. You do not have the appropriate permissions to change the site logo.');
|
||||
$site_slogan_description = $this->t('Defined on the Site Information page. You do not have the appropriate permissions to change the site logo.');
|
||||
}
|
||||
|
||||
$form['block_branding'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Toggle branding elements'),
|
||||
'#description' => $this->t('Choose which branding elements you want to show in this block instance.'),
|
||||
);
|
||||
$form['block_branding']['use_site_logo'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Site logo'),
|
||||
'#description' => $site_logo_description,
|
||||
'#default_value' => $this->configuration['use_site_logo'],
|
||||
);
|
||||
|
||||
$form['block_branding']['use_site_name'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Site name'),
|
||||
'#description' => $site_name_description,
|
||||
'#default_value' => $this->configuration['use_site_name'],
|
||||
);
|
||||
$form['block_branding']['use_site_slogan'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Site slogan'),
|
||||
'#description' => $site_slogan_description,
|
||||
'#default_value' => $this->configuration['use_site_slogan'],
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
$block_branding = $form_state->getValue('block_branding');
|
||||
$this->configuration['use_site_logo'] = $block_branding['use_site_logo'];
|
||||
$this->configuration['use_site_name'] = $block_branding['use_site_name'];
|
||||
$this->configuration['use_site_slogan'] = $block_branding['use_site_slogan'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$build = array();
|
||||
$site_config = $this->configFactory->get('system.site');
|
||||
|
||||
$logo = theme_get_setting('logo');
|
||||
$build['site_logo'] = array(
|
||||
'#theme' => 'image',
|
||||
'#uri' => $logo['url'],
|
||||
'#alt' => $this->t('Home'),
|
||||
'#access' => $this->configuration['use_site_logo'],
|
||||
);
|
||||
|
||||
$build['site_name'] = array(
|
||||
'#markup' => $site_config->get('name'),
|
||||
'#access' => $this->configuration['use_site_name'],
|
||||
);
|
||||
|
||||
$build['site_slogan'] = array(
|
||||
'#markup' => Xss::filterAdmin($site_config->get('slogan')),
|
||||
'#access' => $this->configuration['use_site_slogan'],
|
||||
);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return Cache::mergeTags(
|
||||
parent::getCacheTags(),
|
||||
$this->configFactory->get('system.site')->getCacheTags()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Block\SystemBreadcrumbBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a block to display the breadcrumbs.
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_breadcrumb_block",
|
||||
* admin_label = @Translation("Breadcrumbs")
|
||||
* )
|
||||
*/
|
||||
class SystemBreadcrumbBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The breadcrumb manager.
|
||||
*
|
||||
* @var \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface
|
||||
*/
|
||||
protected $breadcrumbManager;
|
||||
|
||||
/**
|
||||
* The current route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* Constructs a new SystemBreadcrumbBlock object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface $breadcrumb_manager
|
||||
* The breadcrumb manager.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The current route match.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, BreadcrumbBuilderInterface $breadcrumb_manager, RouteMatchInterface $route_match) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->breadcrumbManager = $breadcrumb_manager;
|
||||
$this->routeMatch = $route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('breadcrumb'),
|
||||
$container->get('current_route_match')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$breadcrumb = $this->breadcrumbManager->build($this->routeMatch);
|
||||
if (!empty($breadcrumb)) {
|
||||
// $breadcrumb is expected to be an array of rendered breadcrumb links.
|
||||
return array(
|
||||
'#theme' => 'breadcrumb',
|
||||
'#links' => $breadcrumb,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Make cacheable in https://www.drupal.org/node/2483183
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
59
core/modules/system/src/Plugin/Block/SystemMainBlock.php
Normal file
59
core/modules/system/src/Plugin/Block/SystemMainBlock.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Block\SystemMainBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Block\MainContentBlockPluginInterface;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a 'Main page content' block.
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_main_block",
|
||||
* admin_label = @Translation("Main page content")
|
||||
* )
|
||||
*/
|
||||
class SystemMainBlock extends BlockBase implements MainContentBlockPluginInterface {
|
||||
|
||||
/**
|
||||
* The render array representing the main page content.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $mainContent;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setMainContent(array $main_content) {
|
||||
$this->mainContent = $main_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return $this->mainContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
$form['cache']['#disabled'] = TRUE;
|
||||
$form['cache']['#description'] = $this->t("This block's maximum age cannot be configured, because it depends on the contents.");
|
||||
$form['cache']['max_age']['#value'] = Cache::PERMANENT;
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
202
core/modules/system/src/Plugin/Block/SystemMenuBlock.php
Normal file
202
core/modules/system/src/Plugin/Block/SystemMenuBlock.php
Normal file
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Block\SystemMenuBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Menu\MenuActiveTrailInterface;
|
||||
use Drupal\Core\Menu\MenuLinkTreeInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a generic Menu block.
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_menu_block",
|
||||
* admin_label = @Translation("Menu"),
|
||||
* category = @Translation("Menus"),
|
||||
* deriver = "Drupal\system\Plugin\Derivative\SystemMenuBlock"
|
||||
* )
|
||||
*/
|
||||
class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The menu link tree service.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuLinkTreeInterface
|
||||
*/
|
||||
protected $menuTree;
|
||||
|
||||
/**
|
||||
* The active menu trail service.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuActiveTrailInterface
|
||||
*/
|
||||
protected $menuActiveTrail;
|
||||
|
||||
/**
|
||||
* Constructs a new SystemMenuBlock.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param array $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Menu\MenuLinkTreeInterface $menu_tree
|
||||
* The menu tree service.
|
||||
* @param \Drupal\Core\Menu\MenuActiveTrailInterface $menu_active_trail
|
||||
* The active menu trail service.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree, MenuActiveTrailInterface $menu_active_trail) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->menuTree = $menu_tree;
|
||||
$this->menuActiveTrail = $menu_active_trail;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('menu.link_tree'),
|
||||
$container->get('menu.active_trail')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockForm($form, FormStateInterface $form_state) {
|
||||
$config = $this->configuration;
|
||||
|
||||
$defaults = $this->defaultConfiguration();
|
||||
$form['menu_levels'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Menu levels'),
|
||||
// Open if not set to defaults.
|
||||
'#open' => $defaults['level'] !== $config['level'] || $defaults['depth'] !== $config['depth'],
|
||||
'#process' => [[get_class(), 'processMenuLevelParents']],
|
||||
);
|
||||
|
||||
$options = range(0, $this->menuTree->maxDepth());
|
||||
unset($options[0]);
|
||||
|
||||
$form['menu_levels']['level'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Initial menu level'),
|
||||
'#default_value' => $config['level'],
|
||||
'#options' => $options,
|
||||
'#description' => $this->t('The menu will only be visible if the menu item for the current page is at or below the selected starting level. Select level 1 to always keep this menu visible.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$options[0] = $this->t('Unlimited');
|
||||
|
||||
$form['menu_levels']['depth'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Maximum number of menu levels to display'),
|
||||
'#default_value' => $config['depth'],
|
||||
'#options' => $options,
|
||||
'#description' => $this->t('The maximum number of menu levels to show, starting from the initial menu level. For example: with an initial level 2 and a maximum number of 3, menu levels 2, 3 and 4 can be displayed.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form API callback: Processes the menu_levels field element.
|
||||
*
|
||||
* Adjusts the #parents of menu_levels to save its children at the top level.
|
||||
*/
|
||||
public static function processMenuLevelParents(&$element, FormStateInterface $form_state, &$complete_form) {
|
||||
array_pop($element['#parents']);
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blockSubmit($form, FormStateInterface $form_state) {
|
||||
$this->configuration['level'] = $form_state->getValue('level');
|
||||
$this->configuration['depth'] = $form_state->getValue('depth');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$menu_name = $this->getDerivativeId();
|
||||
$parameters = $this->menuTree->getCurrentRouteMenuTreeParameters($menu_name);
|
||||
|
||||
// Adjust the menu tree parameters based on the block's configuration.
|
||||
$level = $this->configuration['level'];
|
||||
$depth = $this->configuration['depth'];
|
||||
$parameters->setMinDepth($level);
|
||||
// When the depth is configured to zero, there is no depth limit. When depth
|
||||
// is non-zero, it indicates the number of levels that must be displayed.
|
||||
// Hence this is a relative depth that we must convert to an actual
|
||||
// (absolute) depth, that may never exceed the maximum depth.
|
||||
if ($depth > 0) {
|
||||
$parameters->setMaxDepth(min($level + $depth - 1, $this->menuTree->maxDepth()));
|
||||
}
|
||||
|
||||
$tree = $this->menuTree->load($menu_name, $parameters);
|
||||
$manipulators = array(
|
||||
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
|
||||
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
|
||||
);
|
||||
$tree = $this->menuTree->transform($tree, $manipulators);
|
||||
return $this->menuTree->build($tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return [
|
||||
'level' => 1,
|
||||
'depth' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
// Even when the menu block renders to the empty string for a user, we want
|
||||
// the cache tag for this menu to be set: whenever the menu is changed, this
|
||||
// menu block must also be re-rendered for that user, because maybe a menu
|
||||
// link that is accessible for that user has been added.
|
||||
$cache_tags = parent::getCacheTags();
|
||||
$cache_tags[] = 'config:system.menu.' . $this->getDerivativeId();
|
||||
return $cache_tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
// ::build() uses MenuLinkTreeInterface::getCurrentRouteMenuTreeParameters()
|
||||
// to generate menu tree parameters, and those take the active menu trail
|
||||
// into account. Therefore, we must vary the rendered menu by the active
|
||||
// trail of the rendered menu.
|
||||
// Additional cache contexts, e.g. those that determine link text or
|
||||
// accessibility of a menu, will be bubbled automatically.
|
||||
$menu_name = $this->getDerivativeId();
|
||||
return [
|
||||
'route.menu_active_trails:' . $menu_name,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
67
core/modules/system/src/Plugin/Block/SystemMessagesBlock.php
Normal file
67
core/modules/system/src/Plugin/Block/SystemMessagesBlock.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Block\SystemMessagesBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Block\MessagesBlockPluginInterface;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a block to display the messages.
|
||||
*
|
||||
* @see drupal_set_message()
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_messages_block",
|
||||
* admin_label = @Translation("Messages")
|
||||
* )
|
||||
*/
|
||||
class SystemMessagesBlock extends BlockBase implements MessagesBlockPluginInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array(
|
||||
'label_display' => FALSE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return ['#type' => 'status_messages'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
// @see ::getCacheMaxAge()
|
||||
$form['cache']['#description'] = $this->t('This block is cacheable forever, it is not configurable.');
|
||||
$form['cache']['max_age']['#value'] = Cache::PERMANENT;
|
||||
$form['cache']['max_age']['#disabled'] = TRUE;
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
// The messages are session-specific and hence aren't cacheable, but the
|
||||
// block itself *is* cacheable because it uses a #lazy_builder callback and
|
||||
// hence the block has a globally cacheable render array.
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Block\SystemPoweredByBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a 'Powered by Drupal' block.
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_powered_by_block",
|
||||
* admin_label = @Translation("Powered by Drupal")
|
||||
* )
|
||||
*/
|
||||
class SystemPoweredByBlock extends BlockBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
return array('#markup' => '<span>' . $this->t('Powered by <a href="@poweredby">Drupal</a>', array('@poweredby' => 'https://www.drupal.org')) . '</span>');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
// @see ::getCacheMaxAge()
|
||||
$form['cache']['#disabled'] = TRUE;
|
||||
$form['cache']['max_age']['#value'] = Cache::PERMANENT;
|
||||
$form['cache']['#description'] = $this->t('This block is always cached forever, it is not configurable.');
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
// The 'Powered by Drupal' block is permanently cacheable, because its
|
||||
// contents can never change.
|
||||
return Cache::PERMANENT;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Condition\CurrentThemeCondition.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Condition;
|
||||
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\Extension\ThemeHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Theme\ThemeManagerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a 'Current Theme' condition.
|
||||
*
|
||||
* @Condition(
|
||||
* id = "current_theme",
|
||||
* label = @Translation("Current Theme"),
|
||||
* )
|
||||
*/
|
||||
class CurrentThemeCondition extends ConditionPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The theme manager.
|
||||
*
|
||||
* @var \Drupal\Core\Theme\ThemeManagerInterface
|
||||
*/
|
||||
protected $themeManager;
|
||||
|
||||
/**
|
||||
* The theme handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ThemeHandlerInterface
|
||||
*/
|
||||
protected $themeHandler;
|
||||
|
||||
/**
|
||||
* Constructs a CurrentThemeCondition condition plugin.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
|
||||
* The theme manager.
|
||||
* @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
|
||||
* The theme handler.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ThemeManagerInterface $theme_manager, ThemeHandlerInterface $theme_handler) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->themeManager = $theme_manager;
|
||||
$this->themeHandler = $theme_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('theme.manager'),
|
||||
$container->get('theme_handler')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array('theme' => '') + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form['theme'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Theme'),
|
||||
'#default_value' => $this->configuration['theme'],
|
||||
'#options' => array_map(function ($theme_info) {
|
||||
return $theme_info->info['name'];
|
||||
}, $this->themeHandler->listInfo()),
|
||||
);
|
||||
return parent::buildConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->configuration['theme'] = $form_state->getValue('theme');
|
||||
parent::submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
if (!$this->configuration['theme']) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return $this->themeManager->getActiveTheme()->getName() == $this->configuration['theme'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
if ($this->isNegated()) {
|
||||
return $this->t('The current theme is not @theme', array('@theme' => $this->configuration['theme']));
|
||||
}
|
||||
|
||||
return $this->t('The current theme is @theme', array('@theme' => $this->configuration['theme']));
|
||||
}
|
||||
|
||||
}
|
162
core/modules/system/src/Plugin/Condition/RequestPath.php
Normal file
162
core/modules/system/src/Plugin/Condition/RequestPath.php
Normal file
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\system\Plugin\Condition\RequestPath.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Plugin\Condition;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
use Drupal\Core\Path\CurrentPathStack;
|
||||
use Drupal\Core\Path\PathMatcherInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Provides a 'Request Path' condition.
|
||||
*
|
||||
* @Condition(
|
||||
* id = "request_path",
|
||||
* label = @Translation("Request Path"),
|
||||
* )
|
||||
*/
|
||||
class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* An alias manager to find the alias for the current system path.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasManagerInterface
|
||||
*/
|
||||
protected $aliasManager;
|
||||
|
||||
/**
|
||||
* The path matcher.
|
||||
*
|
||||
* @var \Drupal\Core\Path\PathMatcherInterface
|
||||
*/
|
||||
protected $pathMatcher;
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
*/
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* The current path.
|
||||
*
|
||||
* @var \Drupal\Core\Path\CurrentPathStack
|
||||
*/
|
||||
protected $currentPath;
|
||||
|
||||
/**
|
||||
* Constructs a RequestPath condition plugin.
|
||||
*
|
||||
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
|
||||
* An alias manager to find the alias for the current system path.
|
||||
* @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
|
||||
* The path matcher service.
|
||||
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
||||
* The request stack.
|
||||
* @param \Drupal\Core\Path\CurrentPathStack $current_path
|
||||
* The current path.
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param array $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(AliasManagerInterface $alias_manager, PathMatcherInterface $path_matcher, RequestStack $request_stack, CurrentPathStack $current_path, array $configuration, $plugin_id, array $plugin_definition) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->aliasManager = $alias_manager;
|
||||
$this->pathMatcher = $path_matcher;
|
||||
$this->requestStack = $request_stack;
|
||||
$this->currentPath = $current_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('path.alias_manager'),
|
||||
$container->get('path.matcher'),
|
||||
$container->get('request_stack'),
|
||||
$container->get('path.current'),
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array('pages' => '') + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form['pages'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Pages'),
|
||||
'#default_value' => $this->configuration['pages'],
|
||||
'#description' => $this->t("Specify pages by using their paths. Enter one path per line. The '*' character is a wildcard. Example paths are %user for the current user's page and %user-wildcard for every user page. %front is the front page.", array(
|
||||
'%user' => 'user',
|
||||
'%user-wildcard' => 'user/*',
|
||||
'%front' => '<front>',
|
||||
)),
|
||||
);
|
||||
return parent::buildConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->configuration['pages'] = $form_state->getValue('pages');
|
||||
parent::submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
$pages = array_map('trim', explode("\n", $this->configuration['pages']));
|
||||
$pages = implode(', ', $pages);
|
||||
if (!empty($this->configuration['negate'])) {
|
||||
return $this->t('Do not return true on the following pages: @pages', array('@pages' => $pages));
|
||||
}
|
||||
return $this->t('Return true on the following pages: @pages', array('@pages' => $pages));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
// Convert path to lowercase. This allows comparison of the same path
|
||||
// with different case. Ex: /Page, /page, /PAGE.
|
||||
$pages = Unicode::strtolower($this->configuration['pages']);
|
||||
if (!$pages) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
// Compare the lowercase path alias (if any) and internal path.
|
||||
$path = rtrim($this->currentPath->getPath($request), '/');
|
||||
$path_alias = Unicode::strtolower($this->aliasManager->getAliasByPath($path));
|
||||
|
||||
return $this->pathMatcher->matchPath($path_alias, $pages) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $pages));
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue