Update Composer, update everything
This commit is contained in:
parent
ea3e94409f
commit
dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions
|
@ -1,5 +1,5 @@
|
|||
uuid: ''
|
||||
name: 'Drupal'
|
||||
name: ''
|
||||
mail: ''
|
||||
slogan: ''
|
||||
page:
|
||||
|
|
|
@ -5,8 +5,11 @@ system.site:
|
|||
label: 'Site information'
|
||||
mapping:
|
||||
uuid:
|
||||
type: string
|
||||
type: uuid
|
||||
label: 'Site UUID'
|
||||
constraints:
|
||||
Uuid: []
|
||||
NotNull: []
|
||||
name:
|
||||
type: label
|
||||
label: 'Site name'
|
||||
|
@ -185,13 +188,6 @@ system.performance:
|
|||
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'
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
float: right;
|
||||
}
|
||||
.ajax-progress-throbber .throbber {
|
||||
background: transparent url(../../../../misc/throbber-active.gif) no-repeat 0px center;
|
||||
background: transparent url(../../../../misc/throbber-active.gif) no-repeat 0 center;
|
||||
display: inline;
|
||||
padding: 1px 5px 2px;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
.progress__percentage {
|
||||
color: #555;
|
||||
overflow: hidden;
|
||||
font-size: .875em;
|
||||
font-size: 0.875em;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
.progress__description {
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
|
||||
.system-status-report-counters__item {
|
||||
width: 100%;
|
||||
padding: .5em 0;
|
||||
padding: 0.5em 0;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
background-color: rgba(0, 0, 0, 0.063);
|
||||
margin-bottom: .5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 60em) {
|
||||
|
|
|
@ -117,8 +117,8 @@ small .admin-link:after {
|
|||
text-transform: none;
|
||||
}
|
||||
.system-modules td details a {
|
||||
color: #5C5C5B;
|
||||
border: 0px;
|
||||
color: #5c5c5b;
|
||||
border: 0;
|
||||
}
|
||||
.system-modules td details {
|
||||
border: 0;
|
||||
|
@ -211,7 +211,7 @@ small .admin-link:after {
|
|||
background-color: transparent;
|
||||
}
|
||||
[dir="rtl"] .system-status-report__status-title {
|
||||
padding: 10px 40px 10px 6px;
|
||||
padding: 10px 40px 10px 6px;
|
||||
}
|
||||
.system-status-report__status-icon:before {
|
||||
content: "";
|
||||
|
@ -223,7 +223,7 @@ small .admin-link:after {
|
|||
left: 12px; /* LTR */
|
||||
top: 12px;
|
||||
}
|
||||
[dir="rtl"] .system-status-report__status-icon:before {
|
||||
[dir="rtl"] .system-status-report__status-icon:before {
|
||||
left: auto;
|
||||
right: 12px;
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ small .admin-link:after {
|
|||
background-image: url(../../../misc/icons/e29700/warning.svg);
|
||||
}
|
||||
.system-status-report__entry__value {
|
||||
padding: 1em .5em;
|
||||
padding: 1em 0.5em;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,3 +394,8 @@ small .admin-link:after {
|
|||
.cron-description__run-cron {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.system-cron-settings__link {
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
table.diff {
|
||||
border-spacing: 4px;
|
||||
margin-bottom: 20px;
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
table.diff .diff-context {
|
||||
|
|
62
web/core/modules/system/js/system.date.es6.js
Normal file
62
web/core/modules/system/js/system.date.es6.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* @file
|
||||
* Provides date format preview feature.
|
||||
*/
|
||||
|
||||
(function($, Drupal, drupalSettings) {
|
||||
const dateFormats = drupalSettings.dateFormats;
|
||||
|
||||
/**
|
||||
* Display the preview for date format entered.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attach behavior for previewing date formats on input elements.
|
||||
*/
|
||||
Drupal.behaviors.dateFormat = {
|
||||
attach(context) {
|
||||
const $context = $(context);
|
||||
const $source = $context
|
||||
.find('[data-drupal-date-formatter="source"]')
|
||||
.once('dateFormat');
|
||||
const $target = $context
|
||||
.find('[data-drupal-date-formatter="preview"]')
|
||||
.once('dateFormat');
|
||||
const $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
|
||||
* The jQuery event triggered.
|
||||
*/
|
||||
function dateFormatHandler(e) {
|
||||
const baseValue = $(e.target).val() || '';
|
||||
const dateString = baseValue.replace(
|
||||
/\\?(.?)/gi,
|
||||
(key, value) => (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);
|
|
@ -1,40 +1,24 @@
|
|||
/**
|
||||
* @file
|
||||
* Provides date format preview feature.
|
||||
*/
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var dateFormats = drupalSettings.dateFormats;
|
||||
|
||||
/**
|
||||
* Display the preview for date format entered.
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attach behavior for previewing date formats on input elements.
|
||||
*/
|
||||
Drupal.behaviors.dateFormat = {
|
||||
attach: function (context) {
|
||||
attach: function attach(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
|
||||
* The jQuery event triggered.
|
||||
*/
|
||||
function dateFormatHandler(e) {
|
||||
var baseValue = $(e.target).val() || '';
|
||||
var dateString = baseValue.replace(/\\?(.?)/gi, function (key, value) {
|
||||
|
@ -45,13 +29,7 @@
|
|||
$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');
|
||||
$source.on('keyup.dateFormat change.dateFormat input.dateFormat', dateFormatHandler).trigger('keyup');
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
||||
})(jQuery, Drupal, drupalSettings);
|
84
web/core/modules/system/js/system.es6.js
Normal file
84
web/core/modules/system/js/system.es6.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @file
|
||||
* System behaviors.
|
||||
*/
|
||||
|
||||
(function($, Drupal, drupalSettings) {
|
||||
// Cache IDs in an array for ease of use.
|
||||
const ids = [];
|
||||
|
||||
/**
|
||||
* Attaches field copy behavior from input fields to other input fields.
|
||||
*
|
||||
* 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}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the field copy behavior to an input field.
|
||||
*/
|
||||
Drupal.behaviors.copyFieldValue = {
|
||||
attach(context) {
|
||||
// List of fields IDs on which to bind the event listener.
|
||||
// Create an array of IDs to use with jQuery.
|
||||
Object.keys(drupalSettings.copyFieldValue || {}).forEach(element => {
|
||||
ids.push(element);
|
||||
});
|
||||
|
||||
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(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(e, value) {
|
||||
const $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
|
||||
* The event triggered.
|
||||
*/
|
||||
valueSourceBlurHandler(e) {
|
||||
const value = $(e.target).val();
|
||||
const targetIds = drupalSettings.copyFieldValue[e.target.id];
|
||||
$(`#${targetIds.join(', #')}`).trigger('value:copy', value);
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal, drupalSettings);
|
|
@ -1,81 +1,41 @@
|
|||
/**
|
||||
* @file
|
||||
* System behaviors.
|
||||
*/
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, drupalSettings) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// Cache IDs in an array for ease of use.
|
||||
var ids = [];
|
||||
|
||||
/**
|
||||
* Attaches field copy behavior from input fields to other input fields.
|
||||
*
|
||||
* 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}
|
||||
*
|
||||
* @prop {Drupal~behaviorAttach} attach
|
||||
* Attaches the field copy behavior to an input field.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
attach: function attach(context) {
|
||||
Object.keys(drupalSettings.copyFieldValue || {}).forEach(function (element) {
|
||||
ids.push(element);
|
||||
});
|
||||
|
||||
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) {
|
||||
detach: function detach(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) {
|
||||
valueTargetCopyHandler: function valueTargetCopyHandler(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
|
||||
* The event triggered.
|
||||
*/
|
||||
valueSourceBlurHandler: function (e) {
|
||||
valueSourceBlurHandler: function valueSourceBlurHandler(e) {
|
||||
var value = $(e.target).val();
|
||||
var targetIds = drupalSettings.copyFieldValue[e.target.id];
|
||||
$('#' + targetIds.join(', #')).trigger('value:copy', value);
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery, Drupal, drupalSettings);
|
||||
})(jQuery, Drupal, drupalSettings);
|
102
web/core/modules/system/js/system.modules.es6.js
Normal file
102
web/core/modules/system/js/system.modules.es6.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* @file
|
||||
* Module page behaviors.
|
||||
*/
|
||||
|
||||
(function($, Drupal, debounce) {
|
||||
/**
|
||||
* 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, .module-name, .module-description
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.tableFilterByText = {
|
||||
attach(context, settings) {
|
||||
const $input = $('input.table-filter-text').once('table-filter-text');
|
||||
const $table = $($input.attr('data-table'));
|
||||
let $rowsAndDetails;
|
||||
let $rows;
|
||||
let $details;
|
||||
let searching = false;
|
||||
|
||||
function hidePackageDetails(index, element) {
|
||||
const $packDetails = $(element);
|
||||
const $visibleRows = $packDetails.find('tbody tr:visible');
|
||||
$packDetails.toggle($visibleRows.length > 0);
|
||||
}
|
||||
|
||||
function filterModuleList(e) {
|
||||
const query = $(e.target).val();
|
||||
// Case insensitive expression to find query at the beginning of a word.
|
||||
const re = new RegExp(`\\b${query}`, 'i');
|
||||
|
||||
function showModuleRow(index, row) {
|
||||
const $row = $(row);
|
||||
const $sources = $row.find(
|
||||
'.table-filter-text-source, .module-name, .module-description',
|
||||
);
|
||||
const textMatch = $sources.text().search(re) !== -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);
|
||||
|
||||
Drupal.announce(
|
||||
Drupal.t('!modules modules are available in the modified list.', {
|
||||
'!modules': $rowsAndDetails.find('tbody tr:visible').length,
|
||||
}),
|
||||
);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
function preventEnterKey(event) {
|
||||
if (event.which === 13) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
if ($table.length) {
|
||||
$rowsAndDetails = $table.find('tr, details');
|
||||
$rows = $table.find('tbody tr');
|
||||
$details = $rowsAndDetails.filter('.package-listing');
|
||||
|
||||
$input.on({
|
||||
keyup: debounce(filterModuleList, 200),
|
||||
keydown: preventEnterKey,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
|
@ -1,31 +1,18 @@
|
|||
/**
|
||||
* @file
|
||||
* Module page behaviors.
|
||||
*/
|
||||
* DO NOT EDIT THIS FILE.
|
||||
* See the following change record for more information,
|
||||
* https://www.drupal.org/node/2815083
|
||||
* @preserve
|
||||
**/
|
||||
|
||||
(function ($, Drupal, debounce) {
|
||||
|
||||
'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, .module-name, .module-description
|
||||
*
|
||||
* @type {Drupal~behavior}
|
||||
*/
|
||||
Drupal.behaviors.tableFilterByText = {
|
||||
attach: function (context, settings) {
|
||||
attach: function attach(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 $rowsAndDetails = void 0;
|
||||
var $rows = void 0;
|
||||
var $details = void 0;
|
||||
var searching = false;
|
||||
|
||||
function hidePackageDetails(index, element) {
|
||||
|
@ -36,7 +23,7 @@
|
|||
|
||||
function filterModuleList(e) {
|
||||
var query = $(e.target).val();
|
||||
// Case insensitive expression to find query at the beginning of a word.
|
||||
|
||||
var re = new RegExp('\\b' + query, 'i');
|
||||
|
||||
function showModuleRow(index, row) {
|
||||
|
@ -45,38 +32,25 @@
|
|||
var textMatch = $sources.text().search(re) !== -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);
|
||||
|
||||
Drupal.announce(
|
||||
Drupal.t(
|
||||
'!modules modules are available in the modified list.',
|
||||
{'!modules': $rowsAndDetails.find('tbody tr:visible').length}
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (searching) {
|
||||
Drupal.announce(Drupal.t('!modules modules are available in the modified list.', {
|
||||
'!modules': $rowsAndDetails.find('tbody tr:visible').length
|
||||
}));
|
||||
} 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);
|
||||
|
||||
$details.filter('[data-drupal-system-state="forced-open"]').removeAttr('data-drupal-system-state').attr('open', false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,5 +73,4 @@
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
}(jQuery, Drupal, Drupal.debounce));
|
||||
})(jQuery, Drupal, Drupal.debounce);
|
|
@ -2,12 +2,14 @@ id: d6_date_formats
|
|||
label: Date format configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable_multirow
|
||||
variables:
|
||||
- date_format_long
|
||||
- date_format_medium
|
||||
- date_format_short
|
||||
source_module: system
|
||||
process:
|
||||
id:
|
||||
plugin: static_map
|
|
@ -3,6 +3,7 @@ id: d6_menu
|
|||
label: Menus
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: menu
|
||||
process:
|
|
@ -2,12 +2,14 @@ id: d6_system_cron
|
|||
label: Cron settings
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- cron_threshold_warning
|
||||
- cron_threshold_error
|
||||
- cron_last
|
||||
source_module: system
|
||||
process:
|
||||
'threshold/requirements_warning': cron_threshold_warning
|
||||
'threshold/requirements_error': cron_threshold_error
|
|
@ -2,12 +2,14 @@ id: d6_system_date
|
|||
label: System date configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- configurable_timezones
|
||||
- date_first_day
|
||||
- date_default_timezone
|
||||
source_module: system
|
||||
process:
|
||||
'timezone/user/configurable': configurable_timezones
|
||||
first_day: date_first_day
|
|
@ -2,11 +2,13 @@ id: d6_system_file
|
|||
label: File system configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- file_directory_temp
|
||||
- allow_insecure_uploads
|
||||
source_module: system
|
||||
process:
|
||||
'path/temporary': file_directory_temp
|
||||
allow_insecure_uploads:
|
|
@ -2,6 +2,7 @@ id: d6_system_performance
|
|||
label: Performance configuration
|
||||
migration_tags:
|
||||
- Drupal 6
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
|
@ -10,11 +11,11 @@ source:
|
|||
- cache_lifetime
|
||||
- cache
|
||||
- page_compression
|
||||
source_module: system
|
||||
process:
|
||||
'css/preprocess': preprocess_css
|
||||
'js/preprocess': preprocess_js
|
||||
'cache/page/max_age': cache_lifetime
|
||||
'response/gzip': page_compression
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: system.performance
|
|
@ -2,10 +2,12 @@ id: d7_global_theme_settings
|
|||
label: D7 global theme settings
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- theme_settings
|
||||
source_module: system
|
||||
process:
|
||||
'features/logo': theme_settings/toggle_logo
|
||||
'features/name': theme_settings/toggle_name
|
|
@ -2,6 +2,7 @@ id: d7_menu
|
|||
label: Menus
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: menu
|
||||
process:
|
|
@ -1,10 +1,13 @@
|
|||
id: d7_system_authorize
|
||||
label: Drupal 7 file transfer authorize configuration
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- authorize_filetransfer_default
|
||||
source_module: system
|
||||
process:
|
||||
filetransfer_default: authorize_filetransfer_default
|
||||
destination:
|
|
@ -2,11 +2,13 @@ id: d7_system_cron
|
|||
label: Drupal 7 cron settings
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- cron_threshold_warning
|
||||
- cron_threshold_error
|
||||
source_module: system
|
||||
process:
|
||||
'threshold/requirements_warning': cron_threshold_warning
|
||||
'threshold/requirements_error': cron_threshold_error
|
|
@ -1,6 +1,8 @@
|
|||
id: d7_system_date
|
||||
label: Drupal 7 system date configuration
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
|
@ -10,6 +12,7 @@ source:
|
|||
- configurable_timezones
|
||||
- empty_timezone_message
|
||||
- user_default_timezone
|
||||
source_module: system
|
||||
process:
|
||||
'country/default': site_default_country
|
||||
first_day: date_first_day
|
|
@ -2,11 +2,13 @@ id: d7_system_file
|
|||
label: Drupal 7 file system configuration
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- allow_insecure_uploads
|
||||
- file_temporary_path
|
||||
source_module: system
|
||||
process:
|
||||
allow_insecure_uploads:
|
||||
plugin: static_map
|
|
@ -1,10 +1,13 @@
|
|||
id: d7_system_mail
|
||||
label: Drupal 7 system mail configuration
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- mail_system
|
||||
source_module: system
|
||||
process:
|
||||
'interface/default':
|
||||
plugin: static_map
|
|
@ -2,6 +2,7 @@ id: d7_system_performance
|
|||
label: Drupal 7 performance configuration
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
|
@ -9,11 +10,11 @@ source:
|
|||
- preprocess_js
|
||||
- cache_lifetime
|
||||
- page_compression
|
||||
source_module: system
|
||||
process:
|
||||
'css/preprocess': preprocess_css
|
||||
'js/preprocess': preprocess_js
|
||||
'cache/page/max_age': cache_lifetime
|
||||
'response/gzip': page_compression
|
||||
destination:
|
||||
plugin: config
|
||||
config_name: system.performance
|
|
@ -2,6 +2,7 @@ id: d7_theme_settings
|
|||
label: D7 theme settings
|
||||
migration_tags:
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: d7_theme_settings
|
||||
constants:
|
|
@ -3,10 +3,12 @@ label: Image toolkit configuration
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- image_toolkit
|
||||
source_module: system
|
||||
process:
|
||||
toolkit: image_toolkit
|
||||
destination:
|
|
@ -3,10 +3,12 @@ label: Image quality configuration
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- image_jpeg_quality
|
||||
source_module: system
|
||||
process:
|
||||
jpeg_quality: image_jpeg_quality
|
||||
destination:
|
|
@ -3,10 +3,12 @@ label: System logging
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- error_level
|
||||
source_module: system
|
||||
process:
|
||||
error_level:
|
||||
plugin: static_map
|
|
@ -3,10 +3,12 @@ label: Maintenance page configuration
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- site_offline_message
|
||||
source_module: system
|
||||
process:
|
||||
message: site_offline_message
|
||||
destination:
|
|
@ -3,11 +3,13 @@ label: RSS configuration
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
variables:
|
||||
- feed_default_items
|
||||
- feed_item_length
|
||||
source_module: system
|
||||
process:
|
||||
'items/limit': feed_default_items
|
||||
'items/view_mode': feed_item_length
|
|
@ -3,6 +3,7 @@ label: Site configuration
|
|||
migration_tags:
|
||||
- Drupal 6
|
||||
- Drupal 7
|
||||
- Configuration
|
||||
source:
|
||||
plugin: variable
|
||||
constants:
|
||||
|
@ -16,6 +17,7 @@ source:
|
|||
- site_404
|
||||
- drupal_weight_select_max
|
||||
- admin_compact_mode
|
||||
source_module: system
|
||||
process:
|
||||
name: site_name
|
||||
mail: site_mail
|
|
@ -61,11 +61,22 @@ class BatchController implements ContainerInjectionInterface {
|
|||
return $output;
|
||||
}
|
||||
elseif (isset($output)) {
|
||||
$title = isset($output['#title']) ? $output['#title'] : NULL;
|
||||
$page = [
|
||||
'#type' => 'page',
|
||||
'#title' => $title,
|
||||
'#show_messages' => FALSE,
|
||||
'content' => $output,
|
||||
];
|
||||
|
||||
// Also inject title as a page header (if available).
|
||||
if ($title) {
|
||||
$page['header'] = [
|
||||
'#type' => 'page_title',
|
||||
'#title' => $title,
|
||||
];
|
||||
}
|
||||
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -335,11 +335,11 @@ class DbUpdateController extends ControllerBase {
|
|||
|
||||
// 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');
|
||||
$this->messenger()->addWarning($this->t('Some of the pending updates cannot be applied because their dependencies were not met.'));
|
||||
}
|
||||
|
||||
if (empty($count)) {
|
||||
drupal_set_message($this->t('No pending updates.'));
|
||||
$this->messenger()->addStatus($this->t('No pending updates.'));
|
||||
unset($build);
|
||||
$build['links'] = [
|
||||
'#theme' => 'links',
|
||||
|
@ -524,7 +524,7 @@ class DbUpdateController extends ControllerBase {
|
|||
$build['status_report'] = [
|
||||
'#type' => 'status_report',
|
||||
'#requirements' => $requirements,
|
||||
'#suffix' => $this->t('Check the messages and <a href=":url">try again</a>.', [':url' => $try_again_url])
|
||||
'#suffix' => $this->t('Check the messages and <a href=":url">try again</a>.', [':url' => $try_again_url]),
|
||||
];
|
||||
|
||||
$build['#title'] = $this->t('Requirements problem');
|
||||
|
|
|
@ -4,7 +4,6 @@ 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;
|
||||
|
@ -81,7 +80,7 @@ class EntityAutocompleteController extends ControllerBase {
|
|||
// 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));
|
||||
$typed_string = mb_strtolower(array_pop($typed_string));
|
||||
|
||||
// Selection settings are passed in as a hashed key of a serialized array
|
||||
// stored in the key/value store.
|
||||
|
|
|
@ -9,6 +9,18 @@ use Drupal\Core\Controller\ControllerBase;
|
|||
*/
|
||||
class Http4xxController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The default 4xx error content.
|
||||
*
|
||||
* @return array
|
||||
* A render array containing the message to display for 4xx errors.
|
||||
*/
|
||||
public function on4xx() {
|
||||
return [
|
||||
'#markup' => $this->t('A client error happened'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default 401 content.
|
||||
*
|
||||
|
|
|
@ -100,7 +100,7 @@ class SystemController extends ControllerBase {
|
|||
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.', [':status' => $this->url('system.status')]), 'error');
|
||||
$this->messenger()->addError($this->t('One or more problems were detected with your Drupal installation. Check the <a href=":status">status report</a> for more information.', [':status' => $this->url('system.status')]));
|
||||
}
|
||||
// Load all menu links below it.
|
||||
$parameters = new MenuTreeParameters();
|
||||
|
@ -187,7 +187,7 @@ class SystemController extends ControllerBase {
|
|||
uasort($themes, 'system_sort_modules_by_info_name');
|
||||
|
||||
$theme_default = $config->get('default');
|
||||
$theme_groups = ['installed' => [], 'uninstalled' => []];
|
||||
$theme_groups = ['installed' => [], 'uninstalled' => []];
|
||||
$admin_theme = $config->get('admin');
|
||||
$admin_theme_options = [];
|
||||
|
||||
|
|
|
@ -71,15 +71,15 @@ class ThemeController extends ControllerBase {
|
|||
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.', ['%theme' => $themes[$theme]->info['name']]), 'error');
|
||||
$this->messenger()->addError($this->t('%theme is the default theme and cannot be uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
else {
|
||||
$this->themeHandler->uninstall([$theme]);
|
||||
drupal_set_message($this->t('The %theme theme has been uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
$this->messenger()->addStatus($this->t('The %theme theme has been uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
|
||||
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
|
@ -108,15 +108,15 @@ class ThemeController extends ControllerBase {
|
|||
try {
|
||||
if ($this->themeHandler->install([$theme])) {
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
drupal_set_message($this->t('The %theme theme has been installed.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
$this->messenger()->addStatus($this->t('The %theme theme has been installed.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
|
||||
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
|
||||
}
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->messenger()->addError(
|
||||
$this->formatPlural(
|
||||
count($config_objects),
|
||||
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||
|
@ -124,12 +124,11 @@ class ThemeController extends ControllerBase {
|
|||
[
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $theme,
|
||||
]),
|
||||
'error'
|
||||
])
|
||||
);
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message($e->getTranslatedMessage($this->getStringTranslation(), $theme), 'error');
|
||||
$this->messenger()->addError($e->getTranslatedMessage($this->getStringTranslation(), $theme));
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
|
@ -171,17 +170,18 @@ class ThemeController extends ControllerBase {
|
|||
// 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.', [
|
||||
'%admin_theme' => $themes[$admin_theme]->info['name'],
|
||||
'%selected_theme' => $themes[$theme]->info['name'],
|
||||
]));
|
||||
$this->messenger()
|
||||
->addStatus($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.', [
|
||||
'%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.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
$this->messenger()->addStatus($this->t('%theme is now the default theme.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
|
||||
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
|
|
|
@ -24,7 +24,7 @@ class TimezoneController {
|
|||
* Daylight saving time indicator. If abbr does not exist then the time
|
||||
* zone is searched solely by offset and isdst.
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* The timezone name in JsonResponse object.
|
||||
*/
|
||||
public function getTimezone($abbreviation = '', $offset = -1, $is_daylight_saving_time = NULL) {
|
||||
|
|
|
@ -36,7 +36,6 @@ class CronController extends ControllerBase {
|
|||
return new static($container->get('cron'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run Cron once.
|
||||
*
|
||||
|
@ -58,10 +57,10 @@ class CronController extends ControllerBase {
|
|||
*/
|
||||
public function runManually() {
|
||||
if ($this->cron->run()) {
|
||||
drupal_set_message($this->t('Cron ran successfully.'));
|
||||
$this->messenger()->addStatus($this->t('Cron ran successfully.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('Cron run failed.'), 'error');
|
||||
$this->messenger()->addError($this->t('Cron run failed.'));
|
||||
}
|
||||
|
||||
return $this->redirect('system.status');
|
||||
|
|
|
@ -14,18 +14,23 @@ use Drupal\Core\Session\AccountInterface;
|
|||
*/
|
||||
class DateFormatAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $viewLabelOperation = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
// There are no restrictions on viewing a date format.
|
||||
if ($operation == 'view') {
|
||||
// There are no restrictions on viewing the label of a date format.
|
||||
if ($operation === 'view label') {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
// Locked date formats cannot be updated or deleted.
|
||||
elseif (in_array($operation, ['update', 'delete'])) {
|
||||
if ($entity->isLocked()) {
|
||||
return AccessResult::forbidden()->addCacheableDependency($entity);
|
||||
return AccessResult::forbidden('The DateFormat config entity is locked.')->addCacheableDependency($entity);
|
||||
}
|
||||
else {
|
||||
return parent::checkAccess($entity, $operation, $account)->addCacheableDependency($entity);
|
||||
|
|
|
@ -15,6 +15,13 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface;
|
|||
* @ConfigEntityType(
|
||||
* id = "action",
|
||||
* label = @Translation("Action"),
|
||||
* label_collection = @Translation("Actions"),
|
||||
* label_singular = @Translation("action"),
|
||||
* label_plural = @Translation("actions"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count action",
|
||||
* plural = "@count actions",
|
||||
* ),
|
||||
* admin_permission = "administer actions",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\system\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\system\MenuInterface;
|
||||
|
||||
/**
|
||||
|
@ -11,6 +12,13 @@ use Drupal\system\MenuInterface;
|
|||
* @ConfigEntityType(
|
||||
* id = "menu",
|
||||
* label = @Translation("Menu"),
|
||||
* label_collection = @Translation("Menus"),
|
||||
* label_singular = @Translation("menu"),
|
||||
* label_plural = @Translation("menus"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count menu",
|
||||
* plural = "@count menus",
|
||||
* ),
|
||||
* handlers = {
|
||||
* "access" = "Drupal\system\MenuAccessControlHandler"
|
||||
* },
|
||||
|
@ -71,4 +79,43 @@ class Menu extends ConfigEntityBase implements MenuInterface {
|
|||
return (bool) $this->locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preDelete(EntityStorageInterface $storage, array $entities) {
|
||||
parent::preDelete($storage, $entities);
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
foreach ($entities as $menu) {
|
||||
// Delete all links from the menu.
|
||||
$menu_link_manager->deleteLinksInMenu($menu->id());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save() {
|
||||
$return = parent::save();
|
||||
\Drupal::cache('menu')->invalidateAll();
|
||||
// Invalidate the block cache to update menu-based derivatives.
|
||||
if (\Drupal::moduleHandler()->moduleExists('block')) {
|
||||
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete() {
|
||||
parent::delete();
|
||||
\Drupal::cache('menu')->invalidateAll();
|
||||
|
||||
// Invalidate the block cache to update menu-based derivatives.
|
||||
if (\Drupal::moduleHandler()->moduleExists('block')) {
|
||||
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,10 +4,11 @@ namespace Drupal\system\EventSubscriber;
|
|||
|
||||
use Drupal\Core\Routing\RouteSubscriberBase;
|
||||
use Drupal\Core\Routing\RoutingEvents;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* Adds the _admin_route option to each admin route.
|
||||
* Adds the _admin_route option to each admin HTML route.
|
||||
*/
|
||||
class AdminRouteSubscriber extends RouteSubscriberBase {
|
||||
|
||||
|
@ -16,7 +17,7 @@ class AdminRouteSubscriber extends RouteSubscriberBase {
|
|||
*/
|
||||
protected function alterRoutes(RouteCollection $collection) {
|
||||
foreach ($collection->all() as $route) {
|
||||
if (strpos($route->getPath(), '/admin') === 0 && !$route->hasOption('_admin_route')) {
|
||||
if (strpos($route->getPath(), '/admin') === 0 && !$route->hasOption('_admin_route') && static::isHtmlRoute($route)) {
|
||||
$route->setOption('_admin_route', TRUE);
|
||||
}
|
||||
}
|
||||
|
@ -36,4 +37,19 @@ class AdminRouteSubscriber extends RouteSubscriberBase {
|
|||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given route is a HTML route.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to analyze.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if HTML is a valid format for this route.
|
||||
*/
|
||||
protected static function isHtmlRoute(Route $route) {
|
||||
// If a route has no explicit format, then HTML is valid.
|
||||
$format = $route->hasRequirement('_format') ? explode('|', $route->getRequirement('_format')) : ['html'];
|
||||
return in_array('html', $format, TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,8 +14,11 @@ use Drupal\Core\Form\ConfigFormBaseTrait;
|
|||
|
||||
/**
|
||||
* Configure cron settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class CronForm extends FormBase {
|
||||
|
||||
use ConfigFormBaseTrait;
|
||||
|
||||
/**
|
||||
|
@ -42,7 +45,7 @@ class CronForm extends FormBase {
|
|||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
|
@ -104,6 +107,7 @@ class CronForm extends FormBase {
|
|||
$form['run'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Run cron'),
|
||||
'#submit' => ['::runCron'],
|
||||
];
|
||||
$status = '<p>' . $this->t('Last run: %time ago.', ['%time' => $this->dateFormatter->formatTimeDiffSince($this->state->get('system.cron_last'))]) . '</p>';
|
||||
$form['status'] = [
|
||||
|
@ -112,7 +116,7 @@ class CronForm extends FormBase {
|
|||
|
||||
$cron_url = $this->url('system.cron', ['key' => $this->state->get('system.cron_key')], ['absolute' => TRUE]);
|
||||
$form['cron_url'] = [
|
||||
'#markup' => '<p>' . t('To run cron from outside the site, go to <a href=":cron">@cron</a>', [':cron' => $cron_url, '@cron' => $cron_url]) . '</p>',
|
||||
'#markup' => '<p>' . t('To run cron from outside the site, go to <a href=":cron" class="system-cron-settings__link">@cron</a>', [':cron' => $cron_url, '@cron' => $cron_url]) . '</p>',
|
||||
];
|
||||
|
||||
if (!$this->moduleHandler->moduleExists('automated_cron')) {
|
||||
|
@ -131,7 +135,7 @@ class CronForm extends FormBase {
|
|||
'#type' => 'checkbox',
|
||||
'#title' => t('Detailed cron logging'),
|
||||
'#default_value' => $this->config('system.cron')->get('logging'),
|
||||
'#description' => 'Run times of individual cron jobs will be written to watchdog',
|
||||
'#description' => $this->t('Run times of individual cron jobs will be written to watchdog'),
|
||||
];
|
||||
|
||||
$form['actions']['#type'] = 'actions';
|
||||
|
@ -145,22 +149,25 @@ class CronForm extends FormBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Runs cron and reloads the page.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->config('system.cron')
|
||||
->set('logging', $form_state->getValue('logging'))
|
||||
->save();
|
||||
drupal_set_message(t('The configuration options have been saved.'));
|
||||
$this->messenger()->addStatus(t('The configuration options have been saved.'));
|
||||
}
|
||||
|
||||
// Run cron manually from Cron form.
|
||||
/**
|
||||
* Form submission handler for running cron manually.
|
||||
*/
|
||||
public function runCron(array &$form, FormStateInterface $form_state) {
|
||||
if ($this->cron->run()) {
|
||||
drupal_set_message(t('Cron ran successfully.'));
|
||||
$this->messenger()->addStatus($this->t('Cron ran successfully.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Cron run failed.'), 'error');
|
||||
$this->messenger()->addError($this->t('Cron run failed.'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Provides a form for adding a date format.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DateFormatAddForm extends DateFormatFormBase {
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Builds a form to delete a date format.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DateFormatDeleteForm extends EntityDeleteForm {
|
||||
|
||||
|
@ -43,8 +45,8 @@ class DateFormatDeleteForm extends EntityDeleteForm {
|
|||
public function getQuestion() {
|
||||
return t('Are you sure you want to delete the format %name : %format?', [
|
||||
'%name' => $this->entity->label(),
|
||||
'%format' => $this->dateFormatter->format(REQUEST_TIME, $this->entity->id())]
|
||||
);
|
||||
'%format' => $this->dateFormatter->format(REQUEST_TIME, $this->entity->id()),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Provides a form for editing a date format.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DateFormatEditForm extends DateFormatFormBase {
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ abstract class DateFormatFormBase extends EntityForm {
|
|||
$pattern = trim($form_state->getValue('date_format_pattern'));
|
||||
foreach ($this->dateFormatStorage->loadMultiple() as $format) {
|
||||
if ($format->getPattern() == $pattern && ($format->id() == $this->entity->id())) {
|
||||
drupal_set_message(t('The existing format/name combination has not been altered.'));
|
||||
$this->messenger()->addStatus($this->t('The existing format/name combination has not been altered.'));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -149,10 +149,10 @@ abstract class DateFormatFormBase extends EntityForm {
|
|||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$status = $this->entity->save();
|
||||
if ($status == SAVED_UPDATED) {
|
||||
drupal_set_message(t('Custom date format updated.'));
|
||||
$this->messenger()->addStatus($this->t('Custom date format updated.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Custom date format added.'));
|
||||
$this->messenger()->addStatus($this->t('Custom date format added.'));
|
||||
}
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('collection'));
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Configure file system settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FileSystemForm extends ConfigFormBase {
|
||||
|
||||
|
@ -125,10 +127,10 @@ class FileSystemForm extends ConfigFormBase {
|
|||
$period[0] = t('Never');
|
||||
$form['temporary_maximum_age'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('Delete orphaned files after'),
|
||||
'#title' => t('Delete temporary 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.'),
|
||||
'#description' => t('Temporary files are not referenced, but are in the file system and therefore may show up in administrative lists. <strong>Warning:</strong> If enabled, temporary files will be permanently deleted and may not be recoverable.'),
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
|
|
|
@ -10,6 +10,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Configures image toolkit settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ImageToolkitForm extends ConfigFormBase {
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Configure logging settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class LoggingForm extends ConfigFormBase {
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Builds a confirmation form for enabling modules with dependencies.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModulesListConfirmForm extends ConfirmFormBase {
|
||||
|
||||
|
@ -172,29 +174,27 @@ class ModulesListConfirmForm extends ConfirmFormBase {
|
|||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->messenger()->addError(
|
||||
$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.',
|
||||
[
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $this->modules['install'][$e->getExtension()]
|
||||
]),
|
||||
'error'
|
||||
'@extension' => $this->modules['install'][$e->getExtension()],
|
||||
])
|
||||
);
|
||||
return;
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $this->modules['install'][$e->getExtension()]),
|
||||
'error'
|
||||
$this->messenger()->addError(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $this->modules['install'][$e->getExtension()])
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$module_names = array_values($this->modules['install']);
|
||||
drupal_set_message($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
$this->messenger()->addStatus($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
'%name' => $module_names[0],
|
||||
'%names' => implode(', ', $module_names),
|
||||
]));
|
||||
|
|
|
@ -4,6 +4,8 @@ namespace Drupal\system\Form;
|
|||
|
||||
/**
|
||||
* Builds a confirmation form for enabling experimental modules.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModulesListExperimentalConfirmForm extends ModulesListConfirmForm {
|
||||
|
||||
|
@ -25,7 +27,7 @@ class ModulesListExperimentalConfirmForm extends ModulesListConfirmForm {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildMessageList() {
|
||||
drupal_set_message($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']), 'warning');
|
||||
$this->messenger()->addWarning($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']));
|
||||
|
||||
$items = parent::buildMessageList();
|
||||
// Add the list of experimental modules after any other messages.
|
||||
|
|
|
@ -7,6 +7,7 @@ use Drupal\Core\Config\PreExistingConfigException;
|
|||
use Drupal\Core\Config\UnmetDependenciesException;
|
||||
use Drupal\Core\Access\AccessManagerInterface;
|
||||
use Drupal\Core\Extension\Extension;
|
||||
use Drupal\Core\Extension\InfoParserException;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Extension\ModuleInstallerInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
|
@ -25,6 +26,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
* each module's name, description, and information about which modules it
|
||||
* requires. See \Drupal\Core\Extension\InfoParser for info on module.info.yml
|
||||
* descriptors.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModulesListForm extends FormBase {
|
||||
|
||||
|
@ -141,8 +144,14 @@ class ModulesListForm extends FormBase {
|
|||
];
|
||||
|
||||
// Sort all modules by their names.
|
||||
$modules = system_rebuild_module_data();
|
||||
uasort($modules, 'system_sort_modules_by_info_name');
|
||||
try {
|
||||
$modules = system_rebuild_module_data();
|
||||
uasort($modules, 'system_sort_modules_by_info_name');
|
||||
}
|
||||
catch (InfoParserException $e) {
|
||||
$this->messenger()->addError($this->t('Modules could not be listed due to an error: %error', ['%error' => $e->getMessage()]));
|
||||
$modules = [];
|
||||
}
|
||||
|
||||
// Iterate over each of the modules.
|
||||
$form['modules']['#tree'] = TRUE;
|
||||
|
@ -176,6 +185,7 @@ class ModulesListForm extends FormBase {
|
|||
// Lastly, sort all packages by title.
|
||||
uasort($form['modules'], ['\Drupal\Component\Utility\SortArray', 'sortByTitleProperty']);
|
||||
|
||||
$form['#attached']['library'][] = 'core/drupal.tableresponsive';
|
||||
$form['#attached']['library'][] = 'system/drupal.system.modules';
|
||||
$form['actions'] = ['#type' => 'actions'];
|
||||
$form['actions']['submit'] = [
|
||||
|
@ -386,7 +396,7 @@ class ModulesListForm extends FormBase {
|
|||
}
|
||||
|
||||
// Add all dependencies to a list.
|
||||
while (list($module) = each($modules['install'])) {
|
||||
foreach ($modules['install'] as $module => $value) {
|
||||
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'];
|
||||
|
@ -447,30 +457,28 @@ class ModulesListForm extends FormBase {
|
|||
try {
|
||||
$this->moduleInstaller->install(array_keys($modules['install']));
|
||||
$module_names = array_values($modules['install']);
|
||||
drupal_set_message($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
$this->messenger()->addStatus($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
'%name' => $module_names[0],
|
||||
'%names' => implode(', ', $module_names),
|
||||
]));
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->messenger()->addError(
|
||||
$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.',
|
||||
[
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $modules['install'][$e->getExtension()]
|
||||
]),
|
||||
'error'
|
||||
'@extension' => $modules['install'][$e->getExtension()],
|
||||
])
|
||||
);
|
||||
return;
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()]),
|
||||
'error'
|
||||
$this->messenger()->addError(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()])
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
|||
|
||||
/**
|
||||
* Builds a confirmation form to uninstall selected modules.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModulesUninstallConfirmForm extends ConfirmFormBase {
|
||||
use ConfigDependencyDeleteFormTrait;
|
||||
|
@ -129,7 +131,7 @@ class ModulesUninstallConfirmForm extends ConfirmFormBase {
|
|||
|
||||
// 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');
|
||||
$this->messenger()->addError($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.'));
|
||||
return $this->redirect('system.modules_uninstall');
|
||||
}
|
||||
|
||||
|
@ -159,7 +161,7 @@ class ModulesUninstallConfirmForm extends ConfirmFormBase {
|
|||
// Uninstall the modules.
|
||||
$this->moduleInstaller->uninstall($this->modules);
|
||||
|
||||
drupal_set_message($this->t('The selected modules have been uninstalled.'));
|
||||
$this->messenger()->addStatus($this->t('The selected modules have been uninstalled.'));
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Provides a form for uninstalling modules.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ModulesUninstallForm extends FormBase {
|
||||
|
||||
|
@ -114,8 +116,6 @@ class ModulesUninstallForm extends FormBase {
|
|||
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));
|
||||
|
@ -140,10 +140,9 @@ class ModulesUninstallForm extends FormBase {
|
|||
$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.)
|
||||
// we can allow this module to be uninstalled.
|
||||
foreach (array_keys($module->required_by) as $dependent) {
|
||||
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
|
||||
if (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;
|
||||
|
|
|
@ -3,25 +3,21 @@
|
|||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure performance settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class PerformanceForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The render cache bin.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $renderCache;
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
|
@ -43,26 +39,34 @@ class PerformanceForm extends ConfigFormBase {
|
|||
*/
|
||||
protected $jsCollectionOptimizer;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* 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\DateFormatterInterface $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.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, CacheBackendInterface $render_cache, DateFormatterInterface $date_formatter, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer) {
|
||||
public function __construct(ConfigFactoryInterface $config_factory, DateFormatterInterface $date_formatter, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct($config_factory);
|
||||
|
||||
$this->renderCache = $render_cache;
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->cssCollectionOptimizer = $css_collection_optimizer;
|
||||
$this->jsCollectionOptimizer = $js_collection_optimizer;
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,10 +75,10 @@ class PerformanceForm extends ConfigFormBase {
|
|||
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')
|
||||
$container->get('asset.js.collection_optimizer'),
|
||||
$container->get('module_handler')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -116,7 +120,6 @@ class PerformanceForm extends ConfigFormBase {
|
|||
'#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()
|
||||
|
@ -125,10 +128,14 @@ class PerformanceForm extends ConfigFormBase {
|
|||
$period[0] = '<' . t('no caching') . '>';
|
||||
$form['caching']['page_cache_maximum_age'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('Page cache maximum age'),
|
||||
'#title' => t('Browser and proxy 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.'),
|
||||
'#description' => t('This is used as the value for max-age in Cache-Control headers.'),
|
||||
];
|
||||
$form['caching']['internal_page_cache'] = [
|
||||
'#markup' => $this->t('Drupal provides an <a href=":module_enable">Internal Page Cache module</a> that is recommended for small to medium-sized websites.', [':module_enable' => Url::fromRoute('system.modules_list')->toString()]),
|
||||
'#access' => !$this->moduleHandler->moduleExists('page_cache'),
|
||||
];
|
||||
|
||||
$directory = 'public://';
|
||||
|
@ -168,10 +175,6 @@ class PerformanceForm extends ConfigFormBase {
|
|||
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'))
|
||||
|
@ -187,7 +190,7 @@ class PerformanceForm extends ConfigFormBase {
|
|||
*/
|
||||
public function submitCacheClear(array &$form, FormStateInterface $form_state) {
|
||||
drupal_flush_all_caches();
|
||||
drupal_set_message(t('Caches cleared.'));
|
||||
$this->messenger()->addStatus($this->t('Caches cleared.'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|||
|
||||
/**
|
||||
* Provides a form removing module content entities data before uninstallation.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
|
||||
|
||||
|
@ -157,7 +159,7 @@ class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
|
|||
'@entity_type_singular' => $entity_type->getSingularLabel(),
|
||||
'@entity_type_plural' => $entity_type->getPluralLabel(),
|
||||
]
|
||||
)
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -225,7 +227,7 @@ class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
|
|||
$storage->delete($entities);
|
||||
}
|
||||
// Sometimes deletes cause secondary deletes. For example, deleting a
|
||||
// taxonomy term can cause it's children to be be deleted too.
|
||||
// taxonomy term can cause its children to be be deleted too.
|
||||
$context['sandbox']['progress'] = $context['sandbox']['max'] - $storage->getQuery()->count()->execute();
|
||||
|
||||
// Inform the batch engine that we are not finished and provide an
|
||||
|
@ -248,7 +250,7 @@ class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
|
|||
*/
|
||||
public static function moduleBatchFinished($success, $results, $operations) {
|
||||
$entity_type_plural = \Drupal::entityTypeManager()->getDefinition($results['entity_type_id'])->getPluralLabel();
|
||||
drupal_set_message(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
|
||||
\Drupal::messenger()->addStatus(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
|
||||
|
||||
return new RedirectResponse(Url::fromRoute('system.modules_uninstall')->setAbsolute()->toString());
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Configure regional settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RegionalForm extends ConfigFormBase {
|
||||
|
||||
|
@ -65,7 +67,7 @@ class RegionalForm extends ConfigFormBase {
|
|||
$system_date = $this->config('system.date');
|
||||
|
||||
// Date settings:
|
||||
$zones = system_time_zones();
|
||||
$zones = system_time_zones(NULL, TRUE);
|
||||
|
||||
$form['locale'] = [
|
||||
'#type' => 'details',
|
||||
|
@ -123,7 +125,7 @@ class RegionalForm extends ConfigFormBase {
|
|||
'#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.')
|
||||
'#description' => t('Only applied if users may set their own time zone.'),
|
||||
];
|
||||
|
||||
$form['timezone']['configurable_timezones_wrapper']['user_default_timezone'] = [
|
||||
|
@ -135,7 +137,7 @@ class RegionalForm extends ConfigFormBase {
|
|||
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.')
|
||||
'#description' => t('Only applied if users may set their own time zone.'),
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
|
|
|
@ -6,7 +6,9 @@ use Drupal\Core\Form\ConfigFormBase;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Configure RSS settings for this site.
|
||||
* Configure RSS settings for this site
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class RssFeedsForm extends ConfigFormBase {
|
||||
|
||||
|
@ -33,7 +35,7 @@ class RssFeedsForm extends ConfigFormBase {
|
|||
'#type' => 'textarea',
|
||||
'#title' => t('Feed description'),
|
||||
'#default_value' => $rss_config->get('channel.description'),
|
||||
'#description' => t('Description of your site, included in each feed.')
|
||||
'#description' => t('Description of your site, included in each feed.'),
|
||||
];
|
||||
$options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30];
|
||||
$form['feed_default_items'] = [
|
||||
|
@ -41,7 +43,7 @@ class RssFeedsForm extends ConfigFormBase {
|
|||
'#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.')
|
||||
'#description' => t('Default number of items to include in each feed.'),
|
||||
];
|
||||
$form['feed_view_mode'] = [
|
||||
'#type' => 'select',
|
||||
|
@ -52,7 +54,7 @@ class RssFeedsForm extends ConfigFormBase {
|
|||
'teaser' => t('Titles plus teaser'),
|
||||
'fulltext' => t('Full text'),
|
||||
],
|
||||
'#description' => t('Global setting for the default display of content items in each feed.')
|
||||
'#description' => t('Global setting for the default display of content items in each feed.'),
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
|
|
|
@ -12,6 +12,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Configure site information settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SiteInformationForm extends ConfigFormBase {
|
||||
|
||||
|
@ -172,7 +174,7 @@ class SiteInformationForm extends ConfigFormBase {
|
|||
|
||||
}
|
||||
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.", ['%path' => $form_state->getValue('site_frontpage')]));
|
||||
$form_state->setErrorByName('site_frontpage', $this->t("Either the path '%path' is invalid or you do not have access to it.", ['%path' => $form_state->getValue('site_frontpage')]));
|
||||
}
|
||||
// Get the normal paths of both error pages.
|
||||
if (!$form_state->isValueEmpty('site_403')) {
|
||||
|
@ -189,11 +191,11 @@ class SiteInformationForm extends ConfigFormBase {
|
|||
}
|
||||
// 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.", ['%path' => $form_state->getValue('site_403')]));
|
||||
$form_state->setErrorByName('site_403', $this->t("Either the path '%path' is invalid or you do not have access to it.", ['%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.", ['%path' => $form_state->getValue('site_404')]));
|
||||
$form_state->setErrorByName('site_404', $this->t("Either the path '%path' is invalid or you do not have access to it.", ['%path' => $form_state->getValue('site_404')]));
|
||||
}
|
||||
|
||||
parent::validateForm($form, $form_state);
|
||||
|
|
|
@ -11,6 +11,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
|
||||
/**
|
||||
* Configure maintenance settings for this site.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SiteMaintenanceModeForm extends ConfigFormBase {
|
||||
|
||||
|
@ -54,6 +56,7 @@ class SiteMaintenanceModeForm extends ConfigFormBase {
|
|||
$container->get('user.permissions')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
124
web/core/modules/system/src/Form/SystemBrandingOffCanvasForm.php
Normal file
124
web/core/modules/system/src/Form/SystemBrandingOffCanvasForm.php
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\PluginFormBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* The settings_tray form handler for the SystemBrandingBlock.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SystemBrandingOffCanvasForm extends PluginFormBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* The block plugin.
|
||||
*
|
||||
* @var \Drupal\Core\Block\BlockPluginInterface
|
||||
*/
|
||||
protected $plugin;
|
||||
|
||||
/**
|
||||
* The config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* SystemBrandingOffCanvasForm constructor.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, AccountInterface $current_user) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = $this->plugin->buildConfigurationForm($form, $form_state);
|
||||
|
||||
$form['block_branding']['#type'] = 'details';
|
||||
$form['block_branding']['#weight'] = 10;
|
||||
|
||||
// Unset links to Site Information form, we can make these changes here.
|
||||
unset($form['block_branding']['use_site_name']['#description'], $form['block_branding']['use_site_slogan']['#description']);
|
||||
|
||||
$site_config = $this->configFactory->getEditable('system.site');
|
||||
// Load the immutable config to load the overrides.
|
||||
$site_config_immutable = $this->configFactory->get('system.site');
|
||||
$form['site_information'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => t('Site details'),
|
||||
'#open' => TRUE,
|
||||
'#access' => $this->currentUser->hasPermission('administer site configuration') && !$site_config_immutable->hasOverrides('name') && !$site_config_immutable->hasOverrides('slogan'),
|
||||
];
|
||||
$form['site_information']['site_name'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Site name'),
|
||||
'#default_value' => $site_config->get('name'),
|
||||
'#required' => TRUE,
|
||||
];
|
||||
$form['site_information']['site_slogan'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Slogan'),
|
||||
'#default_value' => $site_config->get('slogan'),
|
||||
'#description' => t("How this is used depends on your site's theme."),
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->plugin->validateConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$site_config = $this->configFactory->get('system.site');
|
||||
if (AccessResult::allowedIf(!$site_config->hasOverrides('name') && !$site_config->hasOverrides('slogan'))->isAllowed()) {
|
||||
$site_info = $form_state->getValue('site_information');
|
||||
$this->configFactory->getEditable('system.site')
|
||||
->set('name', $site_info['site_name'])
|
||||
->set('slogan', $site_info['site_slogan'])
|
||||
->save();
|
||||
}
|
||||
|
||||
$this->plugin->submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
181
web/core/modules/system/src/Form/SystemMenuOffCanvasForm.php
Normal file
181
web/core/modules/system/src/Form/SystemMenuOffCanvasForm.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Component\Plugin\PluginInspectionInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\PluginFormBase;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Routing\RedirectDestinationTrait;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\system\MenuInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* The setting_tray form handler for the SystemMenuBlock.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SystemMenuOffCanvasForm extends PluginFormBase implements ContainerInjectionInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
use RedirectDestinationTrait;
|
||||
|
||||
/**
|
||||
* The plugin.
|
||||
*
|
||||
* @var \Drupal\Core\Block\BlockPluginInterface
|
||||
*/
|
||||
protected $plugin;
|
||||
|
||||
/**
|
||||
* The menu entity that the block uses and that will be edited in this form.
|
||||
*
|
||||
* @var \Drupal\system\MenuInterface
|
||||
*/
|
||||
protected $menu;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $menuStorage;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* SystemMenuOffCanvasForm constructor.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $menu_storage
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
*/
|
||||
public function __construct(EntityStorageInterface $menu_storage, EntityTypeManagerInterface $entity_type_manager, TranslationInterface $string_translation, ConfigFactoryInterface $config_factory) {
|
||||
$this->menuStorage = $menu_storage;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->stringTranslation = $string_translation;
|
||||
$this->configFactory = $config_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity_type.manager')->getStorage('menu'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('string_translation'),
|
||||
$container->get('config.factory')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form = $this->plugin->buildConfigurationForm([], $form_state);
|
||||
// Move the menu levels section to the bottom.
|
||||
$form['menu_levels']['#weight'] = 100;
|
||||
|
||||
$form['entity_form'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Edit menu %label', ['%label' => $this->menu->label()]),
|
||||
'#open' => TRUE,
|
||||
'#access' => !$this->hasMenuOverrides() && $this->menu->access('edit'),
|
||||
];
|
||||
$form['entity_form'] += $this->getEntityForm($this->menu)->buildForm([], $form_state);
|
||||
|
||||
// Print the menu link titles as text instead of a link.
|
||||
if (!empty($form['entity_form']['links']['links'])) {
|
||||
foreach (Element::children($form['entity_form']['links']['links']) as $child) {
|
||||
$title = $form['entity_form']['links']['links'][$child]['title'][1]['#title'];
|
||||
$form['entity_form']['links']['links'][$child]['title'][1] = ['#markup' => $title];
|
||||
}
|
||||
}
|
||||
// Change the header text.
|
||||
$form['entity_form']['links']['links']['#header'][0] = $this->t('Link');
|
||||
$form['entity_form']['links']['links']['#header'][1]['data'] = $this->t('On');
|
||||
|
||||
// Remove the label, ID, description, and buttons from the entity form.
|
||||
unset($form['entity_form']['label'], $form['entity_form']['id'], $form['entity_form']['description'], $form['entity_form']['actions']);
|
||||
// Since the overview form is further nested than expected, update the
|
||||
// #parents. See \Drupal\menu_ui\MenuForm::form().
|
||||
$form_state->set('menu_overview_form_parents', ['settings', 'entity_form', 'links']);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->plugin->validateConfigurationForm($form, $form_state);
|
||||
if (!$this->hasMenuOverrides()) {
|
||||
$this->getEntityForm($this->menu)->validateForm($form, $form_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->plugin->submitConfigurationForm($form, $form_state);
|
||||
if (!$this->hasMenuOverrides()) {
|
||||
$this->getEntityForm($this->menu)->submitForm($form, $form_state);
|
||||
$this->menu->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity form for this menu.
|
||||
*
|
||||
* @param \Drupal\system\MenuInterface $menu
|
||||
* The menu entity.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityFormInterface
|
||||
* The entity form.
|
||||
*/
|
||||
protected function getEntityForm(MenuInterface $menu) {
|
||||
$entity_form = $this->entityTypeManager->getFormObject('menu', 'edit');
|
||||
$entity_form->setEntity($menu);
|
||||
return $entity_form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPlugin(PluginInspectionInterface $plugin) {
|
||||
$this->plugin = $plugin;
|
||||
$this->menu = $this->menuStorage->loadOverrideFree($this->plugin->getDerivativeId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the menu has configuration overrides.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the menu has configuration overrides, otherwise FALSE.
|
||||
*/
|
||||
protected function hasMenuOverrides() {
|
||||
// @todo Replace the following with $this->menu->hasOverrides() in https://www.drupal.org/project/drupal/issues/2910353
|
||||
// and remove this function.
|
||||
return $this->configFactory->get($this->menu->getEntityType()
|
||||
->getConfigPrefix() . '.' . $this->menu->id())->hasOverrides();
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
|
|||
|
||||
/**
|
||||
* Form to select the administration theme.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ThemeAdminForm extends ConfigFormBase {
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ use Drupal\Core\Theme\ThemeManagerInterface;
|
|||
|
||||
/**
|
||||
* Displays theme configuration for entire site and individual themes.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ThemeSettingsForm extends ConfigFormBase {
|
||||
|
||||
|
@ -134,11 +136,11 @@ class ThemeSettingsForm extends ConfigFormBase {
|
|||
|
||||
$form['var'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $var
|
||||
'#value' => $var,
|
||||
];
|
||||
$form['config_key'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $config_key
|
||||
'#value' => $config_key,
|
||||
];
|
||||
|
||||
// Toggle settings
|
||||
|
@ -212,7 +214,10 @@ class ThemeSettingsForm extends ConfigFormBase {
|
|||
'#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.")
|
||||
'#description' => t("If you don't have direct file access to the server, use this field to upload your logo."),
|
||||
'#upload_validators' => [
|
||||
'file_validate_is_image' => [],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -252,7 +257,12 @@ class ThemeSettingsForm extends ConfigFormBase {
|
|||
$form['favicon']['settings']['favicon_upload'] = [
|
||||
'#type' => 'file',
|
||||
'#title' => t('Upload favicon image'),
|
||||
'#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon.")
|
||||
'#description' => t("If you don't have direct file access to the server, use this field to upload your shortcut icon."),
|
||||
'#upload_validators' => [
|
||||
'file_validate_extensions' => [
|
||||
'ico png gif jpg jpeg apng svg',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -324,9 +334,21 @@ class ThemeSettingsForm extends ConfigFormBase {
|
|||
// 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;
|
||||
$theme_path = drupal_get_path('theme', $theme);
|
||||
$theme_settings_file = $theme_path . '/theme-settings.php';
|
||||
$theme_file = $theme_path . '/' . $theme . '.theme';
|
||||
$filenames = [$theme_settings_file, $theme_file];
|
||||
foreach ($filenames as $filename) {
|
||||
if (file_exists($filename)) {
|
||||
require_once $filename;
|
||||
|
||||
// The file must be required for the cached form too.
|
||||
$files = $form_state->getBuildInfo()['files'];
|
||||
if (!in_array($filename, $files)) {
|
||||
$files[] = $filename;
|
||||
}
|
||||
$form_state->addBuildInfo('files', $files);
|
||||
}
|
||||
}
|
||||
|
||||
// Call theme-specific settings.
|
||||
|
@ -355,37 +377,23 @@ class ThemeSettingsForm extends ConfigFormBase {
|
|||
parent::validateForm($form, $form_state);
|
||||
|
||||
if ($this->moduleHandler->moduleExists('file')) {
|
||||
// Handle file uploads.
|
||||
$validators = ['file_validate_is_image' => []];
|
||||
|
||||
// Check for a new uploaded logo.
|
||||
$file = file_save_upload('logo_upload', $validators, FALSE, 0);
|
||||
if (isset($file)) {
|
||||
// File upload was attempted.
|
||||
if (isset($form['logo'])) {
|
||||
$file = _file_save_upload_from_form($form['logo']['settings']['logo_upload'], $form_state, 0);
|
||||
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 = ['file_validate_extensions' => ['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 (isset($form['favicon'])) {
|
||||
$file = _file_save_upload_from_form($form['favicon']['settings']['favicon_upload'], $form_state, 0);
|
||||
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.'));
|
||||
}
|
||||
}
|
||||
|
||||
// When intending to use the default logo, unset the logo_path.
|
||||
|
@ -480,7 +488,7 @@ class ThemeSettingsForm extends ConfigFormBase {
|
|||
*/
|
||||
protected function validatePath($path) {
|
||||
// Absolute local file paths are invalid.
|
||||
if (drupal_realpath($path) == $path) {
|
||||
if (\Drupal::service('file_system')->realpath($path) == $path) {
|
||||
return FALSE;
|
||||
}
|
||||
// A path relative to the Drupal root or a fully qualified URI is valid.
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Access\CsrfTokenGenerator;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
|
@ -73,7 +72,7 @@ class MachineNameController implements ContainerInjectionInterface {
|
|||
|
||||
$transliterated = $this->transliteration->transliterate($text, $langcode, '_');
|
||||
if ($lowercase) {
|
||||
$transliterated = Unicode::strtolower($transliterated);
|
||||
$transliterated = mb_strtolower($transliterated);
|
||||
}
|
||||
|
||||
if (isset($replace_pattern) && isset($replace)) {
|
||||
|
|
|
@ -14,17 +14,23 @@ use Drupal\Core\Session\AccountInterface;
|
|||
*/
|
||||
class MenuAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $viewLabelOperation = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
if ($operation === 'view') {
|
||||
// There are no restrictions on viewing the label of a date format.
|
||||
if ($operation === 'view label') {
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
// Locked menus could not be deleted.
|
||||
elseif ($operation == 'delete') {
|
||||
elseif ($operation === 'delete') {
|
||||
if ($entity->isLocked()) {
|
||||
return AccessResult::forbidden()->addCacheableDependency($entity);
|
||||
return AccessResult::forbidden('The Menu config entity is locked.')->addCacheableDependency($entity);
|
||||
}
|
||||
else {
|
||||
return parent::checkAccess($entity, $operation, $account)->addCacheableDependency($entity);
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Controller\TitleResolverInterface;
|
|||
use Drupal\Core\Link;
|
||||
use Drupal\Core\ParamConverter\ParamNotConvertedException;
|
||||
use Drupal\Core\Path\CurrentPathStack;
|
||||
use Drupal\Core\Path\PathMatcherInterface;
|
||||
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
|
||||
use Drupal\Core\Routing\RequestContext;
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
|
@ -79,6 +80,20 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
|||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* The current path service.
|
||||
*
|
||||
* @var \Drupal\Core\Path\CurrentPathStack
|
||||
*/
|
||||
protected $currentPath;
|
||||
|
||||
/**
|
||||
* The patch matcher service.
|
||||
*
|
||||
* @var \Drupal\Core\Path\PathMatcherInterface
|
||||
*/
|
||||
protected $pathMatcher;
|
||||
|
||||
/**
|
||||
* Constructs the PathBasedBreadcrumbBuilder.
|
||||
*
|
||||
|
@ -98,8 +113,10 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
|||
* The current user object.
|
||||
* @param \Drupal\Core\Path\CurrentPathStack $current_path
|
||||
* The current path.
|
||||
* @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
|
||||
* The path matcher service.
|
||||
*/
|
||||
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) {
|
||||
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, PathMatcherInterface $path_matcher = NULL) {
|
||||
$this->context = $context;
|
||||
$this->accessManager = $access_manager;
|
||||
$this->router = $router;
|
||||
|
@ -108,6 +125,7 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
|||
$this->titleResolver = $title_resolver;
|
||||
$this->currentUser = $current_user;
|
||||
$this->currentPath = $current_path;
|
||||
$this->pathMatcher = $path_matcher ?: \Drupal::service('path.matcher');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,6 +142,15 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
|||
$breadcrumb = new Breadcrumb();
|
||||
$links = [];
|
||||
|
||||
// Add the url.path.parent cache context. This code ignores the last path
|
||||
// part so the result only depends on the path parents.
|
||||
$breadcrumb->addCacheContexts(['url.path.parent', 'url.path.is_front']);
|
||||
|
||||
// Do not display a breadcrumb on the frontpage.
|
||||
if ($this->pathMatcher->isFrontPage()) {
|
||||
return $breadcrumb;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -136,9 +163,6 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
|||
// /user is just a redirect, so skip it.
|
||||
// @todo Find a better way to deal with /user.
|
||||
$exclude['/user'] = TRUE;
|
||||
// Add the url.path.parent cache context. This code ignores the last path
|
||||
// part so the result only depends on the path parents.
|
||||
$breadcrumb->addCacheContexts(['url.path.parent']);
|
||||
while (count($path_elements) > 1) {
|
||||
array_pop($path_elements);
|
||||
// Copy the path elements for up-casting.
|
||||
|
@ -160,12 +184,10 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {
|
|||
$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>');
|
||||
}
|
||||
// Add the Home link.
|
||||
$links[] = Link::createFromRoute($this->t('Home'), '<front>');
|
||||
|
||||
return $breadcrumb->setLinks(array_reverse($links));
|
||||
}
|
||||
|
|
|
@ -15,7 +15,10 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
*
|
||||
* @Block(
|
||||
* id = "system_branding_block",
|
||||
* admin_label = @Translation("Site branding")
|
||||
* admin_label = @Translation("Site branding"),
|
||||
* forms = {
|
||||
* "settings_tray" = "Drupal\system\Form\SystemBrandingOffCanvasForm",
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class SystemBrandingBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
|
|
@ -10,7 +10,10 @@ use Drupal\Core\Block\MainContentBlockPluginInterface;
|
|||
*
|
||||
* @Block(
|
||||
* id = "system_main_block",
|
||||
* admin_label = @Translation("Main page content")
|
||||
* admin_label = @Translation("Main page content"),
|
||||
* forms = {
|
||||
* "settings_tray" = FALSE,
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class SystemMainBlock extends BlockBase implements MainContentBlockPluginInterface {
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace Drupal\system\Plugin\Block;
|
|||
use Drupal\Core\Block\BlockBase;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
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;
|
||||
|
@ -17,7 +16,10 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
|||
* id = "system_menu_block",
|
||||
* admin_label = @Translation("Menu"),
|
||||
* category = @Translation("Menus"),
|
||||
* deriver = "Drupal\system\Plugin\Derivative\SystemMenuBlock"
|
||||
* deriver = "Drupal\system\Plugin\Derivative\SystemMenuBlock",
|
||||
* forms = {
|
||||
* "settings_tray" = "\Drupal\system\Form\SystemMenuOffCanvasForm",
|
||||
* },
|
||||
* )
|
||||
*/
|
||||
class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
@ -29,13 +31,6 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
|||
*/
|
||||
protected $menuTree;
|
||||
|
||||
/**
|
||||
* The active menu trail service.
|
||||
*
|
||||
* @var \Drupal\Core\Menu\MenuActiveTrailInterface
|
||||
*/
|
||||
protected $menuActiveTrail;
|
||||
|
||||
/**
|
||||
* Constructs a new SystemMenuBlock.
|
||||
*
|
||||
|
@ -47,13 +42,10 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
|||
* 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) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, MenuLinkTreeInterface $menu_tree) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->menuTree = $menu_tree;
|
||||
$this->menuActiveTrail = $menu_active_trail;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,8 +56,7 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
|||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('menu.link_tree'),
|
||||
$container->get('menu.active_trail')
|
||||
$container->get('menu.link_tree')
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -147,6 +138,25 @@ class SystemMenuBlock extends BlockBase implements ContainerFactoryPluginInterfa
|
|||
$parameters->setMaxDepth(min($level + $depth - 1, $this->menuTree->maxDepth()));
|
||||
}
|
||||
|
||||
// For menu blocks with start level greater than 1, only show menu items
|
||||
// from the current active trail. Adjust the root according to the current
|
||||
// position in the menu in order to determine if we can show the subtree.
|
||||
if ($level > 1) {
|
||||
if (count($parameters->activeTrail) >= $level) {
|
||||
// Active trail array is child-first. Reverse it, and pull the new menu
|
||||
// root based on the parent of the configured start level.
|
||||
$menu_trail_ids = array_reverse(array_values($parameters->activeTrail));
|
||||
$menu_root = $menu_trail_ids[$level - 1];
|
||||
$parameters->setRoot($menu_root)->setMinDepth(1);
|
||||
if ($depth > 0) {
|
||||
$parameters->setMaxDepth(min($level - 1 + $depth - 1, $this->menuTree->maxDepth()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
$tree = $this->menuTree->load($menu_name, $parameters);
|
||||
$manipulators = [
|
||||
['callable' => 'menu.default_tree_manipulators:checkAccess'],
|
||||
|
|
|
@ -9,7 +9,7 @@ use Drupal\Core\Cache\Cache;
|
|||
/**
|
||||
* Provides a block to display the messages.
|
||||
*
|
||||
* @see drupal_set_message()
|
||||
* @see @see \Drupal\Core\Messenger\MessengerInterface
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_messages_block",
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
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;
|
||||
|
@ -139,7 +138,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
|||
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']);
|
||||
$pages = mb_strtolower($this->configuration['pages']);
|
||||
if (!$pages) {
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -149,7 +148,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
|||
$path = $this->currentPath->getPath($request);
|
||||
// Do not trim a trailing slash if that is the complete path.
|
||||
$path = $path === '/' ? $path : rtrim($path, '/');
|
||||
$path_alias = Unicode::strtolower($this->aliasManager->getAliasByPath($path));
|
||||
$path_alias = mb_strtolower($this->aliasManager->getAliasByPath($path));
|
||||
|
||||
return $this->pathMatcher->matchPath($path_alias, $pages) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $pages));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
namespace Drupal\system\Plugin\ImageToolkit;
|
||||
|
||||
use Drupal\Component\Utility\Color;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\ImageToolkit\ImageToolkitBase;
|
||||
|
@ -224,7 +223,7 @@ class GDToolkit extends ImageToolkitBase {
|
|||
$destination = drupal_tempnam('temporary://', 'gd_');
|
||||
}
|
||||
// Convert stream wrapper URI to normal path.
|
||||
$destination = drupal_realpath($destination);
|
||||
$destination = \Drupal::service('file_system')->realpath($destination);
|
||||
}
|
||||
|
||||
$function = 'image' . image_type_to_extension($this->getType(), FALSE);
|
||||
|
@ -395,7 +394,7 @@ class GDToolkit extends ImageToolkitBase {
|
|||
foreach (static::supportedTypes() as $image_type) {
|
||||
// @todo Automatically fetch possible extensions for each mime type.
|
||||
// @see https://www.drupal.org/node/2311679
|
||||
$extension = Unicode::strtolower(image_type_to_extension($image_type, FALSE));
|
||||
$extension = mb_strtolower(image_type_to_extension($image_type, FALSE));
|
||||
$extensions[] = $extension;
|
||||
// Add some known similar extensions.
|
||||
if ($extension === 'jpeg') {
|
||||
|
|
|
@ -45,7 +45,7 @@ class Rotate extends GDImageToolkitOperationBase {
|
|||
// Validate or set background color argument.
|
||||
if (!empty($arguments['background'])) {
|
||||
// Validate the background color: Color::hexToRgb does so for us.
|
||||
$background = Color::hexToRgb($arguments['background']) + [ 'alpha' => 0 ];
|
||||
$background = Color::hexToRgb($arguments['background']) + ['alpha' => 0];
|
||||
}
|
||||
else {
|
||||
// Background color is not specified: use transparent white as background.
|
||||
|
|
|
@ -20,6 +20,16 @@ class ScaleAndCrop extends GDImageToolkitOperationBase {
|
|||
*/
|
||||
protected function arguments() {
|
||||
return [
|
||||
'x' => [
|
||||
'description' => 'The horizontal offset for the start of the crop, in pixels',
|
||||
'required' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
'y' => [
|
||||
'description' => 'The vertical offset for the start the crop, in pixels',
|
||||
'required' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
'width' => [
|
||||
'description' => 'The target width, in pixels',
|
||||
],
|
||||
|
@ -38,8 +48,12 @@ class ScaleAndCrop extends GDImageToolkitOperationBase {
|
|||
|
||||
$scaleFactor = max($arguments['width'] / $actualWidth, $arguments['height'] / $actualHeight);
|
||||
|
||||
$arguments['x'] = (int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
|
||||
$arguments['y'] = (int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
|
||||
$arguments['x'] = isset($arguments['x']) ?
|
||||
(int) round($arguments['x']) :
|
||||
(int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
|
||||
$arguments['y'] = isset($arguments['y']) ?
|
||||
(int) round($arguments['y']) :
|
||||
(int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
|
||||
$arguments['resize'] = [
|
||||
'width' => (int) round($actualWidth * $scaleFactor),
|
||||
'height' => (int) round($actualHeight * $scaleFactor),
|
||||
|
|
|
@ -14,6 +14,7 @@ use Drupal\migrate\Row;
|
|||
* )
|
||||
*/
|
||||
class TimeZone extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Gets system data for a legacy extension.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "extension",
|
||||
* source_module = "system"
|
||||
* )
|
||||
*/
|
||||
class Extension extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('system', 's')
|
||||
->fields('s');
|
||||
|
||||
if (isset($this->configuration['name'])) {
|
||||
$query->condition('name', (array) $this->configuration['name'], 'IN');
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'filename' => $this->t('Filename'),
|
||||
'name' => $this->t('Name'),
|
||||
'type' => $this->t('Type'),
|
||||
'owner' => $this->t('Owner'),
|
||||
'status' => $this->t('Status'),
|
||||
'throttle' => $this->t('Throttle'),
|
||||
'bootstrap' => $this->t('Bootstrap'),
|
||||
'schema_version' => $this->t('Schema version'),
|
||||
'weight' => $this->t('Weight'),
|
||||
'info' => $this->t('Information array'),
|
||||
];
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
$row->setSourceProperty('info', unserialize($row->getSourceProperty('info')));
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "menu",
|
||||
* source_provider = "menu"
|
||||
* source_module = "menu"
|
||||
* )
|
||||
*/
|
||||
class Menu extends DrupalSqlBase {
|
||||
|
|
|
@ -9,7 +9,7 @@ use Drupal\migrate_drupal\Plugin\migrate\source\VariableMultiRow;
|
|||
*
|
||||
* @MigrateSource(
|
||||
* id = "d7_theme_settings",
|
||||
* source_provider = "system"
|
||||
* source_module = "system"
|
||||
* )
|
||||
*/
|
||||
class ThemeSettings extends VariableMultiRow {
|
||||
|
|
|
@ -2,506 +2,20 @@
|
|||
|
||||
namespace Drupal\system\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\RevisionableInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Routing\RedirectDestinationTrait;
|
||||
use Drupal\Core\TypedData\TranslatableInterface;
|
||||
use Drupal\views\Entity\Render\EntityTranslationRenderTrait;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\field\FieldPluginBase;
|
||||
use Drupal\views\Plugin\views\field\UncacheableFieldHandlerTrait;
|
||||
use Drupal\views\Plugin\views\style\Table;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
@trigger_error(__NAMESPACE__ . '\BulkForm is deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.0. Use \Drupal\views\Plugin\views\field\BulkForm instead. See https://www.drupal.org/node/2916716.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\views\Plugin\views\field\BulkForm as ViewsBulkForm;
|
||||
|
||||
/**
|
||||
* Defines a actions-based bulk operation form element.
|
||||
*
|
||||
* @ViewsField("bulk_form")
|
||||
* @ViewsField("legacy_bulk_form")
|
||||
*
|
||||
* @deprecated in Drupal 8.5.x, will be removed before Drupal 9.0.0. Use
|
||||
* \Drupal\views\Plugin\views\field\BulkForm instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2916716
|
||||
*/
|
||||
class BulkForm extends FieldPluginBase implements CacheableDependencyInterface {
|
||||
|
||||
use RedirectDestinationTrait;
|
||||
use UncacheableFieldHandlerTrait;
|
||||
use EntityTranslationRenderTrait;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The action storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $actionStorage;
|
||||
|
||||
/**
|
||||
* An array of actions that can be executed.
|
||||
*
|
||||
* @var \Drupal\system\ActionConfigEntityInterface[]
|
||||
*/
|
||||
protected $actions = [];
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* Constructs a new BulkForm 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\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->actionStorage = $entity_manager->getStorage('action');
|
||||
$this->languageManager = $language_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('language_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$entity_type = $this->getEntityType();
|
||||
// Filter the actions to only include those for this entity type.
|
||||
$this->actions = array_filter($this->actionStorage->loadMultiple(), function ($action) use ($entity_type) {
|
||||
return $action->getType() == $entity_type;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
// @todo Consider making the bulk operation form cacheable. See
|
||||
// https://www.drupal.org/node/2503009.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return $this->languageManager->isMultilingual() ? $this->getEntityTranslationRenderer()->getCacheContexts() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheTags() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEntityTypeId() {
|
||||
return $this->getEntityType();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityManager() {
|
||||
return $this->entityManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getLanguageManager() {
|
||||
return $this->languageManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getView() {
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['action_title'] = ['default' => $this->t('Action')];
|
||||
$options['include_exclude'] = [
|
||||
'default' => 'exclude',
|
||||
];
|
||||
$options['selected_actions'] = [
|
||||
'default' => [],
|
||||
];
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$form['action_title'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Action title'),
|
||||
'#default_value' => $this->options['action_title'],
|
||||
'#description' => $this->t('The title shown above the actions dropdown.'),
|
||||
];
|
||||
|
||||
$form['include_exclude'] = [
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Available actions'),
|
||||
'#options' => [
|
||||
'exclude' => $this->t('All actions, except selected'),
|
||||
'include' => $this->t('Only selected actions'),
|
||||
],
|
||||
'#default_value' => $this->options['include_exclude'],
|
||||
];
|
||||
$form['selected_actions'] = [
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Selected actions'),
|
||||
'#options' => $this->getBulkOptions(FALSE),
|
||||
'#default_value' => $this->options['selected_actions'],
|
||||
];
|
||||
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::validateOptionsForm($form, $form_state);
|
||||
|
||||
$selected_actions = $form_state->getValue(['options', 'selected_actions']);
|
||||
$form_state->setValue(['options', 'selected_actions'], array_values(array_filter($selected_actions)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preRender(&$values) {
|
||||
parent::preRender($values);
|
||||
|
||||
// If the view is using a table style, provide a placeholder for a
|
||||
// "select all" checkbox.
|
||||
if (!empty($this->view->style_plugin) && $this->view->style_plugin instanceof Table) {
|
||||
// Add the tableselect css classes.
|
||||
$this->options['element_label_class'] .= 'select-all';
|
||||
// Hide the actual label of the field on the table header.
|
||||
$this->options['label'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue(ResultRow $row, $field = NULL) {
|
||||
return '<!--form-item-' . $this->options['id'] . '--' . $row->index . '-->';
|
||||
}
|
||||
|
||||
/**
|
||||
* Form constructor for the bulk form.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*/
|
||||
public function viewsForm(&$form, FormStateInterface $form_state) {
|
||||
// Make sure we do not accidentally cache this form.
|
||||
// @todo Evaluate this again in https://www.drupal.org/node/2503009.
|
||||
$form['#cache']['max-age'] = 0;
|
||||
|
||||
// Add the tableselect javascript.
|
||||
$form['#attached']['library'][] = 'core/drupal.tableselect';
|
||||
$use_revision = array_key_exists('revision', $this->view->getQuery()->getEntityTableInfo());
|
||||
|
||||
// Only add the bulk form options and buttons if there are results.
|
||||
if (!empty($this->view->result)) {
|
||||
// Render checkboxes for all rows.
|
||||
$form[$this->options['id']]['#tree'] = TRUE;
|
||||
foreach ($this->view->result as $row_index => $row) {
|
||||
$entity = $this->getEntityTranslation($this->getEntity($row), $row);
|
||||
|
||||
$form[$this->options['id']][$row_index] = [
|
||||
'#type' => 'checkbox',
|
||||
// We are not able to determine a main "title" for each row, so we can
|
||||
// only output a generic label.
|
||||
'#title' => $this->t('Update this item'),
|
||||
'#title_display' => 'invisible',
|
||||
'#default_value' => !empty($form_state->getValue($this->options['id'])[$row_index]) ? 1 : NULL,
|
||||
'#return_value' => $this->calculateEntityBulkFormKey($entity, $use_revision),
|
||||
];
|
||||
}
|
||||
|
||||
// Replace the form submit button label.
|
||||
$form['actions']['submit']['#value'] = $this->t('Apply to selected items');
|
||||
|
||||
// Ensure a consistent container for filters/operations in the view header.
|
||||
$form['header'] = [
|
||||
'#type' => 'container',
|
||||
'#weight' => -100,
|
||||
];
|
||||
|
||||
// Build the bulk operations action widget for the header.
|
||||
// Allow themes to apply .container-inline on this separate container.
|
||||
$form['header'][$this->options['id']] = [
|
||||
'#type' => 'container',
|
||||
];
|
||||
$form['header'][$this->options['id']]['action'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->options['action_title'],
|
||||
'#options' => $this->getBulkOptions(),
|
||||
];
|
||||
|
||||
// Duplicate the form actions into the action container in the header.
|
||||
$form['header'][$this->options['id']]['actions'] = $form['actions'];
|
||||
}
|
||||
else {
|
||||
// Remove the default actions build array.
|
||||
unset($form['actions']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available operations for this form.
|
||||
*
|
||||
* @param bool $filtered
|
||||
* (optional) Whether to filter actions to selected actions.
|
||||
* @return array
|
||||
* An associative array of operations, suitable for a select element.
|
||||
*/
|
||||
protected function getBulkOptions($filtered = TRUE) {
|
||||
$options = [];
|
||||
// Filter the action list.
|
||||
foreach ($this->actions as $id => $action) {
|
||||
if ($filtered) {
|
||||
$in_selected = in_array($id, $this->options['selected_actions']);
|
||||
// If the field is configured to include only the selected actions,
|
||||
// skip actions that were not selected.
|
||||
if (($this->options['include_exclude'] == 'include') && !$in_selected) {
|
||||
continue;
|
||||
}
|
||||
// Otherwise, if the field is configured to exclude the selected
|
||||
// actions, skip actions that were selected.
|
||||
elseif (($this->options['include_exclude'] == 'exclude') && $in_selected) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$options[$id] = $action->label();
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the bulk form.
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* Thrown when the user tried to access an action without access to it.
|
||||
*/
|
||||
public function viewsFormSubmit(&$form, FormStateInterface $form_state) {
|
||||
if ($form_state->get('step') == 'views_form_views_form') {
|
||||
// Filter only selected checkboxes. Use the actual user input rather than
|
||||
// the raw form values array, since the site data may change before the
|
||||
// bulk form is submitted, which can lead to data loss.
|
||||
$user_input = $form_state->getUserInput();
|
||||
$selected = array_filter($user_input[$this->options['id']]);
|
||||
$entities = [];
|
||||
$action = $this->actions[$form_state->getValue('action')];
|
||||
$count = 0;
|
||||
|
||||
foreach ($selected as $bulk_form_key) {
|
||||
$entity = $this->loadEntityFromBulkFormKey($bulk_form_key);
|
||||
|
||||
// Skip execution if the user did not have access.
|
||||
if (!$action->getPlugin()->access($entity, $this->view->getUser())) {
|
||||
$this->drupalSetMessage($this->t('No access to execute %action on the @entity_type_label %entity_label.', [
|
||||
'%action' => $action->label(),
|
||||
'@entity_type_label' => $entity->getEntityType()->getLabel(),
|
||||
'%entity_label' => $entity->label()
|
||||
]), 'error');
|
||||
continue;
|
||||
}
|
||||
|
||||
$count++;
|
||||
|
||||
$entities[$bulk_form_key] = $entity;
|
||||
}
|
||||
|
||||
$action->execute($entities);
|
||||
|
||||
$operation_definition = $action->getPluginDefinition();
|
||||
if (!empty($operation_definition['confirm_form_route_name'])) {
|
||||
$options = [
|
||||
'query' => $this->getDestinationArray(),
|
||||
];
|
||||
$form_state->setRedirect($operation_definition['confirm_form_route_name'], [], $options);
|
||||
}
|
||||
else {
|
||||
// Don't display the message unless there are some elements affected and
|
||||
// there is no confirmation form.
|
||||
if ($count) {
|
||||
drupal_set_message($this->formatPlural($count, '%action was applied to @count item.', '%action was applied to @count items.', [
|
||||
'%action' => $action->label(),
|
||||
]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message to be displayed when there are no selected items.
|
||||
*
|
||||
* @return string
|
||||
* Message displayed when no items are selected.
|
||||
*/
|
||||
protected function emptySelectedMessage() {
|
||||
return $this->t('No items selected.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewsFormValidate(&$form, FormStateInterface $form_state) {
|
||||
$selected = array_filter($form_state->getValue($this->options['id']));
|
||||
if (empty($selected)) {
|
||||
$form_state->setErrorByName('', $this->emptySelectedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
if ($this->languageManager->isMultilingual()) {
|
||||
$this->getEntityTranslationRenderer()->query($this->query, $this->relationship);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clickSortable() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps drupal_set_message().
|
||||
*/
|
||||
protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) {
|
||||
drupal_set_message($message, $type, $repeat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a bulk form key.
|
||||
*
|
||||
* This generates a key that is used as the checkbox return value when
|
||||
* submitting a bulk form. This key allows the entity for the row to be loaded
|
||||
* totally independently of the executed view row.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity to calculate a bulk form key for.
|
||||
* @param bool $use_revision
|
||||
* Whether the revision id should be added to the bulk form key. This should
|
||||
* be set to TRUE only if the view is listing entity revisions.
|
||||
*
|
||||
* @return string
|
||||
* The bulk form key representing the entity's id, language and revision (if
|
||||
* applicable) as one string.
|
||||
*
|
||||
* @see self::loadEntityFromBulkFormKey()
|
||||
*/
|
||||
protected function calculateEntityBulkFormKey(EntityInterface $entity, $use_revision) {
|
||||
$key_parts = [$entity->language()->getId(), $entity->id()];
|
||||
|
||||
if ($entity instanceof RevisionableInterface && $use_revision) {
|
||||
$key_parts[] = $entity->getRevisionId();
|
||||
}
|
||||
|
||||
// An entity ID could be an arbitrary string (although they are typically
|
||||
// numeric). JSON then Base64 encoding ensures the bulk_form_key is
|
||||
// safe to use in HTML, and that the key parts can be retrieved.
|
||||
$key = json_encode($key_parts);
|
||||
return base64_encode($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an entity based on a bulk form key.
|
||||
*
|
||||
* @param string $bulk_form_key
|
||||
* The bulk form key representing the entity's id, language and revision (if
|
||||
* applicable) as one string.
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* The entity loaded in the state (language, optionally revision) specified
|
||||
* as part of the bulk form key.
|
||||
*/
|
||||
protected function loadEntityFromBulkFormKey($bulk_form_key) {
|
||||
$key = base64_decode($bulk_form_key);
|
||||
$key_parts = json_decode($key);
|
||||
$revision_id = NULL;
|
||||
|
||||
// If there are 3 items, vid will be last.
|
||||
if (count($key_parts) === 3) {
|
||||
$revision_id = array_pop($key_parts);
|
||||
}
|
||||
|
||||
// The first two items will always be langcode and ID.
|
||||
$id = array_pop($key_parts);
|
||||
$langcode = array_pop($key_parts);
|
||||
|
||||
// Load the entity or a specific revision depending on the given key.
|
||||
$storage = $this->entityManager->getStorage($this->getEntityType());
|
||||
$entity = $revision_id ? $storage->loadRevision($revision_id) : $storage->load($id);
|
||||
|
||||
if ($entity instanceof TranslatableInterface) {
|
||||
$entity = $entity->getTranslation($langcode);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
class BulkForm extends ViewsBulkForm {
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class SystemConfigSubscriber implements EventSubscriberInterface {
|
|||
/**
|
||||
* Constructs the SystemConfigSubscriber.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
|
||||
* @param \Drupal\Core\Routing\RouteBuilderInterface $router_builder
|
||||
* The router builder service.
|
||||
*/
|
||||
public function __construct(RouteBuilderInterface $router_builder) {
|
||||
|
@ -68,10 +68,13 @@ class SystemConfigSubscriber implements EventSubscriberInterface {
|
|||
* This event listener checks that the system.site:uuid's in the source and
|
||||
* target match.
|
||||
*
|
||||
* @param ConfigImporterEvent $event
|
||||
* @param \Drupal\Core\Config\ConfigImporterEvent $event
|
||||
* The config import event.
|
||||
*/
|
||||
public function onConfigImporterValidateSiteUUID(ConfigImporterEvent $event) {
|
||||
if (!$event->getConfigImporter()->getStorageComparer()->getSourceStorage()->exists('system.site')) {
|
||||
$event->getConfigImporter()->logError($this->t('This import does not contain system.site configuration, so has been rejected.'));
|
||||
}
|
||||
if (!$event->getConfigImporter()->getStorageComparer()->validateSiteUuid()) {
|
||||
$event->getConfigImporter()->logError($this->t('Site UUID in source storage does not match the target storage.'));
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ class SystemManager {
|
|||
|
||||
// Check run-time requirements and status information.
|
||||
$requirements = $this->moduleHandler->invokeAll('requirements', ['runtime']);
|
||||
uasort($requirements, function($a, $b) {
|
||||
uasort($requirements, function ($a, $b) {
|
||||
if (!isset($a['weight'])) {
|
||||
if (!isset($b['weight'])) {
|
||||
return strcasecmp($a['title'], $b['title']);
|
||||
|
@ -152,7 +152,8 @@ class SystemManager {
|
|||
* hidden, so we supply the contents of the block.
|
||||
*
|
||||
* @return array
|
||||
* A render array suitable for drupal_render.
|
||||
* A render array suitable for
|
||||
* \Drupal\Core\Render\RendererInterface::render().
|
||||
*/
|
||||
public function getBlockContents() {
|
||||
// We hard-code the menu name here since otherwise a link in the tools menu
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Tests the usage of form caching for AJAX forms.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxFormCacheTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Tests the usage of form cache for AJAX forms.
|
||||
*/
|
||||
public function testFormCacheUsage() {
|
||||
/** @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable */
|
||||
$key_value_expirable = \Drupal::service('keyvalue.expirable')->get('form');
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Ensure that the cache is empty.
|
||||
$this->assertEqual(0, count($key_value_expirable->getAll()));
|
||||
|
||||
// Visit an AJAX form that is not cached, 3 times.
|
||||
$uncached_form_url = Url::fromRoute('ajax_forms_test.commands_form');
|
||||
$this->drupalGet($uncached_form_url);
|
||||
$this->drupalGet($uncached_form_url);
|
||||
$this->drupalGet($uncached_form_url);
|
||||
|
||||
// The number of cache entries should not have changed.
|
||||
$this->assertEqual(0, count($key_value_expirable->getAll()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AJAX forms in blocks.
|
||||
*/
|
||||
public function testBlockForms() {
|
||||
$this->container->get('module_installer')->install(['block', 'search']);
|
||||
$this->rebuildContainer();
|
||||
$this->container->get('router.builder')->rebuild();
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$this->drupalPlaceBlock('search_form_block', ['weight' => -5]);
|
||||
$this->drupalPlaceBlock('ajax_forms_test_block');
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->drupalPostAjaxForm(NULL, ['test1' => 'option1'], 'test1');
|
||||
$this->assertOptionSelectedWithDrupalSelector('edit-test1', 'option1');
|
||||
$this->assertOptionWithDrupalSelector('edit-test1', 'option3');
|
||||
$this->drupalPostForm(NULL, ['test1' => 'option1'], 'Submit');
|
||||
$this->assertText('Submission successful.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AJAX forms on pages with a query string.
|
||||
*/
|
||||
public function testQueryString() {
|
||||
$this->container->get('module_installer')->install(['block']);
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$this->drupalPlaceBlock('ajax_forms_test_block');
|
||||
|
||||
$url = Url::fromRoute('entity.user.canonical', ['user' => $this->rootUser->id()], ['query' => ['foo' => 'bar']]);
|
||||
$this->drupalGet($url);
|
||||
$this->drupalPostAjaxForm(NULL, ['test1' => 'option1'], 'test1');
|
||||
$url->setOption('query', [
|
||||
'foo' => 'bar',
|
||||
FormBuilderInterface::AJAX_FORM_REQUEST => 1,
|
||||
MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax',
|
||||
]);
|
||||
$this->assertUrl($url);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
/**
|
||||
* Tests that form elements in groups work correctly with AJAX.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxInGroupTest extends AjaxTestBase {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['access content']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits forms with select and checkbox elements via Ajax.
|
||||
*/
|
||||
public function testSimpleAjaxFormValue() {
|
||||
$this->drupalGet('/ajax_forms_test_get_form');
|
||||
$this->assertText('Test group');
|
||||
$this->assertText('AJAX checkbox in a group');
|
||||
|
||||
$this->drupalPostAjaxForm(NULL, ['checkbox_in_group' => TRUE], 'checkbox_in_group');
|
||||
$this->assertText('Test group');
|
||||
$this->assertText('AJAX checkbox in a group');
|
||||
$this->assertText('AJAX checkbox in a nested group');
|
||||
$this->assertText('Another AJAX checkbox in a nested group');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\Core\Ajax\AddCssCommand;
|
||||
use Drupal\Core\Ajax\AfterCommand;
|
||||
use Drupal\Core\Ajax\AjaxResponse;
|
||||
use Drupal\Core\Ajax\AlertCommand;
|
||||
use Drupal\Core\Ajax\AppendCommand;
|
||||
use Drupal\Core\Ajax\BeforeCommand;
|
||||
use Drupal\Core\Ajax\ChangedCommand;
|
||||
use Drupal\Core\Ajax\CssCommand;
|
||||
use Drupal\Core\Ajax\DataCommand;
|
||||
use Drupal\Core\Ajax\HtmlCommand;
|
||||
use Drupal\Core\Ajax\InvokeCommand;
|
||||
use Drupal\Core\Ajax\InsertCommand;
|
||||
use Drupal\Core\Ajax\PrependCommand;
|
||||
use Drupal\Core\Ajax\RemoveCommand;
|
||||
use Drupal\Core\Ajax\RestripeCommand;
|
||||
use Drupal\Core\Ajax\SettingsCommand;
|
||||
use Drupal\Core\EventSubscriber\AjaxResponseSubscriber;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/**
|
||||
* Performs tests on AJAX framework commands.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class CommandsTest extends AjaxTestBase {
|
||||
/**
|
||||
* Tests the various Ajax Commands.
|
||||
*/
|
||||
public function testAjaxCommands() {
|
||||
$form_path = 'ajax_forms_test_ajax_commands_form';
|
||||
$web_user = $this->drupalCreateUser(['access content']);
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
$edit = [];
|
||||
|
||||
// Tests the 'add_css' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'add_css' command")]);
|
||||
$expected = new AddCssCommand('my/file.css');
|
||||
$this->assertCommand($commands, $expected->render(), "'add_css' AJAX command issued with correct data.");
|
||||
|
||||
// Tests the 'after' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'After': Click to put something after the div")]);
|
||||
$expected = new AfterCommand('#after_div', 'This will be placed after');
|
||||
$this->assertCommand($commands, $expected->render(), "'after' AJAX command issued with correct data.");
|
||||
|
||||
// Tests the 'alert' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'Alert': Click to alert")]);
|
||||
$expected = new AlertCommand(t('Alert'));
|
||||
$this->assertCommand($commands, $expected->render(), "'alert' AJAX Command issued with correct text.");
|
||||
|
||||
// Tests the 'append' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'Append': Click to append something")]);
|
||||
$expected = new AppendCommand('#append_div', 'Appended text');
|
||||
$this->assertCommand($commands, $expected->render(), "'append' AJAX command issued with correct data.");
|
||||
|
||||
// Tests the 'before' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'before': Click to put something before the div")]);
|
||||
$expected = new BeforeCommand('#before_div', 'Before text');
|
||||
$this->assertCommand($commands, $expected->render(), "'before' AJAX command issued with correct data.");
|
||||
|
||||
// Tests the 'changed' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX changed: Click to mark div changed.")]);
|
||||
$expected = new ChangedCommand('#changed_div');
|
||||
$this->assertCommand($commands, $expected->render(), "'changed' AJAX command issued with correct selector.");
|
||||
|
||||
// Tests the 'changed' command using the second argument.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX changed: Click to mark div changed with asterisk.")]);
|
||||
$expected = new ChangedCommand('#changed_div', '#changed_div_mark_this');
|
||||
$this->assertCommand($commands, $expected->render(), "'changed' AJAX command (with asterisk) issued with correct selector.");
|
||||
|
||||
// Tests the 'css' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("Set the '#box' div to be blue.")]);
|
||||
$expected = new CssCommand('#css_div', ['background-color' => 'blue']);
|
||||
$this->assertCommand($commands, $expected->render(), "'css' AJAX command issued with correct selector.");
|
||||
|
||||
// Tests the 'data' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX data command: Issue command.")]);
|
||||
$expected = new DataCommand('#data_div', 'testkey', 'testvalue');
|
||||
$this->assertCommand($commands, $expected->render(), "'data' AJAX command issued with correct key and value.");
|
||||
|
||||
// Tests the 'html' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX html: Replace the HTML in a selector.")]);
|
||||
$expected = new HtmlCommand('#html_div', 'replacement text');
|
||||
$this->assertCommand($commands, $expected->render(), "'html' AJAX command issued with correct data.");
|
||||
|
||||
// Tests the 'insert' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX insert: Let client insert based on #ajax['method'].")]);
|
||||
$expected = new InsertCommand('#insert_div', 'insert replacement text');
|
||||
$this->assertCommand($commands, $expected->render(), "'insert' AJAX command issued with correct data.");
|
||||
|
||||
// Tests the 'invoke' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX invoke command: Invoke addClass() method.")]);
|
||||
$expected = new InvokeCommand('#invoke_div', 'addClass', ['error']);
|
||||
$this->assertCommand($commands, $expected->render(), "'invoke' AJAX command issued with correct method and argument.");
|
||||
|
||||
// Tests the 'prepend' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'prepend': Click to prepend something")]);
|
||||
$expected = new PrependCommand('#prepend_div', 'prepended text');
|
||||
$this->assertCommand($commands, $expected->render(), "'prepend' AJAX command issued with correct data.");
|
||||
|
||||
// Tests the 'remove' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'remove': Click to remove text")]);
|
||||
$expected = new RemoveCommand('#remove_text');
|
||||
$this->assertCommand($commands, $expected->render(), "'remove' AJAX command issued with correct command and selector.");
|
||||
|
||||
// Tests the 'restripe' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'restripe' command")]);
|
||||
$expected = new RestripeCommand('#restripe_table');
|
||||
$this->assertCommand($commands, $expected->render(), "'restripe' AJAX command issued with correct selector.");
|
||||
|
||||
// Tests the 'settings' command.
|
||||
$commands = $this->drupalPostAjaxForm($form_path, $edit, ['op' => t("AJAX 'settings' command")]);
|
||||
$expected = new SettingsCommand(['ajax_forms_test' => ['foo' => 42]]);
|
||||
$this->assertCommand($commands, $expected->render(), "'settings' AJAX command issued with correct data.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test: Settings command exists regardless of JS aggregation.
|
||||
*/
|
||||
public function testAttachedSettings() {
|
||||
$assert = function($message) {
|
||||
$response = new AjaxResponse();
|
||||
$response->setAttachments([
|
||||
'library' => ['core/drupalSettings'],
|
||||
'drupalSettings' => ['foo' => 'bar'],
|
||||
]);
|
||||
|
||||
$ajax_response_attachments_processor = \Drupal::service('ajax_response.attachments_processor');
|
||||
$subscriber = new AjaxResponseSubscriber($ajax_response_attachments_processor);
|
||||
$event = new FilterResponseEvent(
|
||||
\Drupal::service('http_kernel'),
|
||||
new Request(),
|
||||
HttpKernelInterface::MASTER_REQUEST,
|
||||
$response
|
||||
);
|
||||
$subscriber->onResponse($event);
|
||||
$expected = [
|
||||
'command' => 'settings',
|
||||
];
|
||||
$this->assertCommand($response->getCommands(), $expected, $message);
|
||||
};
|
||||
|
||||
$config = $this->config('system.performance');
|
||||
|
||||
$config->set('js.preprocess', FALSE)->save();
|
||||
$assert('Settings command exists when JS aggregation is disabled.');
|
||||
|
||||
$config->set('js.preprocess', TRUE)->save();
|
||||
$assert('Settings command exists when JS aggregation is enabled.');
|
||||
}
|
||||
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\ajax_test\Controller\AjaxTestController;
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Performs tests on opening and manipulating dialogs via AJAX commands.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class DialogTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['ajax_test', 'ajax_forms_test', 'contact'];
|
||||
|
||||
/**
|
||||
* Test sending non-JS and AJAX requests to open and manipulate modals.
|
||||
*/
|
||||
public function testDialog() {
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer contact forms']));
|
||||
// Ensure the elements render without notices or exceptions.
|
||||
$this->drupalGet('ajax-test/dialog');
|
||||
|
||||
// Set up variables for this test.
|
||||
$dialog_renderable = AjaxTestController::dialogContents();
|
||||
$dialog_contents = \Drupal::service('renderer')->renderRoot($dialog_renderable);
|
||||
$modal_expected_response = [
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#drupal-modal',
|
||||
'settings' => NULL,
|
||||
'data' => $dialog_contents,
|
||||
'dialogOptions' => [
|
||||
'modal' => TRUE,
|
||||
'title' => 'AJAX Dialog & contents',
|
||||
],
|
||||
];
|
||||
$form_expected_response = [
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#drupal-modal',
|
||||
'settings' => NULL,
|
||||
'dialogOptions' => [
|
||||
'modal' => TRUE,
|
||||
'title' => 'Ajax Form contents',
|
||||
],
|
||||
];
|
||||
$entity_form_expected_response = [
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#drupal-modal',
|
||||
'settings' => NULL,
|
||||
'dialogOptions' => [
|
||||
'modal' => TRUE,
|
||||
'title' => 'Add contact form',
|
||||
],
|
||||
];
|
||||
$normal_expected_response = [
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#ajax-test-dialog-wrapper-1',
|
||||
'settings' => NULL,
|
||||
'data' => $dialog_contents,
|
||||
'dialogOptions' => [
|
||||
'modal' => FALSE,
|
||||
'title' => 'AJAX Dialog & contents',
|
||||
],
|
||||
];
|
||||
$no_target_expected_response = [
|
||||
'command' => 'openDialog',
|
||||
'selector' => '#drupal-dialog-ajax-testdialog-contents',
|
||||
'settings' => NULL,
|
||||
'data' => $dialog_contents,
|
||||
'dialogOptions' => [
|
||||
'modal' => FALSE,
|
||||
'title' => 'AJAX Dialog & contents',
|
||||
],
|
||||
];
|
||||
$close_expected_response = [
|
||||
'command' => 'closeDialog',
|
||||
'selector' => '#ajax-test-dialog-wrapper-1',
|
||||
'persist' => FALSE,
|
||||
];
|
||||
|
||||
// Check that requesting a modal dialog without JS goes to a page.
|
||||
$this->drupalGet('ajax-test/dialog-contents');
|
||||
$this->assertRaw($dialog_contents, 'Non-JS modal dialog page present.');
|
||||
|
||||
// Check that requesting a modal dialog with XMLHttpRequest goes to a page.
|
||||
$this->drupalGetXHR('ajax-test/dialog-contents');
|
||||
$this->assertRaw($dialog_contents, 'Modal dialog page on XMLHttpRequest present.');
|
||||
|
||||
// Emulate going to the JS version of the page and check the JSON response.
|
||||
$ajax_result = $this->drupalGetAjax('ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal']]);
|
||||
$this->assertEqual($modal_expected_response, $ajax_result[3], 'Modal dialog JSON response matches.');
|
||||
// Test the HTML escaping of & character.
|
||||
$this->assertEqual($ajax_result[3]['dialogOptions']['title'], 'AJAX Dialog & contents');
|
||||
$this->assertNotEqual($ajax_result[3]['dialogOptions']['title'], 'AJAX Dialog & contents');
|
||||
|
||||
// Check that requesting a "normal" dialog without JS goes to a page.
|
||||
$this->drupalGet('ajax-test/dialog-contents');
|
||||
$this->assertRaw($dialog_contents, 'Non-JS normal dialog page present.');
|
||||
|
||||
// Emulate going to the JS version of the page and check the JSON response.
|
||||
// This needs to use WebTestBase::drupalPostAjaxForm() so that the correct
|
||||
// dialog options are sent.
|
||||
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [
|
||||
// We have to mock a form element to make drupalPost submit from a link.
|
||||
'textfield' => 'test',
|
||||
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
|
||||
'submit' => [
|
||||
'dialogOptions[target]' => 'ajax-test-dialog-wrapper-1',
|
||||
]
|
||||
]);
|
||||
$this->assertEqual($normal_expected_response, $ajax_result[3], 'Normal dialog JSON response matches.');
|
||||
|
||||
// Emulate going to the JS version of the page and check the JSON response.
|
||||
// This needs to use WebTestBase::drupalPostAjaxForm() so that the correct
|
||||
// dialog options are sent.
|
||||
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [
|
||||
// We have to mock a form element to make drupalPost submit from a link.
|
||||
'textfield' => 'test',
|
||||
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
|
||||
// Don't send a target.
|
||||
'submit' => []
|
||||
]);
|
||||
// Make sure the selector ID starts with the right string.
|
||||
$this->assert(strpos($ajax_result[3]['selector'], $no_target_expected_response['selector']) === 0, 'Selector starts with right string.');
|
||||
unset($ajax_result[3]['selector']);
|
||||
unset($no_target_expected_response['selector']);
|
||||
$this->assertEqual($no_target_expected_response, $ajax_result[3], 'Normal dialog with no target JSON response matches.');
|
||||
|
||||
// Emulate closing the dialog via an AJAX request. There is no non-JS
|
||||
// version of this test.
|
||||
$ajax_result = $this->drupalGetAjax('ajax-test/dialog-close');
|
||||
$this->assertEqual($close_expected_response, $ajax_result[0], 'Close dialog JSON response matches.');
|
||||
|
||||
// Test submitting via a POST request through the button for modals. This
|
||||
// approach more accurately reflects the real responses by Drupal because
|
||||
// all of the necessary page variables are emulated.
|
||||
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [], 'button1');
|
||||
|
||||
// Check that CSS and JavaScript are "added" to the page dynamically.
|
||||
$this->assertTrue(in_array('core/drupal.dialog.ajax', explode(',', $ajax_result[0]['settings']['ajaxPageState']['libraries'])), 'core/drupal.dialog.ajax library is added to the page.');
|
||||
$dialog_css_exists = strpos($ajax_result[1]['data'], 'dialog.css') !== FALSE;
|
||||
$this->assertTrue($dialog_css_exists, 'jQuery UI dialog CSS added to the page.');
|
||||
$dialog_js_exists = strpos($ajax_result[2]['data'], 'dialog-min.js') !== FALSE;
|
||||
$this->assertTrue($dialog_js_exists, 'jQuery UI dialog JS added to the page.');
|
||||
$dialog_js_exists = strpos($ajax_result[2]['data'], 'dialog.ajax.js') !== FALSE;
|
||||
$this->assertTrue($dialog_js_exists, 'Drupal dialog JS added to the page.');
|
||||
|
||||
// Check that the response matches the expected value.
|
||||
$this->assertEqual($modal_expected_response, $ajax_result[4], 'POST request modal dialog JSON response matches.');
|
||||
// Test the HTML escaping of & character.
|
||||
$this->assertNotEqual($ajax_result[4]['dialogOptions']['title'], 'AJAX Dialog & contents');
|
||||
|
||||
// Abbreviated test for "normal" dialogs, testing only the difference.
|
||||
$ajax_result = $this->drupalPostAjaxForm('ajax-test/dialog', [], 'button2');
|
||||
$this->assertEqual($normal_expected_response, $ajax_result[4], 'POST request normal dialog JSON response matches.');
|
||||
|
||||
// Check that requesting a form dialog without JS goes to a page.
|
||||
$this->drupalGet('ajax-test/dialog-form');
|
||||
// Check we get a chunk of the code, we can't test the whole form as form
|
||||
// build id and token with be different.
|
||||
$form = $this->xpath("//form[@id='ajax-test-form']");
|
||||
$this->assertTrue(!empty($form), 'Non-JS form page present.');
|
||||
|
||||
// Emulate going to the JS version of the form and check the JSON response.
|
||||
$ajax_result = $this->drupalGetAjax('ajax-test/dialog-form', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal']]);
|
||||
$expected_ajax_settings = [
|
||||
'edit-preview' => [
|
||||
'callback' => '::preview',
|
||||
'event' => 'click',
|
||||
'url' => Url::fromRoute('ajax_test.dialog_form', [], ['query' => [
|
||||
MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal',
|
||||
FormBuilderInterface::AJAX_FORM_REQUEST => TRUE,
|
||||
]])->toString(),
|
||||
'dialogType' => 'ajax',
|
||||
'submit' => [
|
||||
'_triggering_element_name' => 'op',
|
||||
'_triggering_element_value' => 'Preview',
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->assertEqual($expected_ajax_settings, $ajax_result[0]['settings']['ajax']);
|
||||
$this->setRawContent($ajax_result[3]['data']);
|
||||
// Remove the data, the form build id and token will never match.
|
||||
unset($ajax_result[3]['data']);
|
||||
$form = $this->xpath("//form[@id='ajax-test-form']");
|
||||
$this->assertTrue(!empty($form), 'Modal dialog JSON contains form.');
|
||||
$this->assertEqual($form_expected_response, $ajax_result[3]);
|
||||
|
||||
// Check that requesting an entity form dialog without JS goes to a page.
|
||||
$this->drupalGet('admin/structure/contact/add');
|
||||
// Check we get a chunk of the code, we can't test the whole form as form
|
||||
// build id and token with be different.
|
||||
$form = $this->xpath("//form[@id='contact-form-add-form']");
|
||||
$this->assertTrue(!empty($form), 'Non-JS entity form page present.');
|
||||
|
||||
// Emulate going to the JS version of the form and check the JSON response.
|
||||
$ajax_result = $this->drupalGetAjax('admin/structure/contact/add', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_modal']]);
|
||||
$this->setRawContent($ajax_result[3]['data']);
|
||||
// Remove the data, the form build id and token will never match.
|
||||
unset($ajax_result[3]['data']);
|
||||
$form = $this->xpath("//form[@id='contact-form-add-form']");
|
||||
$this->assertTrue(!empty($form), 'Modal dialog JSON contains entity form.');
|
||||
$this->assertEqual($entity_form_expected_response, $ajax_result[3]);
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Ajax;
|
|||
* @group Ajax
|
||||
*/
|
||||
class ElementValidationTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Tries to post an Ajax change to a form that has a validated element.
|
||||
*
|
||||
|
|
|
@ -10,6 +10,7 @@ use Drupal\Core\Ajax\DataCommand;
|
|||
* @group Ajax
|
||||
*/
|
||||
class FormValuesTest extends AjaxTestBase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use Drupal\Core\Asset\AttachedAssets;
|
|||
* @group Ajax
|
||||
*/
|
||||
class FrameworkTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Verifies the Ajax rendering of a command in the settings.
|
||||
*/
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests that AJAX-enabled forms work when multiple instances of the same form
|
||||
* are on a page.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class MultiFormTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['form_test'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Page']);
|
||||
|
||||
// Create a multi-valued field for 'page' nodes to use for Ajax testing.
|
||||
$field_name = 'field_ajax_test';
|
||||
FieldStorageConfig::create([
|
||||
'entity_type' => 'node',
|
||||
'field_name' => $field_name,
|
||||
'type' => 'text',
|
||||
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||
])->save();
|
||||
FieldConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'node',
|
||||
'bundle' => 'page',
|
||||
])->save();
|
||||
entity_get_form_display('node', 'page', 'default')
|
||||
->setComponent($field_name, ['type' => 'text_textfield'])
|
||||
->save();
|
||||
|
||||
// Log in a user who can create 'page' nodes.
|
||||
$this->drupalLogin ($this->drupalCreateUser(['create page content']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that pages with the 'node_page_form' included twice work correctly.
|
||||
*/
|
||||
public function testMultiForm() {
|
||||
// HTML IDs for elements within the field are potentially modified with
|
||||
// each Ajax submission, but these variables are stable and help target the
|
||||
// desired elements.
|
||||
$field_name = 'field_ajax_test';
|
||||
|
||||
$form_xpath = '//form[starts-with(@id, "node-page-form")]';
|
||||
$field_xpath = '//div[contains(@class, "field--name-field-ajax-test")]';
|
||||
$button_name = $field_name . '_add_more';
|
||||
$button_value = t('Add another item');
|
||||
$button_xpath_suffix = '//input[@name="' . $button_name . '"]';
|
||||
$field_items_xpath_suffix = '//input[@type="text"]';
|
||||
|
||||
// Ensure the initial page contains both node forms and the correct number
|
||||
// of field items and "add more" button for the multi-valued field within
|
||||
// each form.
|
||||
$this->drupalGet('form-test/two-instances-of-same-form');
|
||||
|
||||
$fields = $this->xpath($form_xpath . $field_xpath);
|
||||
$this->assertEqual(count($fields), 2);
|
||||
foreach ($fields as $field) {
|
||||
$this->assertEqual(count($field->xpath('.' . $field_items_xpath_suffix)), 1, 'Found the correct number of field items on the initial page.');
|
||||
$this->assertFieldsByValue($field->xpath('.' . $button_xpath_suffix), NULL, 'Found the "add more" button on the initial page.');
|
||||
}
|
||||
|
||||
$this->assertNoDuplicateIds(t('Initial page contains unique IDs'), 'Other');
|
||||
|
||||
// Submit the "add more" button of each form twice. After each corresponding
|
||||
// page update, ensure the same as above.
|
||||
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$forms = $this->xpath($form_xpath);
|
||||
foreach ($forms as $offset => $form) {
|
||||
$form_html_id = (string) $form['id'];
|
||||
$this->drupalPostAjaxForm(NULL, [], [$button_name => $button_value], NULL, [], [], $form_html_id);
|
||||
$form = $this->xpath($form_xpath)[$offset];
|
||||
$field = $form->xpath('.' . $field_xpath);
|
||||
|
||||
$this->assertEqual(count($field[0]->xpath('.' . $field_items_xpath_suffix)), $i + 2, 'Found the correct number of field items after an AJAX submission.');
|
||||
$this->assertFieldsByValue($field[0]->xpath('.' . $button_xpath_suffix), NULL, 'Found the "add more" button after an AJAX submission.');
|
||||
$this->assertNoDuplicateIds(t('Updated page contains unique IDs'), 'Other');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Bootstrap;
|
||||
|
||||
use Drupal\Core\DependencyInjection\Container;
|
||||
|
||||
/**
|
||||
* Container base class which triggers an error.
|
||||
*/
|
||||
class ErrorContainer extends Container {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) {
|
||||
if ($id === 'http_kernel') {
|
||||
// Enforce a recoverable error.
|
||||
$callable = function(ErrorContainer $container) {
|
||||
};
|
||||
$callable(1);
|
||||
}
|
||||
else {
|
||||
return parent::get($id, $invalidBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Bootstrap;
|
||||
|
||||
use Drupal\Core\DependencyInjection\Container;
|
||||
|
||||
/**
|
||||
* Base container which throws an exception.
|
||||
*/
|
||||
class ExceptionContainer extends Container {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) {
|
||||
if ($id === 'http_kernel') {
|
||||
throw new \Exception('Thrown exception during Container::get');
|
||||
}
|
||||
else {
|
||||
return parent::get($id, $invalidBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -9,6 +9,12 @@ use Drupal\Core\Url;
|
|||
* Provides test assertions for testing page-level cache contexts & tags.
|
||||
*
|
||||
* Can be used by test classes that extend \Drupal\simpletest\WebTestBase.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0. Use
|
||||
* \Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait
|
||||
* instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2896632
|
||||
*/
|
||||
trait AssertPageCacheContextsAndTagsTrait {
|
||||
|
||||
|
@ -91,7 +97,7 @@ trait AssertPageCacheContextsAndTagsTrait {
|
|||
// Assert page cache item + expected cache tags.
|
||||
$cid_parts = [$url->setAbsolute()->toString(), 'html'];
|
||||
$cid = implode(':', $cid_parts);
|
||||
$cache_entry = \Drupal::cache('render')->get($cid);
|
||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||
sort($cache_entry->tags);
|
||||
$this->assertEqual($cache_entry->tags, $expected_tags);
|
||||
$this->debugCacheTags($cache_entry->tags, $expected_tags);
|
||||
|
|
|
@ -69,7 +69,7 @@ abstract class GenericCacheBackendUnitTestBase extends KernelTestBase {
|
|||
* @return \Drupal\Core\Cache\CacheBackendInterface
|
||||
* Cache backend to test.
|
||||
*/
|
||||
protected abstract function createCacheBackend($bin);
|
||||
abstract protected function createCacheBackend($bin);
|
||||
|
||||
/**
|
||||
* Allows specific implementation to change the environment before a test run.
|
||||
|
@ -303,9 +303,11 @@ abstract class GenericCacheBackendUnitTestBase extends KernelTestBase {
|
|||
$reference = [
|
||||
'test3',
|
||||
'test7',
|
||||
'test21', // Cid does not exist.
|
||||
// Cid does not exist.
|
||||
'test21',
|
||||
'test6',
|
||||
'test19', // Cid does not exist until added before second getMultiple().
|
||||
// Cid does not exist until added before second getMultiple().
|
||||
'test19',
|
||||
'test2',
|
||||
];
|
||||
|
||||
|
@ -443,13 +445,16 @@ abstract class GenericCacheBackendUnitTestBase extends KernelTestBase {
|
|||
$backend->set('test7', 17);
|
||||
|
||||
$backend->delete('test1');
|
||||
$backend->delete('test23'); // Nonexistent key should not cause an error.
|
||||
// Nonexistent key should not cause an error.
|
||||
$backend->delete('test23');
|
||||
$backend->deleteMultiple([
|
||||
'test3',
|
||||
'test5',
|
||||
'test7',
|
||||
'test19', // Nonexistent key should not cause an error.
|
||||
'test21', // Nonexistent key should not cause an error.
|
||||
// Nonexistent key should not cause an error.
|
||||
'test19',
|
||||
// Nonexistent key should not cause an error.
|
||||
'test21',
|
||||
]);
|
||||
|
||||
// Test if expected keys have been deleted.
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Drupal\system\Tests\Cache;
|
|||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
|
||||
/**
|
||||
* Provides helper methods for page cache tags tests.
|
||||
|
@ -47,14 +47,14 @@ abstract class PageCacheTagsTestBase extends WebTestBase {
|
|||
*/
|
||||
protected function verifyPageCache(Url $url, $hit_or_miss, $tags = FALSE) {
|
||||
$this->drupalGet($url);
|
||||
$message = SafeMarkup::format('Page cache @hit_or_miss for %path.', ['@hit_or_miss' => $hit_or_miss, '%path' => $url->toString()]);
|
||||
$message = new FormattableMarkup('Page cache @hit_or_miss for %path.', ['@hit_or_miss' => $hit_or_miss, '%path' => $url->toString()]);
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), $hit_or_miss, $message);
|
||||
|
||||
if ($hit_or_miss === 'HIT' && is_array($tags)) {
|
||||
$absolute_url = $url->setAbsolute()->toString();
|
||||
$cid_parts = [$absolute_url, 'html'];
|
||||
$cid = implode(':', $cid_parts);
|
||||
$cache_entry = \Drupal::cache('render')->get($cid);
|
||||
$cache_entry = \Drupal::cache('page')->get($cid);
|
||||
sort($cache_entry->tags);
|
||||
$tags = array_unique($tags);
|
||||
sort($tags);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue