diff --git a/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php b/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php index 3110a06a585e14ff4be23515b4287cdc57505181..c0272af31404a3dadd8f3f8820151d06bfa82ac5 100644 --- a/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php +++ b/typo3/sysext/backend/Classes/Form/Container/InlineControlContainer.php @@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Resource\Folder; use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; +use TYPO3\CMS\Core\Utility\StringUtility; /** * Inline element entry container. @@ -438,8 +439,9 @@ class InlineControlContainer extends AbstractContainer $foreign_table = $inlineConfiguration['foreign_table']; $allowed = $groupFieldConfiguration['allowed']; - $objectPrefix = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']) . '-' . $foreign_table; - $nameObject = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']); + $currentStructureDomObjectIdPrefix = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']); + $objectPrefix = $currentStructureDomObjectIdPrefix . '-' . $foreign_table; + $nameObject = $currentStructureDomObjectIdPrefix; $mode = 'db'; $showUpload = false; $elementBrowserEnabled = true; @@ -501,7 +503,7 @@ class InlineControlContainer extends AbstractContainer $maxFileSize = GeneralUtility::getMaxUploadFileSize() * 1024; $item .= ' <a href="#" class="btn btn-default t3js-drag-uploader inlineNewFileUploadButton ' . $this->inlineData['config'][$nameObject]['md5'] . '" ' . $buttonStyle . ' - data-dropzone-target="#' . htmlspecialchars($this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid'])) . '" + data-dropzone-target="#' . htmlspecialchars(StringUtility::escapeCssSelector($currentStructureDomObjectIdPrefix)) . '" data-insert-dropzone-before="1" data-file-irre-object="' . htmlspecialchars($objectPrefix) . '" data-file-allowed="' . htmlspecialchars($allowed) . '" diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/DragUploader.js b/typo3/sysext/backend/Resources/Public/JavaScript/DragUploader.js index e2dc9ddae0cc1833224baa4f53860b921bc6a7db..bbcbabf9656f463c629c9f746efa1c0e93006fe5 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/DragUploader.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/DragUploader.js @@ -57,15 +57,16 @@ define(['jquery', var me = this; me.$body = $('body'); me.$element = $(element); - me.$trigger = $(me.$element.data('dropzone-trigger')); + me.$trigger = $(me.$element.data('dropzoneTrigger')); me.$dropzone = $('<div />').addClass('dropzone').hide(); - me.irreObjectUid = me.$element.data('file-irre-object'); - if (me.irreObjectUid && me.$element.nextAll(me.$element.data('dropzone-target')).length !== 0) { + me.irreObjectUid = me.$element.data('fileIrreObject'); + var dropZoneEscapedTarget = me.$element.data('dropzoneTarget'); + if (me.irreObjectUid && me.$element.nextAll(dropZoneEscapedTarget).length !== 0) { me.dropZoneInsertBefore = true; - me.$dropzone.insertBefore(me.$element.data('dropzone-target')); + me.$dropzone.insertBefore(dropZoneEscapedTarget); } else { me.dropZoneInsertBefore = false; - me.$dropzone.insertAfter(me.$element.data('dropzone-target')); + me.$dropzone.insertAfter(dropZoneEscapedTarget); } me.$dropzoneMask = $('<div />').addClass('dropzone-mask').appendTo(me.$dropzone); me.$fileInput = $('<input type="file" multiple name="files[]" />').addClass('upload-file-picker').appendTo(me.$body); diff --git a/typo3/sysext/core/Classes/Utility/StringUtility.php b/typo3/sysext/core/Classes/Utility/StringUtility.php index a4800dfa46e108b35db97444b36ccd7e0e7fbb72..c9ff0c9aa18eefcaa4802c50880ace94e8021229 100644 --- a/typo3/sysext/core/Classes/Utility/StringUtility.php +++ b/typo3/sysext/core/Classes/Utility/StringUtility.php @@ -93,4 +93,18 @@ class StringUtility $uniqueId = uniqid($prefix, true); return str_replace('.', '', $uniqueId); } + + /** + * Escape a CSS selector to be used for DOM queries + * + * This method takes care to escape any CSS selector meta character. + * The result may be used to query the DOM like $('#' + escapedSelector) + * + * @param string $selector + * @return string + */ + public static function escapeCssSelector(string $selector) : string + { + return preg_replace('([#:.\\[\\],=@])', '\\$1', $selector); + } } diff --git a/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php b/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php index 73cd95d17099882c556c46a2a699ae7ba8735d1b..52f14afe345818a81bd4affc828bfc0538876b2f 100644 --- a/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php +++ b/typo3/sysext/core/Tests/Unit/Utility/StringUtilityTest.php @@ -217,4 +217,28 @@ class StringUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase { $this->assertNotContains('.', StringUtility::getUniqueId()); } + + /** + * @param string $selector + * @param string $expectedValue + * @dataProvider escapeCssSelectorDataProvider + */ + public function escapeCssSelector(string $selector, string $expectedValue) + { + $this->assertEquals($expectedValue, StringUtility::escapeCssSelector($selector)); + } + + /** + * @return array + */ + public function escapeCssSelectorDataProvider() : array + { + return [ + ['data.field', 'data\\.field'], + ['#theId', '\\#theId'], + ['.theId:hover', '\\.theId\\:hover'], + ['.theId:hover', '\\.theId\\:hover'], + ['input[name=foo]', 'input\\[name\\=foo\\]'], + ]; + } }