diff --git a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/GridEditor.ts b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/GridEditor.ts
index bb7d8de90ff121a2f09b5d9664fc0cd5ed348ed1..54be1901447f035a854072dcd81a65e6e19a5496 100644
--- a/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/GridEditor.ts
+++ b/Build/Sources/TypeScript/backend/Resources/Public/TypeScript/GridEditor.ts
@@ -65,7 +65,8 @@ export class GridEditor {
   protected selectorDocHeaderSave: string = '.t3js-grideditor-savedok';
   protected selectorDocHeaderSaveClose: string = '.t3js-grideditor-savedokclose';
   protected selectorConfigPreview: string = '.t3js-grideditor-preview-config';
-  protected selectorConfigPreviewButton: string = '.t3js-grideditor-preview-button';
+  protected selectorPreviewArea: string = '.t3js-tsconfig-preview-area';
+  protected selectorCodeMirror: string = '.t3js-grideditor-preview-config .CodeMirror';
 
   /**
    * Remove all markup
@@ -91,9 +92,6 @@ export class GridEditor {
     this.nameLabel = config !== null ? config.nameLabel : 'Name';
     this.columnLabel = config !== null ? config.columnLabel : 'Column';
     this.targetElement = $(this.selectorEditor);
-    $(this.selectorConfigPreview).hide();
-
-    $(this.selectorConfigPreviewButton).empty().append(TYPO3.lang['button.showPageTsConfig']);
 
     this.initializeEvents();
     this.drawTable();
@@ -115,7 +113,6 @@ export class GridEditor {
     $(document).on('click', this.selectorLinkShrinkLeft, this.linkShrinkLeftHandler);
     $(document).on('click', this.selectorLinkExpandDown, this.linkExpandDownHandler);
     $(document).on('click', this.selectorLinkShrinkUp, this.linkShrinkUpHandler);
-    $(document).on('click', this.selectorConfigPreviewButton, this.configPreviewButtonHandler);
   }
 
   /**
@@ -267,23 +264,6 @@ export class GridEditor {
     this.writeConfig(this.export2LayoutRecord());
   }
 
-  /**
-   *
-   * @param {Event} e
-   */
-  protected configPreviewButtonHandler = (e: Event) => {
-    e.preventDefault();
-    const $preview = $(this.selectorConfigPreview);
-    const $button = $(this.selectorConfigPreviewButton);
-    if ($preview.is(':visible')) {
-      $button.empty().append(TYPO3.lang['button.showPageTsConfig']);
-      $(this.selectorConfigPreview).slideUp();
-    } else {
-      $button.empty().append(TYPO3.lang['button.hidePageTsConfig']);
-      $(this.selectorConfigPreview).slideDown();
-    }
-  }
-
   /**
    * Create a new cell from defaultCell
    * @returns {Object}
@@ -306,8 +286,8 @@ export class GridEditor {
         config += '\t\t\t' + line + '\n';
       }
     }
-    $(this.selectorConfigPreview).find('code').empty().append(
-      'mod.web_layout.BackendLayouts {\n' +
+
+    let content = 'mod.web_layout.BackendLayouts {\n' +
       '  exampleKey {\n' +
       '    title = Example\n' +
       '    icon = EXT:example_extension/Resources/Public/Images/BackendLayouts/default.gif\n' +
@@ -315,8 +295,17 @@ export class GridEditor {
       config.replace(new RegExp('\t', 'g'), '  ') +
       '    }\n' +
       '  }\n' +
-      '}\n',
+      '}\n';
+
+    $(this.selectorConfigPreview).find(this.selectorPreviewArea).empty().append(
+      content
     );
+
+    // Update CodeMirror content if instantiated
+    const codemirror: any = document.querySelector(this.selectorCodeMirror);
+    if (codemirror) {
+      codemirror.CodeMirror.setValue(content)
+    }
   }
 
   /**
diff --git a/typo3/sysext/backend/Classes/Form/Element/BackendLayoutWizardElement.php b/typo3/sysext/backend/Classes/Form/Element/BackendLayoutWizardElement.php
index 40eed8f10743454d273b9a07ae57e264165f39be..542f360da5b5afd2335616adb03797b655b57557 100644
--- a/typo3/sysext/backend/Classes/Form/Element/BackendLayoutWizardElement.php
+++ b/typo3/sysext/backend/Classes/Form/Element/BackendLayoutWizardElement.php
@@ -16,6 +16,7 @@
 namespace TYPO3\CMS\Backend\Form\Element;
 
 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -67,6 +68,34 @@ class BackendLayoutWizardElement extends AbstractFormElement
         $fieldWizardHtml = $fieldWizardResult['html'];
         $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
 
+        // Use CodeMirror if available
+        if (ExtensionManagementUtility::isLoaded('t3editor')) {
+            $codeMirrorConfig = [
+                'label' => $lang->getLL('buttons.pageTsConfig'),
+                'panel' => 'top',
+                'mode' => 'TYPO3/CMS/T3editor/Mode/typoscript/typoscript',
+                'nolazyload' => 'true',
+                'options' => GeneralUtility::jsonEncodeForHtmlAttribute([
+                    'height' => 'auto',
+                    'readOnly' => 'true'
+                ], false),
+            ];
+            $editor = '
+                <typo3-t3editor-codemirror class="t3js-grideditor-preview-config grideditor-preview" ' . GeneralUtility::implodeAttributes($codeMirrorConfig, true) . '>
+                    <textarea class="t3js-tsconfig-preview-area"></textarea>
+                </typo3-t3editor-codemirror>';
+
+            $resultArray['stylesheetFiles'][] = 'EXT:t3editor/Resources/Public/JavaScript/Contrib/codemirror/lib/codemirror.css';
+            $resultArray['stylesheetFiles'][] = 'EXT:t3editor/Resources/Public/Css/t3editor.css';
+            $resultArray['requireJsModules'][] = ['TYPO3/CMS/T3editor/Element/CodeMirrorElement' => null];
+        } else {
+            $editor = '
+                <label>' . htmlspecialchars($lang->getLL('buttons.pageTsConfig')) . '</label>
+                <div class="t3js-grideditor-preview-config grideditor-preview">
+                    <textarea class="t3js-tsconfig-preview-area form-control" rows="25"></textarea>
+                </div>';
+        }
+
         $json = (string)json_encode($this->rows, JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS);
         $html = [];
         $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
@@ -135,8 +164,7 @@ class BackendLayoutWizardElement extends AbstractFormElement
         $html[] =                   '</tr>';
         $html[] =                   '<tr>';
         $html[] =                       '<td colspan="2">';
-        $html[] =                           '<a href="#" class="btn btn-default btn-sm t3js-grideditor-preview-button"></a>';
-        $html[] =                           '<pre class="t3js-grideditor-preview-config grideditor-preview"><code></code></pre>';
+        $html[] =                           $editor;
         $html[] =                       '</td>';
         $html[] =                   '</tr>';
         $html[] =               '</table>';
diff --git a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf
index aabfed846e4acf5ab6fbf6c9ece291310e9106e4..da85a5d31c939f7531700e285583a8203fd9f653 100644
--- a/typo3/sysext/backend/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/backend/Resources/Private/Language/locallang.xlf
@@ -127,12 +127,6 @@ Have a nice day.</source>
 			<trans-unit id="login.donate" resname="login.donate">
 				<source>Donate</source>
 			</trans-unit>
-			<trans-unit id="button.showPageTsConfig" resname="button.showPageTsConfig">
-				<source>Show PageTS-Config</source>
-			</trans-unit>
-			<trans-unit id="button.hidePageTsConfig" resname="button.hidePageTsConfig">
-				<source>Hide PageTS-Config</source>
-			</trans-unit>
 			<trans-unit id="formEngine.databaseRecordErrorInlineChildChild" resname="formEngine.databaseRecordErrorInlineChildChild">
 				<source>The record with uid %2$s from table %1$s could not be retrieved from the database. This data inconsistency can occur if
 				a base record has been deleted but the intermediate record from table %3$s with uid %4$s still points to it. To fix
diff --git a/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf b/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
index 7929b5b30f564ecb3162cace87b717cac1980bd5..470fe6186a9ce9b879986851ca0e897857853fe4 100644
--- a/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
+++ b/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
@@ -135,6 +135,9 @@
 			<trans-unit id="buttons.reviewFailedValidationFields" resname="buttons.reviewFailedValidationFields">
 				<source>Review fields with failed validations</source>
 			</trans-unit>
+			<trans-unit id="buttons.pageTsConfig" resname="buttons.pageTsConfig">
+				<source>PageTS Config</source>
+			</trans-unit>
 		</body>
 	</file>
 </xliff>
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js b/typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js
index c67f24eee72556a5d3413b56123aafe95cc2fb88..e46f5728c1171d50c2f519f838ac2c0049ecd6f6 100644
--- a/typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","./Enum/Severity","jquery","./Modal","bootstrap"],(function(t,e,n,o,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.GridEditor=void 0,o=__importDefault(o);class a{constructor(t=null){this.colCount=1,this.rowCount=1,this.nameLabel="name",this.columnLabel="column label",this.defaultCell={spanned:0,rowspan:1,colspan:1,name:"",colpos:"",column:void 0},this.selectorEditor=".t3js-grideditor",this.selectorAddColumn=".t3js-grideditor-addcolumn",this.selectorRemoveColumn=".t3js-grideditor-removecolumn",this.selectorAddRowTop=".t3js-grideditor-addrow-top",this.selectorRemoveRowTop=".t3js-grideditor-removerow-top",this.selectorAddRowBottom=".t3js-grideditor-addrow-bottom",this.selectorRemoveRowBottom=".t3js-grideditor-removerow-bottom",this.selectorLinkEditor=".t3js-grideditor-link-editor",this.selectorLinkExpandRight=".t3js-grideditor-link-expand-right",this.selectorLinkShrinkLeft=".t3js-grideditor-link-shrink-left",this.selectorLinkExpandDown=".t3js-grideditor-link-expand-down",this.selectorLinkShrinkUp=".t3js-grideditor-link-shrink-up",this.selectorDocHeaderSave=".t3js-grideditor-savedok",this.selectorDocHeaderSaveClose=".t3js-grideditor-savedokclose",this.selectorConfigPreview=".t3js-grideditor-preview-config",this.selectorConfigPreviewButton=".t3js-grideditor-preview-button",this.modalButtonClickHandler=t=>{const e=t.target;"cancel"===e.name?i.currentModal.trigger("modal-dismiss"):"ok"===e.name&&(this.setName(i.currentModal.find(".t3js-grideditor-field-name").val(),i.currentModal.data("col"),i.currentModal.data("row")),this.setColumn(i.currentModal.find(".t3js-grideditor-field-colpos").val(),i.currentModal.data("col"),i.currentModal.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord()),i.currentModal.trigger("modal-dismiss"))},this.addColumnHandler=t=>{t.preventDefault(),this.addColumn(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.removeColumnHandler=t=>{t.preventDefault(),this.removeColumn(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.addRowTopHandler=t=>{t.preventDefault(),this.addRowTop(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.addRowBottomHandler=t=>{t.preventDefault(),this.addRowBottom(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.removeRowTopHandler=t=>{t.preventDefault(),this.removeRowTop(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.removeRowBottomHandler=t=>{t.preventDefault(),this.removeRowBottom(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkEditorHandler=t=>{t.preventDefault();const e=o.default(t.target);this.showOptions(e.data("col"),e.data("row"))},this.linkExpandRightHandler=t=>{t.preventDefault();const e=o.default(t.target);this.addColspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkShrinkLeftHandler=t=>{t.preventDefault();const e=o.default(t.target);this.removeColspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkExpandDownHandler=t=>{t.preventDefault();const e=o.default(t.target);this.addRowspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkShrinkUpHandler=t=>{t.preventDefault();const e=o.default(t.target);this.removeRowspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.configPreviewButtonHandler=t=>{t.preventDefault();const e=o.default(this.selectorConfigPreview),n=o.default(this.selectorConfigPreviewButton);e.is(":visible")?(n.empty().append(TYPO3.lang["button.showPageTsConfig"]),o.default(this.selectorConfigPreview).slideUp()):(n.empty().append(TYPO3.lang["button.hidePageTsConfig"]),o.default(this.selectorConfigPreview).slideDown())};const e=o.default(this.selectorEditor);this.colCount=e.data("colcount"),this.rowCount=e.data("rowcount"),this.field=o.default('input[name="'+e.data("field")+'"]'),this.data=e.data("data"),this.nameLabel=null!==t?t.nameLabel:"Name",this.columnLabel=null!==t?t.columnLabel:"Column",this.targetElement=o.default(this.selectorEditor),o.default(this.selectorConfigPreview).hide(),o.default(this.selectorConfigPreviewButton).empty().append(TYPO3.lang["button.showPageTsConfig"]),this.initializeEvents(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())}static stripMarkup(t){return t=t.replace(/<(.*)>/gi,""),o.default("<p>"+t+"</p>").text()}initializeEvents(){o.default(document).on("click",this.selectorAddColumn,this.addColumnHandler),o.default(document).on("click",this.selectorRemoveColumn,this.removeColumnHandler),o.default(document).on("click",this.selectorAddRowTop,this.addRowTopHandler),o.default(document).on("click",this.selectorAddRowBottom,this.addRowBottomHandler),o.default(document).on("click",this.selectorRemoveRowTop,this.removeRowTopHandler),o.default(document).on("click",this.selectorRemoveRowBottom,this.removeRowBottomHandler),o.default(document).on("click",this.selectorLinkEditor,this.linkEditorHandler),o.default(document).on("click",this.selectorLinkExpandRight,this.linkExpandRightHandler),o.default(document).on("click",this.selectorLinkShrinkLeft,this.linkShrinkLeftHandler),o.default(document).on("click",this.selectorLinkExpandDown,this.linkExpandDownHandler),o.default(document).on("click",this.selectorLinkShrinkUp,this.linkShrinkUpHandler),o.default(document).on("click",this.selectorConfigPreviewButton,this.configPreviewButtonHandler)}getNewCell(){return o.default.extend({},this.defaultCell)}writeConfig(t){this.field.val(t);const e=t.split("\n");let n="";for(const t of e)t&&(n+="\t\t\t"+t+"\n");o.default(this.selectorConfigPreview).find("code").empty().append("mod.web_layout.BackendLayouts {\n  exampleKey {\n    title = Example\n    icon = EXT:example_extension/Resources/Public/Images/BackendLayouts/default.gif\n    config {\n"+n.replace(new RegExp("\t","g"),"  ")+"    }\n  }\n}\n")}addRowTop(){const t=[];for(let e=0;e<this.colCount;e++){const n=this.getNewCell();n.name=e+"x"+this.data.length,t[e]=n}this.data.unshift(t),this.rowCount++}addRowBottom(){const t=[];for(let e=0;e<this.colCount;e++){const n=this.getNewCell();n.name=e+"x"+this.data.length,t[e]=n}this.data.push(t),this.rowCount++}removeRowTop(){if(this.rowCount<=1)return!1;const t=[];for(let e=1;e<this.rowCount;e++)t.push(this.data[e]);for(let t=0;t<this.colCount;t++)1===this.data[0][t].spanned&&this.findUpperCellWidthRowspanAndDecreaseByOne(t,0);return this.data=t,this.rowCount--,!0}removeRowBottom(){if(this.rowCount<=1)return!1;const t=[];for(let e=0;e<this.rowCount-1;e++)t.push(this.data[e]);for(let t=0;t<this.colCount;t++)1===this.data[this.rowCount-1][t].spanned&&this.findUpperCellWidthRowspanAndDecreaseByOne(t,this.rowCount-1);return this.data=t,this.rowCount--,!0}findUpperCellWidthRowspanAndDecreaseByOne(t,e){const n=this.getCell(t,e-1);return!!n&&(1===n.spanned?this.findUpperCellWidthRowspanAndDecreaseByOne(t,e-1):n.rowspan>1&&this.removeRowspan(t,e-1),!0)}removeColumn(){if(this.colCount<=1)return!1;const t=[];for(let e=0;e<this.rowCount;e++){const n=[];for(let t=0;t<this.colCount-1;t++)n.push(this.data[e][t]);1===this.data[e][this.colCount-1].spanned&&this.findLeftCellWidthColspanAndDecreaseByOne(this.colCount-1,e),t.push(n)}return this.data=t,this.colCount--,!0}findLeftCellWidthColspanAndDecreaseByOne(t,e){const n=this.getCell(t-1,e);return!!n&&(1===n.spanned?this.findLeftCellWidthColspanAndDecreaseByOne(t-1,e):n.colspan>1&&this.removeColspan(t-1,e),!0)}addColumn(){for(let t=0;t<this.rowCount;t++){const e=this.getNewCell();e.name=this.colCount+"x"+t,this.data[t].push(e)}this.colCount++}drawTable(){const t=o.default("<colgroup>");for(let e=0;e<this.colCount;e++){const e=100/this.colCount;t.append(o.default("<col>").css({width:parseInt(e.toString(),10)+"%"}))}const e=o.default('<table id="base" class="table editor">');e.append(t);for(let t=0;t<this.rowCount;t++){if(0===this.data[t].length)continue;const n=o.default("<tr>");for(let e=0;e<this.colCount;e++){const i=this.data[t][e];if(1===i.spanned)continue;const l=100/this.rowCount,s=100/this.colCount,r=o.default("<td>").css({height:parseInt(l.toString(),10)*i.rowspan+"%",width:parseInt(s.toString(),10)*i.colspan+"%"}),d=o.default('<div class="cell_container">');r.append(d);const c=o.default('<a href="#" data-col="'+e+'" data-row="'+t+'">');d.append(c.clone().attr("class","t3js-grideditor-link-editor link link_editor").attr("title",TYPO3.lang.grid_editCell)),this.cellCanSpanRight(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-expand-right link link_expand_right").attr("title",TYPO3.lang.grid_mergeCell)),this.cellCanShrinkLeft(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-shrink-left link link_shrink_left").attr("title",TYPO3.lang.grid_splitCell)),this.cellCanSpanDown(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-expand-down link link_expand_down").attr("title",TYPO3.lang.grid_mergeCell)),this.cellCanShrinkUp(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-shrink-up link link_shrink_up").attr("title",TYPO3.lang.grid_splitCell)),r.append(o.default('<div class="cell_data">').html(TYPO3.lang.grid_name+": "+(i.name?a.stripMarkup(i.name):TYPO3.lang.grid_notSet)+"<br />"+TYPO3.lang.grid_column+": "+(void 0===i.column||isNaN(i.column)?TYPO3.lang.grid_notSet:parseInt(i.column,10)))),i.colspan>1&&r.attr("colspan",i.colspan),i.rowspan>1&&r.attr("rowspan",i.rowspan),n.append(r)}e.append(n)}o.default(this.targetElement).empty().append(e)}setName(t,e,n){const o=this.getCell(e,n);return!!o&&(o.name=a.stripMarkup(t),!0)}setColumn(t,e,n){const o=this.getCell(e,n);return!!o&&(o.column=parseInt(t.toString(),10),!0)}showOptions(t,e){const l=this.getCell(t,e);if(!l)return!1;let s;s=0===l.column?0:l.column?parseInt(l.column.toString(),10):"";const r=o.default("<div>"),d=o.default('<div class="form-group">'),c=o.default("<label>"),h=o.default("<input>");r.append([d.clone().append([c.clone().text(TYPO3.lang.grid_nameHelp),h.clone().attr("type","text").attr("class","t3js-grideditor-field-name form-control").attr("name","name").val(a.stripMarkup(l.name)||"")]),d.clone().append([c.clone().text(TYPO3.lang.grid_columnHelp),h.clone().attr("type","text").attr("class","t3js-grideditor-field-colpos form-control").attr("name","column").val(s)])]);const u=i.show(TYPO3.lang.grid_windowTitle,r,n.SeverityEnum.notice,[{active:!0,btnClass:"btn-default",name:"cancel",text:o.default(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel"},{btnClass:"btn-primary",name:"ok",text:o.default(this).data("button-ok-text")||TYPO3.lang["button.ok"]||"OK"}]);return u.data("col",t),u.data("row",e),u.on("button.clicked",this.modalButtonClickHandler),!0}getCell(t,e){return!(t>this.colCount-1)&&(!(e>this.rowCount-1)&&(this.data.length>e-1&&this.data[e].length>t-1?this.data[e][t]:null))}cellCanSpanRight(t,e){if(t===this.colCount-1)return!1;const n=this.getCell(t,e);let o;if(n.rowspan>1){for(let i=e;i<e+n.rowspan;i++)if(o=this.getCell(t+n.colspan,i),!o||1===o.spanned||o.colspan>1||o.rowspan>1)return!1}else if(o=this.getCell(t+n.colspan,e),!o||1===n.spanned||1===o.spanned||o.colspan>1||o.rowspan>1)return!1;return!0}cellCanSpanDown(t,e){if(e===this.rowCount-1)return!1;const n=this.getCell(t,e);let o;if(n.colspan>1){for(let i=t;i<t+n.colspan;i++)if(o=this.getCell(i,e+n.rowspan),!o||1===o.spanned||o.colspan>1||o.rowspan>1)return!1}else if(o=this.getCell(t,e+n.rowspan),!o||1===n.spanned||1===o.spanned||o.colspan>1||o.rowspan>1)return!1;return!0}cellCanShrinkLeft(t,e){return this.data[e][t].colspan>1}cellCanShrinkUp(t,e){return this.data[e][t].rowspan>1}addColspan(t,e){const n=this.getCell(t,e);if(!n||!this.cellCanSpanRight(t,e))return!1;for(let o=e;o<e+n.rowspan;o++)this.data[o][t+n.colspan].spanned=1;return n.colspan+=1,!0}addRowspan(t,e){const n=this.getCell(t,e);if(!n||!this.cellCanSpanDown(t,e))return!1;for(let o=t;o<t+n.colspan;o++)this.data[e+n.rowspan][o].spanned=1;return n.rowspan+=1,!0}removeColspan(t,e){const n=this.getCell(t,e);if(!n||!this.cellCanShrinkLeft(t,e))return!1;n.colspan-=1;for(let o=e;o<e+n.rowspan;o++)this.data[o][t+n.colspan].spanned=0;return!0}removeRowspan(t,e){const n=this.getCell(t,e);if(!n||!this.cellCanShrinkUp(t,e))return!1;n.rowspan-=1;for(let o=t;o<t+n.colspan;o++)this.data[e+n.rowspan][o].spanned=0;return!0}export2LayoutRecord(){let t="backend_layout {\n\tcolCount = "+this.colCount+"\n\trowCount = "+this.rowCount+"\n\trows {\n";for(let e=0;e<this.rowCount;e++){t+="\t\t"+(e+1)+" {\n",t+="\t\t\tcolumns {\n";let n=0;for(let o=0;o<this.colCount;o++){const i=this.getCell(o,e);i&&(i.spanned||(n++,t+="\t\t\t\t"+n+" {\n",t+="\t\t\t\t\tname = "+(i.name?i.name:o+"x"+e)+"\n",i.colspan>1&&(t+="\t\t\t\t\tcolspan = "+i.colspan+"\n"),i.rowspan>1&&(t+="\t\t\t\t\trowspan = "+i.rowspan+"\n"),"number"==typeof i.column&&(t+="\t\t\t\t\tcolPos = "+i.column+"\n"),t+="\t\t\t\t}\n"))}t+="\t\t\t}\n",t+="\t\t}\n"}return t+="\t}\n}\n",t}}e.GridEditor=a}));
\ No newline at end of file
+var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","./Enum/Severity","jquery","./Modal","bootstrap"],(function(t,e,o,n,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.GridEditor=void 0,n=__importDefault(n);class a{constructor(t=null){this.colCount=1,this.rowCount=1,this.nameLabel="name",this.columnLabel="column label",this.defaultCell={spanned:0,rowspan:1,colspan:1,name:"",colpos:"",column:void 0},this.selectorEditor=".t3js-grideditor",this.selectorAddColumn=".t3js-grideditor-addcolumn",this.selectorRemoveColumn=".t3js-grideditor-removecolumn",this.selectorAddRowTop=".t3js-grideditor-addrow-top",this.selectorRemoveRowTop=".t3js-grideditor-removerow-top",this.selectorAddRowBottom=".t3js-grideditor-addrow-bottom",this.selectorRemoveRowBottom=".t3js-grideditor-removerow-bottom",this.selectorLinkEditor=".t3js-grideditor-link-editor",this.selectorLinkExpandRight=".t3js-grideditor-link-expand-right",this.selectorLinkShrinkLeft=".t3js-grideditor-link-shrink-left",this.selectorLinkExpandDown=".t3js-grideditor-link-expand-down",this.selectorLinkShrinkUp=".t3js-grideditor-link-shrink-up",this.selectorDocHeaderSave=".t3js-grideditor-savedok",this.selectorDocHeaderSaveClose=".t3js-grideditor-savedokclose",this.selectorConfigPreview=".t3js-grideditor-preview-config",this.selectorPreviewArea=".t3js-tsconfig-preview-area",this.selectorCodeMirror=".t3js-grideditor-preview-config .CodeMirror",this.modalButtonClickHandler=t=>{const e=t.target;"cancel"===e.name?i.currentModal.trigger("modal-dismiss"):"ok"===e.name&&(this.setName(i.currentModal.find(".t3js-grideditor-field-name").val(),i.currentModal.data("col"),i.currentModal.data("row")),this.setColumn(i.currentModal.find(".t3js-grideditor-field-colpos").val(),i.currentModal.data("col"),i.currentModal.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord()),i.currentModal.trigger("modal-dismiss"))},this.addColumnHandler=t=>{t.preventDefault(),this.addColumn(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.removeColumnHandler=t=>{t.preventDefault(),this.removeColumn(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.addRowTopHandler=t=>{t.preventDefault(),this.addRowTop(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.addRowBottomHandler=t=>{t.preventDefault(),this.addRowBottom(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.removeRowTopHandler=t=>{t.preventDefault(),this.removeRowTop(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.removeRowBottomHandler=t=>{t.preventDefault(),this.removeRowBottom(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkEditorHandler=t=>{t.preventDefault();const e=n.default(t.target);this.showOptions(e.data("col"),e.data("row"))},this.linkExpandRightHandler=t=>{t.preventDefault();const e=n.default(t.target);this.addColspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkShrinkLeftHandler=t=>{t.preventDefault();const e=n.default(t.target);this.removeColspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkExpandDownHandler=t=>{t.preventDefault();const e=n.default(t.target);this.addRowspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())},this.linkShrinkUpHandler=t=>{t.preventDefault();const e=n.default(t.target);this.removeRowspan(e.data("col"),e.data("row")),this.drawTable(),this.writeConfig(this.export2LayoutRecord())};const e=n.default(this.selectorEditor);this.colCount=e.data("colcount"),this.rowCount=e.data("rowcount"),this.field=n.default('input[name="'+e.data("field")+'"]'),this.data=e.data("data"),this.nameLabel=null!==t?t.nameLabel:"Name",this.columnLabel=null!==t?t.columnLabel:"Column",this.targetElement=n.default(this.selectorEditor),this.initializeEvents(),this.drawTable(),this.writeConfig(this.export2LayoutRecord())}static stripMarkup(t){return t=t.replace(/<(.*)>/gi,""),n.default("<p>"+t+"</p>").text()}initializeEvents(){n.default(document).on("click",this.selectorAddColumn,this.addColumnHandler),n.default(document).on("click",this.selectorRemoveColumn,this.removeColumnHandler),n.default(document).on("click",this.selectorAddRowTop,this.addRowTopHandler),n.default(document).on("click",this.selectorAddRowBottom,this.addRowBottomHandler),n.default(document).on("click",this.selectorRemoveRowTop,this.removeRowTopHandler),n.default(document).on("click",this.selectorRemoveRowBottom,this.removeRowBottomHandler),n.default(document).on("click",this.selectorLinkEditor,this.linkEditorHandler),n.default(document).on("click",this.selectorLinkExpandRight,this.linkExpandRightHandler),n.default(document).on("click",this.selectorLinkShrinkLeft,this.linkShrinkLeftHandler),n.default(document).on("click",this.selectorLinkExpandDown,this.linkExpandDownHandler),n.default(document).on("click",this.selectorLinkShrinkUp,this.linkShrinkUpHandler)}getNewCell(){return n.default.extend({},this.defaultCell)}writeConfig(t){this.field.val(t);const e=t.split("\n");let o="";for(const t of e)t&&(o+="\t\t\t"+t+"\n");let i="mod.web_layout.BackendLayouts {\n  exampleKey {\n    title = Example\n    icon = EXT:example_extension/Resources/Public/Images/BackendLayouts/default.gif\n    config {\n"+o.replace(new RegExp("\t","g"),"  ")+"    }\n  }\n}\n";n.default(this.selectorConfigPreview).find(this.selectorPreviewArea).empty().append(i);const a=document.querySelector(this.selectorCodeMirror);a&&a.CodeMirror.setValue(i)}addRowTop(){const t=[];for(let e=0;e<this.colCount;e++){const o=this.getNewCell();o.name=e+"x"+this.data.length,t[e]=o}this.data.unshift(t),this.rowCount++}addRowBottom(){const t=[];for(let e=0;e<this.colCount;e++){const o=this.getNewCell();o.name=e+"x"+this.data.length,t[e]=o}this.data.push(t),this.rowCount++}removeRowTop(){if(this.rowCount<=1)return!1;const t=[];for(let e=1;e<this.rowCount;e++)t.push(this.data[e]);for(let t=0;t<this.colCount;t++)1===this.data[0][t].spanned&&this.findUpperCellWidthRowspanAndDecreaseByOne(t,0);return this.data=t,this.rowCount--,!0}removeRowBottom(){if(this.rowCount<=1)return!1;const t=[];for(let e=0;e<this.rowCount-1;e++)t.push(this.data[e]);for(let t=0;t<this.colCount;t++)1===this.data[this.rowCount-1][t].spanned&&this.findUpperCellWidthRowspanAndDecreaseByOne(t,this.rowCount-1);return this.data=t,this.rowCount--,!0}findUpperCellWidthRowspanAndDecreaseByOne(t,e){const o=this.getCell(t,e-1);return!!o&&(1===o.spanned?this.findUpperCellWidthRowspanAndDecreaseByOne(t,e-1):o.rowspan>1&&this.removeRowspan(t,e-1),!0)}removeColumn(){if(this.colCount<=1)return!1;const t=[];for(let e=0;e<this.rowCount;e++){const o=[];for(let t=0;t<this.colCount-1;t++)o.push(this.data[e][t]);1===this.data[e][this.colCount-1].spanned&&this.findLeftCellWidthColspanAndDecreaseByOne(this.colCount-1,e),t.push(o)}return this.data=t,this.colCount--,!0}findLeftCellWidthColspanAndDecreaseByOne(t,e){const o=this.getCell(t-1,e);return!!o&&(1===o.spanned?this.findLeftCellWidthColspanAndDecreaseByOne(t-1,e):o.colspan>1&&this.removeColspan(t-1,e),!0)}addColumn(){for(let t=0;t<this.rowCount;t++){const e=this.getNewCell();e.name=this.colCount+"x"+t,this.data[t].push(e)}this.colCount++}drawTable(){const t=n.default("<colgroup>");for(let e=0;e<this.colCount;e++){const e=100/this.colCount;t.append(n.default("<col>").css({width:parseInt(e.toString(),10)+"%"}))}const e=n.default('<table id="base" class="table editor">');e.append(t);for(let t=0;t<this.rowCount;t++){if(0===this.data[t].length)continue;const o=n.default("<tr>");for(let e=0;e<this.colCount;e++){const i=this.data[t][e];if(1===i.spanned)continue;const l=100/this.rowCount,r=100/this.colCount,s=n.default("<td>").css({height:parseInt(l.toString(),10)*i.rowspan+"%",width:parseInt(r.toString(),10)*i.colspan+"%"}),d=n.default('<div class="cell_container">');s.append(d);const c=n.default('<a href="#" data-col="'+e+'" data-row="'+t+'">');d.append(c.clone().attr("class","t3js-grideditor-link-editor link link_editor").attr("title",TYPO3.lang.grid_editCell)),this.cellCanSpanRight(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-expand-right link link_expand_right").attr("title",TYPO3.lang.grid_mergeCell)),this.cellCanShrinkLeft(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-shrink-left link link_shrink_left").attr("title",TYPO3.lang.grid_splitCell)),this.cellCanSpanDown(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-expand-down link link_expand_down").attr("title",TYPO3.lang.grid_mergeCell)),this.cellCanShrinkUp(e,t)&&d.append(c.clone().attr("class","t3js-grideditor-link-shrink-up link link_shrink_up").attr("title",TYPO3.lang.grid_splitCell)),s.append(n.default('<div class="cell_data">').html(TYPO3.lang.grid_name+": "+(i.name?a.stripMarkup(i.name):TYPO3.lang.grid_notSet)+"<br />"+TYPO3.lang.grid_column+": "+(void 0===i.column||isNaN(i.column)?TYPO3.lang.grid_notSet:parseInt(i.column,10)))),i.colspan>1&&s.attr("colspan",i.colspan),i.rowspan>1&&s.attr("rowspan",i.rowspan),o.append(s)}e.append(o)}n.default(this.targetElement).empty().append(e)}setName(t,e,o){const n=this.getCell(e,o);return!!n&&(n.name=a.stripMarkup(t),!0)}setColumn(t,e,o){const n=this.getCell(e,o);return!!n&&(n.column=parseInt(t.toString(),10),!0)}showOptions(t,e){const l=this.getCell(t,e);if(!l)return!1;let r;r=0===l.column?0:l.column?parseInt(l.column.toString(),10):"";const s=n.default("<div>"),d=n.default('<div class="form-group">'),c=n.default("<label>"),h=n.default("<input>");s.append([d.clone().append([c.clone().text(TYPO3.lang.grid_nameHelp),h.clone().attr("type","text").attr("class","t3js-grideditor-field-name form-control").attr("name","name").val(a.stripMarkup(l.name)||"")]),d.clone().append([c.clone().text(TYPO3.lang.grid_columnHelp),h.clone().attr("type","text").attr("class","t3js-grideditor-field-colpos form-control").attr("name","column").val(r)])]);const u=i.show(TYPO3.lang.grid_windowTitle,s,o.SeverityEnum.notice,[{active:!0,btnClass:"btn-default",name:"cancel",text:n.default(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel"},{btnClass:"btn-primary",name:"ok",text:n.default(this).data("button-ok-text")||TYPO3.lang["button.ok"]||"OK"}]);return u.data("col",t),u.data("row",e),u.on("button.clicked",this.modalButtonClickHandler),!0}getCell(t,e){return!(t>this.colCount-1)&&(!(e>this.rowCount-1)&&(this.data.length>e-1&&this.data[e].length>t-1?this.data[e][t]:null))}cellCanSpanRight(t,e){if(t===this.colCount-1)return!1;const o=this.getCell(t,e);let n;if(o.rowspan>1){for(let i=e;i<e+o.rowspan;i++)if(n=this.getCell(t+o.colspan,i),!n||1===n.spanned||n.colspan>1||n.rowspan>1)return!1}else if(n=this.getCell(t+o.colspan,e),!n||1===o.spanned||1===n.spanned||n.colspan>1||n.rowspan>1)return!1;return!0}cellCanSpanDown(t,e){if(e===this.rowCount-1)return!1;const o=this.getCell(t,e);let n;if(o.colspan>1){for(let i=t;i<t+o.colspan;i++)if(n=this.getCell(i,e+o.rowspan),!n||1===n.spanned||n.colspan>1||n.rowspan>1)return!1}else if(n=this.getCell(t,e+o.rowspan),!n||1===o.spanned||1===n.spanned||n.colspan>1||n.rowspan>1)return!1;return!0}cellCanShrinkLeft(t,e){return this.data[e][t].colspan>1}cellCanShrinkUp(t,e){return this.data[e][t].rowspan>1}addColspan(t,e){const o=this.getCell(t,e);if(!o||!this.cellCanSpanRight(t,e))return!1;for(let n=e;n<e+o.rowspan;n++)this.data[n][t+o.colspan].spanned=1;return o.colspan+=1,!0}addRowspan(t,e){const o=this.getCell(t,e);if(!o||!this.cellCanSpanDown(t,e))return!1;for(let n=t;n<t+o.colspan;n++)this.data[e+o.rowspan][n].spanned=1;return o.rowspan+=1,!0}removeColspan(t,e){const o=this.getCell(t,e);if(!o||!this.cellCanShrinkLeft(t,e))return!1;o.colspan-=1;for(let n=e;n<e+o.rowspan;n++)this.data[n][t+o.colspan].spanned=0;return!0}removeRowspan(t,e){const o=this.getCell(t,e);if(!o||!this.cellCanShrinkUp(t,e))return!1;o.rowspan-=1;for(let n=t;n<t+o.colspan;n++)this.data[e+o.rowspan][n].spanned=0;return!0}export2LayoutRecord(){let t="backend_layout {\n\tcolCount = "+this.colCount+"\n\trowCount = "+this.rowCount+"\n\trows {\n";for(let e=0;e<this.rowCount;e++){t+="\t\t"+(e+1)+" {\n",t+="\t\t\tcolumns {\n";let o=0;for(let n=0;n<this.colCount;n++){const i=this.getCell(n,e);i&&(i.spanned||(o++,t+="\t\t\t\t"+o+" {\n",t+="\t\t\t\t\tname = "+(i.name?i.name:n+"x"+e)+"\n",i.colspan>1&&(t+="\t\t\t\t\tcolspan = "+i.colspan+"\n"),i.rowspan>1&&(t+="\t\t\t\t\trowspan = "+i.rowspan+"\n"),"number"==typeof i.column&&(t+="\t\t\t\t\tcolPos = "+i.column+"\n"),t+="\t\t\t\t}\n"))}t+="\t\t\t}\n",t+="\t\t}\n"}return t+="\t}\n}\n",t}}e.GridEditor=a}));
\ No newline at end of file