From e933bef6f331780b91acd317fafb40f25a48c3f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Frank=20Na=CC=88gler?= <frank.naegler@typo3.org>
Date: Mon, 18 Jan 2016 16:01:04 +0100
Subject: [PATCH] [TASK] Refactoring of BackendLayoutWizard

This patch remove the usage of ExtJS and move the JavaScript
logic into the new AMD module: TYPO3/CMS/Backend/GridEditor

Old images has been removed and CSS moved into backend.css.

Resolves: #72793
Releases: master
Change-Id: I13bf37d46941c7cdd094153036cd00e20f89c8e0
Reviewed-on: https://review.typo3.org/46061
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
---
 .../TYPO3/_main_backend_layout_wizard.less    | 116 ++++
 Build/Resources/Public/Less/backend.less      |   1 +
 .../BackendLayoutWizardController.php         | 160 +++--
 .../Resources/Public/Css/grideditor.css       | 241 -------
 .../t3grid-edit-inactive-1.png                | Bin 206 -> 0 bytes
 .../t3grid-edit-inactive.png                  | Bin 206 -> 0 bytes
 .../BackendLayoutWizard/t3grid-edit.png       | Bin 249 -> 0 bytes
 .../t3grid-editor-down-inactive.png           | Bin 328 -> 0 bytes
 .../t3grid-editor-down.png                    | Bin 367 -> 0 bytes
 .../t3grid-editor-left-inactive.png           | Bin 401 -> 0 bytes
 .../t3grid-editor-left.png                    | Bin 426 -> 0 bytes
 .../t3grid-editor-right-inactive.png          | Bin 383 -> 0 bytes
 .../t3grid-editor-right.png                   | Bin 414 -> 0 bytes
 .../t3grid-editor-up-inactive.png             | Bin 338 -> 0 bytes
 .../BackendLayoutWizard/t3grid-editor-up.png  | Bin 387 -> 0 bytes
 .../t3grid-layer-icon-close.png               | Bin 165 -> 0 bytes
 .../t3grid-layer-icon-help.png                | Bin 194 -> 0 bytes
 .../t3grid-layer-icon-save.png                | Bin 174 -> 0 bytes
 .../BackendLayoutWizard/t3grid-tabledown.png  | Bin 236 -> 0 bytes
 .../BackendLayoutWizard/t3grid-tableleft.png  | Bin 207 -> 0 bytes
 .../BackendLayoutWizard/t3grid-tableright.png | Bin 258 -> 0 bytes
 .../BackendLayoutWizard/t3grid-tableup.png    | Bin 219 -> 0 bytes
 .../Resources/Public/JavaScript/GridEditor.js | 640 ++++++++++++++++++
 .../Resources/Public/JavaScript/grideditor.js | 635 -----------------
 .../t3skin/Resources/Public/Css/backend.css   | 101 +++
 25 files changed, 948 insertions(+), 946 deletions(-)
 create mode 100644 Build/Resources/Public/Less/TYPO3/_main_backend_layout_wizard.less
 delete mode 100644 typo3/sysext/backend/Resources/Public/Css/grideditor.css
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit-inactive-1.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit-inactive.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-down-inactive.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-down.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-left-inactive.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-left.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-right-inactive.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-right.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-up-inactive.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-up.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-close.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-help.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-save.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tabledown.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableleft.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableright.png
 delete mode 100644 typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableup.png
 create mode 100644 typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js
 delete mode 100644 typo3/sysext/backend/Resources/Public/JavaScript/grideditor.js

diff --git a/Build/Resources/Public/Less/TYPO3/_main_backend_layout_wizard.less b/Build/Resources/Public/Less/TYPO3/_main_backend_layout_wizard.less
new file mode 100644
index 000000000000..830d5aa65ca8
--- /dev/null
+++ b/Build/Resources/Public/Less/TYPO3/_main_backend_layout_wizard.less
@@ -0,0 +1,116 @@
+
+.grideditor {
+	td {
+		vertical-align: middle;
+		&.editor_cell {
+			height: 100%;
+		}
+	}
+
+	table.editor {
+		border-right: 1px gray dashed;
+		border-bottom: 1px gray dashed;
+
+		td {
+			vertical-align: middle;
+			border-top: 1px gray dashed;
+			border-left: 1px gray dashed;
+			text-align: center;
+			background-color: white;
+			min-height: 100px;
+		}
+	}
+
+	div#editor {
+		height: 100%;
+	}
+
+	div.cell_container {
+		width: 80px;
+		height: 80px;
+		position: relative;
+		left: 50%;
+		margin-left: -30px;
+		opacity: 0.3;
+	}
+
+	div.cell_container:hover {
+		opacity: 0.5;
+	}
+
+	.link {
+		display: block;
+		position: absolute;
+		width: 20px;
+		height: 40px;
+		overflow: hidden;
+		opacity: 0.5;
+		&:hover {
+			text-decoration: none;
+			opacity: 1;
+		}
+
+		&_expand_down,
+		&_shrink_up {
+			width: 40px;
+			height: 20px;
+		}
+
+		&_expand_right {
+			left: 52px;
+			top: 0;
+			&:before {
+				font-family: FontAwesome;
+				content: "@{fa-var-caret-right}";
+				font-size: 42px;
+				line-height: 42px;
+			}
+		}
+
+		&_shrink_left {
+			left: -8px;
+			top: 0;
+			&:before {
+				font-family: FontAwesome;
+				content: "@{fa-var-caret-left}";
+				font-size: 42px;
+				line-height: 42px;
+			}
+		}
+
+		&_expand_down {
+			left: 12px;
+			top: 40px;
+			&:before {
+				font-family: FontAwesome;
+				content: "@{fa-var-caret-down}";
+				font-size: 42px;
+				line-height: 19px;
+			}
+		}
+
+		&_shrink_up {
+			left: 12px;
+			top: -20px;
+			&:before {
+				font-family: FontAwesome;
+				content: "@{fa-var-caret-up}";
+				font-size: 42px;
+				line-height: 20px;
+			}
+		}
+
+		&_editor {
+			width: 40px;
+			height: 40px;
+			left: 12px;
+			top: 0;
+			&:before {
+				font-family: FontAwesome;
+				content: "@{fa-var-pencil-square}";
+				font-size: 42px;
+				line-height: 42px;
+			}
+		}
+	}
+}
diff --git a/Build/Resources/Public/Less/backend.less b/Build/Resources/Public/Less/backend.less
index a8025ca8de67..f6000c8c1a1d 100644
--- a/Build/Resources/Public/Less/backend.less
+++ b/Build/Resources/Public/Less/backend.less
@@ -60,6 +60,7 @@
 @import "TYPO3/_main_body.less";
 @import "TYPO3/_main_content.less";
 @import "TYPO3/_main_elementbrowser.less";
+@import "TYPO3/_main_backend_layout_wizard";
 @import "TYPO3/_main_form.less";
 @import "TYPO3/_main_scaffolding.less";
 @import "TYPO3/_module_menu.less";
diff --git a/typo3/sysext/backend/Classes/Controller/BackendLayoutWizardController.php b/typo3/sysext/backend/Classes/Controller/BackendLayoutWizardController.php
index fea863f63564..c54cc03d2f5f 100644
--- a/typo3/sysext/backend/Classes/Controller/BackendLayoutWizardController.php
+++ b/typo3/sysext/backend/Classes/Controller/BackendLayoutWizardController.php
@@ -22,7 +22,6 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -30,15 +29,15 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class BackendLayoutWizardController extends AbstractModule
 {
-    // GET vars:
-    // Wizard parameters, coming from TCEforms linking to the wizard.
     /**
+     * GET vars:
+     * Wizard parameters, coming from TCEforms linking to the wizard.
      * @var array
      */
     public $P;
 
-    // Accumulated content.
     /**
+     * Accumulated content.
      * @var string
      */
     public $content;
@@ -53,6 +52,21 @@ class BackendLayoutWizardController extends AbstractModule
      */
     public $fieldName;
 
+    /**
+     * @var array
+     */
+    protected $rows;
+
+    /**
+     * @var int
+     */
+    protected $colCount;
+
+    /**
+     * @var int
+     */
+    protected $rowCount;
+
     /**
      * Constructor
      */
@@ -85,10 +99,7 @@ class BackendLayoutWizardController extends AbstractModule
 
         /** @var \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer */
         $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
-        $pageRenderer->loadExtJS();
-        $pageRenderer->addJsFile(ExtensionManagementUtility::extRelPath('backend')
-            . 'Resources/Public/JavaScript/grideditor.js');
-        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
+        $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/GridEditor');
         $pageRenderer->addInlineSetting(
             'ContextHelp',
             'moduleUrl',
@@ -103,24 +114,28 @@ class BackendLayoutWizardController extends AbstractModule
             )
         );
         $pageRenderer->addJsInlineCode('storeData', '
-			function storeData(data) {
-				if (parent.opener && parent.opener.document && parent.opener.document.' . $this->formName . ' && parent.opener.document.' . $this->formName . '[' . GeneralUtility::quoteJSvalue($this->fieldName) . ']) {
-					parent.opener.document.' . $this->formName . '[' . GeneralUtility::quoteJSvalue($this->fieldName) . '].value = data;
-					parent.opener.TBE_EDITOR.fieldChanged("backend_layout","' . $uid . '","config","data[backend_layout][' . $uid . '][config]");
-				}
-			}
-			', false);
+            function storeData(data) {
+                if (parent.opener && parent.opener.document && parent.opener.document.' . $this->formName
+                . ' && parent.opener.document.' . $this->formName . '['
+                    . GeneralUtility::quoteJSvalue($this->fieldName) . ']) {
+                    parent.opener.document.' . $this->formName . '['
+                    . GeneralUtility::quoteJSvalue($this->fieldName) . '].value = data;
+                    parent.opener.TBE_EDITOR.fieldChanged("backend_layout","' . $uid . '","config",'
+                    . '"data[backend_layout][' . $uid . '][config]");
+                }
+            }
+            ', false);
         $languageLabels = array(
-            'save' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_labelSave', true),
-            'title' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_windowTitle', true),
-            'editCell' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_editCell', true),
-            'mergeCell' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_mergeCell', true),
-            'splitCell' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_splitCell', true),
-            'name' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_name', true),
-            'column' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_column', true),
-            'notSet' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_notSet', true),
-            'nameHelp' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_nameHelp', true),
-            'columnHelp' => $lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_columnHelp', true)
+            'save' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_labelSave')),
+            'title' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_windowTitle')),
+            'editCell' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_editCell')),
+            'mergeCell' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_mergeCell')),
+            'splitCell' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_splitCell')),
+            'name' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_name')),
+            'column' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_column')),
+            'notSet' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_notSet')),
+            'nameHelp' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_nameHelp')),
+            'columnHelp' => htmlspecialchars($lang->sL('LLL:EXT:lang/locallang_wizards.xlf:grid_columnHelp'))
         );
         $pageRenderer->addInlineLanguageLabelArray($languageLabels);
         // Select record
@@ -199,18 +214,9 @@ class BackendLayoutWizardController extends AbstractModule
                 }
             }
         }
-        $pageRenderer->addExtOnReadyCode('
-			t3Grid = new TYPO3.Backend.t3Grid({
-				data: ' . json_encode($rows, JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS) . ',
-				colCount: ' . (int)$colCount . ',
-				rowCount: ' . (int)$rowCount . ',
-				targetElement: \'editor\'
-			});
-			t3Grid.drawTable();
-			');
-
-        $this->moduleTemplate->getPageRenderer()->addCssFile(ExtensionManagementUtility::extRelPath('backend')
-            . 'Resources/Public/Css/grideditor.css');
+        $this->rows = $rows;
+        $this->colCount = (int)$colCount;
+        $this->rowCount = (int)$rowCount;
     }
 
     /**
@@ -265,21 +271,18 @@ class BackendLayoutWizardController extends AbstractModule
         $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
         $lang = $this->getLanguageService();
 
-        $resourcePath = ExtensionManagementUtility::extRelPath('backend')
-            . 'Resources/Public/Images/BackendLayoutWizard/';
-
         $saveButton = $buttonBar->makeInputButton()
             ->setName('_savedok')
             ->setValue('1')
             ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc'))
-            ->setOnClick('storeData(t3Grid.export2LayoutRecord());return true;')
+            ->setClasses('t3js-grideditor-savedok')
             ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
 
         $saveAndCloseButton = $buttonBar->makeInputButton()
             ->setName('_savedokandclose')
             ->setValue('1')
             ->setTitle($lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc'))
-            ->setOnClick('storeData(t3Grid.export2LayoutRecord());window.close();return true;')
+            ->setClasses('t3js-grideditor-savedokclose')
             ->setIcon(
                 $this->moduleTemplate->getIconFactory()->getIcon('actions-document-save-close', Icon::SIZE_SMALL)
             );
@@ -296,34 +299,51 @@ class BackendLayoutWizardController extends AbstractModule
             ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL));
         $buttonBar->addButton($closeButton, ButtonBar::BUTTON_POSITION_LEFT, 30);
 
-        $this->content .= '
-		<table border="0" width="90%" height="90%" id="outer_container">
-			<tr>
-				<td class="editor_cell">
-					<div id="editor">
-					</div>
-				</td>
-				<td width="20" valign="center">
-					<a class="addCol" href="#" title="' . $lang->getLL('grid_addColumn') . '" onclick="t3Grid.addColumn(); t3Grid.drawTable(\'editor\');">
-						<img src="' . $resourcePath . 't3grid-tableright.png" border="0" />
-					</a><br />
-					<a class="removeCol" href="#" title="' . $lang->getLL('grid_removeColumn') . '" onclick="t3Grid.removeColumn(); t3Grid.drawTable(\'editor\');">
-						<img src="' . $resourcePath . 't3grid-tableleft.png" border="0" />
-					</a>
-				</td>
-			</tr>
-			<tr>
-				<td colspan="2" height="20" align="center">
-					<a class="addCol" href="#" title="' . $lang->getLL('grid_addRow') . '" onclick="t3Grid.addRow(); t3Grid.drawTable(\'editor\');">
-						<img src="' . $resourcePath . 't3grid-tabledown.png" border="0" />
-					</a>
-					<a class="removeCol" href="#" title="' . $lang->getLL('grid_removeRow') . '" onclick="t3Grid.removeRow(); t3Grid.drawTable(\'editor\');">
-						<img src="' . $resourcePath . 't3grid-tableup.png" border="0" />
-					</a>
-				</td>
-			</tr>
-		</table>
-		';
+        $markup = array();
+        $markup[] = '';
+        $markup[] = '<table class="grideditor table table-bordered"">';
+        $markup[] = '    <tr>';
+        $markup[] = '        <td class="editor_cell">';
+        $markup[] = '           <div id="editor" class="t3js-grideditor" data-data="' . htmlspecialchars(
+            json_encode(
+                $this->rows,
+                JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS
+            )
+        ) . '" '
+        . 'data-rowcount="' . (int)$this->rowCount . '" '
+        . 'data-colcount="' . (int)$this->colCount . '">';
+        $markup[] = '            </div>';
+        $markup[] = '        </td>';
+        $markup[] = '        <td>';
+        $markup[] = '            <div class="btn-group-vertical">';
+        $markup[] = '               <a class="btn btn-default btn-sm t3js-grideditor-addcolumn" href="#" title="'
+            . htmlspecialchars($lang->getLL('grid_addColumn')) . '">';
+        $markup[] = '                <i class="fa fa-fw fa-arrow-right"></i>';
+        $markup[] = '               </a>';
+        $markup[] = '               <a class="btn btn-default btn-sm t3js-grideditor-removecolumn" href="#" title="'
+            . htmlspecialchars($lang->getLL('grid_removeColumn')) . '">';
+        $markup[] = '                <i class="fa fa-fw fa-arrow-left"></i>';
+        $markup[] = '               </a>';
+        $markup[] = '            </div>';
+        $markup[] = '        </td>';
+        $markup[] = '    </tr>';
+        $markup[] = '    <tr>';
+        $markup[] = '        <td colspan="2" align="center">';
+        $markup[] = '            <div class="btn-group">';
+        $markup[] = '               <a class="btn btn-default btn-sm t3js-grideditor-addrow" href="#" title="'
+            . htmlspecialchars($lang->getLL('grid_addRow')) . '">';
+        $markup[] = '                <i class="fa fa-fw fa-arrow-down"></i>';
+        $markup[] = '               </a>';
+        $markup[] = '               <a class="btn btn-default btn-sm t3js-grideditor-removerow" href="#" title="'
+            . htmlspecialchars($lang->getLL('grid_removeRow')) . '">';
+        $markup[] = '                <i class="fa fa-fw fa-arrow-up"></i>';
+        $markup[] = '               </a>';
+        $markup[] = '            </div>';
+        $markup[] = '        </td>';
+        $markup[] = '    </tr>';
+        $markup[] = '</table>';
+
+        $this->content .= implode(LF, $markup);
     }
 
     /**
diff --git a/typo3/sysext/backend/Resources/Public/Css/grideditor.css b/typo3/sysext/backend/Resources/Public/Css/grideditor.css
deleted file mode 100644
index ce087003a4c8..000000000000
--- a/typo3/sysext/backend/Resources/Public/Css/grideditor.css
+++ /dev/null
@@ -1,241 +0,0 @@
-* {
-	padding: 0;
-	margin: 0;
-	position: relative;
-}
-
-body { padding: 10px; }
-
-table#outer_container td, table#editor td {
-	vertical-align: middle;
-}
-
-table#outer_container td.editor_cell {
-	height: 100%;
-}
-
-table.editor {
-	border-right: 1px gray dashed;
-	border-bottom: 1px gray dashed;
-}
-
-table.editor td {
-	border-top: 1px gray dashed;
-	border-left: 1px gray dashed;
-	text-align: center;
-	z-index: 2000;
-	background-color: white;
-	min-height: 100px;
-}
-
-div#editor {
-	height: 100%;
-}
-
-div.cell_container {
-	width: 60px;
-	height: 60px;
-	position: relative;
-	left: 50%;
-	margin-left: -30px;
-	opacity: 0.3;
-}
-
-div.cell_container:hover {
-	opacity: 1;
-}
-
-.link_expand_right, .link_shrink_left, .link_expand_down, .link_shrink_up, .link_editor {
-	display: block;
-	position: absolute;
-	width: 14px;
-	height: 32px;
-	z-index: 1100;
-}
-
-.link_expand_down, .link_shrink_up {
-	width: 32px;
-	height: 14px;
-}
-
-.link_expand_right {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-right-inactive.png);
-	left: 46px;
-	top: 14px;
-}
-
-.link_expand_right:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-right.png);
-}
-
-
-.link_shrink_left {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-left-inactive.png);
-	left: 0px;
-	top: 14px;
-}
-
-.link_shrink_left:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-left.png);
-}
-
-.link_expand_down {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-down-inactive.png);
-	left: 14px;
-	top: 46px;
-}
-
-.link_expand_down:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-down.png);
-}
-
-.link_shrink_up {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-up-inactive.png);
-	left: 14px;
-	top: 0px;
-}
-
-.link_shrink_up:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-up.png);
-}
-
-.link_editor {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-edit-inactive.png);
-	width: 32px;
-	height: 32px;
-	left: 14px;
-	top: 14px;
-}
-
-.link_editor:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-edit.png);
-}
-
-.question {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-layer-icon-help.png) !important;
-}
-
-.save {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-layer-icon-save.png) !important;
-}
-
-.cancel {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-layer-icon-close.png) !important;
-}
-
-table#outer_container td, table#editor td {
-	vertical-align: middle;
-}
-
-table#outer_container td.editor_cell {
-	height: 100%;
-}
-
-table.editor {
-	border-right: 1px gray dashed;
-	border-bottom: 1px gray dashed;
-}
-
-table.editor td {
-	border-top: 1px gray dashed;
-	border-left: 1px gray dashed;
-	text-align: center;
-	z-index: 2000;
-	background-color: white;
-	min-height: 100px;
-}
-
-div#editor {
-	height: 100%;
-}
-
-div.cell_container {
-	width: 60px;
-	height: 60px;
-	position: relative;
-	left: 50%;
-	margin-left: -30px;
-	opacity: 0.3;
-}
-
-div.cell_container:hover {
-	opacity: 1;
-}
-
-.link_expand_right, .link_shrink_left, .link_expand_down, .link_shrink_up, .link_editor {
-	display: block;
-	position: absolute;
-	width: 14px;
-	height: 32px;
-	z-index: 1100;
-}
-
-.link_expand_down, .link_shrink_up {
-	width: 32px;
-	height: 14px;
-}
-
-.link_expand_right {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-right-inactive.png);
-	left: 46px;
-	top: 14px;
-}
-
-.link_expand_right:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-right.png);
-}
-
-
-.link_shrink_left {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-left-inactive.png);
-	left: 0px;
-	top: 14px;
-}
-
-.link_shrink_left:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-left.png);
-}
-
-.link_expand_down {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-down-inactive.png);
-	left: 14px;
-	top: 46px;
-}
-
-.link_expand_down:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-down.png);
-}
-
-.link_shrink_up {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-up-inactive.png);
-	left: 14px;
-	top: 0px;
-}
-
-.link_shrink_up:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-editor-up.png);
-}
-
-.link_editor {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-edit-inactive.png);
-	width: 32px;
-	height: 32px;
-	left: 14px;
-	top: 14px;
-}
-
-.link_editor:hover {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-edit.png);
-}
-
-.question {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-layer-icon-help.png) !important;
-}
-
-.save {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-layer-icon-save.png) !important;
-}
-
-.cancel {
-	background-image: url(../Images/BackendLayoutWizard/t3grid-layer-icon-close.png) !important;
-}
diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit-inactive-1.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit-inactive-1.png
deleted file mode 100644
index 077cd7718777ac5aa1ac49d481a447516dc7cf9a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 206
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UQ$1ZALp+WrYy9_@OwsuN-jh+r
zG+~M41MiuP`~LTCkaAoCq<8<@o^0Br!EEzy{;&Vv>M#F~(s2_=WN`Vt^1u7P@ClEZ
zTE5+V(!#i@jQ>(H<FdaRes3#y6>_ZOm^(Jg_A|=;w`VjJ-ZZy?ael{zzRL`33%<Q}
zc;T3rmc-!1ue7Cqn#bXj4I-PiE^pw?Sg@q%yd49>8ZDnQ-EJ3810BfV>FVdQ&MBb@
E0M-;zkN^Mx

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit-inactive.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit-inactive.png
deleted file mode 100644
index 077cd7718777ac5aa1ac49d481a447516dc7cf9a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 206
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UQ$1ZALp+WrYy9_@OwsuN-jh+r
zG+~M41MiuP`~LTCkaAoCq<8<@o^0Br!EEzy{;&Vv>M#F~(s2_=WN`Vt^1u7P@ClEZ
zTE5+V(!#i@jQ>(H<FdaRes3#y6>_ZOm^(Jg_A|=;w`VjJ-ZZy?ael{zzRL`33%<Q}
zc;T3rmc-!1ue7Cqn#bXj4I-PiE^pw?Sg@q%yd49>8ZDnQ-EJ3810BfV>FVdQ&MBb@
E0M-;zkN^Mx

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-edit.png
deleted file mode 100644
index 98a0ab12a3437ae884a3f88c690e1d7384a49ad2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 249
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy_5nU2uI1(B+1c4;_KbBdj6ph#
z{|}S{W&VG-|Np|wl#~>ptf!~v|8;@?UtPLd$auGm@k}n`kxa%%6^#FPW&hui;koFa
z0Z;=|NswP~!+~oh(+>lA>7Fi*Ar)~?FT3*{P~dTOeB|V-``tc!lk>IdXBa<x>lNhY
zC^cAUR=$kQhC$~I(?0%0_6d2vHSaK%)#?{BeY<*((b|+{uYEl`!*7lPc}CT(zd0to
sWJo%7vxH${#v}LWJ#kqQfBrvZKFy_-bH*-39cU$kr>mdKI;Vst08@lspa1{>

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-down-inactive.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-down-inactive.png
deleted file mode 100644
index 72a6782a0179f42e349738521ad4dec32fe2be07..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 328
zcmV-O0k{5%P)<h;3K|Lk000e1NJLTq001BW000gM1^@s6PTU@{0003GNkl<Zc-p<r
zJ4?fG6o&EtH_$;5DT-1QFHq3I$-$4+OYTMy92_hNqM$>UE*-={hfW1Y2R}}e9v{T^
zgg}}^+YZ0sEbn=Yh?uJ|yoM~;t?>IN;4%o7a06M8HkKy=7rt+>f;ME%?y(9p2?#xJ
zYz=piIeEl73^d@}b(1Q1fXvu4HWGg{AaI<tO*}znq=T*04-N2bTd8eyApg`w6(&Uk
zJj=>bMHeH;AM~)Bv8@4at2NCIdWazfjqrl~DZ3iraOBv-D<Vja7;iYt+tq+(vxoz{
zV+hF*p^sXDJq@rMjiPGkV+cu!Fu-xaEe){h^)ikyKm_>};{zvUw#o;nQ+y@@zHkOp
aHsBljb*U93{_EcW0000<MNUMnLSTZ4YlL9{

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-down.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-down.png
deleted file mode 100644
index 13b5e706365085d3ea2ea48d600d891378420a6e..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 367
zcmV-#0g(QQP)<h;3K|Lk000e1NJLTq001BW000gM1^@s6PTU@{0003tNkl<Zc-p<w
zy-LGi6vpw~fewm@C`wWMfPxNA4zBrVo7Bs4a8M9LL5D6~I*5Y~P6bB?FQ-Y4|7S>P
zV-gjT4!<+xeb0Fg331HKx#;&VVGDMx>}-LheiU877UYJ^<>>;#!<C2wSi|nfTFr7*
zrZ`*+!|)c?kOwl>XERmiaA~90>)pd@_QdSXe4fe=T;A$-yN|G%44AoHl%-OLrkzfw
zGl0!uASwfMJwu+g%5qdn(cHoiDGX_j{bGc@s*LP6)L-C4;5+FP=nZHA*~JJ+5CoZ2
zDuPoy;{ckanVPK(WhwKI3xKeFydajDC9FV#R~)Igt_2+5_Yd)g31XzMoEYzDtEcV-
zqzwg3O2WrDfz!+a@I3DrW5h5>f)AYPPSXoGuIrxR69)Ohxz7H(z&At}6{-&%dzSzJ
N002ovPDHLkV1oF0qdNcq

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-left-inactive.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-left-inactive.png
deleted file mode 100644
index 64e32a2e6877cd798ce380eac638685cd67a6475..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 401
zcmV;C0dD?@P)<h;3K|Lk000e1NJLTq000gE001Be1^@s6BJN3-00044Nkl<Zc-o!O
zJ4-@w9LDjp2T>su1rZ1l6hz?A(9o+>QB(1nnwr;>dLo5_8eD2<Z0NmsOZ@c}6|cv?
zI()Y0J3X3+Y(zPz8OE#~gp^^mQkk@eF#eR`OSwE^K>}@vGJGzT`VNpr3j%d$==vdY
zXhMdTN0nmn7&@Ae3Fc9`P_V*43o>JI^pww^qJ}nPf%!<!X3z184#dQCRLEp5@qsR6
ziE)%qr){XC2T>SAxm4;JpO95)nPl=7-;i}^kBP)DWL;V+9+ypM$yiJ_p*=*SKah24
z@krzbUywBn?udm#Hq;@jA_Str;1%A{gQyUVMFN2fyrBzOhG1IQ?>|Eo9f%pm^MXE~
z6$V<6MHns?@On?6qY0VC$eiEfIYJf<$Rq~K`P}Y(q|ks2sY9>J)n~yy8W5<%JEwDG
v7hyD^4&4sNq;2@nR)#LSebyG-CV|>N2b|P9e8v(u00000NkvXXu0mjfdeE#Q

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-left.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-left.png
deleted file mode 100644
index b68f4d5944affd7e2695777668f76dad7ee2b6ab..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 426
zcmV;b0agBqP)<h;3K|Lk000e1NJLTq000gE001Be1^@s6BJN3-00009a7bBm000XU
z000XU0RWnu7ytkPTuDShR5;6>)k`bHQ5?qc?=y0ll#n7yN=Z>D3k%AnkSr{exs-)z
zOxgX-*b_B|)x3szK^ET6JQj15(9HS&Po2){)44srb7Y$=O|@E$oP;El%k{?4+wJxr
z@X%;XN_t5J8}<6Mq-WqZ8rJXcXCyU&YhWY_CP^|EP!Sl7+GCO=^FRx@1jeEcN77<I
z7eCP;xE#>=_wr)k3h)k`0wb~axE5wQ28Lq;uz~c3eFO}}CTAO|1snj1jogml4cJSQ
z)qP1#?47hB|FpfHx;m=WYNoo%4l9+)hosFcaMyNIu$va*Zg<;uOK_MLVtdQb3{g`W
zNY`FBv;-#uBlinpdlh&E&iaP@ABgR~wb&10dx_qj|5X1Vi0y@dFM)hC>~uPm%jMaC
z3qSEd2v9DSW^BKNH#Hv(0ZPT<RKPdDSTqDE777!#pMbkm5TI~%HQu!!mGztZ0+l~4
UoZlY3t^fc407*qoM6N<$f`=!zzW@LL

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-right-inactive.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-right-inactive.png
deleted file mode 100644
index c67ec41db010f139e392425211751424baf822e1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 383
zcmV-_0f7FAP)<h;3K|Lk000e1NJLTq000gE001Be1^@s6BJN3-0003-Nkl<Zc-o!P
zyK+GR5XSL+2{U@V-i%hQ*K5<I%1lZOf<YJrAue%=TwcUWU=$RmF}g3`BxjPtIv1z-
zZTD|>SH2dD0Ers_C**TJKTwdwfet@rGmt?c5*s>vpH5-gQ<&re9llK_u-H<B<ctpI
z<1x;xDMn(U!`Wzr3sw{-G3jtR9Kyzm5+tO<*TDb|Hk2eCj{AMM*wT#(hrJ#=*wO7t
zIOulakwJHV;Y+83D;(+mC+xM`@F6PCtrmP(N~hU`AJT3#;KNd$>UH=Km1eDmD;()}
ztBq<E9vSq1$9km#4|a6=Ikj>bF1Dn9^|4ffgAFA~R9Gn%VPi!J64GJ0P{0K%ij$ah
zSjy*dW=$~?3mq17Iaq8dLUKljg=`k4J%vdw(BVTS12QN?Vnc_yboxL+5(hfWrcwbC
d7dqtd<r`xSklfUZvS|PS002ovPDHLkV1l+#oMQk0

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-right.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-right.png
deleted file mode 100644
index 6bb63b25d53c4daf0accac146da035bcf3a5bfe3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 414
zcmV;P0b%}$P)<h;3K|Lk000e1NJLTq000gE001Be1^@s6BJN3-0004HNkl<Zc-ocK
zy>7xV6o%n*6P3Dm?_P<ub0_`+#33QXBq98j35i?eCIZR;Ll(q#`e7kN!AYFqO(fgT
z=wtd_t=^cK%8J5}!pVdtQc@5EG#-!X3eT(M^1U_$Vw5iyi;r3mfN!1V^ZBPS#9@9Y
zo6TllMi2-2sXh9xgh`UHrWE~@!s&F%1*OO;gmD~mNeAR>VH8DNS{!G9$qNj_kgEbZ
zqV<0$B^#ClZthS90UIaf1#qh%KCEjr8fn)7um1-5zR#KzEZPIykp?`c#iTZC=6T+Z
zJlADiIG|m35nzK{$6?ckj&pH`!!00@g9Vd-a<l;?1%(h?l`X{45n>HUcWB!-SCpXy
zkp98JV8A6EkPk>Nu;1@<K`B!AQ44#$9&1XGngE5+vMhdT52R*JDeQJS{7`0fyK2f+
z!cM!*w@!d+t{TC1tHme>RFm8oHk-{epn5y%LiJkJg~gzvKRg(a7G?hSeE<Le07*qo
IM6N<$f+07vCjbBd

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-up-inactive.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-up-inactive.png
deleted file mode 100644
index b9438a7cde2262599573ba932e6bd696c2dd39d8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 338
zcmV-Y0j>UtP)<h;3K|Lk000e1NJLTq001BW000gM1^@s6PTU@{0003QNkl<ZNXNC*
z&q@MO6vy##Owx8DK^P(=YAAuwMnod0MM027=)$0Oy+`EV?1kJ&Pvc{Z--~BpkgLrZ
zr-9E#ulM}UJ=bwP&vO>@xmE+e@Wc}D5%zIhhsT6axWEiofzM7bKwr7nI)LJ-V}cvY
zcX^D^(`=|Yfph8de#e>u#&}kpK!}B9DgGE@Z4pyhn}}lsXBeOp@>CP@n;9OE+-C$u
z>AVA1ak)(ACAqA3IEXTWQ+(kGDedi+5EcC3cH17?0{DNc7aT??9#oYO*R~M00LK`j
zi}aqweKiST-W|zZ0dmrL51E*X+g@O<EkIU^zv3w7;=TsH(cTPTihttmA3EQ3i3wW4
k0H*Vg7-#;Mri`Px0+?Z6_l)5}YybcN07*qoM6N<$g5|50!~g&Q

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-up.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-editor-up.png
deleted file mode 100644
index 24022ca2737de22d40d08d7e098e0b2ca569f3ac..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 387
zcmV-}0et?6P)<h;3K|Lk000e1NJLTq001BW000gM1^@s6PTU@{0003>Nkl<Zc-p<w
zPe%lC9LMorZ9RaMhz=1EiH_+INkkG|I&|qt%%9)PZ)P7vBpnhRBBE2LE?w#p5mAbW
z^a$F`(tLZ*Sjmpj&hE?}UWS?P@ALiGolzp9YGIhy9IhZOAJ~D)D=A>xwsIUtxvs0U
z*2;tLdCK>FWsFflEC>>{AeiOgC8W(ew!>r&oG~CH&Pp;h*b(nac3PH|uK?jQxPWAM
z!&X@Zrg0AW$166AE--~NNCzUkV1u&*MHHCCDZU{citvneGAg|knDC7`K@*ZwgeNlA
z$QtUVz&MAGxqd;qMaCo7RWgUO3ZyVR#-Sr$>jtD(WId3%qAAg~D_wx0QHBpuhZN|Z
z>}7s|N@f8bjxcn9Pe=*w*s;W4FqkU9%_<M~QHPZ1mR*ajy}vJEm7BY0K>FZ@oeO^p
h?4b$iqieo``5%)HqVwVp^`HO%002ovPDHLkV1n2#sHp$|

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-close.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-close.png
deleted file mode 100644
index 6c52209da40c99c38e52e968d2d4f93a84a53ebb..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 165
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPGa3-AeX)z{aTk&$WcTM!bF`0wAp
z_wT=4xqjc;-hJo3Q}-V|+uR+wAE?sF)5S4_BRV-jgoT-rO;OdrAVr{vky+uesR+lR
z0Evfd1(zncxwuwqyR6!)Br=t8dXx4sgY+mV4hG3%2?-|{irE-0FH)$zEM##DXc~j3
LtDnm{r-UW|ZY4Er

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-help.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-help.png
deleted file mode 100644
index b5b79e078af7c7d12ecdf61b0806675c23f6627d..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 194
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!aez;VtG>Rzr>Ez`M=xb$WZu93
z5)zSk<@)`Iq{`;L1%8o5|Ni~E|LED)okyq4T2)Zd>l;y6-8}86k>CoTb}vsC$B>G+
z+VhcI2Mjn|FWQ(oKYv%hb*h7}%7eeB9hsLM(W^BV*M75Dxm;lN9|!4xOr|+SjLchD
r^Y%OO-}@P?J+EUygzTp7>7VWIZDLi;<T5k@n#$nm>gTe~DWM4f!PQAb

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-save.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-layer-icon-save.png
deleted file mode 100644
index af37bcda998fc3d9782fcc69c83ee68d00a807f2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 174
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Vt`MGtEZ=@zP`SUj7&&G;{SGr
z=Dr30{{4IK`1!$O=Rbb_YHDfY_uPmPsMy2P#WAGf*4FceVhsiyE(Z^ACB3UpFyD2|
zWSXDUCwbnrGxc-+Z1hbiWC^nPCHqav|Kal9hL%IGi<yt7a^9Rg&*5sf!@Ae%){Lf6
WEG8KTlRANBGI+ZBxvX<aXaWG>>pv3!

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tabledown.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tabledown.png
deleted file mode 100644
index 674e479fba7d440d6b1aff3d51515ca16441be78..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 236
zcmV<I02BX-P)<h;3K|Lk000e1NJLTq000pH000OG1^@s6AG8#y00029Nkl<Zc-ocB
zxedZV5J1rpc1R6NOe?<ksDYLM$F$;r$b>k866j$0gJj9FYyrX3NIN@ULI?*uG2s5E
z2aXcF-+JdRh)cSz)468w-tUEyIOjIj+7@w+h|VRwv(^xiPlTfInACOMA}T$e8+YiN
zrZGfh9ubyFS(Yv0h+~~oeN|P4h^$3~PiavUXGCa3=cs3Ih{(5y@Hx%%yhWV2!RY?i
mh;Wc*S$4t;SM2nCDe?xsD%F^`NucBa0000<MNUMnLSTZckY^kK

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableleft.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableleft.png
deleted file mode 100644
index 763d37023f93bf93285e3185369cd8d57080d117..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 207
zcmV;=05JcFP)<h;3K|Lk000e1NJLTq000L7000jN1^@s6C;`>J0001%Nkl<ZD9?4v
zF%H5o5Jb_x>mzX)%1Bn?f|d>>D4^j0kTM72GLaD7t|=m{keKO4Z$?r|1XVNyR25a7
zy6RE>;1$@{@C=-Q*Al+~FwSufKe&W~2jIdwqqJ@N1U3Lo(-awoVU!qSN6vR3te!DO
z+^oy692CUdy9^Hjtsy=QdI6~+Zk96iz`KUH*)GGaj_#QI_5-Bva^4dZF0}vv002ov
JPDHLkV1k|#PtgDX

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableright.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableright.png
deleted file mode 100644
index e425e73921f961b8a6ce7a1780c741c684c933f1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 258
zcmV+d0sa1oP)<h;3K|Lk000e1NJLTq000L7000jN1^@s6C;`>J0002VNkl<ZD9>$B
zOAdlS3~dJzJr7qAjo<;;xG}`Lu)wg>oeSX#Z1F6v4AHi>WTHT9^71<K`p09Q7sR|*
zyqOsW5P`nIkw^vr7X`x191%S<AXfi87eg!KZL1K)&htbxOFRz&&YBz2GzIS`zJ&{E
zlu6ST0k&-`^FgYr8aM!v!@cX4Q53<cEJ1z!k{%FO|H}3baidG$zS9;(F$jpb)~tHI
ziV3lz`5l31q5QH841#8QKIW$|+vv3hz!+9G6U3|70YoO^2M^hP=PW`Z<p2Nx07*qo
IM6N<$f{Z?ACIA2c

diff --git a/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableup.png b/typo3/sysext/backend/Resources/Public/Images/BackendLayoutWizard/t3grid-tableup.png
deleted file mode 100644
index 056cf582669b4ddceeb926fe4b76e03d978a1d37..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 219
zcmV<103`p3P)<h;3K|Lk000e1NJLTq000pH000OG1^@s6AG8#y0001@Nkl<Zc-o!J
zy$!-J5J2G*Ny!YRW|jQdiR~F!32@CSDX2_IsxSf@m?xx25h6e+zQVq{C(b#sZ7WUF
zh}K%_x|Xsmr6`IG&bZ^iUtU$!b8d{0mK$rWc<$#S3Kyh_KqUV)qF9bdZycHD-y({o
zi1a}qlFdaF!-zEMx()#EsX!!qjVL}N(gK0VYK&~1wLQ`wPDIw?z29TNb)g<N>>i$2
V%{dWF=(qp?002ovPDHLkV1g!lSXTf5

diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js b/typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js
new file mode 100644
index 000000000000..37783910f3e2
--- /dev/null
+++ b/typo3/sysext/backend/Resources/Public/JavaScript/GridEditor.js
@@ -0,0 +1,640 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Backend/GridEditor
+ */
+define(['jquery', 'TYPO3/CMS/Backend/Modal', 'TYPO3/CMS/Backend/Severity', 'bootstrap'], function($, Modal, Severity) {
+	'use strict';
+
+	/**
+	 * The main ContextHelp object
+	 *
+	 * @type {{colCount: number, rowCount: number, data: {}, nameLabel: string, columnLabel: string, targetElement: null}}
+	 * @exports TYPO3/CMS/Backend/GridEditor
+	 */
+	var GridEditor = {
+		selectorEditor: '.t3js-grideditor',
+		selectorAddColumn: '.t3js-grideditor-addcolumn',
+		selectorRemoveColumn: '.t3js-grideditor-removecolumn',
+		selectorAddRow: '.t3js-grideditor-addrow',
+		selectorRemoveRow: '.t3js-grideditor-removerow',
+		selectorLinkEditor: '.t3js-grideditor-link-editor',
+		selectorLinkExpandRight: '.t3js-grideditor-link-expand-right',
+		selectorLinkShrinkLeft: '.t3js-grideditor-link-shrink-left',
+		selectorLinkExpandDown: '.t3js-grideditor-link-expand-down',
+		selectorLinkShrinkUp: '.t3js-grideditor-link-shrink-up',
+		selectorDocHeaderSave: '.t3js-grideditor-savedok',
+		selectorDocHeaderSaveClose: '.t3js-grideditor-savedokclose',
+		colCount: 1,
+		rowCount: 1,
+		data: [],
+		nameLabel: 'name',
+		columnLabel: 'columen label',
+		targetElement: null
+	};
+
+	/**
+	 *
+	 * @param {Object} config
+	 */
+	GridEditor.initialize = function(config) {
+		config = config || {};
+		var $element = $(GridEditor.selectorEditor);
+		GridEditor.colCount = $element.data('colcount');
+		GridEditor.rowCount = $element.data('rowcount');
+		GridEditor.data = $element.data('data');
+		GridEditor.nameLabel = config.nameLabel || 'Name';
+		GridEditor.columnLabel = config.columnLabel || 'Column';
+		GridEditor.targetElement = $(GridEditor.selectorEditor);
+
+		$(document).on('click', GridEditor.selectorDocHeaderSave, function(e) {
+			e.preventDefault();
+			storeData(GridEditor.export2LayoutRecord());
+		});
+		$(document).on('click', GridEditor.selectorDocHeaderSaveClose, function(e) {
+			e.preventDefault();
+			storeData(GridEditor.export2LayoutRecord());
+			window.close();
+		});
+		$(document).on('click', GridEditor.selectorAddColumn, function(e) {
+			e.preventDefault();
+			GridEditor.addColumn();
+			GridEditor.drawTable();
+		});
+		$(document).on('click', GridEditor.selectorRemoveColumn, function(e) {
+			e.preventDefault();
+			GridEditor.removeColumn();
+			GridEditor.drawTable();
+		});
+		$(document).on('click', GridEditor.selectorAddRow, function(e) {
+			e.preventDefault();
+			GridEditor.addRow();
+			GridEditor.drawTable();
+		});
+		$(document).on('click', GridEditor.selectorRemoveRow, function(e) {
+			e.preventDefault();
+			GridEditor.removeRow();
+			GridEditor.drawTable();
+		});
+		$(document).on('click', GridEditor.selectorLinkEditor, function(e) {
+			e.preventDefault();
+			var $element = $(this);
+			var col = $element.data('col');
+			var row = $element.data('row');
+			GridEditor.showOptions(col, row);
+		});
+		$(document).on('click', GridEditor.selectorLinkExpandRight, function(e) {
+			e.preventDefault();
+			var $element = $(this);
+			var col = $element.data('col');
+			var row = $element.data('row');
+			GridEditor.addColspan(col, row);
+			GridEditor.drawTable();
+		});
+		$(document).on('click', GridEditor.selectorLinkShrinkLeft, function(e) {
+			e.preventDefault();
+			var $element = $(this);
+			var col = $element.data('col');
+			var row = $element.data('row');
+			GridEditor.removeColspan(col, row);
+			GridEditor.drawTable();
+		});
+		$(document).on('click', GridEditor.selectorLinkExpandDown, function(e) {
+			e.preventDefault();
+			var $element = $(this);
+			var col = $element.data('col');
+			var row = $element.data('row');
+			GridEditor.addRowspan(col, row);
+			GridEditor.drawTable();
+		});
+		$(document).on('click', GridEditor.selectorLinkShrinkUp, function(e) {
+			e.preventDefault();
+			var $element = $(this);
+			var col = $element.data('col');
+			var row = $element.data('row');
+			GridEditor.removeRowspan(col, row);
+			GridEditor.drawTable();
+		});
+
+		GridEditor.drawTable();
+	};
+
+	/**
+	 * Add a new row
+	 */
+	GridEditor.addRow = function() {
+		var newRow = [];
+		for (var i = 0; i < GridEditor.colCount; i++) {
+			newRow[i] = {spanned: false, rowspan: 1, colspan: 1};
+		}
+		GridEditor.data.push(newRow);
+		GridEditor.rowCount++;
+	};
+
+	/**
+	 * Removes the last row of the grid and adjusts all cells that might be effected
+	 * by that change. (Removing colspans)
+	 */
+	GridEditor.removeRow = function() {
+		if (GridEditor.rowCount <= 1) {
+			return false;
+		}
+		var newData = [];
+		for (var rowIndex = 0; rowIndex < GridEditor.rowCount - 1; rowIndex++) {
+			newData.push(GridEditor.data[rowIndex]);
+		}
+
+		// fix rowspan in former last row
+		for (var colIndex = 0; colIndex < GridEditor.colCount; colIndex++) {
+			if (GridEditor.data[GridEditor.rowCount - 1][colIndex].spanned == true) {
+				GridEditor.findUpperCellWidthRowspanAndDecreaseByOne(colIndex, GridEditor.rowCount - 1);
+			}
+		}
+
+		GridEditor.data = newData;
+		GridEditor.rowCount--;
+	};
+
+	/**
+	 * Takes a cell and looks above it if there are any cells that have colspans that
+	 * spans into the given cell. This is used when a row was removed from the grid
+	 * to make sure that no cell with wrong colspans exists in the grid.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row integer
+	 */
+	GridEditor.findUpperCellWidthRowspanAndDecreaseByOne = function(col, row) {
+		var upperCell = GridEditor.getCell(col, row - 1);
+		if (!upperCell) {
+			return false;
+		}
+
+		if (upperCell.spanned == true) {
+			GridEditor.findUpperCellWidthRowspanAndDecreaseByOne(col, row - 1);
+		} else {
+			if (upperCell.rowspan > 1) {
+				GridEditor.removeRowspan(col, row - 1);
+			}
+		}
+	};
+
+	/**
+	 * Removes the outermost right column from the grid.
+	 */
+	GridEditor.removeColumn = function() {
+		if (GridEditor.colCount <= 1) {
+			return false;
+		}
+		var newData = [];
+
+		for (var rowIndex = 0; rowIndex < GridEditor.rowCount; rowIndex++) {
+			var newRow = [];
+			for (var colIndex = 0; colIndex < GridEditor.colCount - 1; colIndex++) {
+				newRow.push(GridEditor.data[rowIndex][colIndex]);
+			}
+			if (GridEditor.data[rowIndex][GridEditor.colCount - 1].spanned == true) {
+				GridEditor.findLeftCellWidthColspanAndDecreaseByOne(GridEditor.colCount - 1, rowIndex);
+			}
+			newData.push(newRow);
+		}
+
+		GridEditor.data = newData;
+		GridEditor.colCount--;
+	};
+
+	/**
+	 * Checks if there are any cells on the left side of a given cell with a
+	 * rowspan that spans over the given cell.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 */
+	GridEditor.findLeftCellWidthColspanAndDecreaseByOne = function(col, row) {
+		var leftCell = GridEditor.getCell(col - 1, row);
+		if (!leftCell) {
+			return false;
+		}
+
+		if (leftCell.spanned == true) {
+			GridEditor.findLeftCellWidthColspanAndDecreaseByOne(col - 1, row);
+		} else {
+			if (leftCell.colspan > 1) {
+				GridEditor.removeColspan(col - 1, row);
+			}
+		}
+	};
+
+	/**
+	 * Adds a column at the right side of the grid.
+	 */
+	GridEditor.addColumn = function() {
+		for (var rowIndex = 0; rowIndex < GridEditor.rowCount; rowIndex++) {
+			GridEditor.data[rowIndex].push({
+				spanned: false,
+				rowspan: 1,
+				colspan: 1,
+				name: GridEditor.colCount + 'x' + rowIndex
+			});
+		}
+		GridEditor.colCount++;
+	};
+
+	/**
+	 * Draws the grid as table into a given container.
+	 * It also adds all needed links and bindings to the cells to make it editable.
+	 */
+	GridEditor.drawTable = function() {
+		var col;
+		var $colgroup = $('<colgroup>');
+		for (col = 0; col < GridEditor.colCount; col++) {
+			$colgroup.append($('<col>').css({
+				width: parseInt(100 / GridEditor.colCount, 10) + '%'
+			}));
+		}
+		var $table = $('<table id="base" class="table editor">');
+		$table.append($colgroup);
+
+		for (var row = 0; row < GridEditor.rowCount; row++) {
+			var rowData = GridEditor.data[row];
+			if (rowData.length == 0) {
+				continue;
+			}
+
+			var $row = $('<tr>');
+
+			for (col = 0; col < GridEditor.colCount; col++) {
+				var cell = GridEditor.data[row][col];
+				if (cell.spanned == true) {
+					continue;
+				}
+				var $cell = $('<td>').css({
+					height: parseInt(100 / GridEditor.rowCount, 10) * cell.rowspan + '%',
+					width: parseInt(100 / GridEditor.colCount, 10) * cell.colspan + '%'
+				});
+				var $container = $('<div class="cell_container">');
+				$cell.append($container);
+				var dataString = ' data-col="' + col + '" data-row="' + row + '"';
+				$container.append($('<a class="t3js-grideditor-link-editor link link_editor" title="' + TYPO3.lang['editCell'] + '" ' + dataString + '  href="#"><!-- --></a>'));
+				if (GridEditor.cellCanSpanRight(col, row)) {
+					$container.append($('<a class="t3js-grideditor-link-expand-right link link_expand_right" href="#"  title="' + TYPO3.lang['mergeCell'] + '" ' + dataString + '><!-- --></a>'));
+				}
+				if (GridEditor.cellCanShrinkLeft(col, row)) {
+					$container.append('<a class="t3js-grideditor-link-shrink-left link link_shrink_left" href="#" title="' + TYPO3.lang['splitCell'] + '" ' + dataString + '><!-- --></a>');
+				}
+				if (GridEditor.cellCanSpanDown(col, row)) {
+					$container.append('<a class="t3js-grideditor-link-expand-down link link_expand_down" href="#" title="' + TYPO3.lang['mergeCell'] + '" ' + dataString + '><!-- --></a>');
+				}
+				if (GridEditor.cellCanShrinkUp(col, row)) {
+					$container.append('<a class="t3js-grideditor-link-shrink-up link link_shrink_up" href="#" title="' + TYPO3.lang['splitCell'] + '" ' + dataString + '><!-- --></a>');
+				}
+				$cell.append('<div class="cell_data">' + TYPO3.lang['name'] + ': ' + (cell.name ? GridEditor.stripMarkup(cell.name) : TYPO3.lang['notSet'])
+					+ '<br />' + TYPO3.lang['column'] + ': '
+					+ (cell.column === undefined ? TYPO3.lang['notSet'] : parseInt(cell.column, 10)) + '</div>');
+
+				if (cell.colspan > 1) {
+					$cell.attr('colspan', cell.colspan);
+				}
+				if (cell.rowspan > 1) {
+					$cell.attr('rowspan', cell.rowspan);
+				}
+				$row.append($cell);
+			}
+			$table.append($row);
+		}
+		$(GridEditor.targetElement).empty().append($table);
+	};
+
+	/**
+	 * Sets the name of a certain grid element.
+	 *
+	 * @param {String} newName
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 *
+	 * @returns {Boolean}
+	 */
+	GridEditor.setName = function(newName, col, row) {
+		var cell = GridEditor.getCell(col, row);
+		if (!cell) return false;
+		cell.name = GridEditor.stripMarkup(newName);
+		return true;
+	};
+
+	/**
+	 * Sets the column field for a certain grid element. This is NOT the column of the
+	 * element itself.
+	 *
+	 * @param {Integer} newColumn
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 *
+	 * @returns {Boolean}
+	 */
+	GridEditor.setColumn = function(newColumn, col, row) {
+		var cell = GridEditor.getCell(col, row);
+		if (!cell) {
+			return false;
+		}
+		cell.column = GridEditor.stripMarkup(newColumn);
+		return true;
+	};
+
+	/**
+	 * Creates an ExtJs Window with two input fields and shows it. On save, the data
+	 * is written into the grid element.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 *
+	 * @returns {Boolean}
+     */
+	GridEditor.showOptions = function(col, row) {
+		var cell = GridEditor.getCell(col, row);
+		if (!cell) {
+			return false;
+		}
+
+		var $markup = $('<div>');
+		$markup.append(
+			'<div>' +
+				'<div class="form-group">' +
+					'<label>' + TYPO3.lang['nameHelp'] + '</label>' +
+					'<input type="text" class="t3js-grideditor-field-name form-control" name="name" value="' + (GridEditor.stripMarkup(cell.name) || '') + '">' +
+				'</div>' +
+				'<div class="form-group">' +
+					'<label>' + TYPO3.lang['columnHelp'] + '</label>' +
+					'<input type="text" class="t3js-grideditor-field-colpos form-control" name="name" value="' + (parseInt(cell.column, 10) || '') + '">' +
+				'</div>' +
+			'</div>'
+		);
+		var $modal = Modal.show(TYPO3.lang['title'], $markup, Severity.notice, [
+			{
+				text: $(this).data('button-close-text') || TYPO3.lang['button.cancel'] || 'Cancel',
+				active: true,
+				btnClass: 'btn-default',
+				name: 'cancel'
+			},
+			{
+				text: $(this).data('button-ok-text') || TYPO3.lang['button.ok'] || 'OK',
+				btnClass: 'btn-' + Modal.getSeverityClass(Severity.notice),
+				name: 'ok'
+			}
+		]);
+		$modal.data('col', col);
+		$modal.data('row', row);
+		$modal.on('button.clicked', function(e) {
+			if (e.target.name === 'cancel') {
+				$(this).trigger('modal-dismiss');
+			} else if (e.target.name === 'ok') {
+				GridEditor.setName($modal.find('.t3js-grideditor-field-name').val(), $modal.data('col'), $modal.data('row'));
+				GridEditor.setColumn($modal.find('.t3js-grideditor-field-colpos').val(), $modal.data('col'), $modal.data('row'));
+				GridEditor.drawTable();
+				$(this).trigger('modal-dismiss');
+			}
+		});
+	};
+
+	/**
+	 * Returns a cell element from the grid.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Object}
+	 */
+	GridEditor.getCell = function(col, row) {
+		if (col > GridEditor.colCount - 1) {
+			return false;
+		}
+		if (row > GridEditor.rowCount - 1) {
+			return false;
+		}
+		return GridEditor.data[row][col];
+	};
+
+	/**
+	 * Checks whether a cell can span to the right or not. A cell can span to the right
+	 * if it is not in the last column and if there is no cell beside it that is
+	 * already overspanned by some other cell.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.cellCanSpanRight = function(col, row) {
+		if (col == GridEditor.colCount - 1) {
+			return false;
+		}
+
+		var cell = GridEditor.getCell(col, row);
+		var checkCell;
+		if (cell.rowspan > 1) {
+			for (var rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
+				checkCell = GridEditor.getCell(col + cell.colspan, rowIndex);
+				if (!checkCell || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
+					return false;
+				}
+			}
+		} else {
+			checkCell = GridEditor.getCell(col + cell.colspan, row);
+			if (!checkCell || cell.spanned == true || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
+				return false;
+			}
+		}
+
+		return true;
+	};
+
+	/**
+	 * Checks whether a cell can span down or not.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.cellCanSpanDown = function(col, row) {
+		if (row == GridEditor.rowCount - 1) {
+			return false;
+		}
+
+		var cell = GridEditor.getCell(col, row);
+		var checkCell;
+		if (cell.colspan > 1) {
+			// we have to check all cells on the right side for the complete colspan
+			for (var colIndex = col; colIndex < col + cell.colspan; colIndex++) {
+				checkCell = GridEditor.getCell(colIndex, row + cell.rowspan);
+				if (!checkCell || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
+					return false;
+				}
+			}
+		} else {
+			checkCell = GridEditor.getCell(col, row + cell.rowspan);
+			if (!checkCell || cell.spanned == true || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
+				return false;
+			}
+		}
+
+		return true;
+	};
+
+	/**
+	 * Checks if a cell can shrink to the left. It can shrink if the colspan of the
+	 * cell is bigger than 1.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.cellCanShrinkLeft = function(col, row) {
+		return (GridEditor.data[row][col].colspan > 1);
+	};
+
+	/**
+	 * Returns if a cell can shrink up. This is the case if a cell has at least
+	 * a rowspan of 2.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.cellCanShrinkUp = function(col, row) {
+		return (GridEditor.data[row][col].rowspan > 1);
+	};
+
+	/**
+	 * Adds a colspan to a grid element.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.addColspan = function(col, row) {
+		var cell = GridEditor.getCell(col, row);
+		if (!cell || !GridEditor.cellCanSpanRight(col, row)) {
+			return false;
+		}
+
+		for (var rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
+			GridEditor.data[rowIndex][col + cell.colspan].spanned = true;
+		}
+		cell.colspan += 1;
+	};
+
+	/**
+	 * Adds a rowspan to grid element.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.addRowspan = function(col, row) {
+		var cell = GridEditor.getCell(col, row);
+		if (!cell || !GridEditor.cellCanSpanDown(col, row)) {
+			return false;
+		}
+
+		for (var colIndex = col; colIndex < col + cell.colspan; colIndex++) {
+			GridEditor.data[row + cell.rowspan][colIndex].spanned = true;
+		}
+		cell.rowspan += 1;
+	};
+
+	/**
+	 * Removes a colspan from a grid element.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.removeColspan = function(col, row) {
+		var cell = GridEditor.getCell(col, row);
+		if (!cell || !GridEditor.cellCanShrinkLeft(col, row)) {
+			return false;
+		}
+
+		cell.colspan -= 1;
+		for (var rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
+			GridEditor.data[rowIndex][col + cell.colspan].spanned = false;
+		}
+	};
+
+	/**
+	 * Removes a rowspan from a grid element.
+	 *
+	 * @param {Integer} col
+	 * @param {Integer} row
+	 * @returns {Boolean}
+	 */
+	GridEditor.removeRowspan = function(col, row) {
+		var cell = GridEditor.getCell(col, row);
+		if (!cell || !GridEditor.cellCanShrinkUp(col, row)) {
+			return false;
+		}
+
+		cell.rowspan -= 1;
+		for (var colIndex = col; colIndex < col + cell.colspan; colIndex++) {
+			GridEditor.data[row + cell.rowspan][colIndex].spanned = false;
+		}
+	};
+
+	/**
+	 * Exports the current grid to a TypoScript notation that can be read by the
+	 * page module and is human readable.
+	 *
+	 * @returns {String}
+     */
+	GridEditor.export2LayoutRecord = function() {
+		var result = "backend_layout {\n\tcolCount = " + GridEditor.colCount + "\n\trowCount = " + GridEditor.rowCount + "\n\trows {\n";
+		for (var row = 0; row < GridEditor.rowCount; row++) {
+			result += "\t\t" + (row + 1) + " {\n";
+			result += "\t\t\tcolumns {\n";
+			var colIndex = 0;
+			for (var col = 0; col < GridEditor.colCount; col++) {
+				var cell = GridEditor.getCell(col, row);
+				if (cell && !cell.spanned) {
+					colIndex++;
+					result += "\t\t\t\t" + (colIndex) + " {\n";
+					result += "\t\t\t\t\tname = " + ((!cell.name) ? col + "x" + row : cell.name) + "\n";
+					if (cell.colspan > 1) {
+						result += "\t\t\t\t\tcolspan = " + cell.colspan + "\n";
+					}
+					if (cell.rowspan > 1) {
+						result += "\t\t\t\t\trowspan = " + cell.rowspan + "\n";
+					}
+					if (typeof(cell.column) === 'number') {
+						result += "\t\t\t\t\tcolPos = " + cell.column + "\n";
+					}
+					result += "\t\t\t\t}\n";
+				}
+
+			}
+			result += "\t\t\t}\n";
+			result += "\t\t}\n";
+		}
+
+		result += "\t}\n}\n";
+		return result;
+	};
+
+	/**
+	 *
+	 * @param {String} input
+	 * @returns {*|jQuery}
+	 */
+	GridEditor.stripMarkup = function(input) {
+		return $('<p>' + input + '</p>').text();
+	};
+
+	GridEditor.initialize();
+	return GridEditor;
+});
diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/grideditor.js b/typo3/sysext/backend/Resources/Public/JavaScript/grideditor.js
deleted file mode 100644
index 79c8c3d2d715..000000000000
--- a/typo3/sysext/backend/Resources/Public/JavaScript/grideditor.js
+++ /dev/null
@@ -1,635 +0,0 @@
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * A JavaScript object to handle, edit, draw and export a grid. The grid is basically
- * a table with some colspan and rowspan. Each cell can additionally hold a name and
- * column.
- */
-Ext.namespace('TYPO3.Backend.t3Grid');
-
-TYPO3.Backend.t3Grid = Ext.extend(Ext.Component, {
-
-	constructor: function(config) {
-
-		config = Ext.apply({
-			colCount: config.colCount,
-			rowCount: config.rowCount,
-			data: config.data,
-			nameLabel: config.nameLabel,
-			columnLabel: config.columnLabel,
-			targetElement: config.targetElement
-		}, config);
-
-		TYPO3.Backend.t3Grid.superclass.constructor.call(this, config);
-	},
-
-	/**
-	 * Adds a row below the grid
-	 */
-	addRow: function() {
-		var newRow = [];
-		for (var i = 0; i < this.colCount; i++) {
-			newRow[i] = {spanned:false,rowspan:1,colspan:1};
-		}
-		this.data.push(newRow);
-		this.rowCount++;
-	},
-
-	/**
-	 * Removes the last row of the grid and adjusts all cells that might be effected
-	 * by that change. (Removing colspans)
-	 *
-	 * @returns void
-	 */
-	removeRow: function() {
-		if (this.rowCount <= 1) return false;
-		var newData = [];
-		for (var rowIndex = 0; rowIndex < this.rowCount - 1; rowIndex++) {
-			newData.push(this.data[rowIndex]);
-		}
-
-		// fix rowspan in former last row
-		for (var colIndex = 0; colIndex < this.colCount; colIndex++) {
-			if (this.data[this.rowCount - 1][colIndex].spanned == true) {
-				this.findUpperCellWidthRowspanAndDecreaseByOne(colIndex, this.rowCount - 1);
-			}
-		}
-
-		this.data = newData;
-		this.rowCount--;
-	},
-
-	/**
-	 * Takes a cell and looks above it if there are any cells that have colspans that
-	 * spans into the given cell. This is used when a row was removed from the grid
-	 * to make sure that no cell with wrong colspans exists in the grid.
-	 *
-	 * @param col integer
-	 * @param row integer
-	 * @return void
-	 */
-	findUpperCellWidthRowspanAndDecreaseByOne: function(col, row) {
-		var upperCell = this.getCell(col, row - 1);
-		if (!upperCell) return false;
-
-		if (upperCell.spanned == true) {
-			this.findUpperCellWidthRowspanAndDecreaseByOne(col, row - 1);
-		} else {
-			if (upperCell.rowspan > 1) {
-				this.removeRowspan(col, row - 1);
-			}
-		}
-	},
-
-	/**
-	 * Removes the outermost right column from the grid.
-	 *
-	 * @return void
-	 */
-	removeColumn: function() {
-		if (this.colCount <= 1) return false;
-		var newData = [];
-
-		for (var rowIndex = 0; rowIndex < this.rowCount; rowIndex++) {
-			var newRow = [];
-			for (colIndex = 0; colIndex < this.colCount - 1; colIndex++) {
-				newRow.push(this.data[rowIndex][colIndex]);
-			}
-			if (this.data[rowIndex][this.colCount - 1].spanned == true) {
-				this.findLeftCellWidthColspanAndDecreaseByOne(this.colCount - 1, rowIndex);
-			}
-			newData.push(newRow);
-		}
-
-		this.data = newData;
-		this.colCount--;
-	},
-
-	/**
-	 * Checks if there are any cells on the left side of a given cell with a
-	 * rowspan that spans over the given cell.
-	 *
-	 * @param col integer
-	 * @param row integer
-	 * @return void
-	 */
-	findLeftCellWidthColspanAndDecreaseByOne: function(col, row) {
-		var leftCell = this.getCell(col - 1, row);
-		if (!leftCell) return false;
-
-		if (leftCell.spanned == true) {
-			this.findLeftCellWidthColspanAndDecreaseByOne(col - 1, row);
-		} else {
-			if (leftCell.colspan > 1) {
-				this.removeColspan(col - 1, row);
-			}
-		}
-	},
-
-	/**
-	 * Adds a column at the right side of the grid.
-	 *
-	 * @return void
-	 */
-	addColumn: function() {
-		for (var rowIndex = 0; rowIndex < this.rowCount; rowIndex++) {
-			this.data[rowIndex].push({
-				spanned: false,
-				rowspan: 1,
-				colspan: 1,
-				name: this.colCount + 'x' + rowIndex
-			});
-		}
-		this.colCount++;
-	},
-
-	/**
-	 * Draws the grid as table into a given container.
-	 * It also adds all needed links and bindings to the cells to make it editable.
-	 *
-	 * @return void
-	 */
-	drawTable: function() {
-		var domHelper = Ext.DomHelper;
-		var newTable = {
-			tag: 'table',
-			children: [],
-			id: 'base',
-			border: '0',
-			width: '100%',
-			height: '100%',
-			cls: 'editor',
-			cellspacing: '0',
-			cellpadding: '0'
-		};
-
-		var colgroups = {
-			tag: 'colgroup',
-			children: []
-		};
-		for (var col = 0; col < this.colCount; col++) {
-			colgroups.children.push({
-				tag: 'col',
-				style: 'width:' + parseInt(100 / this.colCount, 10) + '%'
-			});
-		}
-		newTable.children.push(colgroups);
-
-		for (var row = 0; row < this.rowCount; row++) {
-			var rowData = this.data[row];
-			if (rowData.length == 0) continue;
-
-			var rowSpec = {tag: 'tr', children:[]};
-
-			for (var col = 0; col < this.colCount; col++) {
-				var cell = this.data[row][col];
-				if (cell.spanned == true) {
-					continue;
-				}
-
-				var cellHtml = '<div class="cell_container"><a class="link_editor" id="e_'
-						+ col + '_' + row + '" title="' + TYPO3.l10n.localize('editCell') + '" href="#"><!-- --></a>';
-				if (this.cellCanSpanRight(col, row)) {
-					cellHtml += '<a href="#" id="r_'
-						+ col + '_' + row + '" title="' + TYPO3.l10n.localize('mergeCell') + '" class="link_expand_right"><!-- --></a>';
-				}
-				if (this.cellCanShrinkLeft(col, row)) {
-					cellHtml += '<a href="#" id="l_'
-						+ col + '_' + row + '" title="' + TYPO3.l10n.localize('splitCell') + '" class="link_shrink_left"><!-- --></a>';
-				}
-				if (this.cellCanSpanDown(col, row)) {
-					cellHtml += '<a href="#" id="d_'
-						+ col + '_' + row + '" title="' + TYPO3.l10n.localize('mergeCell') + '" class="link_expand_down"><!-- --></a>';
-				}
-				if (this.cellCanShrinkUp(col, row)) {
-					cellHtml += '<a href="#" id="u_'
-						+ col + '_' + row + '" title="' + TYPO3.l10n.localize('splitCell') + '" class="link_shrink_up"><!-- --></a>';
-				}
-				cellHtml += '</div>';
-
-				cellHtml += '<div class="cell_data">' + TYPO3.l10n.localize('name') + ': ' + (cell.name ? Ext.util.Format.htmlEncode(cell.name) : TYPO3.l10n.localize('notSet'))
-						+ '<br />' + TYPO3.l10n.localize('column') + ': '
-						+ (cell.column === undefined ? TYPO3.l10n.localize('notSet') : parseInt(cell.column, 10)) + '</div>';
-
-				// create cells
-				var child = {
-					tag: 'td',
-					height: parseInt(100 / this.rowCount, 10) * cell.rowspan + '%',
-					width: parseInt(100 / this.colCount, 10) * cell.colspan + '%',
-					html: cellHtml
-				};
-				if (cell.colspan > 1) {
-					child.colspan = cell.colspan;
-				}
-				if (cell.rowspan > 1) {
-					child.rowspan = cell.rowspan;
-				}
-				rowSpec.children.push(child);
-			}
-
-			newTable.children.push(rowSpec);
-
-		}
-
-		domHelper.overwrite(Ext.Element.get(this.targetElement), newTable);
-		this.bindLinks();
-	},
-
-	/**
-	 * Sets the name of a certain grid element.
-	 *
-	 * @param newName string
-	 * @param col integer
-	 * @param row integer
-	 *
-	 * @return boolean
-	 */
-	setName: function(newName, col, row) {
-		var cell = this.getCell(col, row);
-		if (!cell) return false;
-		cell.name = newName;
-		return true;
-	},
-
-	/**
-	 * Sets the column field for a certain grid element. This is NOT the column of the
-	 * element itself.
-	 *
-	 * @param newColumn integer
-	 * @param col integer
-	 * @param row integer
-	 *
-	 * @return boolean
-	 */
-	setColumn: function(newColumn, col, row) {
-		var cell = this.getCell(col, row);
-		if (!cell) return false;
-		cell.column = newColumn;
-		return true;
-	},
-
-	/**
-	 * Searches for all a tags with certain classes and binds some actions to them.
-	 *
-	 * @return void
-	 */
-	bindLinks: function() {
-		for (var row = 0; row < this.rowCount; row++) {
-			for (var col = 0; col < this.colCount; col++) {
-				// span right
-				var el = Ext.Element.get('r_' + col + '_' + row);
-				if (el) {
-					el.addListener('click', function(e, sender, params) {
-						this.addColspan(params.colIndex, params.rowIndex);
-						this.drawTable();
-					}, this, {stopEvent:true, colIndex:col, rowIndex:row});
-				}
-
-				// reduce to left
-				var el = Ext.Element.get('l_' + col + '_' + row);
-				if (el) {
-					el.addListener('click', function(e, sender, params) {
-						this.removeColspan(params.colIndex, params.rowIndex);
-						this.drawTable();
-					}, this, {stopEvent:true, colIndex:col, rowIndex:row});
-				}
-
-				// span down
-				var el = Ext.Element.get('d_' + col + '_' + row);
-				if (el) {
-					el.addListener('click', function(e, sender, params) {
-						this.addRowspan(params.colIndex, params.rowIndex);
-						this.drawTable();
-					}, this, {stopEvent:true, colIndex:col, rowIndex:row});
-				}
-
-				// reduce up
-				var el = Ext.Element.get('u_' + col + '_' + row);
-				if (el) {
-					el.addListener('click', function(e, sender, params) {
-						this.removeRowspan(params.colIndex, params.rowIndex);
-						this.drawTable();
-					}, this, {stopEvent:true, colIndex:col, rowIndex:row});
-				}
-
-				// edit
-				var el = Ext.Element.get('e_' + col + '_' + row);
-				if (el) {
-					el.addListener('click', function(e, sender, params) {
-						this.showOptions(sender, params.colIndex, params.rowIndex);
-					}, this, {stopEvent:true, colIndex:col, rowIndex:row});
-				}
-			}
-		}
-	},
-
-	/**
-	 * Creates an ExtJs Window with two input fields and shows it. On save, the data
-	 * is written into the grid element.
-	 *
-	 * @param sender DOM-object (the link)
-	 * @param col integer
-	 * @param row integer
-	 */
-	showOptions: function(sender, col, row) {
-		var win;
-		sender = Ext.get('base');
-		var cell = this.getCell(col, row);
-		if (!cell) return false;
-
-		if (!win) {
-			var fieldName = new Ext.form.TextField({
-				fieldLabel: TYPO3.l10n.localize('name'),
-				name: 'name',
-				width: 270,
-				value: cell.name,
-				tabIndex: 1,
-				listeners: {
-					render: function(c) {
-						c.getEl().set({
-							'data-toggle': 'tooltip',
-							'data-placement': 'bottom',
-							'data-title': TYPO3.l10n.localize('nameHelp')
-						});
-					},
-					afterrender: function(cmp) {
-						TYPO3.Tooltip.initialize('[data-toggle="tooltip"]');
-					}
-				}
-			});
-
-			var fieldColumn = new Ext.form.NumberField({
-				fieldLabel: TYPO3.l10n.localize('column'),
-				name: 'column',
-				width: 50,
-				value: cell.column,
-				tabIndex: 2,
-				listeners: {
-					render: function(c) {
-						c.getEl().set({
-							'data-toggle': 'tooltip',
-							'data-placement': 'bottom',
-							'data-title': TYPO3.l10n.localize('columnHelp')
-						});
-					},
-					afterrender: function(cmp) {
-						TYPO3.Tooltip.initialize('[data-toggle="tooltip"]');
-					}
-				}
-			});
-
-			win = new Ext.Window({
-				layout: 'fit',
-				title: TYPO3.l10n.localize('title'),
-				width: 400,
-				modal: true,
-				closable: true,
-				resizable: false,
-
-				items: [
-					{
-						xtype: 'fieldset',
-						autoHeight: true,
-						autoWidth: true,
-						labelWidth: 100,
-						border: false,
-
-						items: [fieldName, fieldColumn]
-					}
-				],
-
-				buttons: [
-					{
-						iconCls:'save',
-						text: TYPO3.l10n.localize('save'),
-						handler: function(fieldName, fieldColumn, col, row) {
-							t3Grid.setName(fieldName.getValue(), col, row);
-							t3Grid.setColumn(fieldColumn.getValue(), col, row);
-							win.close();
-							t3Grid.drawTable();
-						}.createDelegate(this, [fieldName, fieldColumn, col, row])
-					}
-				]
-			});
-		}
-		win.show(this);
-	},
-
-	/**
-	 * Returns a cell element from the grid.
-	 *
-	 * @param col integer
-	 * @param row integer
-	 * return Object
-	 */
-	getCell: function(col, row) {
-		if (col > this.colCount - 1) return false;
-		if (row > this.rowCount - 1) return false;
-		return this.data[row][col];
-	},
-
-	/**
-	 * Checks whether a cell can span to the right or not. A cell can span to the right
-	 * if it is not in the last column and if there is no cell beside it that is
-	 * already overspanned by some other cell.
-	 *
-	 * @param col integer
-	 * @param row integer
-	 *
-	 * @return boolean
-	 */
-	cellCanSpanRight: function(col, row) {
-		if (col == this.colCount - 1) {
-			return false;
-		}
-
-		var cell = this.getCell(col, row);
-		if (cell.rowspan > 1) {
-			for (var rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
-				var checkCell = this.getCell(col + cell.colspan, rowIndex);
-				if (!checkCell || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
-					return false;
-				}
-			}
-		} else {
-			var checkCell = this.getCell(col + cell.colspan, row);
-			if (!checkCell || cell.spanned == true || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
-				return false;
-			}
-		}
-
-		return true;
-	},
-
-	/**
-	 * Checks whether a cell can span down or not.
-	 *
-	 * @param col integer
-	 * @param row integer
-	 *
-	 * @return boolean
-	 */
-	cellCanSpanDown: function(col, row) {
-		if (row == this.rowCount - 1) {
-			return false;
-		}
-
-		var cell = this.getCell(col, row);
-		if (cell.colspan > 1) {
-			// we have to check all cells on the right side for the complete colspan
-			for (var colIndex = col; colIndex < col + cell.colspan; colIndex++) {
-				var checkCell = this.getCell(colIndex, row + cell.rowspan);
-				if (!checkCell || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
-					return false;
-				}
-			}
-		} else {
-			var checkCell = this.getCell(col, row + cell.rowspan);
-			if (!checkCell || cell.spanned == true || checkCell.spanned == true || checkCell.colspan > 1 || checkCell.rowspan > 1) {
-				return false;
-			}
-		}
-
-		return true;
-	},
-
-	/**
-	 * Checks if a cell can shrink to the left. It can shrink if the colspan of the
-	 * cell is bigger than 1.
-	 *
-	 * @param col integr
-	 * @param row integer
-	 *
-	 * @return boolean
-	 */
-	cellCanShrinkLeft: function(col, row) {
-		return (this.data[row][col].colspan > 1);
-	},
-
-	/**
-	 * Returns if a cell can shrink up. This is the case if a cell has at least
-	 * a rowspan of 2.
-	 *
-	 * @param col integr
-	 * @param row integer
-	 *
-	 * @return boolean
-	 */
-	cellCanShrinkUp: function(col, row) {
-		return (this.data[row][col].rowspan > 1);
-	},
-
-	/**
-	 * Adds a colspan to a grid element.
-	 *
-	 * @param col integr
-	 * @param row integer
-	 */
-	addColspan: function(col, row) {
-		var cell = this.getCell(col, row);
-		if (!cell || !this.cellCanSpanRight(col, row)) return false;
-
-		for (var rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
-			this.data[rowIndex][col + cell.colspan].spanned = true;
-		}
-		cell.colspan += 1;
-	},
-
-	/**
-	 * Adds a rowspan to grid element.
-	 *
-	 * @param col integr
-	 * @param row integer
-	 *
-	 * @return void
-	 */
-	addRowspan: function(col, row) {
-		var cell = this.getCell(col, row);
-		if (!cell || !this.cellCanSpanDown(col, row)) return false;
-
-		for (var colIndex = col; colIndex < col + cell.colspan; colIndex++) {
-			this.data[row + cell.rowspan][colIndex].spanned = true;
-		}
-		cell.rowspan += 1;
-	},
-
-	/**
-	 * Removes a colspan from a grid element.
-	 *
-	 * @param col integr
-	 * @param row integer
-	 *
-	 * @return void
-	 */
-	removeColspan: function(col, row) {
-		var cell = this.getCell(col, row);
-		if (!cell || !this.cellCanShrinkLeft(col, row)) return false;
-
-		cell.colspan -= 1;
-		for (var rowIndex = row; rowIndex < row + cell.rowspan; rowIndex++) {
-			this.data[rowIndex][col + cell.colspan].spanned = false;
-		}
-	},
-
-	/**
-	 * Removes a rowspan from a grid element.
-	 *
-	 * @param col integr
-	 * @param row integer
-	 *
-	 * @return void
-	 */
-	removeRowspan: function(col, row) {
-		var cell = this.getCell(col, row);
-		if (!cell || !this.cellCanShrinkUp(col, row)) return false;
-
-		cell.rowspan -= 1;
-		for (var colIndex = col; colIndex < col + cell.colspan; colIndex++) {
-			this.data[row + cell.rowspan][colIndex].spanned = false;
-		}
-	},
-
-	/**
-	 * Exports the current grid to a TypoScript notation that can be read by the
-	 * page module and is human readable.
-	 *
-	 * @return string
-	 */
-	export2LayoutRecord: function() {
-		var result = "backend_layout {\n\tcolCount = " + this.colCount + "\n\trowCount = " + this.rowCount + "\n\trows {\n";
-		for (var row = 0; row < this.rowCount; row++) {
-			result += "\t\t" + (row + 1) + " {\n";
-			result += "\t\t\tcolumns {\n";
-			colIndex = 0;
-			for (var col = 0; col < this.colCount; col++) {
-				var cell = this.getCell(col, row);
-				if (cell && !cell.spanned) {
-					colIndex++;
-					result += "\t\t\t\t" + (colIndex) + " {\n";
-					result += "\t\t\t\t\tname = " + ((!cell.name) ? col + "x" + row : cell.name) + "\n";
-					if (cell.colspan > 1) result += "\t\t\t\t\tcolspan = " + cell.colspan + "\n";
-					if (cell.rowspan > 1) result += "\t\t\t\t\trowspan = " + cell.rowspan + "\n";
-					if (typeof(cell.column) === 'number') result += "\t\t\t\t\tcolPos = " + cell.column + "\n";
-					result += "\t\t\t\t}\n";
-				}
-
-			}
-			result += "\t\t\t}\n";
-			result += "\t\t}\n";
-		}
-
-		result += "\t}\n}\n";
-		return result;
-	}
-});
diff --git a/typo3/sysext/t3skin/Resources/Public/Css/backend.css b/typo3/sysext/t3skin/Resources/Public/Css/backend.css
index 5b3277582134..0c7b2666d5ac 100644
--- a/typo3/sysext/t3skin/Resources/Public/Css/backend.css
+++ b/typo3/sysext/t3skin/Resources/Public/Css/backend.css
@@ -12029,6 +12029,107 @@ span.warningboxheader {
   padding-bottom: 30px;
   margin: 0 15px 30px 15px;
 }
+.grideditor td {
+  vertical-align: middle;
+}
+.grideditor td.editor_cell {
+  height: 100%;
+}
+.grideditor table.editor {
+  border-right: 1px gray dashed;
+  border-bottom: 1px gray dashed;
+}
+.grideditor table.editor td {
+  vertical-align: middle;
+  border-top: 1px gray dashed;
+  border-left: 1px gray dashed;
+  text-align: center;
+  background-color: white;
+  min-height: 100px;
+}
+.grideditor div#editor {
+  height: 100%;
+}
+.grideditor div.cell_container {
+  width: 80px;
+  height: 80px;
+  position: relative;
+  left: 50%;
+  margin-left: -30px;
+  opacity: 0.3;
+}
+.grideditor div.cell_container:hover {
+  opacity: 0.5;
+}
+.grideditor .link {
+  display: block;
+  position: absolute;
+  width: 20px;
+  height: 40px;
+  overflow: hidden;
+  opacity: 0.5;
+}
+.grideditor .link:hover {
+  text-decoration: none;
+  opacity: 1;
+}
+.grideditor .link_expand_down,
+.grideditor .link_shrink_up {
+  width: 40px;
+  height: 20px;
+}
+.grideditor .link_expand_right {
+  left: 52px;
+  top: 0;
+}
+.grideditor .link_expand_right:before {
+  font-family: FontAwesome;
+  content: "\f0da";
+  font-size: 42px;
+  line-height: 42px;
+}
+.grideditor .link_shrink_left {
+  left: -8px;
+  top: 0;
+}
+.grideditor .link_shrink_left:before {
+  font-family: FontAwesome;
+  content: "\f0d9";
+  font-size: 42px;
+  line-height: 42px;
+}
+.grideditor .link_expand_down {
+  left: 12px;
+  top: 40px;
+}
+.grideditor .link_expand_down:before {
+  font-family: FontAwesome;
+  content: "\f0d7";
+  font-size: 42px;
+  line-height: 19px;
+}
+.grideditor .link_shrink_up {
+  left: 12px;
+  top: -20px;
+}
+.grideditor .link_shrink_up:before {
+  font-family: FontAwesome;
+  content: "\f0d8";
+  font-size: 42px;
+  line-height: 20px;
+}
+.grideditor .link_editor {
+  width: 40px;
+  height: 40px;
+  left: 12px;
+  top: 0;
+}
+.grideditor .link_editor:before {
+  font-family: FontAwesome;
+  content: "\f14b";
+  font-size: 42px;
+  line-height: 42px;
+}
 *::-ms-clear {
   display: none;
 }
-- 
GitLab