From 7bbb4178229f049f83fe0582bbc741623d60c4a5 Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Sun, 6 Mar 2016 13:18:46 +0100
Subject: [PATCH] [TASK] The Number of The Workspace

This change ports EXT:workspace to Bootstrap and jQuery.

The workspace interface is simplified now, similar actions are tied together:
- The record history is now part of ``getRowDetails()`` to get rid of the extra
  button and popup.
- The "Send to stage" buttons are now also in the record information modal
  as separate buttons.

The JavaScript has some wrapper methods to simplify the remaining
ExtDirect calls.

ExtDirectServer::getDifferenceHandler() now instantiates the DiffUtility and
does not use the internal diff library directly anymore.

Resolves: #74359
Releases: master
Change-Id: Id706ae8a886f05aafeb402cdc2352068f1021dbe
Reviewed-on: https://review.typo3.org/46573
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Susanne Moog <typo3@susannemoog.de>
Tested-by: Susanne Moog <typo3@susannemoog.de>
---
 Build/Gruntfile.js                            |    9 +
 .../Public/Less/TYPO3/_module_workspaces.less |  320 +----
 .../t3skin/Resources/Public/Css/backend.css   |  247 +---
 .../Classes/Controller/AbstractController.php |   47 +-
 .../Classes/Controller/PreviewController.php  |  232 ++--
 .../Classes/Controller/ReviewController.php   |  166 ++-
 .../Classes/ExtDirect/ActionHandler.php       |  140 +-
 .../Classes/ExtDirect/ExtDirectServer.php     |  144 +-
 .../Classes/Service/GridDataService.php       |    2 +
 .../Classes/Service/HistoryService.php        |    8 +
 .../Classes/Service/StagesService.php         |    1 -
 .../Resources/Private/Language/locallang.xlf  |   46 +-
 .../Resources/Private/Layouts/Empty.html      |    1 +
 .../Resources/Private/Layouts/Module.html     |    5 +-
 .../Resources/Private/Layouts/Nodoc.html      |    9 +
 .../Resources/Private/Layouts/Popup.html      |   17 -
 .../Resources/Private/Less/preview.less       |   69 +
 .../Resources/Private/Partials/Legend.html    |    4 +-
 .../Private/Partials/Navigation.html          |    2 +
 .../Partials/Preview/StageButtons.html        |   11 +
 .../Private/Partials/WorkingTable.html        |   94 ++
 .../Templates/Preview/Ajax/StageButtons.html  |    3 +
 .../Private/Templates/Preview/Help.html       |    4 +-
 .../Private/Templates/Preview/Index.html      |   65 +-
 .../Private/Templates/Preview/NewPage.html    |    2 +
 .../Private/Templates/Preview/Preview.html    |   47 +-
 .../Private/Templates/Review/FullIndex.html   |    8 +-
 .../Private/Templates/Review/Index.html       |   29 +-
 .../Private/Templates/Review/SingleIndex.html |    8 +-
 .../Resources/Public/Css/module.css           |  290 ----
 .../Resources/Public/Css/preview.css          |  389 +-----
 .../Resources/Public/JavaScript/Backend.js    | 1191 +++++++++++++++++
 .../JavaScript/Component/RowDetailTemplate.js |   10 -
 .../JavaScript/Component/RowExpander.js       |  318 -----
 .../Public/JavaScript/Component/TabPanel.js   |  159 ---
 .../Ext.ux.plugins.TabStripContainer.js       |   99 --
 .../Resources/Public/JavaScript/Preview.js    |  305 +++++
 .../Public/JavaScript/Store/mainstore.js      |   85 --
 .../Resources/Public/JavaScript/Workspaces.js |  214 +++
 .../Resources/Public/JavaScript/actions.js    |  403 ------
 .../Resources/Public/JavaScript/component.js  |   44 -
 .../Public/JavaScript/configuration.js        |  400 ------
 .../Resources/Public/JavaScript/grid.js       |  153 ---
 .../JavaScript/gridfilters/GridFilters.js     |  740 ----------
 .../gridfilters/css/GridFilters.css           |   53 -
 .../JavaScript/gridfilters/css/RangeMenu.css  |   20 -
 .../gridfilters/filter/BooleanFilter.js       |  103 --
 .../gridfilters/filter/DateFilter.js          |  313 -----
 .../JavaScript/gridfilters/filter/Filter.js   |  185 ---
 .../gridfilters/filter/ListFilter.js          |  176 ---
 .../gridfilters/filter/NumericFilter.js       |  202 ---
 .../gridfilters/filter/StringFilter.js        |  132 --
 .../JavaScript/gridfilters/images/equals.png  |  Bin 106 -> 0 bytes
 .../JavaScript/gridfilters/images/find.png    |  Bin 638 -> 0 bytes
 .../gridfilters/images/greater_than.png       |  Bin 213 -> 0 bytes
 .../gridfilters/images/less_than.png          |  Bin 215 -> 0 bytes
 .../gridfilters/images/sort_filtered_asc.gif  |  Bin 209 -> 0 bytes
 .../gridfilters/images/sort_filtered_desc.gif |  Bin 209 -> 0 bytes
 .../JavaScript/gridfilters/menu/ListMenu.js   |  177 ---
 .../JavaScript/gridfilters/menu/RangeMenu.js  |  128 --
 .../Resources/Public/JavaScript/helpers.js    |  212 ---
 .../Resources/Public/JavaScript/preview.js    |  391 ------
 .../Resources/Public/JavaScript/toolbar.js    |  407 ------
 .../Resources/Public/JavaScript/workspaces.js |   90 --
 .../ActionHandler/ActionHandlerTest.php       |    2 +-
 65 files changed, 2560 insertions(+), 6571 deletions(-)
 create mode 100644 typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html
 create mode 100644 typo3/sysext/workspaces/Resources/Private/Less/preview.less
 create mode 100644 typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html
 create mode 100644 typo3/sysext/workspaces/Resources/Private/Partials/WorkingTable.html
 create mode 100644 typo3/sysext/workspaces/Resources/Private/Templates/Preview/Ajax/StageButtons.html
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/Css/module.css
 create mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Backend.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowDetailTemplate.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowExpander.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Component/TabPanel.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Ext.ux.plugins.TabStripContainer.js
 create mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Preview.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Store/mainstore.js
 create mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/Workspaces.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/component.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/configuration.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/grid.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/GridFilters.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/GridFilters.css
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/RangeMenu.css
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/BooleanFilter.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/DateFilter.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/Filter.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/ListFilter.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/NumericFilter.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/StringFilter.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/equals.png
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/find.png
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/greater_than.png
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/less_than.png
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/sort_filtered_asc.gif
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/sort_filtered_desc.gif
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/ListMenu.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/RangeMenu.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/helpers.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/preview.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/toolbar.js
 delete mode 100644 typo3/sysext/workspaces/Resources/Public/JavaScript/workspaces.js

diff --git a/Build/Gruntfile.js b/Build/Gruntfile.js
index 7ee9654cf756..1dcf43a8b87f 100644
--- a/Build/Gruntfile.js
+++ b/Build/Gruntfile.js
@@ -39,6 +39,7 @@ module.exports = function(grunt) {
 			install   : '<%= paths.sysext %>install/Resources/',
 			linkvalidator : '<%= paths.sysext %>linkvalidator/Resources/',
 			backend   : '<%= paths.sysext %>backend/Resources/',
+			workspaces: '<%= paths.sysext %>workspaces/Resources/',
 			core      : '<%= paths.sysext %>core/Resources/',
 			flags     : 'bower_components/region-flags/svg/',
 			t3icons   : 'bower_components/wmdbsystems-typo3-icons/dist/'
@@ -77,6 +78,11 @@ module.exports = function(grunt) {
 				files: {
 					"<%= paths.linkvalidator %>Public/Css/linkvalidator.css": "<%= paths.less %>linkvalidator.less"
 				}
+			},
+			workspaces: {
+				files: {
+					"<%= paths.workspaces %>Public/Css/preview.css": "<%= paths.workspaces %>Private/Less/preview.less"
+				}
 			}
 		},
 		postcss: {
@@ -109,6 +115,9 @@ module.exports = function(grunt) {
 			},
 			linkvalidator: {
 				src: '<%= paths.linkvalidator %>Public/Css/*.css'
+			},
+			workspaces: {
+				src: '<%= paths.workspaces %>Public/Css/*.css'
 			}
 		},
 		watch: {
diff --git a/Build/Resources/Public/Less/TYPO3/_module_workspaces.less b/Build/Resources/Public/Less/TYPO3/_module_workspaces.less
index b79e023b96be..162ae0aa46b1 100644
--- a/Build/Resources/Public/Less/TYPO3/_module_workspaces.less
+++ b/Build/Resources/Public/Less/TYPO3/_module_workspaces.less
@@ -1,290 +1,54 @@
-ul.x-tab-strip.x-tab-strip-top {
-	margin-bottom: 0;
-	margin-top: 0;
-	padding-left: 0;
-}
-ul.x-tab-strip.x-tab-strip-top li.last {
-	float: right;
-}
-span.item-state-modified {
-	color: #f78f25;
-}
-span.item-state-moved {
-	color: #457fb8;
-}
-span.item-state-new {
-	color: #3c9934;
-}
-span.item-state-hidden {
-	color: #abaaaa;
-}
-span.item-state-deleted {
-	color: #000000;
-	text-decoration: line-through;
-}
-.legend {
-	margin: 5px;
-	height: 18px;
-	color: #888888;
-}
-.legend dd, .legend dt {
-	display: inline;
-	overflow: hidden;
-}
-.legend dd span {
-	display: inline-block;
-	padding: 4px 4px;
-}
-.x-toolbar {
-	background:none !important;
-}
-.x-grid3 {
-	background: none !important;
-}
-.x-grid3-row-expanded {
-	background-color: #ececec;
-}
-.x-grid3-row-selected {
-	color: #4D4D4D;
-}
-#typo3-mod-php div.typo3-noDoc {
-	margin: 0px 0px;
-}
-#typo3-mod-php div.typo3-noDoc #typo3-docbody {
-	padding: 0px 0px;
-	top: 0px;
-}
-.icon-hidden {
-	display: none;
-	visibility: hidden;
-}
-div.x-grid3-row img.x-action-col-icon {
-	display:none;
-}
+#workspace-panel {
+	tr.collapsing {
+		transition: none;
+	}
+	tr.collapse {
+		display: none;
 
-div.x-grid3-row-over img.x-action-col-icon,
-div.x-grid3-row img.x-action-col-icon.t3-visible {
-	display:inline-block;
+		&.in {
+			display: table-row;
+		}
+	}
 }
 
-div.t3-workspaces-foldoutWrapper {
-	padding: 10px;
-	margin-left: 40px;
-	background-color: #FFFFFF;
-	background-image: linear-gradient(center top, #ececec 0px, #f7f7f7 200px);
-	background-repeat: repeat-x;
-	color: #606060;
-}
-.x-grid3-row-selected div.t3-workspaces-foldoutWrapper {
-	background-image: linear-gradient(center top, #dedede 0px, #f7f7f7 200px);
-	background-repeat: repeat-x;
-}
-div.t3-workspaces-foldoutWrapper table {
-	border-collapse: collapse;
-	width: 100%;
-}
-div.t3-workspaces-foldoutWrapper tr.header {
-	background-color: #B5B5B5;
-	background-image: linear-gradient(center top, #7f7f7f 10%, #5b5b5b 100%);
-	background-repeat: repeat-x;
-}
-div.t3-workspaces-foldoutWrapper tr.header th {
-	padding: 4px 8px;
-	color: #FFFFFF;
-	line-height: 15px;
-}
+span.item-state- {
+	&modified {
+		color: #f78f25;
+	}
 
-.t3-workspaces-foldout-subheaderLeft,
-.t3-workspaces-foldout-subheaderRight {
-	padding: 15px 0 10px 0;
-	margin: 10px;
-}
-.t3-workspaces-foldout-td-contentDiffLeft .t3-workspaces-foldout-contentDiff-container,
-.t3-workspaces-foldout-td-contentDiffRight .t3-workspaces-foldout-contentDiff-container {
-	padding-top: 10px;
-	border-top: 1px solid #cdcdcd;
-}
-.x-grid3-row .t3-workspaces-foldout-td-contentDiffLeft,
-.x-grid3-row .t3-workspaces-foldout-subheaderLeft {
-	padding-right: 10px;
-}
-.x-grid3-row .t3-workspaces-foldout-td-contentDiffRight,
-.x-grid3-row .t3-workspaces-foldout-subheaderRight {
-	padding-left: 10px;
-}
-.x-grid3-row .t3-workspaces-foldout-subheaderLeft .t3-workspaces-foldout-subheader-container {
-	padding-bottom: 10px;
-	border-bottom: 1px solid #cdcdcd;
-}
-table.t3-workspaces-foldout-contentDiff  {
-	padding: 8px 8px;
-	table-layout: auto;
-	background-color: #ffffff;
-}
-table.t3-workspaces-foldout-contentDiff th {
-	padding: 8px 0 8px 8px;
-	width: 80px;
-}
-table.t3-workspaces-foldout-contentDiff td {
-	padding: 8px 8px 8px 0;
-	line-height: 1.3em;
-}
-table.t3-workspaces-foldout-contentDiff .diff-r {
-	text-decoration: line-through;
-}
-.t3-workspaces-foldout-contentDiff .content ins > img {
-	padding: 1px;
-	margin-right: 2px;
-	border: 2px solid green;
-}
-.t3-workspaces-foldout-contentDiff .content del > img {
-	padding: 1px;
-	margin-right: 2px;
-	border: 2px solid red;
-}
-div.t3-workspaces-foldoutWrapper td.char_select_profile_stats {
-	padding-right: 10px;
-}
-div.t3-workspaces-comments {
-	background-color: #dedede;
-	padding: 10px 10px 10px 10px;
-}
-div.t3-workspaces-comments-singleComment {
-	overflow: hidden;
-	margin-bottom: 10px;
-	position: relative;
-}
-div.t3-workspaces-comments-singleComment:last-child {
-	margin: 0;
-}
-div .t3-workspaces-comments-singleComment-author {
-	width: 60px;
-	margin: 10px 0;
-	position: absolute;
-	left: 0px;
-	top: 0px;
-	font-weight: bold;
-	overflow: hidden;
-}
-div .t3-workspaces-comments-singleComment-content-wrapper {
-	background: url(../Images/workspaces-comments-arrow.gif) left 10px no-repeat;
-	margin-left: 70px;
-}
-div .t3-workspaces-comments-singleComment-content-date {
-	font-size: 10px;
-}
-div .t3-workspaces-comments-singleComment-content {
-	background-color: #ffffff;
-	padding: 10px 10px;
-	margin-left: 10px;
-}
-div .t3-workspaces-comments-singleComment-content-title {
-	padding: 8px 0 8px 0;
-	font-weight: bold;
-}
-
-.typo3-workspaces-row-disabled .x-grid3-td-checker {
-	visibility: hidden;
-}
-
-div.x-grid3-row img.t3-icon-extensions-workspaces {
-	display: inline-block !important;
-	width: 17px;
-	visibility: hidden;
-}
-
-div.x-grid3-row-over img.t3-icon-extensions-workspaces {
-	visibility: visible;
-}
-
-img.t3-icon-workspaces-sendtonextstage {
-	background: url(../Images/version-workspace-sendtonextstage.png) no-repeat;
-}
+	&moved {
+		color: #457fb8;
+	}
 
-img.t3-icon-workspaces-sendtoprevstage {
-	background: url(../Images/version-workspace-sendtoprevstage.png) no-repeat;
-}
+	&new {
+		color: #3c9934;
+	}
 
-table.t3-workspaces-foldout-contentDiff td.content {
-	word-break: break-all;
-}
+	&hidden {
+		color: #abaaaa;
+	}
 
-.typo3-workspaces-collection-level-node,
-.typo3-workspaces-collection-level-leaf,
-.typo3-workspaces-collection-level-none {
-	float: left;
-	width: 18px;
+	&deleted {
+		color: #000000;
+		text-decoration: line-through;
+	}
 }
 
-.x-grid3-row-expander {
-	background-position: left top;
-	float: left;
-}
-.x-grid3-row-collapsed .x-grid3-row-expander {
-	background-position: left top;
-	background-image: url('../Images/zoom_in.png');
-}
-.x-grid3-row-expanded .x-grid3-row-expander {
-	background-position: left top;
-	background-image: url('../Images/zoom_out.png');
-}
-
-.typo3-workspaces-collection-child-collapsed {
-	display: none;
-}
-
-.typo3-workspaces-collection-child-expanded {
-	display: block;
-}
-
-.typo3-workspaces-collection-level-node {
-	width: 18px;
+.legend {
+	margin: 5px;
 	height: 18px;
-	background-position: 4px 2px;
-	background-color: transparent;
-	background-repeat: no-repeat;
-	background-image: url('../../../../t3skin/extjs/images/grid/row-expand-sprite.png');
-}
-.typo3-workspaces-collection-parent-collapsed .typo3-workspaces-collection-level-node {
-	background-position: 4px 2px;
-}
-.typo3-workspaces-collection-parent-expanded .typo3-workspaces-collection-level-node {
-	background-position: -21px 2px;
-}
-
-.x-menu.typo3-workspaces-menu {
-	background-image: none;
-}
-.x-menu.typo3-workspaces-menu a.x-menu-item {
-	padding: 3px 14px;
-}
-
-.x-tab-menu-right {
-	background: #dadada;
-	border-color: #adadad;
-	border-style: solid;
-	border-width: 1px;
-	border-top-left-radius: 3px;
-	border-top-right-radius: 3px;
-	color: #666666;
-	background-position: center 6px;
-	padding: 4px;
-
-	background-image: url('../Images/menu.png');
-	background-repeat: no-repeat;
-	width: 16px;
-	position: absolute;
-	right: 0;
-	top: 0;
-	z-index: 10;
-	cursor:pointer;
-}
-
-.t3-workspaces-foldoutWrapper .char_select_profile_titleLeft .icon,
-.t3-workspaces-foldoutWrapper .char_select_profile_titleRight .icon{
-	float: left;
-}
+	color: #888888;
 
-.t3-workspaces-foldoutWrapper .t3-workspaces-foldout-contentDiff {
-	text-align: left;
+	dd,
+	dt {
+		display: inline;
+		overflow: hidden;
+	}
+
+	dd {
+		span {
+			display: inline-block;
+			padding: 4px 4px;
+		}
+	}
 }
diff --git a/typo3/sysext/t3skin/Resources/Public/Css/backend.css b/typo3/sysext/t3skin/Resources/Public/Css/backend.css
index 539d833f6e27..bd5af74d9784 100644
--- a/typo3/sysext/t3skin/Resources/Public/Css/backend.css
+++ b/typo3/sysext/t3skin/Resources/Public/Css/backend.css
@@ -12621,13 +12621,14 @@ iframe {
   background-position: -80px -224px;
   border-width: 0;
 }
-ul.x-tab-strip.x-tab-strip-top {
-  margin-bottom: 0;
-  margin-top: 0;
-  padding-left: 0;
+#workspace-panel tr.collapsing {
+  transition: none;
 }
-ul.x-tab-strip.x-tab-strip-top li.last {
-  float: right;
+#workspace-panel tr.collapse {
+  display: none;
+}
+#workspace-panel tr.collapse.in {
+  display: table-row;
 }
 span.item-state-modified {
   color: #f78f25;
@@ -12659,240 +12660,6 @@ span.item-state-deleted {
   display: inline-block;
   padding: 4px 4px;
 }
-.x-toolbar {
-  background: none !important;
-}
-.x-grid3 {
-  background: none !important;
-}
-.x-grid3-row-expanded {
-  background-color: #ececec;
-}
-.x-grid3-row-selected {
-  color: #4D4D4D;
-}
-#typo3-mod-php div.typo3-noDoc {
-  margin: 0px 0px;
-}
-#typo3-mod-php div.typo3-noDoc #typo3-docbody {
-  padding: 0px 0px;
-  top: 0px;
-}
-.icon-hidden {
-  display: none;
-  visibility: hidden;
-}
-div.x-grid3-row img.x-action-col-icon {
-  display: none;
-}
-div.x-grid3-row-over img.x-action-col-icon,
-div.x-grid3-row img.x-action-col-icon.t3-visible {
-  display: inline-block;
-}
-div.t3-workspaces-foldoutWrapper {
-  padding: 10px;
-  margin-left: 40px;
-  background-color: #FFFFFF;
-  background-image: linear-gradient(center top, #ececec 0px, #f7f7f7 200px);
-  background-repeat: repeat-x;
-  color: #606060;
-}
-.x-grid3-row-selected div.t3-workspaces-foldoutWrapper {
-  background-image: linear-gradient(center top, #dedede 0px, #f7f7f7 200px);
-  background-repeat: repeat-x;
-}
-div.t3-workspaces-foldoutWrapper table {
-  border-collapse: collapse;
-  width: 100%;
-}
-div.t3-workspaces-foldoutWrapper tr.header {
-  background-color: #B5B5B5;
-  background-image: linear-gradient(center top, #7f7f7f 10%, #5b5b5b 100%);
-  background-repeat: repeat-x;
-}
-div.t3-workspaces-foldoutWrapper tr.header th {
-  padding: 4px 8px;
-  color: #FFFFFF;
-  line-height: 15px;
-}
-.t3-workspaces-foldout-subheaderLeft,
-.t3-workspaces-foldout-subheaderRight {
-  padding: 15px 0 10px 0;
-  margin: 10px;
-}
-.t3-workspaces-foldout-td-contentDiffLeft .t3-workspaces-foldout-contentDiff-container,
-.t3-workspaces-foldout-td-contentDiffRight .t3-workspaces-foldout-contentDiff-container {
-  padding-top: 10px;
-  border-top: 1px solid #cdcdcd;
-}
-.x-grid3-row .t3-workspaces-foldout-td-contentDiffLeft,
-.x-grid3-row .t3-workspaces-foldout-subheaderLeft {
-  padding-right: 10px;
-}
-.x-grid3-row .t3-workspaces-foldout-td-contentDiffRight,
-.x-grid3-row .t3-workspaces-foldout-subheaderRight {
-  padding-left: 10px;
-}
-.x-grid3-row .t3-workspaces-foldout-subheaderLeft .t3-workspaces-foldout-subheader-container {
-  padding-bottom: 10px;
-  border-bottom: 1px solid #cdcdcd;
-}
-table.t3-workspaces-foldout-contentDiff {
-  padding: 8px 8px;
-  table-layout: auto;
-  background-color: #ffffff;
-}
-table.t3-workspaces-foldout-contentDiff th {
-  padding: 8px 0 8px 8px;
-  width: 80px;
-}
-table.t3-workspaces-foldout-contentDiff td {
-  padding: 8px 8px 8px 0;
-  line-height: 1.3em;
-}
-table.t3-workspaces-foldout-contentDiff .diff-r {
-  text-decoration: line-through;
-}
-.t3-workspaces-foldout-contentDiff .content ins > img {
-  padding: 1px;
-  margin-right: 2px;
-  border: 2px solid green;
-}
-.t3-workspaces-foldout-contentDiff .content del > img {
-  padding: 1px;
-  margin-right: 2px;
-  border: 2px solid red;
-}
-div.t3-workspaces-foldoutWrapper td.char_select_profile_stats {
-  padding-right: 10px;
-}
-div.t3-workspaces-comments {
-  background-color: #dedede;
-  padding: 10px 10px 10px 10px;
-}
-div.t3-workspaces-comments-singleComment {
-  overflow: hidden;
-  margin-bottom: 10px;
-  position: relative;
-}
-div.t3-workspaces-comments-singleComment:last-child {
-  margin: 0;
-}
-div .t3-workspaces-comments-singleComment-author {
-  width: 60px;
-  margin: 10px 0;
-  position: absolute;
-  left: 0px;
-  top: 0px;
-  font-weight: bold;
-  overflow: hidden;
-}
-div .t3-workspaces-comments-singleComment-content-wrapper {
-  background: url(../Images/workspaces-comments-arrow.gif) left 10px no-repeat;
-  margin-left: 70px;
-}
-div .t3-workspaces-comments-singleComment-content-date {
-  font-size: 10px;
-}
-div .t3-workspaces-comments-singleComment-content {
-  background-color: #ffffff;
-  padding: 10px 10px;
-  margin-left: 10px;
-}
-div .t3-workspaces-comments-singleComment-content-title {
-  padding: 8px 0 8px 0;
-  font-weight: bold;
-}
-.typo3-workspaces-row-disabled .x-grid3-td-checker {
-  visibility: hidden;
-}
-div.x-grid3-row img.t3-icon-extensions-workspaces {
-  display: inline-block !important;
-  width: 17px;
-  visibility: hidden;
-}
-div.x-grid3-row-over img.t3-icon-extensions-workspaces {
-  visibility: visible;
-}
-img.t3-icon-workspaces-sendtonextstage {
-  background: url(../Images/version-workspace-sendtonextstage.png) no-repeat;
-}
-img.t3-icon-workspaces-sendtoprevstage {
-  background: url(../Images/version-workspace-sendtoprevstage.png) no-repeat;
-}
-table.t3-workspaces-foldout-contentDiff td.content {
-  word-break: break-all;
-}
-.typo3-workspaces-collection-level-node,
-.typo3-workspaces-collection-level-leaf,
-.typo3-workspaces-collection-level-none {
-  float: left;
-  width: 18px;
-}
-.x-grid3-row-expander {
-  background-position: left top;
-  float: left;
-}
-.x-grid3-row-collapsed .x-grid3-row-expander {
-  background-position: left top;
-  background-image: url('../Images/zoom_in.png');
-}
-.x-grid3-row-expanded .x-grid3-row-expander {
-  background-position: left top;
-  background-image: url('../Images/zoom_out.png');
-}
-.typo3-workspaces-collection-child-collapsed {
-  display: none;
-}
-.typo3-workspaces-collection-child-expanded {
-  display: block;
-}
-.typo3-workspaces-collection-level-node {
-  width: 18px;
-  height: 18px;
-  background-position: 4px 2px;
-  background-color: transparent;
-  background-repeat: no-repeat;
-  background-image: url('../../../../t3skin/extjs/images/grid/row-expand-sprite.png');
-}
-.typo3-workspaces-collection-parent-collapsed .typo3-workspaces-collection-level-node {
-  background-position: 4px 2px;
-}
-.typo3-workspaces-collection-parent-expanded .typo3-workspaces-collection-level-node {
-  background-position: -21px 2px;
-}
-.x-menu.typo3-workspaces-menu {
-  background-image: none;
-}
-.x-menu.typo3-workspaces-menu a.x-menu-item {
-  padding: 3px 14px;
-}
-.x-tab-menu-right {
-  background: #dadada;
-  border-color: #adadad;
-  border-style: solid;
-  border-width: 1px;
-  border-top-left-radius: 3px;
-  border-top-right-radius: 3px;
-  color: #666666;
-  background-position: center 6px;
-  padding: 4px;
-  background-image: url('../Images/menu.png');
-  background-repeat: no-repeat;
-  width: 16px;
-  position: absolute;
-  right: 0;
-  top: 0;
-  z-index: 10;
-  cursor: pointer;
-}
-.t3-workspaces-foldoutWrapper .char_select_profile_titleLeft .icon,
-.t3-workspaces-foldoutWrapper .char_select_profile_titleRight .icon {
-  float: left;
-}
-.t3-workspaces-foldoutWrapper .t3-workspaces-foldout-contentDiff {
-  text-align: left;
-}
 [id="typo3-topbar"],
 [id="typo3-topbar"] .x-panel-body {
   min-width: 1000px;
diff --git a/typo3/sysext/workspaces/Classes/Controller/AbstractController.php b/typo3/sysext/workspaces/Classes/Controller/AbstractController.php
index 6235cee61c35..ad173223ed9e 100644
--- a/typo3/sysext/workspaces/Classes/Controller/AbstractController.php
+++ b/typo3/sysext/workspaces/Classes/Controller/AbstractController.php
@@ -19,12 +19,14 @@ use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+use TYPO3\CMS\Workspaces\Service\AdditionalColumnService;
+use TYPO3\CMS\Workspaces\Service\AdditionalResourceService;
 
 /**
  * Abstract action controller.
  */
-class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
+class AbstractController extends ActionController
 {
     /**
      * @var string
@@ -62,6 +64,7 @@ class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
         // @todo Evaluate how the intval() call can be used with Extbase validators/filters
         $this->pageId = (int)GeneralUtility::_GP('id');
         $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+        $lang = $this->getLanguageService();
         $icons = array(
             'language' => $iconFactory->getIcon('flags-multiple', Icon::SIZE_SMALL)->render(),
             'integrity' => $iconFactory->getIcon('status-dialog-information', Icon::SIZE_SMALL)->render(),
@@ -74,18 +77,18 @@ class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
         $this->pageRenderer->addInlineSetting('Workspaces', 'id', $this->pageId);
         $this->pageRenderer->addInlineSetting('Workspaces', 'depth', $this->pageId === 0 ? 999 : 1);
         $this->pageRenderer->addInlineSetting('Workspaces', 'language', $this->getLanguageSelection());
-        $this->pageRenderer->addInlineLanguageLabelArray(array(
-            'title' => $GLOBALS['LANG']->getLL('title'),
-            'path' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.path'),
-            'table' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.table'),
-            'depth' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_perm.xlf:Depth'),
-            'depth_0' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_0'),
-            'depth_1' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_1'),
-            'depth_2' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_2'),
-            'depth_3' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_3'),
-            'depth_4' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_4'),
-            'depth_infi' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi')
-        ));
+        $this->pageRenderer->addInlineLanguageLabelArray([
+            'title' => $lang->getLL('title'),
+            'path' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.path'),
+            'table' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.table'),
+            'depth' => $lang->sL('LLL:EXT:lang/locallang_mod_web_perm.xlf:Depth'),
+            'depth_0' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_0'),
+            'depth_1' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_1'),
+            'depth_2' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_2'),
+            'depth_3' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_3'),
+            'depth_4' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_4'),
+            'depth_infi' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi')
+        ]);
         $this->pageRenderer->addInlineLanguageLabelFile('EXT:workspaces/Resources/Private/Language/locallang.xlf');
         $this->assignExtensionSettings();
     }
@@ -125,19 +128,19 @@ class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
     }
 
     /**
-     * @return \TYPO3\CMS\Workspaces\Service\AdditionalColumnService
+     * @return AdditionalColumnService
      */
     protected function getAdditionalColumnService()
     {
-        return $this->objectManager->get(\TYPO3\CMS\Workspaces\Service\AdditionalColumnService::class);
+        return $this->objectManager->get(AdditionalColumnService::class);
     }
 
     /**
-     * @return \TYPO3\CMS\Workspaces\Service\AdditionalResourceService
+     * @return AdditionalResourceService
      */
     protected function getAdditionalResourceService()
     {
-        return $this->objectManager->get(\TYPO3\CMS\Workspaces\Service\AdditionalResourceService::class);
+        return $this->objectManager->get(AdditionalResourceService::class);
     }
 
     /**
@@ -148,6 +151,14 @@ class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
         return $GLOBALS['BE_USER'];
     }
 
+    /**
+     * @return \TYPO3\CMS\Lang\LanguageService
+     */
+    protected function getLanguageService()
+    {
+        return $GLOBALS['LANG'];
+    }
+
     /**
      * @return PageRenderer
      */
diff --git a/typo3/sysext/workspaces/Classes/Controller/PreviewController.php b/typo3/sysext/workspaces/Classes/Controller/PreviewController.php
index 41e668535209..5885fa5cee64 100644
--- a/typo3/sysext/workspaces/Classes/Controller/PreviewController.php
+++ b/typo3/sysext/workspaces/Classes/Controller/PreviewController.php
@@ -16,9 +16,16 @@ namespace TYPO3\CMS\Workspaces\Controller;
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\View\BackendTemplateView;
+use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
+use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
+use TYPO3\CMS\Workspaces\Service\StagesService;
+use TYPO3\CMS\Workspaces\Service\WorkspaceService;
 
 /**
  * Implements the preview controller of the workspace module.
@@ -26,12 +33,12 @@ use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
 class PreviewController extends AbstractController
 {
     /**
-     * @var \TYPO3\CMS\Workspaces\Service\StagesService
+     * @var StagesService
      */
     protected $stageService;
 
     /**
-     * @var \TYPO3\CMS\Workspaces\Service\WorkspaceService
+     * @var WorkspaceService
      */
     protected $workspaceService;
 
@@ -59,32 +66,17 @@ class PreviewController extends AbstractController
     {
         parent::initializeAction();
         $backendRelPath = ExtensionManagementUtility::extRelPath('backend');
-        $workspacesRelPath = ExtensionManagementUtility::extRelPath('workspaces');
-        $this->stageService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class);
-        $this->workspaceService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        $this->stageService = GeneralUtility::makeInstance(StagesService::class);
+        $this->workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
         $this->pageRenderer->addJsFile($backendRelPath . 'Resources/Public/JavaScript/ExtDirect.StateProvider.js');
-        $resourcePath = $workspacesRelPath . 'Resources/Public/Css/preview.css';
-        $GLOBALS['TBE_STYLES']['extJS']['theme'] = $resourcePath;
-        $this->pageRenderer->loadExtJS();
+        $this->pageRenderer->loadExtJS(false, false);
         // Load  JavaScript:
         $this->pageRenderer->addExtDirectCode(array(
             'TYPO3.Workspaces',
             'TYPO3.ExtDirectStateProvider'
         ));
-        $states = $GLOBALS['BE_USER']->uc['moduleData']['Workspaces']['States'];
+        $states = $this->getBackendUser()->uc['moduleData']['Workspaces']['States'];
         $this->pageRenderer->addInlineSetting('Workspaces', 'States', $states);
-        $this->pageRenderer->addJsFile($backendRelPath . 'Resources/Public/JavaScript/notifications.js');
-        $this->pageRenderer->addJsFile($backendRelPath . 'Resources/Public/JavaScript/iframepanel.js');
-        $resourcePathJavaScript = $workspacesRelPath . 'Resources/Public/JavaScript/';
-        $jsFiles = array(
-            'Ext.ux.plugins.TabStripContainer.js',
-            'Store/mainstore.js',
-            'helpers.js',
-            'actions.js'
-        );
-        foreach ($jsFiles as $jsFile) {
-            $this->pageRenderer->addJsFile($resourcePathJavaScript . $jsFile);
-        }
         $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', BackendUtility::getModuleUrl('record_edit'));
         $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', BackendUtility::getModuleUrl('record_history'));
         // @todo this part should be done with inlineLocallanglabels
@@ -101,81 +93,103 @@ class PreviewController extends AbstractController
      */
     public function indexAction($previewWS = null)
     {
+        $backendUser = $this->getBackendUser();
+
         // Get all the GET parameters to pass them on to the frames
         $queryParameters = GeneralUtility::_GET();
-            // Remove the GET parameters related to the workspaces module and the page id
+
+        // Remove the GET parameters related to the workspaces module and the page id
         unset($queryParameters['tx_workspaces_web_workspacesworkspaces']);
         unset($queryParameters['M']);
         unset($queryParameters['id']);
-            // Assemble a query string from the retrieved parameters
+
+        // Assemble a query string from the retrieved parameters
         $queryString = GeneralUtility::implodeArrayForUrl('', $queryParameters);
 
         // fetch the next and previous stage
         $workspaceItemsArray = $this->workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $this->pageId, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
         list(, $nextStage) = $this->stageService->getNextStageForElementCollection($workspaceItemsArray);
         list(, $previousStage) = $this->stageService->getPreviousStageForElementCollection($workspaceItemsArray);
-        /** @var $wsService \TYPO3\CMS\Workspaces\Service\WorkspaceService */
-        $wsService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        /** @var $wsService WorkspaceService */
+        $wsService = GeneralUtility::makeInstance(WorkspaceService::class);
         $wsList = $wsService->getAvailableWorkspaces();
-        $activeWorkspace = $GLOBALS['BE_USER']->workspace;
+        $activeWorkspace = $backendUser->workspace;
         if (!is_null($previewWS)) {
             if (in_array($previewWS, array_keys($wsList)) && $activeWorkspace != $previewWS) {
                 $activeWorkspace = $previewWS;
-                $GLOBALS['BE_USER']->setWorkspace($activeWorkspace);
+                $backendUser->setWorkspace($activeWorkspace);
                 BackendUtility::setUpdateSignal('updatePageTree');
             }
         }
-        /** @var $uriBuilder \TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder */
-        $uriBuilder = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::class);
+        /** @var $uriBuilder UriBuilder */
+        $uriBuilder = $this->objectManager->get(UriBuilder::class);
         $wsSettingsPath = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
-        $wsSettingsUri = $uriBuilder->uriFor('singleIndex', array(), \TYPO3\CMS\Workspaces\Controller\ReviewController::class, 'workspaces', 'web_workspacesworkspaces');
+        $wsSettingsUri = $uriBuilder->uriFor('singleIndex', array(), ReviewController::class, 'workspaces', 'web_workspacesworkspaces');
         $wsSettingsParams = '&tx_workspaces_web_workspacesworkspaces[controller]=Review';
         $wsSettingsUrl = $wsSettingsPath . $wsSettingsUri . $wsSettingsParams;
         $viewDomain = BackendUtility::getViewDomain($this->pageId);
         $wsBaseUrl = $viewDomain . '/index.php?id=' . $this->pageId . $queryString;
         // @todo - handle new pages here
         // branchpoints are not handled anymore because this feature is not supposed anymore
-        if (\TYPO3\CMS\Workspaces\Service\WorkspaceService::isNewPage($this->pageId)) {
-            $wsNewPageUri = $uriBuilder->uriFor('newPage', array(), \TYPO3\CMS\Workspaces\Controller\PreviewController::class, 'workspaces', 'web_workspacesworkspaces');
+        if (WorkspaceService::isNewPage($this->pageId)) {
+            $wsNewPageUri = $uriBuilder->uriFor('newPage', array(), PreviewController::class, 'workspaces', 'web_workspacesworkspaces');
             $wsNewPageParams = '&tx_workspaces_web_workspacesworkspaces[controller]=Preview';
-            $this->view->assign('liveUrl', $wsSettingsPath . $wsNewPageUri . $wsNewPageParams . '&ADMCMD_prev=IGNORE');
+            $liveUrl = $wsSettingsPath . $wsNewPageUri . $wsNewPageParams . '&ADMCMD_prev=IGNORE';
         } else {
-            $this->view->assign('liveUrl', $wsBaseUrl . '&ADMCMD_noBeUser=1&ADMCMD_prev=IGNORE');
+            $liveUrl = $wsBaseUrl . '&ADMCMD_noBeUser=1&ADMCMD_prev=IGNORE';
         }
-        $this->view->assign('wsUrl', $wsBaseUrl . '&ADMCMD_prev=IGNORE&ADMCMD_view=1&ADMCMD_editIcons=1&ADMCMD_previewWS=' . $GLOBALS['BE_USER']->workspace);
-        $this->view->assign('wsSettingsUrl', $wsSettingsUrl);
-        $this->view->assign('backendDomain', GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'));
+        $wsUrl = $wsBaseUrl . '&ADMCMD_prev=IGNORE&ADMCMD_view=1&ADMCMD_editIcons=1&ADMCMD_previewWS=' . $backendUser->workspace;
+        $backendDomain = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
         $splitPreviewTsConfig = BackendUtility::getModTSconfig($this->pageId, 'workspaces.splitPreviewModes');
         $splitPreviewModes = GeneralUtility::trimExplode(',', $splitPreviewTsConfig['value']);
         $allPreviewModes = array('slider', 'vbox', 'hbox');
         if (!array_intersect($splitPreviewModes, $allPreviewModes)) {
             $splitPreviewModes = $allPreviewModes;
         }
+
+        $wsList = $wsService->getAvailableWorkspaces();
+        $activeWorkspace = $backendUser->workspace;
+
+        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Workspaces/Preview');
         $this->pageRenderer->addInlineSetting('Workspaces', 'SplitPreviewModes', $splitPreviewModes);
-        $GLOBALS['BE_USER']->setAndSaveSessionData('workspaces.backend_domain', GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'));
-        $this->pageRenderer->addInlineSetting('Workspaces', 'disableNextStageButton', $this->isInvalidStage($nextStage));
-        $this->pageRenderer->addInlineSetting('Workspaces', 'disablePreviousStageButton', $this->isInvalidStage($previousStage));
-        $this->pageRenderer->addInlineSetting('Workspaces', 'disableDiscardStageButton', $this->isInvalidStage($nextStage) && $this->isInvalidStage($previousStage));
-        $resourcePath = ExtensionManagementUtility::extRelPath('lang') . 'Resources/Public/JavaScript/';
-        $this->pageRenderer->addJsFile($resourcePath . 'Typo3Lang.js');
-        $this->pageRenderer->addJsInlineCode('workspaces.preview.lll', '
-		TYPO3.lang = {
-			visualPreview: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.visualPreview', true)) . ',
-			listView: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.listView', true)) . ',
-			livePreview: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.livePreview', true)) . ',
-			livePreviewDetail: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.livePreviewDetail', true)) . ',
-			workspacePreview: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.workspacePreview', true)) . ',
-			workspacePreviewDetail: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.workspacePreviewDetail', true)) . ',
-			modeSlider: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.modeSlider', true)) . ',
-			modeVbox: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.modeVbox', true)) . ',
-			modeHbox: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:preview.modeHbox', true)) . ',
-			discard: ' . GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:label_doaction_discard', true)) . ',
-			nextStage: ' . GeneralUtility::quoteJSvalue($nextStage['title']) . ',
-			previousStage: ' . GeneralUtility::quoteJSvalue($previousStage['title']) . '
-		};TYPO3.l10n.initialize();
-');
-        $resourcePath = ExtensionManagementUtility::extRelPath('workspaces') . 'Resources/Public/';
-        $this->pageRenderer->addJsFile($resourcePath . 'JavaScript/preview.js');
+        $this->pageRenderer->addInlineSetting('Workspaces', 'token', FormProtectionFactory::get('backend')->generateToken('extDirect'));
+
+        $cssFile = 'EXT:workspaces/Resources/Public/Css/preview.css';
+        $cssFile = GeneralUtility::getFileAbsFileName($cssFile);
+        $this->pageRenderer->addCssFile(PathUtility::getAbsoluteWebPath($cssFile));
+
+        $backendUser->setAndSaveSessionData('workspaces.backend_domain', GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'));
+
+        $logoPath = GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Public/Images/typo3-topbar@2x.png');
+        list($logoWidth, $logoHeight) = @getimagesize($logoPath);
+
+        // High-resolution?
+        $logoWidth = $logoWidth/2;
+        $logoHeight = $logoHeight/2;
+
+        $this->view->assignMultiple([
+            'logoUrl' => PathUtility::getAbsoluteWebPath($logoPath),
+            'logoLink' => TYPO3_URL_GENERAL,
+            'logoWidth' => $logoWidth,
+            'logoHeight' => $logoHeight,
+            'liveUrl' => $liveUrl,
+            'wsUrl' => $wsUrl,
+            'wsSettingsUrl' => $wsSettingsUrl,
+            'backendDomain' => $backendDomain,
+            'activeWorkspace' => $wsList[$activeWorkspace],
+            'splitPreviewModes' => $splitPreviewModes,
+            'firstPreviewMode' => current($splitPreviewModes),
+            'enablePreviousStageButton' => !$this->isInvalidStage($previousStage),
+            'enableNextStageButton' => !$this->isInvalidStage($nextStage),
+            'enableDiscardStageButton' => !$this->isInvalidStage($nextStage) || !$this->isInvalidStage($previousStage),
+            'nextStage' => $nextStage['title'],
+            'nextStageId' => $nextStage['uid'],
+            'prevStage' => $previousStage['title'],
+            'prevStageId' => $previousStage['uid'],
+        ]);
+        foreach ($this->getAdditionalResourceService()->getLocalizationResources() as $localizationResource) {
+            $this->pageRenderer->addInlineLanguageLabelFile($localizationResource);
+        }
     }
 
     /**
@@ -194,9 +208,10 @@ class PreviewController extends AbstractController
      */
     public function newPageAction()
     {
-        $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:info.newpage.detail'), $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:info.newpage'), \TYPO3\CMS\Core\Messaging\FlashMessage::INFO);
-        /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
-        $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
+        /** @var FlashMessage $flashMessage */
+        $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:info.newpage.detail'), $this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:info.newpage'), FlashMessage::INFO);
+        /** @var $flashMessageService FlashMessageService */
+        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
         /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
         $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
         $defaultFlashMessageQueue->enqueue($flashMessage);
@@ -211,58 +226,59 @@ class PreviewController extends AbstractController
      */
     protected function generateJavascript()
     {
+        $backendUser = $this->getBackendUser();
+        $lang = $this->getLanguageService();
         // If another page module was specified, replace the default Page module with the new one
-        $newPageModule = trim($GLOBALS['BE_USER']->getTSConfigVal('options.overridePageModule'));
+        $newPageModule = trim($backendUser->getTSConfigVal('options.overridePageModule'));
         $pageModule = BackendUtility::isModuleSetInTBE_MODULES($newPageModule) ? $newPageModule : 'web_layout';
-        if (!$GLOBALS['BE_USER']->check('modules', $pageModule)) {
+        if (!$backendUser->check('modules', $pageModule)) {
             $pageModule = '';
         }
         $t3Configuration = array(
             'siteUrl' => GeneralUtility::getIndpEnv('TYPO3_SITE_URL'),
-            'username' => htmlspecialchars($GLOBALS['BE_USER']->user['username']),
+            'username' => htmlspecialchars($backendUser->user['username']),
             'uniqueID' => GeneralUtility::shortMD5(uniqid('', true)),
             'pageModule' => $pageModule,
-            'inWorkspace' => $GLOBALS['BE_USER']->workspace !== 0,
-            'workspaceFrontendPreviewEnabled' => $GLOBALS['BE_USER']->user['workspace_preview'] ? 1 : 0,
-            'moduleMenuWidth' => $this->menuWidth - 1,
+            'inWorkspace' => $backendUser->workspace !== 0,
+            'workspaceFrontendPreviewEnabled' => $backendUser->user['workspace_preview'] ? 1 : 0,
             'topBarHeight' => isset($GLOBALS['TBE_STYLES']['dims']['topFrameH']) ? (int)$GLOBALS['TBE_STYLES']['dims']['topFrameH'] : 30,
             'showRefreshLoginPopup' => isset($GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup']) ? (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['showRefreshLoginPopup'] : false,
-            'debugInWindow' => $GLOBALS['BE_USER']->uc['debugInWindow'] ? 1 : 0,
+            'debugInWindow' => $backendUser->uc['debugInWindow'] ? 1 : 0,
             'ContextHelpWindows' => array(
                 'width' => 600,
                 'height' => 400
             )
         );
         $t3LLLcore = array(
-            'waitTitle' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_logging_in'),
-            'refresh_login_failed' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed'),
-            'refresh_login_failed_message' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed_message'),
-            'refresh_login_title' => sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_title'), htmlspecialchars($GLOBALS['BE_USER']->user['username'])),
-            'login_expired' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_expired'),
-            'refresh_login_username' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_username'),
-            'refresh_login_password' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_password'),
-            'refresh_login_emptyPassword' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_emptyPassword'),
-            'refresh_login_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_button'),
-            'refresh_logout_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_logout_button'),
-            'refresh_exit_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_exit_button'),
-            'please_wait' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.please_wait'),
-            'loadingIndicator' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:loadingIndicator'),
-            'be_locked' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.be_locked'),
-            'refresh_login_countdown_singular' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown_singular'),
-            'refresh_login_countdown' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown'),
-            'login_about_to_expire' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire'),
-            'login_about_to_expire_title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire_title'),
-            'refresh_login_refresh_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_refresh_button'),
-            'refresh_direct_logout_button' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_direct_logout_button'),
-            'tabs_closeAll' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeAll'),
-            'tabs_closeOther' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeOther'),
-            'tabs_close' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.close'),
-            'tabs_openInBrowserWindow' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tabs.openInBrowserWindow'),
-            'donateWindow_title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.title'),
-            'donateWindow_message' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.message'),
-            'donateWindow_button_donate' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.button_donate'),
-            'donateWindow_button_disable' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.button_disable'),
-            'donateWindow_button_postpone' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.button_postpone')
+            'waitTitle' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_logging_in'),
+            'refresh_login_failed' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed'),
+            'refresh_login_failed_message' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_failed_message'),
+            'refresh_login_title' => sprintf($lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_title'), htmlspecialchars($backendUser->user['username'])),
+            'login_expired' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_expired'),
+            'refresh_login_username' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_username'),
+            'refresh_login_password' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_password'),
+            'refresh_login_emptyPassword' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_emptyPassword'),
+            'refresh_login_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_button'),
+            'refresh_logout_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_logout_button'),
+            'refresh_exit_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_exit_button'),
+            'please_wait' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.please_wait'),
+            'loadingIndicator' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:loadingIndicator'),
+            'be_locked' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.be_locked'),
+            'refresh_login_countdown_singular' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown_singular'),
+            'refresh_login_countdown' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_countdown'),
+            'login_about_to_expire' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire'),
+            'login_about_to_expire_title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.login_about_to_expire_title'),
+            'refresh_login_refresh_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_login_refresh_button'),
+            'refresh_direct_logout_button' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:mess.refresh_direct_logout_button'),
+            'tabs_closeAll' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeAll'),
+            'tabs_closeOther' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.closeOther'),
+            'tabs_close' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.close'),
+            'tabs_openInBrowserWindow' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:tabs.openInBrowserWindow'),
+            'donateWindow_title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.title'),
+            'donateWindow_message' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.message'),
+            'donateWindow_button_donate' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.button_donate'),
+            'donateWindow_button_disable' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.button_disable'),
+            'donateWindow_button_postpone' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:donateWindow.button_postpone')
         );
         return '
 		TYPO3.configuration = ' . json_encode($t3Configuration) . ';
@@ -281,4 +297,20 @@ class PreviewController extends AbstractController
 			//backwards compatibility
 		';
     }
+
+    /**
+     * @return \TYPO3\CMS\Lang\LanguageService
+     */
+    protected function getLanguageService()
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+     */
+    protected function getBackendUser()
+    {
+        return $GLOBALS['BE_USER'];
+    }
 }
diff --git a/typo3/sysext/workspaces/Classes/Controller/ReviewController.php b/typo3/sysext/workspaces/Classes/Controller/ReviewController.php
index 3b6c3cb1b6d4..f93c2b341ef6 100644
--- a/typo3/sysext/workspaces/Classes/Controller/ReviewController.php
+++ b/typo3/sysext/workspaces/Classes/Controller/ReviewController.php
@@ -15,7 +15,11 @@ namespace TYPO3\CMS\Workspaces\Controller;
  */
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
 use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Messaging\FlashMessage;
+use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
@@ -66,26 +70,25 @@ class ReviewController extends AbstractController
      */
     public function indexAction()
     {
+        $backendUser = $this->getBackendUser();
+        $moduleTemplate = $this->view->getModuleTemplate();
+
         /** @var WorkspaceService $wsService */
         $wsService = GeneralUtility::makeInstance(WorkspaceService::class);
-        $this->view->assign('showGrid', !($GLOBALS['BE_USER']->workspace === 0 && !$GLOBALS['BE_USER']->isAdmin()));
-        $this->view->assign('showAllWorkspaceTab', true);
-        $this->view->assign('pageUid', GeneralUtility::_GP('id'));
         if (GeneralUtility::_GP('id')) {
             $pageRecord = BackendUtility::getRecord('pages', GeneralUtility::_GP('id'));
             if ($pageRecord) {
-                $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation($pageRecord);
+                $moduleTemplate->getDocHeaderComponent()->setMetaInformation($pageRecord);
                 $this->view->assign('pageTitle', BackendUtility::getRecordTitle('pages', $pageRecord));
             }
         }
-        $this->view->assign('showLegend', !($GLOBALS['BE_USER']->workspace === 0 && !$GLOBALS['BE_USER']->isAdmin()));
         $wsList = $wsService->getAvailableWorkspaces();
-        $activeWorkspace = $GLOBALS['BE_USER']->workspace;
+        $activeWorkspace = $backendUser->workspace;
         $performWorkspaceSwitch = false;
         // Only admins see multiple tabs, we decided to use it this
         // way for usability reasons. Regular users might be confused
         // by switching workspaces with the tabs in a module.
-        if (!$GLOBALS['BE_USER']->isAdmin()) {
+        if (!$backendUser->isAdmin()) {
             $wsCur = array($activeWorkspace => true);
             $wsList = array_intersect_key($wsList, $wsCur);
         } else {
@@ -93,7 +96,7 @@ class ReviewController extends AbstractController
                 $switchWs = (int)GeneralUtility::_GP('workspace');
                 if (in_array($switchWs, array_keys($wsList)) && $activeWorkspace != $switchWs) {
                     $activeWorkspace = $switchWs;
-                    $GLOBALS['BE_USER']->setWorkspace($activeWorkspace);
+                    $backendUser->setWorkspace($activeWorkspace);
                     $performWorkspaceSwitch = true;
                     BackendUtility::setUpdateSignal('updatePageTree');
                 } elseif ($switchWs == WorkspaceService::SELECT_ALL_WORKSPACES) {
@@ -101,26 +104,33 @@ class ReviewController extends AbstractController
                 }
             }
         }
-        $this->pageRenderer->addInlineSetting('Workspaces', 'isLiveWorkspace', (int)$GLOBALS['BE_USER']->workspace === 0);
+        $this->pageRenderer->addInlineSetting('Workspaces', 'isLiveWorkspace', (int)$backendUser->workspace === 0);
         $this->pageRenderer->addInlineSetting('Workspaces', 'workspaceTabs', $this->prepareWorkspaceTabs($wsList, $activeWorkspace));
         $this->pageRenderer->addInlineSetting('Workspaces', 'activeWorkspaceId', $activeWorkspace);
         $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', BackendUtility::getModuleUrl('record_edit'));
-        $this->view->assign('performWorkspaceSwitch', $performWorkspaceSwitch);
-        $this->view->assign('workspaceList', $wsList);
-        $this->view->assign('activeWorkspaceUid', $activeWorkspace);
-        $this->view->assign('activeWorkspaceTitle', WorkspaceService::getWorkspaceTitle($activeWorkspace));
+        $workspaceIsAccessible = !($backendUser->workspace === 0 && !$backendUser->isAdmin());
+        $this->view->assignMultiple([
+            'showGrid' => $workspaceIsAccessible,
+            'showLegend' => $workspaceIsAccessible,
+            'pageUid' => (int)GeneralUtility::_GP('id'),
+            'performWorkspaceSwitch' => $performWorkspaceSwitch,
+            'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace),
+            'activeWorkspaceUid' => $activeWorkspace,
+            'activeWorkspaceTitle' => WorkspaceService::getWorkspaceTitle($activeWorkspace),
+            'showPreviewLink' => $wsService->canCreatePreviewLink(GeneralUtility::_GP('id'), $activeWorkspace)
+        ]);
+
         if ($wsService->canCreatePreviewLink(GeneralUtility::_GP('id'), $activeWorkspace)) {
-            $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
-            $iconFactory = $this->view->getModuleTemplate()->getIconFactory();
+            $buttonBar = $moduleTemplate->getDocHeaderComponent()->getButtonBar();
+            $iconFactory = $moduleTemplate->getIconFactory();
             $showButton = $buttonBar->makeLinkButton()
                 ->setHref('#')
-                ->setOnClick('TYPO3.Workspaces.Actions.generateWorkspacePreviewLinksForAllLanguages();return false;')
+                ->setClasses('t3js-preview-link')
                 ->setTitle($this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:tooltip.generatePagePreview'))
                 ->setIcon($iconFactory->getIcon('module-workspaces-action-preview-link', Icon::SIZE_SMALL));
             $buttonBar->addButton($showButton);
         }
-        $this->view->assign('showPreviewLink', $wsService->canCreatePreviewLink(GeneralUtility::_GP('id'), $activeWorkspace));
-        $GLOBALS['BE_USER']->setAndSaveSessionData('tx_workspace_activeWorkspace', $activeWorkspace);
+        $backendUser->setAndSaveSessionData('tx_workspace_activeWorkspace', $activeWorkspace);
     }
 
     /**
@@ -131,25 +141,26 @@ class ReviewController extends AbstractController
      */
     public function fullIndexAction()
     {
-        $wsService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        $wsService = GeneralUtility::makeInstance(WorkspaceService::class);
         $wsList = $wsService->getAvailableWorkspaces();
 
-        if (!$GLOBALS['BE_USER']->isAdmin()) {
-            $activeWorkspace = $GLOBALS['BE_USER']->workspace;
+        $activeWorkspace = $this->getBackendUser()->workspace;
+        if (!$this->getBackendUser()->isAdmin()) {
             $wsCur = array($activeWorkspace => true);
             $wsList = array_intersect_key($wsList, $wsCur);
         }
 
         $this->pageRenderer->addInlineSetting('Workspaces', 'workspaceTabs', $this->prepareWorkspaceTabs($wsList, WorkspaceService::SELECT_ALL_WORKSPACES));
         $this->pageRenderer->addInlineSetting('Workspaces', 'activeWorkspaceId', WorkspaceService::SELECT_ALL_WORKSPACES);
-        $this->view->assign('pageUid', GeneralUtility::_GP('id'));
-        $this->view->assign('showGrid', true);
-        $this->view->assign('showLegend', true);
-        $this->view->assign('showAllWorkspaceTab', true);
-        $this->view->assign('workspaceList', $wsList);
-        $this->view->assign('activeWorkspaceUid', WorkspaceService::SELECT_ALL_WORKSPACES);
-        $this->view->assign('showPreviewLink', false);
-        $GLOBALS['BE_USER']->setAndSaveSessionData('tx_workspace_activeWorkspace', WorkspaceService::SELECT_ALL_WORKSPACES);
+        $this->view->assignMultiple([
+            'pageUid' => (int)GeneralUtility::_GP('id'),
+            'showGrid' => true,
+            'showLegend' => true,
+            'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace),
+            'activeWorkspaceUid' => WorkspaceService::SELECT_ALL_WORKSPACES,
+            'showPreviewLink', false
+        ]);
+        $this->getBackendUser()->setAndSaveSessionData('tx_workspace_activeWorkspace', WorkspaceService::SELECT_ALL_WORKSPACES);
         // set flag for javascript
         $this->pageRenderer->addInlineSetting('Workspaces', 'allView', '1');
     }
@@ -162,17 +173,19 @@ class ReviewController extends AbstractController
      */
     public function singleIndexAction()
     {
-        $wsService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        $wsService = GeneralUtility::makeInstance(WorkspaceService::class);
         $wsList = $wsService->getAvailableWorkspaces();
-        $activeWorkspace = $GLOBALS['BE_USER']->workspace;
+        $activeWorkspace = $this->getBackendUser()->workspace;
         $wsCur = array($activeWorkspace => true);
         $wsList = array_intersect_key($wsList, $wsCur);
         $backendDomain = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
-        $this->view->assign('pageUid', GeneralUtility::_GP('id'));
-        $this->view->assign('showGrid', true);
-        $this->view->assign('showAllWorkspaceTab', false);
-        $this->view->assign('workspaceList', $wsList);
-        $this->view->assign('backendDomain', $backendDomain);
+        $this->view->assignMultiple([
+            'pageUid' => (int)GeneralUtility::_GP('id'),
+            'showGrid' => true,
+            'workspaceList' => $this->prepareWorkspaceTabs($wsList, $activeWorkspace, false),
+            'activeWorkspaceUid' => $activeWorkspace,
+            'backendDomain' => $backendDomain
+        ]);
         // Setting the document.domain early before JavScript
         // libraries are loaded, try to access top frame reference
         // and possibly run into some CORS issue
@@ -194,68 +207,30 @@ class ReviewController extends AbstractController
         $backendRelPath = ExtensionManagementUtility::extRelPath('backend');
         $this->pageRenderer->addJsFile($backendRelPath . 'Resources/Public/JavaScript/ExtDirect.StateProvider.js');
         if (WorkspaceService::isOldStyleWorkspaceUsed()) {
-            $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:warning.oldStyleWorkspaceInUser'), '', \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING);
-            /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
-            $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
+            /** @var FlashMessage $flashMessage */
+            $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $this->getLanguageService()->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:warning.oldStyleWorkspaceInUser'), '', FlashMessage::WARNING);
+            /** @var $flashMessageService FlashMessageService */
+            $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
             /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
             $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
             $defaultFlashMessageQueue->enqueue($flashMessage);
         }
-        $this->pageRenderer->loadExtJS();
-        $states = $GLOBALS['BE_USER']->uc['moduleData']['Workspaces']['States'];
+        $this->pageRenderer->loadExtJS(false, false);
+        $states = $this->getBackendUser()->uc['moduleData']['Workspaces']['States'];
         $this->pageRenderer->addInlineSetting('Workspaces', 'States', $states);
         // Load  JavaScript:
         $this->pageRenderer->addExtDirectCode(array(
             'TYPO3.Workspaces'
         ));
-        $this->pageRenderer->addJsFile($backendRelPath . 'Resources/Public/JavaScript/extjs/ux/Ext.grid.RowExpander.js');
-        $this->pageRenderer->addJsFile($backendRelPath . 'Resources/Public/JavaScript/extjs/ux/Ext.app.SearchField.js');
-        $this->pageRenderer->addJsFile($backendRelPath . 'Resources/Public/JavaScript/extjs/ux/Ext.ux.FitToParent.js');
-        $resourcePath = ExtensionManagementUtility::extRelPath('workspaces') . 'Resources/Public/JavaScript/';
-
-        // @todo Integrate additional stylesheet resources
-        $this->pageRenderer->addCssFile($resourcePath . 'gridfilters/css/GridFilters.css');
-        $this->pageRenderer->addCssFile($resourcePath . 'gridfilters/css/RangeMenu.css');
-
-        $filters = array(
-            $resourcePath . 'gridfilters/menu/RangeMenu.js',
-            $resourcePath . 'gridfilters/menu/ListMenu.js',
-            $resourcePath . 'gridfilters/GridFilters.js',
-            $resourcePath . 'gridfilters/filter/Filter.js',
-            $resourcePath . 'gridfilters/filter/StringFilter.js',
-            $resourcePath . 'gridfilters/filter/DateFilter.js',
-            $resourcePath . 'gridfilters/filter/ListFilter.js',
-            $resourcePath . 'gridfilters/filter/NumericFilter.js',
-            $resourcePath . 'gridfilters/filter/BooleanFilter.js',
-            $resourcePath . 'gridfilters/filter/BooleanFilter.js',
-        );
-
-        $custom = $this->getAdditionalResourceService()->getJavaScriptResources();
-
-        $resources = array(
-            $resourcePath . 'Component/RowDetailTemplate.js',
-            $resourcePath . 'Component/RowExpander.js',
-            $resourcePath . 'Component/TabPanel.js',
-            $resourcePath . 'Store/mainstore.js',
-            $resourcePath . 'configuration.js',
-            $resourcePath . 'helpers.js',
-            $resourcePath . 'actions.js',
-            $resourcePath . 'component.js',
-            $resourcePath . 'toolbar.js',
-            $resourcePath . 'grid.js',
-            $resourcePath . 'workspaces.js'
-        );
-
-        $javaScriptFiles = array_merge($filters, $custom, $resources);
 
-        foreach ($javaScriptFiles as $javaScriptFile) {
-            $this->pageRenderer->addJsFile($javaScriptFile);
-        }
         foreach ($this->getAdditionalResourceService()->getLocalizationResources() as $localizationResource) {
             $this->pageRenderer->addInlineLanguageLabelFile($localizationResource);
         }
+        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Workspaces/Backend');
         $this->pageRenderer->addInlineSetting('FormEngine', 'moduleUrl', BackendUtility::getModuleUrl('record_edit'));
         $this->pageRenderer->addInlineSetting('RecordHistory', 'moduleUrl', BackendUtility::getModuleUrl('record_history'));
+        $this->pageRenderer->addInlineSetting('Workspaces', 'token', FormProtectionFactory::get('backend')->generateToken('extDirect'));
+        $this->pageRenderer->addInlineSetting('Workspaces', 'id', (int)GeneralUtility::_GP('id'));
     }
 
     /**
@@ -263,9 +238,10 @@ class ReviewController extends AbstractController
      *
      * @param array $workspaceList
      * @param int $activeWorkspace
+     * @param bool $showAllWorkspaceTab
      * @return array
      */
-    protected function prepareWorkspaceTabs(array $workspaceList, $activeWorkspace)
+    protected function prepareWorkspaceTabs(array $workspaceList, $activeWorkspace, $showAllWorkspaceTab = true)
     {
         $tabs = array();
 
@@ -278,12 +254,14 @@ class ReviewController extends AbstractController
             );
         }
 
-        $tabs[] = array(
-            'title' => 'All workspaces',
-            'itemId' => 'workspace-' . WorkspaceService::SELECT_ALL_WORKSPACES,
-            'workspaceId' => WorkspaceService::SELECT_ALL_WORKSPACES,
-            'triggerUrl' => $this->getModuleUri(WorkspaceService::SELECT_ALL_WORKSPACES),
-        );
+        if ($showAllWorkspaceTab) {
+            $tabs[] = array(
+                'title' => 'All workspaces',
+                'itemId' => 'workspace-' . WorkspaceService::SELECT_ALL_WORKSPACES,
+                'workspaceId' => WorkspaceService::SELECT_ALL_WORKSPACES,
+                'triggerUrl' => $this->getModuleUri(WorkspaceService::SELECT_ALL_WORKSPACES),
+            );
+        }
 
         foreach ($workspaceList as $workspaceId => $workspaceTitle) {
             if ($workspaceId === $activeWorkspace) {
@@ -328,4 +306,12 @@ class ReviewController extends AbstractController
     {
         return $GLOBALS['LANG'];
     }
+
+    /**
+     * @return BackendUserAuthentication
+     */
+    protected function getBackendUser()
+    {
+        return $GLOBALS['BE_USER'];
+    }
 }
diff --git a/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php b/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php
index 4a880625204b..9d1f0a95fd8c 100644
--- a/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php
+++ b/typo3/sysext/workspaces/Classes/ExtDirect/ActionHandler.php
@@ -15,10 +15,13 @@ namespace TYPO3\CMS\Workspaces\ExtDirect;
  */
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\View\StandaloneView;
 use TYPO3\CMS\Workspaces\Domain\Record\StageRecord;
 use TYPO3\CMS\Workspaces\Domain\Record\WorkspaceRecord;
 use TYPO3\CMS\Workspaces\Service\StagesService;
+use TYPO3\CMS\Workspaces\Service\WorkspaceService;
 
 /**
  * ExtDirect action handler
@@ -35,7 +38,7 @@ class ActionHandler extends AbstractHandler
      */
     public function __construct()
     {
-        $this->stageService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class);
+        $this->stageService = GeneralUtility::makeInstance(StagesService::class);
     }
 
     /**
@@ -114,7 +117,7 @@ class ActionHandler extends AbstractHandler
      */
     public function viewSingleRecord($table, $uid)
     {
-        return \TYPO3\CMS\Workspaces\Service\WorkspaceService::viewSingleRecord($table, $uid);
+        return WorkspaceService::viewSingleRecord($table, $uid);
     }
 
     /**
@@ -410,10 +413,10 @@ class ActionHandler extends AbstractHandler
     public function discardStagesFromPage($pageId)
     {
         $cmdMapArray = array();
-        /** @var $workspaceService \TYPO3\CMS\Workspaces\Service\WorkspaceService */
-        $workspaceService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        /** @var $workspaceService WorkspaceService */
+        $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
         /** @var $stageService StagesService */
-        $stageService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class);
+        $stageService = GeneralUtility::makeInstance(StagesService::class);
         $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $pageId, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
         foreach ($workspaceItemsArray as $tableName => $items) {
             foreach ($items as $item) {
@@ -437,7 +440,7 @@ class ActionHandler extends AbstractHandler
      * $parameters->stageId
      * </code>
      *
-     * @param stdClass $parameters
+     * @param \stdClass $parameters
      * @return array
      */
     public function sentCollectionToStage(\stdClass $parameters)
@@ -451,7 +454,7 @@ class ActionHandler extends AbstractHandler
         if (!is_object($parameters->affects) || empty($parameters->affects)) {
             throw new \InvalidArgumentException('Missing "affected items" in $parameters array.', 1319488195);
         }
-        $recipients = $this->getRecipientList($parameters->receipients, $parameters->additional, $stageId);
+        $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $stageId);
         foreach ($parameters->affects as $tableName => $items) {
             foreach ($items as $item) {
                 // Publishing uses live id in command map
@@ -516,7 +519,7 @@ class ActionHandler extends AbstractHandler
      * additional: string
      * comments: string
      *
-     * @param stdClass $parameters
+     * @param \stdClass $parameters
      * @return array
      */
     public function sendToNextStageExecute(\stdClass $parameters)
@@ -531,7 +534,7 @@ class ActionHandler extends AbstractHandler
         $elementRecord = BackendUtility::getRecord($table, $uid);
         $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
 
-        $recipients = $this->getRecipientList($parameters->receipients, $parameters->additional, $setStageId);
+        $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
         if ($setStageId == StagesService::STAGE_PUBLISH_EXECUTE_ID) {
             $cmdArray[$table][$t3ver_oid]['version']['action'] = 'swap';
             $cmdArray[$table][$t3ver_oid]['version']['swapWith'] = $uid;
@@ -563,7 +566,7 @@ class ActionHandler extends AbstractHandler
      * additional: string
      * comments: string
      *
-     * @param stdClass $parameters
+     * @param \stdClass $parameters
      * @return array
      */
     public function sendToPrevStageExecute(\stdClass $parameters)
@@ -577,7 +580,7 @@ class ActionHandler extends AbstractHandler
         $elementRecord = BackendUtility::getRecord($table, $uid);
         $currentWorkspace = $this->setTemporaryWorkspace($elementRecord['t3ver_wsid']);
 
-        $recipients = $this->getRecipientList($parameters->receipients, $parameters->additional, $setStageId);
+        $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
         $cmdArray[$table][$uid]['version']['action'] = 'setStage';
         $cmdArray[$table][$uid]['version']['stageId'] = $setStageId;
         $cmdArray[$table][$uid]['version']['comment'] = $comments;
@@ -618,7 +621,7 @@ class ActionHandler extends AbstractHandler
         $setStageId = $parameters->affects->nextStage;
         $comments = $parameters->comments;
         $elements = $parameters->affects->elements;
-        $recipients = $this->getRecipientList($parameters->receipients, $parameters->additional, $setStageId);
+        $recipients = $this->getRecipientList((array)$parameters->recipients, $parameters->additional, $setStageId);
         foreach ($elements as $element) {
             // Avoid any action on records that have already been published to live
             $elementRecord = BackendUtility::getRecord($element->table, $element->uid);
@@ -648,7 +651,7 @@ class ActionHandler extends AbstractHandler
     /**
      * Gets the dialog window to be displayed before a record can be sent to a stage.
      *
-     * @param StageRecord|int $nextStageId
+     * @param StageRecord|int $nextStage
      * @return array
      */
     protected function getSentToStageWindow($nextStage)
@@ -657,43 +660,18 @@ class ActionHandler extends AbstractHandler
             $nextStage = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($nextStage);
         }
 
-        $result = array(
-            'title' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:actionSendToStage'),
-            'items' => array(
-                array(
-                    'xtype' => 'panel',
-                    'bodyStyle' => 'margin-bottom: 7px; border: none;',
-                    'html' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:window.sendToNextStageWindow.itemsWillBeSentTo') . ' ' . $nextStage->getTitle()
-                )
-            )
-        );
-
+        $result = [];
         if ($nextStage->isDialogEnabled()) {
-            $result['items'][] = array(
-                'fieldLabel' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:window.sendToNextStageWindow.sendMailTo'),
-                'xtype' => 'checkboxgroup',
-                'itemCls' => 'x-check-group-alt',
-                'columns' => 1,
-                'style' => 'max-height: 200px',
-                'autoScroll' => true,
-                'items' => array(
-                    $this->getReceipientsOfStage($nextStage->getUid())
-                )
-            );
-            $result['items'][] = array(
-                'fieldLabel' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:window.sendToNextStageWindow.additionalRecipients'),
-                'name' => 'additional',
-                'xtype' => 'textarea',
-                'width' => 250
-            );
+            $result['sendMailTo'] = $this->getRecipientsOfStage($nextStage->getUid());
+            $result['additional'] = [
+                'type' => 'textarea',
+                'value' => ''
+            ];
         }
-        $result['items'][] = array(
-            'fieldLabel' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:window.sendToNextStageWindow.comments'),
-            'name' => 'comments',
-            'xtype' => 'textarea',
-            'width' => 250,
+        $result['comments'] = [
+            'type' => 'textarea',
             'value' => ($nextStage->isInternal() ? '' : $nextStage->getDefaultComment())
-        );
+        ];
 
         return $result;
     }
@@ -704,7 +682,7 @@ class ActionHandler extends AbstractHandler
      * @param StageRecord|int $stageRecord
      * @return array
      */
-    protected function getReceipientsOfStage($stageRecord)
+    protected function getRecipientsOfStage($stageRecord)
     {
         if (!$stageRecord instanceof StageRecord) {
             $stageRecord = WorkspaceRecord::get($this->getCurrentWorkspace())->getStage($stageRecord);
@@ -725,8 +703,9 @@ class ActionHandler extends AbstractHandler
             $disabled = ($checked && !$isPreselectionChangeable);
 
             $result[] = array(
-                'boxLabel' => sprintf('%s (%s)', $name, $backendUser['email']),
-                'name' => 'receipients-' . $backendUserId,
+                'label' => sprintf('%s (%s)', $name, $backendUser['email']),
+                'value' => $backendUserId,
+                'name' => 'recipients-' . $backendUserId,
                 'checked' => $checked,
                 'disabled' => $disabled
             );
@@ -755,7 +734,7 @@ class ActionHandler extends AbstractHandler
     protected function getStageService()
     {
         if (!isset($this->stageService)) {
-            $this->stageService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class);
+            $this->stageService = GeneralUtility::makeInstance(StagesService::class);
         }
         return $this->stageService;
     }
@@ -768,17 +747,19 @@ class ActionHandler extends AbstractHandler
      */
     public function sendPageToPreviousStage($id)
     {
-        $workspaceService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
         $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
         list($currentStage, $previousStage) = $this->getStageService()->getPreviousStageForElementCollection($workspaceItemsArray);
         // get only the relevant items for processing
         $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), $currentStage['uid'], $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
-        return array(
+        $stageFormFields = $this->getSentToStageWindow($previousStage['uid']);
+        $result = array_merge($stageFormFields, [
             'title' => 'Status message: Page send to next stage - ID: ' . $id . ' - Next stage title: ' . $previousStage['title'],
             'items' => $this->getSentToStageWindow($previousStage['uid']),
             'affects' => $workspaceItemsArray,
             'stageId' => $previousStage['uid']
-        );
+        ]);
+        return $result;
     }
 
     /**
@@ -787,48 +768,55 @@ class ActionHandler extends AbstractHandler
      */
     public function sendPageToNextStage($id)
     {
-        $workspaceService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
         $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
         list($currentStage, $nextStage) = $this->getStageService()->getNextStageForElementCollection($workspaceItemsArray);
         // get only the relevant items for processing
         $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($this->stageService->getWorkspaceId(), ($filter = 1), $currentStage['uid'], $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
-        return array(
+        $stageFormFields = $this->getSentToStageWindow($nextStage['uid']);
+        $result = array_merge($stageFormFields, [
             'title' => 'Status message: Page send to next stage - ID: ' . $id . ' - Next stage title: ' . $nextStage['title'],
-            'items' => $this->getSentToStageWindow($nextStage['uid']),
             'affects' => $workspaceItemsArray,
             'stageId' => $nextStage['uid']
-        );
+        ]);
+        return $result;
     }
 
     /**
      * Fetch the current label and visible state of the buttons.
      *
      * @param int $id
-     * @return array Contains the visibility state and label of the stage change buttons.
+     * @return string The pre-rendered HTML for the stage buttons
      */
     public function updateStageChangeButtons($id)
     {
-        $stageService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class);
-        $workspaceService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\WorkspaceService::class);
+        /** @var StagesService $stageService */
+        $stageService = GeneralUtility::makeInstance(StagesService::class);
+        /** @var WorkspaceService $workspaceService */
+        $workspaceService = GeneralUtility::makeInstance(WorkspaceService::class);
         // fetch the next and previous stage
         $workspaceItemsArray = $workspaceService->selectVersionsInWorkspace($stageService->getWorkspaceId(), ($filter = 1), ($stage = -99), $id, ($recursionLevel = 0), ($selectionType = 'tables_modify'));
         list(, $nextStage) = $stageService->getNextStageForElementCollection($workspaceItemsArray);
         list(, $previousStage) = $stageService->getPreviousStageForElementCollection($workspaceItemsArray);
-        $toolbarButtons = array(
-            'feToolbarButtonNextStage' => array(
-                'visible' => is_array($nextStage) && !empty($nextStage),
-                'text' => $nextStage['title']
-            ),
-            'feToolbarButtonPreviousStage' => array(
-                'visible' => is_array($previousStage) && !empty($previousStage),
-                'text' => $previousStage['title']
-            ),
-            'feToolbarButtonDiscardStage' => array(
-                'visible' => is_array($nextStage) && !empty($nextStage) || is_array($previousStage) && !empty($previousStage),
-                'text' => $GLOBALS['LANG']->sL('LLL:EXT:workspaces/Resources/Private/Language/locallang.xlf:label_doaction_discard', true)
-            )
-        );
-        return $toolbarButtons;
+
+        /** @var StandaloneView $view */
+        $view = GeneralUtility::makeInstance(StandaloneView::class);
+        $extensionPath = ExtensionManagementUtility::extPath('workspaces');
+        $view->setPartialRootPaths(['default' => $extensionPath . 'Resources/Private/Partials']);
+        $view->setTemplatePathAndFilename($extensionPath . 'Resources/Private/Templates/Preview/Ajax/StageButtons.html');
+        $request = $view->getRequest();
+        $request->setControllerExtensionName('workspaces');
+        $view->assignMultiple([
+            'enablePreviousStageButton' => is_array($previousStage) && !empty($previousStage),
+            'enableNextStageButton' => is_array($nextStage) && !empty($nextStage),
+            'enableDiscardStageButton' => is_array($nextStage) && !empty($nextStage) || is_array($previousStage) && !empty($previousStage),
+            'nextStage' => $nextStage['title'],
+            'nextStageId' => $nextStage['uid'],
+            'prevStage' => $previousStage['title'],
+            'prevStageId' => $previousStage['uid'],
+        ]);
+        $renderedView = $view->render();
+        return $renderedView;
     }
 
     /**
diff --git a/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php b/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php
index edcb1279f1be..dde139e87964 100644
--- a/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php
+++ b/typo3/sysext/workspaces/Classes/ExtDirect/ExtDirectServer.php
@@ -14,12 +14,25 @@ namespace TYPO3\CMS\Workspaces\ExtDirect;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Backend\Avatar\Avatar;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Database\DatabaseConnection;
+use TYPO3\CMS\Core\Html\RteHtmlParser;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Resource\FileReference;
+use TYPO3\CMS\Core\Resource\ProcessedFile;
+use TYPO3\CMS\Core\Utility\DiffUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
+use TYPO3\CMS\Lang\LanguageService;
+use TYPO3\CMS\Workspaces\Service\GridDataService;
+use TYPO3\CMS\Workspaces\Service\HistoryService;
+use TYPO3\CMS\Workspaces\Service\StagesService;
+use TYPO3\CMS\Workspaces\Service\WorkspaceService;
 
 /**
  * ExtDirect server
@@ -27,17 +40,17 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
 class ExtDirectServer extends AbstractHandler
 {
     /**
-     * @var \TYPO3\CMS\Workspaces\Service\GridDataService
+     * @var GridDataService
      */
     protected $gridDataService;
 
     /**
-     * @var \TYPO3\CMS\Workspaces\Service\StagesService
+     * @var StagesService
      */
     protected $stagesService;
 
     /**
-     * @var \cogpowered\FineDiff\Diff
+     * @var DiffUtility
      */
     protected $differenceHandler;
 
@@ -67,7 +80,7 @@ class ExtDirectServer extends AbstractHandler
     {
         // To avoid too much work we use -1 to indicate that every page is relevant
         $pageId = $parameter->id > 0 ? $parameter->id : -1;
-        if (!isset($parameter->language) || !\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($parameter->language)) {
+        if (!isset($parameter->language) || !MathUtility::canBeInterpretedAsInteger($parameter->language)) {
             $parameter->language = null;
         }
         $versions = $this->getWorkspaceService()->selectVersionsInWorkspace($this->getCurrentWorkspace(), 0, -99, $pageId, $parameter->depth, 'tables_select', $parameter->language);
@@ -75,23 +88,6 @@ class ExtDirectServer extends AbstractHandler
         return $data;
     }
 
-    /**
-     * Gets the editing history of a record.
-     *
-     * @param stdClass $parameters
-     * @return array
-     */
-    public function getHistory($parameters)
-    {
-        /** @var $historyService \TYPO3\CMS\Workspaces\Service\HistoryService */
-        $historyService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\HistoryService::class);
-        $history = $historyService->getHistory($parameters->table, $parameters->liveId);
-        return array(
-            'data' => $history,
-            'total' => count($history)
-        );
-    }
-
     /**
      * Get List of available workspace actions
      *
@@ -102,7 +98,7 @@ class ExtDirectServer extends AbstractHandler
     {
         $currentWorkspace = $this->getCurrentWorkspace();
         $stages = array();
-        if ($currentWorkspace != \TYPO3\CMS\Workspaces\Service\WorkspaceService::SELECT_ALL_WORKSPACES) {
+        if ($currentWorkspace != WorkspaceService::SELECT_ALL_WORKSPACES) {
             $stages = $this->getStagesService()->getStagesForWSUser();
         }
         $data = array(
@@ -122,16 +118,16 @@ class ExtDirectServer extends AbstractHandler
     {
         $diffReturnArray = array();
         $liveReturnArray = array();
-        /** @var $diffUtility \TYPO3\CMS\Core\Utility\DiffUtility */
-        $diffUtility = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Utility\DiffUtility::class);
-        /** @var $parseObj \TYPO3\CMS\Core\Html\RteHtmlParser */
-        $parseObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Html\RteHtmlParser::class);
+        $diffUtility = $this->getDifferenceHandler();
+        /** @var $parseObj RteHtmlParser */
+        $parseObj = GeneralUtility::makeInstance(RteHtmlParser::class);
         $liveRecord = BackendUtility::getRecord($parameter->table, $parameter->t3ver_oid);
         $versionRecord = BackendUtility::getRecord($parameter->table, $parameter->uid);
         $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
         $icon_Live = $iconFactory->getIconForRecord($parameter->table, $liveRecord, Icon::SIZE_SMALL)->render();
         $icon_Workspace = $iconFactory->getIconForRecord($parameter->table, $versionRecord, Icon::SIZE_SMALL)->render();
-        $stagePosition = $this->getStagesService()->getPositionOfCurrentStage($parameter->stage);
+        $stagesService = $this->getStagesService();
+        $stagePosition = $stagesService->getPositionOfCurrentStage($parameter->stage);
         $fieldsOfRecords = array_keys($liveRecord);
         if ($GLOBALS['TCA'][$parameter->table]) {
             if ($GLOBALS['TCA'][$parameter->table]['interface']['showRecordFieldList']) {
@@ -144,14 +140,14 @@ class ExtDirectServer extends AbstractHandler
                 continue;
             }
             // Get the field's label. If not available, use the field name
-            $fieldTitle = $GLOBALS['LANG']->sL(BackendUtility::getItemLabel($parameter->table, $fieldName));
+            $fieldTitle = $this->getLanguageService()->sL(BackendUtility::getItemLabel($parameter->table, $fieldName));
             if (empty($fieldTitle)) {
                 $fieldTitle = $fieldName;
             }
             // Gets the TCA configuration for the current field
             $configuration = $GLOBALS['TCA'][$parameter->table]['columns'][$fieldName]['config'];
             // check for exclude fields
-            if ($GLOBALS['BE_USER']->isAdmin() || $GLOBALS['TCA'][$parameter->table]['columns'][$fieldName]['exclude'] == 0 || GeneralUtility::inList($GLOBALS['BE_USER']->groupData['non_exclude_fields'], $parameter->table . ':' . $fieldName)) {
+            if ($this->getBackendUser()->isAdmin() || $GLOBALS['TCA'][$parameter->table]['columns'][$fieldName]['exclude'] == 0 || GeneralUtility::inList($this->getBackendUser()->groupData['non_exclude_fields'], $parameter->table . ':' . $fieldName)) {
                 // call diff class only if there is a difference
                 if ($configuration['type'] === 'inline' && $configuration['foreign_table'] === 'sys_file_reference') {
                     $useThumbnails = false;
@@ -216,8 +212,8 @@ class ExtDirectServer extends AbstractHandler
                     );
 
                     if ($configuration['type'] == 'group' && $configuration['internal_type'] == 'file') {
-                        $versionThumb = BackendUtility::thumbCode($versionRecord, $parameter->table, $fieldName);
-                        $liveThumb = BackendUtility::thumbCode($liveRecord, $parameter->table, $fieldName);
+                        $versionThumb = BackendUtility::thumbCode($versionRecord, $parameter->table, $fieldName, '');
+                        $liveThumb = BackendUtility::thumbCode($liveRecord, $parameter->table, $fieldName, '');
                         $diffReturnArray[] = array(
                             'field' => $fieldName,
                             'label' => $fieldTitle,
@@ -254,6 +250,22 @@ class ExtDirectServer extends AbstractHandler
             }
         }
         $commentsForRecord = $this->getCommentsForRecord($parameter->uid, $parameter->table);
+
+        /** @var $historyService HistoryService */
+        $historyService = GeneralUtility::makeInstance(HistoryService::class);
+        $history = $historyService->getHistory($parameter->table, $parameter->t3ver_oid);
+
+        $prevStage = $stagesService->getPrevStage($parameter->stage);
+        $nextStage = $stagesService->getNextStage($parameter->stage);
+
+        if (isset($prevStage[0])) {
+            $prevStage = current($prevStage);
+        }
+
+        if (isset($nextStage[0])) {
+            $nextStage = current($nextStage);
+        }
+
         return array(
             'total' => 1,
             'data' => array(
@@ -265,11 +277,21 @@ class ExtDirectServer extends AbstractHandler
                     'icon_Workspace' => $icon_Workspace,
                     // this part is already escaped in getCommentsForRecord()
                     'comments' => $commentsForRecord,
-                    // escape/santinize the others
-                    'path_Live' => htmlspecialchars($parameter->path_Live),
-                    'label_Stage' => htmlspecialchars($parameter->label_Stage),
+                    // escape/sanitize the others
+                    'path_Live' => htmlspecialchars(BackendUtility::getRecordPath($liveRecord['pid'], '', 999)),
+                    'label_Stage' => htmlspecialchars($stagesService->getStageTitle($parameter->stage)),
+                    'label_PrevStage' => $prevStage,
+                    'label_NextStage' => $nextStage,
                     'stage_position' => (int)$stagePosition['position'],
-                    'stage_count' => (int)$stagePosition['count']
+                    'stage_count' => (int)$stagePosition['count'],
+                    'parent' => [
+                        'table' => htmlspecialchars($parameter->table),
+                        'uid' => (int)$parameter->uid
+                    ],
+                    'history' => [
+                        'data' => $history,
+                        'total' => count($history)
+                    ]
                 )
             )
         );
@@ -323,7 +345,7 @@ class ExtDirectServer extends AbstractHandler
         foreach ($candidates as $identifierWithRandomValue => $fileReference) {
             if ($useThumbnails) {
                 $thumbnailFile = $fileReference->getOriginalFile()->process(
-                    \TYPO3\CMS\Core\Resource\ProcessedFile::CONTEXT_IMAGEPREVIEW,
+                    ProcessedFile::CONTEXT_IMAGEPREVIEW,
                     array('width' => 40, 'height' => 40)
                 );
                 $thumbnailMarkup = '<img src="' . $thumbnailFile->getPublicUrl(true) . '" />';
@@ -333,7 +355,7 @@ class ExtDirectServer extends AbstractHandler
             }
         }
 
-        $differences = $this->getDifferenceHandler()->render($liveInformation, $versionInformation);
+        $differences = $this->getDifferenceHandler()->makeDiffDisplay($liveInformation, $versionInformation);
         $liveInformation = str_replace(array_keys($substitutes), array_values($substitutes), trim($liveInformation));
         $differences = str_replace(array_keys($substitutes), array_values($substitutes), trim($differences));
 
@@ -353,14 +375,18 @@ class ExtDirectServer extends AbstractHandler
     public function getCommentsForRecord($uid, $table)
     {
         $sysLogReturnArray = array();
-        $sysLogRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+        $sysLogRows = $this->getDatabaseConnection()->exec_SELECTgetRows(
             'log_data,tstamp,userid',
             'sys_log',
-            'action=6 and details_nr=30 AND tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_log')
+            'action=6 and details_nr=30 AND tablename=' . $this->getDatabaseConnection()->fullQuoteStr($table, 'sys_log')
                 . ' AND recuid=' . (int)$uid,
             '',
             'tstamp DESC'
         );
+
+        /** @var Avatar $avatar */
+        $avatar = GeneralUtility::makeInstance(Avatar::class);
+
         foreach ($sysLogRows as $sysLogRow) {
             $sysLogEntry = array();
             $data = unserialize($sysLogRow['log_data']);
@@ -370,6 +396,7 @@ class ExtDirectServer extends AbstractHandler
             $sysLogEntry['user_username'] = is_array($beUserRecord) ? htmlspecialchars($beUserRecord['username']) : '';
             $sysLogEntry['tstamp'] = htmlspecialchars(BackendUtility::datetime($sysLogRow['tstamp']));
             $sysLogEntry['user_comment'] = nl2br(htmlspecialchars($data['comment']));
+            $sysLogEntry['user_avatar'] = $avatar->render($beUserRecord);
             $sysLogReturnArray[] = $sysLogEntry;
         }
         return $sysLogReturnArray;
@@ -386,7 +413,7 @@ class ExtDirectServer extends AbstractHandler
         $systemLanguages = array(
             array(
                 'uid' => 'all',
-                'title' => \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('language.allLanguages', 'workspaces'),
+                'title' => LocalizationUtility::translate('language.allLanguages', 'workspaces'),
                 'icon' => $iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render()
             )
         );
@@ -407,15 +434,39 @@ class ExtDirectServer extends AbstractHandler
         return $result;
     }
 
+    /**
+     * @return BackendUserAuthentication;
+     */
+    protected function getBackendUser()
+    {
+        return $GLOBALS['BE_USER'];
+    }
+
+    /**
+     * @return LanguageService;
+     */
+    protected function getLanguageService()
+    {
+        return $GLOBALS['LANG'];
+    }
+
+    /**
+     * @return DatabaseConnection;
+     */
+    protected function getDatabaseConnection()
+    {
+        return $GLOBALS['TYPO3_DB'];
+    }
+
     /**
      * Gets the Grid Data Service.
      *
-     * @return \TYPO3\CMS\Workspaces\Service\GridDataService
+     * @return GridDataService
      */
     protected function getGridDataService()
     {
         if (!isset($this->gridDataService)) {
-            $this->gridDataService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\GridDataService::class);
+            $this->gridDataService = GeneralUtility::makeInstance(GridDataService::class);
         }
         return $this->gridDataService;
     }
@@ -423,12 +474,12 @@ class ExtDirectServer extends AbstractHandler
     /**
      * Gets the Stages Service.
      *
-     * @return \TYPO3\CMS\Workspaces\Service\StagesService
+     * @return StagesService
      */
     protected function getStagesService()
     {
         if (!isset($this->stagesService)) {
-            $this->stagesService = GeneralUtility::makeInstance(\TYPO3\CMS\Workspaces\Service\StagesService::class);
+            $this->stagesService = GeneralUtility::makeInstance(StagesService::class);
         }
         return $this->stagesService;
     }
@@ -436,13 +487,12 @@ class ExtDirectServer extends AbstractHandler
     /**
      * Gets the difference handler, parsing differences based on sentences.
      *
-     * @return \cogpowered\FineDiff\Diff
+     * @return DiffUtility
      */
     protected function getDifferenceHandler()
     {
         if (!isset($this->differenceHandler)) {
-            $granularity = new \cogpowered\FineDiff\Granularity\Word();
-            $this->differenceHandler = new \cogpowered\FineDiff\Diff($granularity);
+            $this->differenceHandler = GeneralUtility::makeInstance(DiffUtility::class);
         }
         return $this->differenceHandler;
     }
diff --git a/typo3/sysext/workspaces/Classes/Service/GridDataService.php b/typo3/sysext/workspaces/Classes/Service/GridDataService.php
index 8edebad40099..bec3887ab855 100644
--- a/typo3/sysext/workspaces/Classes/Service/GridDataService.php
+++ b/typo3/sysext/workspaces/Classes/Service/GridDataService.php
@@ -163,8 +163,10 @@ class GridDataService
                     $versionArray['label_Stage'] = htmlspecialchars($stagesObj->getStageTitle($versionRecord['t3ver_stage']));
                     $tempStage = $stagesObj->getNextStage($versionRecord['t3ver_stage']);
                     $versionArray['label_nextStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
+                    $versionArray['value_nextStage'] = (int)$tempStage['uid'];
                     $tempStage = $stagesObj->getPrevStage($versionRecord['t3ver_stage']);
                     $versionArray['label_prevStage'] = htmlspecialchars($stagesObj->getStageTitle($tempStage['uid']));
+                    $versionArray['value_prevStage'] = (int)$tempStage['uid'];
                     $versionArray['path_Live'] = htmlspecialchars(BackendUtility::getRecordPath($record['livepid'], '', 999));
                     $versionArray['path_Workspace'] = htmlspecialchars(BackendUtility::getRecordPath($record['wspid'], '', 999));
                     $versionArray['workspace_Title'] = htmlspecialchars(\TYPO3\CMS\Workspaces\Service\WorkspaceService::getWorkspaceTitle($versionRecord['t3ver_wsid']));
diff --git a/typo3/sysext/workspaces/Classes/Service/HistoryService.php b/typo3/sysext/workspaces/Classes/Service/HistoryService.php
index c872bb6489b3..4483a6d2d754 100644
--- a/typo3/sysext/workspaces/Classes/Service/HistoryService.php
+++ b/typo3/sysext/workspaces/Classes/Service/HistoryService.php
@@ -14,7 +14,9 @@ namespace TYPO3\CMS\Workspaces\Service;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Backend\Backend\Avatar\Avatar;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Service for history
@@ -79,9 +81,15 @@ class HistoryService implements \TYPO3\CMS\Core\SingletonInterface
         } else {
             $differences = $this->getDifferences($entry);
         }
+
+        /** @var Avatar $avatar */
+        $avatar = GeneralUtility::makeInstance(Avatar::class);
+        $beUserRecord = BackendUtility::getRecord('be_users', $entry['user']);
+
         return array(
             'datetime' => htmlspecialchars(BackendUtility::datetime($entry['tstamp'])),
             'user' => htmlspecialchars($this->getUserName($entry['user'])),
+            'user_avatar' => $avatar->render($beUserRecord),
             'differences' => $differences
         );
     }
diff --git a/typo3/sysext/workspaces/Classes/Service/StagesService.php b/typo3/sysext/workspaces/Classes/Service/StagesService.php
index f54579bc283c..7c95c511bede 100644
--- a/typo3/sysext/workspaces/Classes/Service/StagesService.php
+++ b/typo3/sysext/workspaces/Classes/Service/StagesService.php
@@ -318,7 +318,6 @@ class StagesService implements \TYPO3\CMS\Core\SingletonInterface
                 }
                 next($workspaceStageRecs);
             }
-        } else {
         }
         if ($nextStage === false) {
             $nextStage[] = array(
diff --git a/typo3/sysext/workspaces/Resources/Private/Language/locallang.xlf b/typo3/sysext/workspaces/Resources/Private/Language/locallang.xlf
index 45037ccf9dd1..c888fe656f17 100644
--- a/typo3/sysext/workspaces/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/workspaces/Resources/Private/Language/locallang.xlf
@@ -25,16 +25,19 @@
 				<source>Workspaces</source>
 			</trans-unit>
 			<trans-unit id="ok">
-				<source>ok</source>
+				<source>Ok</source>
 			</trans-unit>
 			<trans-unit id="cancel">
-				<source>cancel</source>
+				<source>Cancel</source>
 			</trans-unit>
 			<trans-unit id="chooseMassAction">
-				<source>choose Mass Action</source>
+				<source>Choose mass action</source>
+			</trans-unit>
+			<trans-unit id="chooseSelectionAction">
+				<source>Choose selection action</source>
 			</trans-unit>
 			<trans-unit id="chooseAction">
-				<source>choose Action</source>
+				<source>Choose staging action</source>
 			</trans-unit>
 			<trans-unit id="item">
 				<source>item</source>
@@ -97,6 +100,9 @@
 			<trans-unit id="tooltip.generatePagePreview">
 				<source>Generate page preview links</source>
 			</trans-unit>
+			<trans-unit id="tooltip.showChanges">
+				<source>Show changes</source>
+			</trans-unit>
 			<trans-unit id="previewLink">
 				<source>Preview Link</source>
 			</trans-unit>
@@ -125,23 +131,26 @@
 				<source>Changed</source>
 			</trans-unit>
 			<trans-unit id="column.uid">
-				<source>WS-Id</source>
+				<source>WS ID</source>
 			</trans-unit>
 			<trans-unit id="column.oid">
-				<source>Live-Id</source>
+				<source>Live ID</source>
 			</trans-unit>
 			<trans-unit id="column.workspaceName">
 				<source>Workspace</source>
 			</trans-unit>
 			<trans-unit id="column.livePath">
-				<source>Live-Path</source>
+				<source>Live path</source>
 			</trans-unit>
 			<trans-unit id="column.liveTitle">
-				<source>Live-Title</source>
+				<source>Live title</source>
 			</trans-unit>
 			<trans-unit id="column.wsSwapColumn">
 				<source>Swap workspace</source>
 			</trans-unit>
+			<trans-unit id="column.integrity">
+				<source>Integrity</source>
+			</trans-unit>
 			<trans-unit id="tooltip.viewElementAction">
 				<source>Preview element</source>
 			</trans-unit>
@@ -213,9 +222,30 @@
 			<trans-unit id="window.sendToNextStageWindow.additionalRecipients">
 				<source>Additional recipients</source>
 			</trans-unit>
+			<trans-unit id="window.sendToNextStageWindow.additionalRecipients.hint">
+				<source>One recipient per line</source>
+			</trans-unit>
 			<trans-unit id="window.sendToNextStageWindow.comments">
 				<source>Comments</source>
 			</trans-unit>
+			<trans-unit id="window.recordChanges">
+				<source>Record changes</source>
+			</trans-unit>
+			<trans-unit id="window.recordInformation">
+				<source>Information for "{0}"</source>
+			</trans-unit>
+			<trans-unit id="window.recordChanges.tabs.changeSummary">
+				<source>Summary of changes</source>
+			</trans-unit>
+			<trans-unit id="window.recordChanges.tabs.comments">
+				<source>Comments</source>
+			</trans-unit>
+			<trans-unit id="window.recordChanges.tabs.history">
+				<source>History</source>
+			</trans-unit>
+			<trans-unit id="window.recordHistory">
+				<source>History of record "{0}"</source>
+			</trans-unit>
 			<trans-unit id="error.getStageTitle.stageNotFound">
 				<source>Stage not found</source>
 			</trans-unit>
diff --git a/typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html b/typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html
new file mode 100644
index 000000000000..54d9aa0bb6bc
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Private/Layouts/Empty.html
@@ -0,0 +1 @@
+<f:render section="main" />
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Layouts/Module.html b/typo3/sysext/workspaces/Resources/Private/Layouts/Module.html
index d480d8d62d01..1cf117ca0350 100644
--- a/typo3/sysext/workspaces/Resources/Private/Layouts/Module.html
+++ b/typo3/sysext/workspaces/Resources/Private/Layouts/Module.html
@@ -1,4 +1,5 @@
 <f:if condition="{pageTitle}"><h1>{pageTitle}</h1></f:if>
-<div id="workspacetabs"></div>
-<div class="well well-sm"><f:render section="main" /></div>
+
+<f:render section="main" />
+
 <f:if condition="{showLegend}"><f:render partial="legend" /></f:if>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Layouts/Nodoc.html b/typo3/sysext/workspaces/Resources/Private/Layouts/Nodoc.html
index 18efefcd0bb6..71351b39fcaf 100644
--- a/typo3/sysext/workspaces/Resources/Private/Layouts/Nodoc.html
+++ b/typo3/sysext/workspaces/Resources/Private/Layouts/Nodoc.html
@@ -1,3 +1,12 @@
+<style type="text/css">
+	.module-body {
+		padding: 0;
+	}
+
+	div.typo3-noDoc {
+		margin: 0;
+	}
+</style>
 <div class="typo3-noDoc">
 	<!-- Content of module, for instance listing, info or editing -->
 	<div id="typo3-docbody">
diff --git a/typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html b/typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html
index f935b702f8c5..8b997bb89e17 100644
--- a/typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html
+++ b/typo3/sysext/workspaces/Resources/Private/Layouts/Popup.html
@@ -1,21 +1,4 @@
-<!-- ###FULLDOC### begin -->
 <f:render section="main" />
 <script type="text/javascript">
-	var liveUrl = '{liveUrl}';
-	var wsUrl = '{wsUrl}';
-	var wsSettingsUrl = '{wsSettingsUrl}';
 	document.domain = '{backendDomain}';
-
-	function resize(height) {
-			// poor way to avoid that we require any scrollbars within the frames
-		if (Ext.getCmp('wsContainer')) {
-			var currentHeight = isNaN(Ext.getCmp('wsContainer').getHeight()) ? 0 : Ext.getCmp('wsContainer').getHeight();
-			var finalHeight = Math.max(currentHeight, height * 1.1);
-			Ext.getCmp('visualPanel').setHeight(finalHeight);
-			Ext.getCmp('wsContainer').setHeight(finalHeight);
-			Ext.getCmp('wsPanel').setHeight(finalHeight);
-			Ext.getCmp('liveContainer').setHeight(finalHeight * (100 - Ext.getCmp('sizeSlider').getValue()) / 100);
-			Ext.getCmp('livePanel').setHeight(finalHeight);
-		}
-	}
 </script>
diff --git a/typo3/sysext/workspaces/Resources/Private/Less/preview.less b/typo3/sysext/workspaces/Resources/Private/Less/preview.less
new file mode 100644
index 000000000000..a10257abb866
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Private/Less/preview.less
@@ -0,0 +1,69 @@
+.module-body {
+	padding: 0;
+}
+
+.typo3-topbar-workspace-actions {
+	float: right;
+	height: 100%;
+	display: table;
+}
+
+.workspace-action {
+	display: table-cell;
+	vertical-align: middle;
+	padding: 0 4px;
+
+	&:last-child {
+		padding-right: 16px;
+	}
+
+	.active-preview-mode {
+		display: inline-block;
+		text-align: left;
+	}
+
+	.slider-wrapper {
+		.slider {
+			float: left;
+		}
+
+		b {
+			margin: 7px 10px;
+			display: block;
+			float: left;
+		}
+	}
+}
+
+.workspaces {
+	position: relative;
+
+	iframe {
+		border: 0;
+	}
+}
+
+.preview-mode- {
+	&slider {
+		iframe {
+			position: absolute;
+			top: 0;
+			z-index: 100;
+		}
+		#live-view {
+			border-bottom: 2px solid #c83c3c;
+			z-index: 200;
+		}
+	}
+
+	&vbox iframe {
+		width: 50%;
+		height: 100%;
+		float: left;
+	}
+
+	&hbox iframe {
+		width: 100%;
+		height: 50%;
+	}
+}
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html b/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html
index 9accc01b9e8a..fa91e9df808f 100644
--- a/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html
+++ b/typo3/sysext/workspaces/Resources/Private/Partials/Legend.html
@@ -1,3 +1,4 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <dl class="legend">
 	<dt><f:translate key="legend.label" /></dt>
 	<dd><span class="item-state-modified"><f:translate key="legend.edited" /></span>&nbsp;&nbsp;&bull;&nbsp;</dd>
@@ -5,4 +6,5 @@
 	<dd><span class="item-state-new"><f:translate key="legend.new" /></span>&nbsp;&nbsp;&bull;&nbsp;</dd>
 	<dd><span  class="item-state-hidden"><f:translate key="legend.hidden" /></span>&nbsp;&nbsp;&bull;&nbsp;</dd>
 	<dd><span class="item-state-deleted"><f:translate key="legend.deleted" /></span></dd>
-</dl>
\ No newline at end of file
+</dl>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Partials/Navigation.html b/typo3/sysext/workspaces/Resources/Private/Partials/Navigation.html
index d7af39211429..cbc66a954812 100644
--- a/typo3/sysext/workspaces/Resources/Private/Partials/Navigation.html
+++ b/typo3/sysext/workspaces/Resources/Private/Partials/Navigation.html
@@ -1,3 +1,4 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <ul class="x-tab-strip x-tab-strip-top">
 	<f:for each="{workspaceList}" as="workspace" key="uid">
 		<f:if condition="{uid}=={activeWorkspaceUid}">
@@ -32,3 +33,4 @@
 	</f:if>
 	<div class="x-clear"></div>
  </ul>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html b/typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html
new file mode 100644
index 000000000000..5f74f59d2e44
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Private/Partials/Preview/StageButtons.html
@@ -0,0 +1,11 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
+<f:if condition="{enablePreviousStageButton}">
+	<input type="button" class="btn btn-sm btn-default" value="{prevStage}" data-stage-id="{prevStageId}" data-action="send-to-stage" data-direction="prev">
+</f:if>
+<f:if condition="{enableNextStageButton}">
+	<input type="button" class="btn btn-sm btn-success" value="{nextStage}" data-stage-id="{nextStageId}" data-action="send-to-stage" data-direction="next">
+</f:if>
+<f:if condition="{enableDiscardStageButton}">
+	<input type="button" class="btn btn-sm btn-danger" value="{f:translate(key: 'label_doaction_discard')}" data-action="discard">
+</f:if>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Partials/WorkingTable.html b/typo3/sysext/workspaces/Resources/Private/Partials/WorkingTable.html
new file mode 100644
index 000000000000..d8e0f00bfb3b
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Private/Partials/WorkingTable.html
@@ -0,0 +1,94 @@
+<html
+	xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
+	xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers"
+	data-namespace-typo3-fluid="true"
+>
+<div role="tabpanel">
+	<!-- Nav tabs -->
+	<ul class="nav nav-tabs" role="tablist">
+		<f:for each="{workspaceList}" as="workspace">
+			<li role="presentation" {f:if(condition: '{activeWorkspaceUid} == {workspace.workspaceId}', then: 'class="active"')}><a href="{workspace.triggerUrl}" aria-controls="{workspace.itemId}" role="tab">{workspace.title}</a></li>
+		</f:for>
+	</ul>
+
+	<!-- Tab panes -->
+	<div class="tab-content">
+		<div role="tabpanel" class="tab-pane active">
+			<div class="form-section" id="workspace-panel">
+				<form id="workspace-settings-form" class="form-inline form-inline-spaced">
+					<div class="form-group">
+						<select name="depth" class="form-control" disabled>
+							<option value="0"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.depth_0" /></option>
+							<option value="1"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.depth_1" /></option>
+							<option value="2"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.depth_2" /></option>
+							<option value="3"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.depth_3" /></option>
+							<option value="4"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.depth_4" /></option>
+							<option value="999"><f:translate key="LLL:EXT:lang/locallang_core.xlf:labels.depth_infi" /></option>
+						</select>
+					</div>
+					<div class="form-group">
+						<div class="input-group">
+							<span class="input-group-addon input-group-icon"></span>
+							<select name="languages" class="form-control" disabled></select>
+						</div>
+					</div>
+					<div class="form-group">
+						<div class="input-group">
+							<input class="form-control t3js-clearable" type="text" name="search-text">
+							<span class="input-group-btn">
+								<button type="submit" class="btn btn-default disabled"><core:icon identifier="actions-search" /></button>
+							</span>
+						</div>
+					</div>
+				</form>
+				<div class="hidden" id="workspace-action-icons">
+					<f:comment>We pre-render the required icons that are used in the Workspaces module until we're able to use StandaloneView of Fluid</f:comment>
+					<core:icon identifier="empty-empty" size="small" />
+					<core:icon identifier="actions-version-workspace-preview" size="small" />
+					<core:icon identifier="actions-version-document-remove" size="small" />
+					<core:icon identifier="actions-version-page-open" size="small" />
+					<core:icon identifier="actions-version-swap-version" size="small" />
+					<core:icon identifier="actions-open" size="small" />
+					<core:icon identifier="actions-document-info" size="small" />
+					<core:icon identifier="apps-pagetree-expand" size="small" />
+					<core:icon identifier="apps-pagetree-collapse" size="small" />
+				</div>
+				<table class="table table-striped">
+					<thead>
+					<tr>
+						<th><f:translate key="column.wsTitle" /></th>
+						<th><f:translate key="column.liveTitle" /></th>
+						<th><f:translate key="column.stage" /></th>
+						<th><f:translate key="column.integrity" /></th>
+						<th><core:icon identifier="flags-multiple" size="small" /></th>
+						<th class="text-right">
+							<button type="button" class="btn btn-default t3js-toggle-all"><span class="t3-icon fa fa-check-square-o"></span></button>
+						</th>
+					</tr>
+					</thead>
+					<tbody>
+					</tbody>
+				</table>
+				<form id="workspace-actions-form" class="form-inline form-inline-spaced">
+					<div class="form-group">
+						<select name="stage-action" class="form-control" disabled>
+							<option value=""><f:translate key="chooseAction" /></option>
+						</select>
+					</div>
+					<div class="form-group">
+						<select name="selection-action" class="form-control" disabled>
+							<option value=""><f:translate key="chooseSelectionAction" /></option>
+						</select>
+					</div>
+					<div class="form-group">
+						<select name="mass-action" class="form-control" disabled>
+							<option value=""><f:translate key="chooseMassAction" /></option>
+						</select>
+					</div>
+				</form>
+				<nav id="workspace-pagination"></nav>
+			</div>
+		</div>
+	</div>
+</div>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Ajax/StageButtons.html b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Ajax/StageButtons.html
new file mode 100644
index 000000000000..fac1cc3fceb6
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Ajax/StageButtons.html
@@ -0,0 +1,3 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
+<f:render partial="Preview/StageButtons" arguments="{_all}" />
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html
index 9b56cffcc2cc..1dd38b78d490 100644
--- a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Help.html
@@ -1,3 +1,5 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:layout name="nodoc" />
 
-<f:section name="main">Help contents - not yet defined</f:section>
\ No newline at end of file
+<f:section name="main">Help contents - not yet defined</f:section>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html
index 29d353410a5d..60a1162d17b3 100644
--- a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Index.html
@@ -1,3 +1,66 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:layout name="popup" />
 
-<f:section name="main"></f:section>
\ No newline at end of file
+<f:section name="main">
+	<div id="typo3-topbar">
+		<div class="typo3-topbar-container" role="navigation" id="typo3-top-container">
+			<div class="typo3-topbar-site">
+				<a class="typo3-topbar-site-logo" href="{logoLink}" target="_blank">
+					<img src="{logoUrl}" width="{logoWidth}" height="{logoHeight}" title="TYPO3 Content Management System" alt="">
+				</a>
+				<span class="typo3-topbar-site-name">{activeWorkspace}</span>
+			</div>
+			<div class="typo3-topbar-tabs t3js-workspace-tabs" style="float: left; height: 100%;">
+				<ul class="nav nav-tabs" role="tablist" style="position: absolute; bottom: 0">
+					<li role="presentation" class="active"><a href="#visual" aria-controls="visual" role="tab" data-toggle="tab" data-actions="true"><f:translate key="preview.visualPreview" /></a></li>
+					<li role="presentation"><a href="#list" aria-controls="list" role="tab" data-toggle="tab" data-actions="false"><f:translate key="preview.listView" /></a></li>
+				</ul>
+			</div>
+			<div class="typo3-topbar-workspace-actions t3js-workspace-actions">
+				<div class="workspace-action">
+					<div class="slider-wrapper">
+						<b>Live</b><div
+						id="workspace-stage-slider"
+						data-slider-min="0"
+						data-slider-max="100"
+						data-slider-value="100"
+						style="width: 150px;"
+					></div>
+						<b>Workspace</b>
+					</div>
+				</div>
+				<div class="workspace-action t3js-stage-buttons">
+					<f:render partial="Preview/StageButtons" arguments="{_all}"/>
+				</div>
+				<div class="workspace-action t3js-preview-mode">
+					<div class="btn-group">
+						<button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+							<span class="t3js-active-preview-mode active-preview-mode" data-active-preview-mode="{firstPreviewMode}"><f:translate key="preview.mode{firstPreviewMode -> f:format.case(mode: 'capital')}" /></span> <span class="caret"></span>
+						</button>
+						<ul class="dropdown-menu dropdown-menu-right">
+							<f:for each="{splitPreviewModes}" as="mode">
+								<li><a href="#" data-preview-mode="{mode}"><span><f:translate key="preview.mode{mode -> f:format.case(mode: 'capital')}" /></span></a></li>
+							</f:for>
+						</ul>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+
+	<div role="tabpanel" class="workspace-panel">
+		<div class="tab-content">
+			<div role="tabpanel" class="tab-pane active workspaces preview-mode-slider" id="visual">
+				<div class="t3js-workspace-preview">
+					<iframe src="{liveUrl}" style="height: 0px;" id="live-view"></iframe>
+					<iframe src="{wsUrl}" id="workspace-view"></iframe>
+				</div>
+			</div>
+			<div role="tabpanel" class="tab-pane workspaces" id="list">
+				<iframe src="{wsSettingsUrl}" id="workspace-list"></iframe>
+			</div>
+		</div>
+
+	</div>
+</f:section>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/NewPage.html b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/NewPage.html
index 41fac087cbf6..6207ef52ec84 100644
--- a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/NewPage.html
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/NewPage.html
@@ -1,3 +1,5 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:layout name="nodoc" />
 
 <f:section name="main"></f:section>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Preview.html b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Preview.html
index 2629a2a34034..0c16f8d5965c 100644
--- a/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Preview.html
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Preview/Preview.html
@@ -1,47 +1,4 @@
 <script type="text/javascript">
-
-		// @todo redirect to split module if this is opened standalone
-
-		// having this is very important, otherwise the parent.resize call will fail
+	// having this is very important, otherwise the parent.resize call will fail
 	document.domain = '{backendDomain}';
-
-	var asNumber = function(val) {
-		return isNaN(val) ? 0 : parseInt(val, 10);
-	};
-	var TYPO3 = TYPO3 || {};
-	TYPO3.ready = function () {
-		// make sure we're in the workspace preview module
-		if (typeof parent.resize == 'function') {
-				// try to find the height of the document
-			var docHeight = Math.max(
-				asNumber(window.innerHeight),
-				asNumber(document.height),
-				asNumber(document.body.scrollHeight),
-				asNumber(document.body.offsetHeight),
-				asNumber(document.body.clientHeight),
-				asNumber(document.documentElement.scrollHeight),
-				asNumber(document.documentElement.offsetHeight),
-				asNumber(document.documentElement.clientHeight)
-			);
-			parent.resize(docHeight);
-				// remove the ugly red box if we're in the ws-repview frames
-			var element = document.getElementById('typo3-previewInfo');
-			if (element) {
-				element.parentNode.removeChild(element);
-			}
-		}
-	};
-		// trigger this after content is loaded, inspired by jQuery
-	if (document.addEventListener && !/opera/.test(navigator.userAgent.toLowerCase())) {
-		document.addEventListener("DOMContentLoaded", TYPO3.ready, false);
-	} else {
-		(function() {
-			if (document.readyState != "loaded" && document.readyState != "complete") {
-				setTimeout(arguments.callee, 10);
-			} else {
-				TYPO3.ready();
-			}
-		})();
-	}
-
-</script>
+</script>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Review/FullIndex.html b/typo3/sysext/workspaces/Resources/Private/Templates/Review/FullIndex.html
index e80d90f926cf..8350fe2f258c 100644
--- a/typo3/sysext/workspaces/Resources/Private/Templates/Review/FullIndex.html
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Review/FullIndex.html
@@ -1,5 +1,9 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:layout name="module" />
 
 <f:section name="main">
-<div id="workspacegrid"></div>
-</f:section>
\ No newline at end of file
+
+	<f:render partial="WorkingTable" arguments="{_all}" />
+
+</f:section>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Review/Index.html b/typo3/sysext/workspaces/Resources/Private/Templates/Review/Index.html
index a151608a0538..07863b1fc2bb 100644
--- a/typo3/sysext/workspaces/Resources/Private/Templates/Review/Index.html
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Review/Index.html
@@ -1,18 +1,23 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:layout name="module" />
 
 <f:section name="main">
 
-<f:if condition="{performWorkspaceSwitch}">
-<script type="text/javascript">
-	top.TYPO3.ModuleMenu.App.refreshMenu();
-	top.TYPO3.WorkspacesMenu.performWorkspaceSwitch({activeWorkspaceUid}, "{activeWorkspaceTitle}");
-</script>
-</f:if>
+	<f:if condition="{performWorkspaceSwitch}">
+		<script type="text/javascript">
+			top.TYPO3.ModuleMenu.App.refreshMenu();
+			top.TYPO3.WorkspacesMenu.performWorkspaceSwitch({activeWorkspaceUid}, "{activeWorkspaceTitle}");
+		</script>
+	</f:if>
 
-<f:if condition="{showGrid}">
-	<f:then><div id="workspacegrid"></div>
-	</f:then>
-	<f:else><f:translate key="editorInLive" /></f:else>
-</f:if>
+	<f:if condition="{showGrid}">
+		<f:then>
+			<f:render partial="WorkingTable" arguments="{_all}" />
+		</f:then>
+		<f:else>
+			<f:be.infobox message="{f:translate(key: 'editorInLive')}" state="-1" />
+		</f:else>
+	</f:if>
 
-</f:section>
\ No newline at end of file
+</f:section>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Private/Templates/Review/SingleIndex.html b/typo3/sysext/workspaces/Resources/Private/Templates/Review/SingleIndex.html
index a76244a0c042..8a521e25ad9a 100644
--- a/typo3/sysext/workspaces/Resources/Private/Templates/Review/SingleIndex.html
+++ b/typo3/sysext/workspaces/Resources/Private/Templates/Review/SingleIndex.html
@@ -1,5 +1,9 @@
+<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
 <f:layout name="nodoc" />
 
 <f:section name="main">
-	<div id="workspacegrid"></div>
-</f:section>
\ No newline at end of file
+
+	<f:render partial="WorkingTable" arguments="{_all}" />
+
+</f:section>
+</html>
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/Css/module.css b/typo3/sysext/workspaces/Resources/Public/Css/module.css
deleted file mode 100644
index b79e023b96be..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/Css/module.css
+++ /dev/null
@@ -1,290 +0,0 @@
-ul.x-tab-strip.x-tab-strip-top {
-	margin-bottom: 0;
-	margin-top: 0;
-	padding-left: 0;
-}
-ul.x-tab-strip.x-tab-strip-top li.last {
-	float: right;
-}
-span.item-state-modified {
-	color: #f78f25;
-}
-span.item-state-moved {
-	color: #457fb8;
-}
-span.item-state-new {
-	color: #3c9934;
-}
-span.item-state-hidden {
-	color: #abaaaa;
-}
-span.item-state-deleted {
-	color: #000000;
-	text-decoration: line-through;
-}
-.legend {
-	margin: 5px;
-	height: 18px;
-	color: #888888;
-}
-.legend dd, .legend dt {
-	display: inline;
-	overflow: hidden;
-}
-.legend dd span {
-	display: inline-block;
-	padding: 4px 4px;
-}
-.x-toolbar {
-	background:none !important;
-}
-.x-grid3 {
-	background: none !important;
-}
-.x-grid3-row-expanded {
-	background-color: #ececec;
-}
-.x-grid3-row-selected {
-	color: #4D4D4D;
-}
-#typo3-mod-php div.typo3-noDoc {
-	margin: 0px 0px;
-}
-#typo3-mod-php div.typo3-noDoc #typo3-docbody {
-	padding: 0px 0px;
-	top: 0px;
-}
-.icon-hidden {
-	display: none;
-	visibility: hidden;
-}
-div.x-grid3-row img.x-action-col-icon {
-	display:none;
-}
-
-div.x-grid3-row-over img.x-action-col-icon,
-div.x-grid3-row img.x-action-col-icon.t3-visible {
-	display:inline-block;
-}
-
-div.t3-workspaces-foldoutWrapper {
-	padding: 10px;
-	margin-left: 40px;
-	background-color: #FFFFFF;
-	background-image: linear-gradient(center top, #ececec 0px, #f7f7f7 200px);
-	background-repeat: repeat-x;
-	color: #606060;
-}
-.x-grid3-row-selected div.t3-workspaces-foldoutWrapper {
-	background-image: linear-gradient(center top, #dedede 0px, #f7f7f7 200px);
-	background-repeat: repeat-x;
-}
-div.t3-workspaces-foldoutWrapper table {
-	border-collapse: collapse;
-	width: 100%;
-}
-div.t3-workspaces-foldoutWrapper tr.header {
-	background-color: #B5B5B5;
-	background-image: linear-gradient(center top, #7f7f7f 10%, #5b5b5b 100%);
-	background-repeat: repeat-x;
-}
-div.t3-workspaces-foldoutWrapper tr.header th {
-	padding: 4px 8px;
-	color: #FFFFFF;
-	line-height: 15px;
-}
-
-.t3-workspaces-foldout-subheaderLeft,
-.t3-workspaces-foldout-subheaderRight {
-	padding: 15px 0 10px 0;
-	margin: 10px;
-}
-.t3-workspaces-foldout-td-contentDiffLeft .t3-workspaces-foldout-contentDiff-container,
-.t3-workspaces-foldout-td-contentDiffRight .t3-workspaces-foldout-contentDiff-container {
-	padding-top: 10px;
-	border-top: 1px solid #cdcdcd;
-}
-.x-grid3-row .t3-workspaces-foldout-td-contentDiffLeft,
-.x-grid3-row .t3-workspaces-foldout-subheaderLeft {
-	padding-right: 10px;
-}
-.x-grid3-row .t3-workspaces-foldout-td-contentDiffRight,
-.x-grid3-row .t3-workspaces-foldout-subheaderRight {
-	padding-left: 10px;
-}
-.x-grid3-row .t3-workspaces-foldout-subheaderLeft .t3-workspaces-foldout-subheader-container {
-	padding-bottom: 10px;
-	border-bottom: 1px solid #cdcdcd;
-}
-table.t3-workspaces-foldout-contentDiff  {
-	padding: 8px 8px;
-	table-layout: auto;
-	background-color: #ffffff;
-}
-table.t3-workspaces-foldout-contentDiff th {
-	padding: 8px 0 8px 8px;
-	width: 80px;
-}
-table.t3-workspaces-foldout-contentDiff td {
-	padding: 8px 8px 8px 0;
-	line-height: 1.3em;
-}
-table.t3-workspaces-foldout-contentDiff .diff-r {
-	text-decoration: line-through;
-}
-.t3-workspaces-foldout-contentDiff .content ins > img {
-	padding: 1px;
-	margin-right: 2px;
-	border: 2px solid green;
-}
-.t3-workspaces-foldout-contentDiff .content del > img {
-	padding: 1px;
-	margin-right: 2px;
-	border: 2px solid red;
-}
-div.t3-workspaces-foldoutWrapper td.char_select_profile_stats {
-	padding-right: 10px;
-}
-div.t3-workspaces-comments {
-	background-color: #dedede;
-	padding: 10px 10px 10px 10px;
-}
-div.t3-workspaces-comments-singleComment {
-	overflow: hidden;
-	margin-bottom: 10px;
-	position: relative;
-}
-div.t3-workspaces-comments-singleComment:last-child {
-	margin: 0;
-}
-div .t3-workspaces-comments-singleComment-author {
-	width: 60px;
-	margin: 10px 0;
-	position: absolute;
-	left: 0px;
-	top: 0px;
-	font-weight: bold;
-	overflow: hidden;
-}
-div .t3-workspaces-comments-singleComment-content-wrapper {
-	background: url(../Images/workspaces-comments-arrow.gif) left 10px no-repeat;
-	margin-left: 70px;
-}
-div .t3-workspaces-comments-singleComment-content-date {
-	font-size: 10px;
-}
-div .t3-workspaces-comments-singleComment-content {
-	background-color: #ffffff;
-	padding: 10px 10px;
-	margin-left: 10px;
-}
-div .t3-workspaces-comments-singleComment-content-title {
-	padding: 8px 0 8px 0;
-	font-weight: bold;
-}
-
-.typo3-workspaces-row-disabled .x-grid3-td-checker {
-	visibility: hidden;
-}
-
-div.x-grid3-row img.t3-icon-extensions-workspaces {
-	display: inline-block !important;
-	width: 17px;
-	visibility: hidden;
-}
-
-div.x-grid3-row-over img.t3-icon-extensions-workspaces {
-	visibility: visible;
-}
-
-img.t3-icon-workspaces-sendtonextstage {
-	background: url(../Images/version-workspace-sendtonextstage.png) no-repeat;
-}
-
-img.t3-icon-workspaces-sendtoprevstage {
-	background: url(../Images/version-workspace-sendtoprevstage.png) no-repeat;
-}
-
-table.t3-workspaces-foldout-contentDiff td.content {
-	word-break: break-all;
-}
-
-.typo3-workspaces-collection-level-node,
-.typo3-workspaces-collection-level-leaf,
-.typo3-workspaces-collection-level-none {
-	float: left;
-	width: 18px;
-}
-
-.x-grid3-row-expander {
-	background-position: left top;
-	float: left;
-}
-.x-grid3-row-collapsed .x-grid3-row-expander {
-	background-position: left top;
-	background-image: url('../Images/zoom_in.png');
-}
-.x-grid3-row-expanded .x-grid3-row-expander {
-	background-position: left top;
-	background-image: url('../Images/zoom_out.png');
-}
-
-.typo3-workspaces-collection-child-collapsed {
-	display: none;
-}
-
-.typo3-workspaces-collection-child-expanded {
-	display: block;
-}
-
-.typo3-workspaces-collection-level-node {
-	width: 18px;
-	height: 18px;
-	background-position: 4px 2px;
-	background-color: transparent;
-	background-repeat: no-repeat;
-	background-image: url('../../../../t3skin/extjs/images/grid/row-expand-sprite.png');
-}
-.typo3-workspaces-collection-parent-collapsed .typo3-workspaces-collection-level-node {
-	background-position: 4px 2px;
-}
-.typo3-workspaces-collection-parent-expanded .typo3-workspaces-collection-level-node {
-	background-position: -21px 2px;
-}
-
-.x-menu.typo3-workspaces-menu {
-	background-image: none;
-}
-.x-menu.typo3-workspaces-menu a.x-menu-item {
-	padding: 3px 14px;
-}
-
-.x-tab-menu-right {
-	background: #dadada;
-	border-color: #adadad;
-	border-style: solid;
-	border-width: 1px;
-	border-top-left-radius: 3px;
-	border-top-right-radius: 3px;
-	color: #666666;
-	background-position: center 6px;
-	padding: 4px;
-
-	background-image: url('../Images/menu.png');
-	background-repeat: no-repeat;
-	width: 16px;
-	position: absolute;
-	right: 0;
-	top: 0;
-	z-index: 10;
-	cursor:pointer;
-}
-
-.t3-workspaces-foldoutWrapper .char_select_profile_titleLeft .icon,
-.t3-workspaces-foldoutWrapper .char_select_profile_titleRight .icon{
-	float: left;
-}
-
-.t3-workspaces-foldoutWrapper .t3-workspaces-foldout-contentDiff {
-	text-align: left;
-}
diff --git a/typo3/sysext/workspaces/Resources/Public/Css/preview.css b/typo3/sysext/workspaces/Resources/Public/Css/preview.css
index 76fcaddf3804..257bca294d20 100644
--- a/typo3/sysext/workspaces/Resources/Public/Css/preview.css
+++ b/typo3/sysext/workspaces/Resources/Public/Css/preview.css
@@ -1,353 +1,64 @@
-/**
- * Top bar
+/*!
+ * 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!
  */
-
-/**
- * Tabs
- */
-
-.x-btn button {
-	font-size: 12px;
-}
-
-/* panel containing the tabs */
-.x-tab-panel-header {
-	background-color: #3f3f3f;
-	background-image: url('../../../../../../typo3/sysext/t3skin/extjs/images/backgrounds/topbar.png');
-	background-image: linear-gradient(center top, #494949 0%, #373737 91%, #343434 92%, #2A2A2A 100%);
-	background-repeat: repeat-x;
-	border: none;
-	padding-bottom: 0;
-	padding-top: 9px;
-}
-
-.x-tab-strip-wrap {
-	background: url('../Images/typo3-logo.png') no-repeat 16px 0;
-	padding-left: 140px;
-}
-
-/* normal tab */
-ul.x-tab-strip li {
-	margin-left: 4px;
-}
-
-ul.x-tab-strip-top {
-	border-bottom: 0;
-}
-
-/* reset ExtJS "no skin" nonsense */
-.x-tab-strip-top .x-tab-right,
-.x-tab-strip-top .x-tab-strip-over .x-tab-right {
-	background-position: 0 0;
-}
-
-/* we don't need the active tab to be 1px below the inactive */
-.x-tab-strip-top .x-tab-strip-active .x-tab-right {
-	margin-bottom: 0;
-}
-
-.x-tab-strip span.x-tab-strip-text,
-.x-tab-strip-top .x-tab-strip-active .x-tab-right span.x-tab-strip-text {
-	padding-bottom: 4px;
-}
-
-/* normal tab styling */
-.x-tab-strip .x-tab-right {
-	background-color: #707171;
-	background-image: linear-gradient(center top, #707171 0%, #474747 85%, #363636 100%);
-	-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#707171', EndColorStr='#474747')"; /* IE8 */
-	border-top-left-radius: 3px;
-	border-top-right-radius: 3px;
-}
-
-/* container surrounding text */
-.x-tab-strip-inner {
-	padding: 4px;
-}
-
-/* hover tab */
-.x-tab-strip-over .x-tab-right {
-	background-color: #707171;
-	background-image: linear-gradient(center top, #888888 0%, #474747 85%, #363636 100%);
-	-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#888888', EndColorStr='#474747')"; /* IE8 */
-}
-
-/* active tab */
-.x-tab-strip-active .x-tab-right {
-	background-color: #989898;
-	background-image: linear-gradient(center top, #989898 0%, #6c6c6c 85%, #474747 100%);
-	-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#989898', EndColorStr='#6c6c6c')"; /* IE8 */
-}
-
-/* tab label */
-.x-tab-strip span.x-tab-strip-text {
-	color: #ffffff;
-}
-
-/* text in tabs and buttons should not be italic.. why should it be? */
-.x-tab-strip em,
-.x-btn-text {
-	font-style: normal;
-}
-
-/**
- * Slider
- */
-#controls {
-	padding-top: 5px;
-}
-#slider {
-	padding-top: 5px;
-}
-
-/* remove default ExtJS border */
-.x-panel-body {
-	border: none;
-}
-
-.x-slider-horz .x-slider-thumb {
-	background-image: url('../Images/slider-thumb.png');
-	height: 21px;
-	padding: 0 2px;
-	top: 0;
-	width: 7px;
-}
-
-.x-slider-horz .x-slider-thumb-over, .x-slider-horz .x-slider-thumb-drag {
-	background-position: -7px -21px;
-}
-
-.x-slider-horz .x-slider-inner {
-	background-image: url('../Images/slider-bg.png');
-}
-
-#visual-mode-selector {
-	list-style: none;
-	background-color: #f9f9f9;
-	border: 1px solid #abb2bc;
-	border-top: none;
-}
-
-#visual-mode-selector td {
-	text-align: left;
-}
-
-#visual-mode-selector td button {
-	text-decoration: none;
-}
-
-#visual-mode-options {
-	display: block;
-	height: 20px;
-	margin: 0px 0 0 10px;
-}
-#visual-mode-options.x-btn-menu-active {
-	background-color: #f9f9f9;
-	border: 1px solid #abb2bc;
-	border-bottom: none;
-}
-#visual-mode-options .x-btn-arrow {
-	padding-right: 2px;
-}
-
-#visual-mode-options.x-btn-menu-active .x-btn-text {
-	color: black;
-}
-
-#visual-mode-toolbar {
-	border:none;
-}
-
-/**
- * Preview panel
- */
-.x-panel-body-noheader {
-	border-top: 0;
-}
-
-.x-tip {
-	background-color: #ffffc7;
-	border: 1px solid #cccccc;
-	box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.3);
-}
-
-/* the mask for dialogs */
-.ext-el-mask {
-	background-color: #000000;
-	opacity: 0.75;
-	filter:alpha(opacity=75);
-}
-
-.x-mask-loading {
-	border: none;
-}
-
-.x-mask-loading div {
-	background-image: url("../../../../t3skin/images/spinner/big-f0f0f0.gif");
-	background-position: top center;
-	border: none;
-	color: #828282;
-	padding-top: 40px;
-}
-
-.x-window-tc {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/top-bottom.png);
-}
-.x-window-tl {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/left-corners.png);
-}
-.x-window-tr {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/right-corners.png);
-}
-.x-window-bc {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/top-bottom.png);
-}
-.x-window-bl {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/left-corners.png);
-}
-.x-window-br {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/right-corners.png);
-}
-
-.x-window-ml {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/left-right.png);
-}
-.x-window-mr {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/window/left-right.png);
-}
-
-.x-window-mc {
-	border:1px solid #A2AAB8;
-	background:#e8e8e8;
-}
-
-.x-window-tl .x-window-header {
-    color: #FFFFFF;
-    font: bold 10px verdana,arial,tahoma,verdana,sans-serif;
-    padding: 4px 0;
-}
-.x-window-draggable, .x-window-draggable .x-window-header-text {
-    cursor: move;
-}
-
-.x-window-tl .x-window-header {
-	color:#fff;
-	font:bold 10px verdana, arial,tahoma,verdana,sans-serif;
-	padding:4px 0 4px 0;
-}
-
-.x-window-mc {
-	border-color:#A2AAB8;
-	font: normal 10px verdana, arial,tahoma,helvetica,sans-serif;
-	background-color:#e7e7e7;
-}
-
-.x-window-maximized .x-window-tc {
-	background-color:#fff;
-}
-
-.x-window-bbar .x-toolbar {
-	border-top-color:#A2AAB8;
-}
-
-.x-form-text, textarea.x-form-field {
-    background-color: #FFFFFF;
-    background-image: none;
-    border-color: #B5B8C8;
-}
-
-.x-btn {
-	color: #FFF;
-}
-.t3-icon-system-options-view {
-	float: right;
-}
-#feToolbarButtonNextStage.x-btn, #feToolbarButtonPreviousStage.x-btn, #feToolbarButtonDiscardStage.x-btn {
-	background: url('../Images/button_approve.png') #55A245 repeat-x;
-	border: 1px solid #7c7c7c;
-	border-radius: 1px;
-	margin-right: 10px;
-	margin-top:0px;
-}
-#feToolbarButtonNextStage.x-btn .x-btn-text, #feToolbarButtonPreviousStage.x-btn .x-btn-text, #feToolbarButtonDiscardStage.x-btn .x-btn-text {
-	color: #FFF;
-	line-height: 8px;
-	height: 13px;
-	padding: 0 3px 0 3px;
-}
-#feToolbarButtonPreviousStage.x-btn .x-btn-text {
-	color:#7c7c7c;
+.module-body {
+  padding: 0;
 }
-#feToolbarButtonPreviousStage.x-btn {
-	background-color: #D5D5D5;
-	background-image: url('../Images/button_reject.png');
+.typo3-topbar-workspace-actions {
+  float: right;
+  height: 100%;
+  display: table;
 }
-#feToolbarButtonDiscardStage.x-btn {
-	background-color: #CD0505;
-	background-image: url('../Images/button_discard.png');
+.workspace-action {
+  display: table-cell;
+  vertical-align: middle;
+  padding: 0 4px;
 }
-#sendToStageWindow .x-btn {
-	background-color: #d5d5d5;
-	background-image: url('../../../../../../typo3/sysext/t3skin/extjs/images/backgrounds/button.png');
-	background-repeat: repeat-x;
-	background-image: linear-gradient(center top, #f6f6f6 10%, #d5d5d5 90%);
-	border: 1px solid #7c7c7c;
-	border-radius: 1px;
-	color: #434343;
+.workspace-action:last-child {
+  padding-right: 16px;
 }
-#sendToStageWindow .x-btn-pressed,
-#sendToStageWindow .x-btn-over,
-#sendToStageWindow .x-btn-icon.x-btn-over {
-	background-color: #bdbcbc;
-	background-image: url('../../../../../../typo3/sysext/t3skin/extjs/images/backgrounds/button-hover.png');
-	background-image: linear-gradient(center top, #f6f6f6 10%, #bdbcbc 90%);
-	border-color: #737f91;
-	color: #1e1e1e;
+.workspace-action .active-preview-mode {
+  display: inline-block;
+  text-align: left;
 }
-
-#sendToStageWindow .x-btn-over .x-btn-mc em.x-btn-split,
-#sendToStageWindow .x-btn-click .x-btn-mc em.x-btn-split,
-#sendToStageWindow .x-btn-menu-active .x-btn-mc em.x-btn-split,
-#sendToStageWindow .x-btn-pressed .x-btn-mc em.x-btn-split {
-	background-image:url(../../../../../../typo3/sysext/t3skin/extjs/images/button/s-arrow-o.gif);
+.workspace-action .slider-wrapper .slider {
+  float: left;
 }
-
-.x-tool {
-    background-image: url("../../../../../../typo3/sysext/t3skin/extjs/images/panel/tool-sprites.gif");
+.workspace-action .slider-wrapper b {
+  margin: 7px 10px;
+  display: block;
+  float: left;
 }
-
-.x-tool-close {
-    background-position: 0 0;
+.workspaces {
+  position: relative;
 }
-.x-tool-close-over {
-    background-position: -15px 0;
+.workspaces iframe {
+  border: 0;
 }
-
-/* text */
-.x-btn.sliderButton .x-btn-text {
-    color: #A0A0A0;
-    font-style: normal;
+.preview-mode-slider iframe {
+  position: absolute;
+  top: 0;
+  z-index: 100;
 }
-
-/* alignment of text in Button "Live" */
-#sizeSliderButtonLive .x-btn-mc {
-	text-align: right;
+.preview-mode-slider #live-view {
+  border-bottom: 2px solid #c83c3c;
+  z-index: 200;
 }
-
-/* alignment of text in Button "Workspace" */
-#sizeSliderButtonWorkspace .x-btn-mc {
-	text-align: left;
+.preview-mode-vbox iframe {
+  width: 50%;
+  height: 100%;
+  float: left;
 }
-.x-panel-header {
-	border: none;
-	font-weight: bold;
-	padding-left:0px;
+.preview-mode-hbox iframe {
+  width: 100%;
+  height: 50%;
 }
-
-.x-window-dlg .x-btn {
-     background-color: #D5D5D5;
-     background-image: linear-gradient(center top , #F6F6F6 10%, #D5D5D5 90%);
-     border-radius: 1px 1px 1px 1px;
-     border: 1px solid #7C7C7C;
-     color: #434343;
-}
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Backend.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Backend.js
new file mode 100644
index 000000000000..bbea867b8328
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Public/JavaScript/Backend.js
@@ -0,0 +1,1191 @@
+/*
+/*
+ * 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!
+ */
+
+/**
+ * RequireJS module for the workspace backend module
+ */
+define([
+	'jquery',
+	'TYPO3/CMS/Workspaces/Workspaces',
+	'TYPO3/CMS/Backend/Tooltip',
+	'TYPO3/CMS/Backend/Severity',
+	'TYPO3/CMS/Backend/Modal',
+	'TYPO3/CMS/Backend/Wizard',
+	'nprogress',
+	'TYPO3/CMS/Backend/jquery.clearable'
+], function($, Workspaces, Tooltip, Severity, Modal, Wizard, NProgress) {
+	'use strict';
+
+	var Backend = {
+		workspaceTitle: '',
+		identifiers: {
+			searchForm: '#workspace-settings-form',
+			searchTextField: '#workspace-settings-form input[name="search-text"]',
+			searchSubmitBtn: '#workspace-settings-form button[type="submit"]',
+			depthSelector: '#workspace-settings-form [name="depth"]',
+			languageSelector: '#workspace-settings-form select[name="languages"]',
+			actionForm: '#workspace-actions-form',
+			chooseStageAction: '#workspace-actions-form [name="stage-action"]',
+			chooseSelectionAction: '#workspace-actions-form [name="selection-action"]',
+			chooseMassAction: '#workspace-actions-form [name="mass-action"]',
+			container: '#workspace-panel',
+			actionIcons: '#workspace-action-icons',
+			toggleAll: '.t3js-toggle-all',
+			previewLinksButton: '.t3js-preview-link',
+			pagination: '#workspace-pagination'
+		},
+		settings: {
+			depth: TYPO3.settings.Workspaces.depth,
+			dir: 'ASC',
+			id: TYPO3.settings.Workspaces.id,
+			language: TYPO3.settings.Workspaces.language,
+			limit: 30,
+			query: '',
+			sort: 'label_Live',
+			start: 0,
+			filterTxt: ''
+		},
+		paging: {
+			currentPage: 1,
+			totalPages: 1,
+			totalItems: 0
+		},
+		allToggled: false,
+		elements: {}, // filled in Backend.getElements()
+		latestPath: '',
+		markedRecordsForMassAction: []
+	};
+
+	Backend.initialize = function() {
+		Backend.getElements();
+		Backend.registerEvents();
+
+		if (TYPO3.settings.Workspaces.depth > 0) {
+			Backend.elements.$depthSelector.val(TYPO3.settings.Workspaces.depth);
+		}
+
+		Backend.loadWorkspaceComponents();
+	};
+
+	Backend.getElements = function() {
+		Backend.elements.$searchForm = $(Backend.identifiers.searchForm);
+		Backend.elements.$searchTextField = $(Backend.identifiers.searchTextField);
+		Backend.elements.$searchSubmitBtn = $(Backend.identifiers.searchSubmitBtn);
+		Backend.elements.$depthSelector = $(Backend.identifiers.depthSelector);
+		Backend.elements.$languageSelector = $(Backend.identifiers.languageSelector);
+		Backend.elements.$container = $(Backend.identifiers.container);
+		Backend.elements.$tableBody = Backend.elements.$container.find('tbody');
+		Backend.elements.$actionIcons = $(Backend.identifiers.actionIcons);
+		Backend.elements.$toggleAll =  $(Backend.identifiers.toggleAll);
+		Backend.elements.$chooseStageAction = $(Backend.identifiers.chooseStageAction);
+		Backend.elements.$chooseSelectionAction = $(Backend.identifiers.chooseSelectionAction);
+		Backend.elements.$chooseMassAction = $(Backend.identifiers.chooseMassAction);
+		Backend.elements.$previewLinksButton = $(Backend.identifiers.previewLinksButton);
+		Backend.elements.$pagination = $(Backend.identifiers.pagination);
+	};
+
+	Backend.registerEvents = function() {
+		$(document).on('click', '[data-action="swap"]', function(e) {
+			var $tr = $(e.target).closest('tr');
+			Workspaces.checkIntegrity(
+				{
+					selection: [
+						{
+							liveId: $tr.data('uid'),
+							versionId: $tr.data('t3ver_oid'),
+							table: $tr.data('table')
+						}
+					],
+					type: 'selection'
+				}
+			).done(function(response) {
+				if (response[0].result.result === 'warning') {
+					Backend.addIntegrityCheckWarningToWizard();
+				}
+
+				Wizard.setup.forceSelection = false;
+				Wizard.addSlide(
+					'swap-confirm',
+					'Swap',
+					TYPO3.lang['window.swap.message'],
+					Severity.info
+				);
+				Wizard.addFinalProcessingSlide(function() {
+					// We passed this slide, swap the record now
+					Workspaces.sendExtDirectRequest(
+						Workspaces.generateExtDirectActionsPayload('swapSingleRecord', [
+							$tr.data('table'),
+							$tr.data('t3ver_oid'),
+							$tr.data('uid')
+						])
+					).done(function() {
+						Wizard.dismiss();
+						Backend.getWorkspaceInfos();
+						Backend.refreshPageTree();
+					});
+				}).done(function() {
+					Wizard.show();
+				});
+			});
+		}).on('click', '[data-action="prevstage"]', function(e) {
+			Backend.sendToStage($(e.target).closest('tr'), 'prev');
+		}).on('click', '[data-action="nextstage"]', function(e) {
+			Backend.sendToStage($(e.target).closest('tr'), 'next');
+		}).on('click', '[data-action="changes"]', Backend.viewChanges
+		).on('click', '[data-action="preview"]', Backend.openPreview
+		).on('click', '[data-action="open"]', function(e) {
+			var $tr = $(e.target).closest('tr'),
+				newUrl = TYPO3.settings.FormEngine.moduleUrl + '&returnUrl=' + encodeURIComponent(document.location.href) + '&id=' + TYPO3.settings.Workspaces.id + '&edit[' + $tr.data('table') + '][' + $tr.data('uid') + ']=edit';
+
+			// Append workspace of record in all-workspaces view
+			if (TYPO3.settings.Workspaces.allView) {
+				newUrl += '&workspace=' + $tr.data('t3ver_wsid');
+			}
+			window.location.href = newUrl;
+		}).on('click', '[data-action="version"]', function(e) {
+			var $tr = $(e.target).closest('tr');
+			if ($tr.data('table') === 'pages') {
+				top.loadEditId($tr.data('t3ver_oid'));
+			} else {
+				top.loadEditId($tr.data('pid'));
+			}
+		}).on('click', '[data-action="remove"]', Backend.confirmDeleteRecordFromWorkspace
+		).on('click', '[data-action="expand"]', function(e) {
+			var $me = $(this),
+				$target = Backend.elements.$tableBody.find($me.data('target')),
+				iconIdentifier;
+
+			if ($target.first().attr('aria-expanded') === 'true') {
+				iconIdentifier = 'apps-pagetree-expand';
+			} else {
+				iconIdentifier = 'apps-pagetree-collapse';
+			}
+
+			$me.html(Backend.getPreRenderedIcon(iconIdentifier));
+		});
+
+		Backend.elements.$searchForm.on('submit', function(e) {
+			e.preventDefault();
+			Backend.settings.filterTxt = Backend.elements.$searchTextField.val();
+			Backend.getWorkspaceInfos();
+		});
+
+		Backend.elements.$searchTextField.on('keyup', function() {
+			var $me = $(this);
+
+			if ($me.val() !== '') {
+				Backend.elements.$searchSubmitBtn.removeClass('disabled');
+			} else {
+				Backend.elements.$searchSubmitBtn.addClass('disabled');
+				Backend.getWorkspaceInfos();
+			}
+		}).clearable(
+			{
+				onClear: function() {
+					Backend.elements.$searchSubmitBtn.addClass('disabled');
+					Backend.settings.filterTxt = '';
+					Backend.getWorkspaceInfos();
+				}
+			}
+		);
+
+		// checkboxes in the table
+		Backend.elements.$toggleAll.on('click', function() {
+			Backend.allToggled = !Backend.allToggled;
+			Backend.elements.$tableBody.find('input[type="checkbox"]').prop('checked', Backend.allToggled).trigger('change');
+		});
+		Backend.elements.$tableBody.on('change', 'tr input[type=checkbox]', Backend.handleCheckboxChange);
+
+		// Listen for depth changes
+		Backend.elements.$depthSelector.on('change', function(e) {
+			var $me = $(this);
+			Backend.settings.depth = $me.val();
+
+			Backend.getWorkspaceInfos();
+		});
+
+		// Generate preview links
+		Backend.elements.$previewLinksButton.on('click', Backend.generatePreviewLinks);
+
+		// Listen for language changes
+		Backend.elements.$languageSelector.on('change', function(e) {
+			var $me = $(this);
+			Backend.settings.language = $me.val();
+
+			Workspaces.sendExtDirectRequest([
+				Workspaces.generateExtDirectActionsPayload('saveLanguageSelection', [$me.val()]),
+				Workspaces.generateExtDirectPayload('getWorkspaceInfos', Backend.settings)
+			]).done(function(response) {
+				Backend.elements.$languageSelector.prev().html($me.find(':selected').data('icon'));
+				Backend.renderWorkspaceInfos(response[1].result);
+			});
+		});
+
+		// Listen for actions
+		Backend.elements.$chooseStageAction.on('change', Backend.sendToSpecificStageAction);
+		Backend.elements.$chooseSelectionAction.on('change', Backend.runSelectionAction);
+		Backend.elements.$chooseMassAction.on('change', Backend.runMassAction);
+
+		// clicking an action in the paginator
+		Backend.elements.$pagination.on('click', 'a[data-action]', function(e) {
+			e.preventDefault();
+
+			var $el = $(this),
+				reload = false;
+
+			switch ($el.data('action')) {
+				case 'previous':
+					if (Backend.paging.currentPage > 1) {
+						Backend.paging.currentPage--;
+						reload = true;
+					}
+					break;
+				case 'next':
+					if (Backend.paging.currentPage < Backend.paging.totalPages) {
+						Backend.paging.currentPage++;
+						reload = true;
+					}
+					break;
+				case 'page':
+					Backend.paging.currentPage = parseInt($el.data('page'));
+					reload = true;
+					break;
+			}
+
+			if (reload) {
+				// Adjust settings
+				Backend.settings.start = Backend.settings.limit * (Backend.paging.currentPage - 1);
+				Backend.getWorkspaceInfos();
+			}
+		});
+	};
+
+	Backend.handleCheckboxChange = function(e) {
+		var $checkbox = $(this),
+			$tr = $checkbox.parents('tr'),
+			table = $tr.data('table'),
+			uid = $tr.data('uid'),
+			t3ver_oid = $tr.data('t3ver_oid'),
+			record = table + ':' + uid + ':' + t3ver_oid;
+
+		if ($checkbox.prop('checked')) {
+			Backend.markedRecordsForMassAction.push(record);
+			$tr.addClass('warning');
+		} else {
+			var index = Backend.markedRecordsForMassAction.indexOf(record);
+			if (index > -1) {
+				Backend.markedRecordsForMassAction.splice(index, 1);
+			}
+			$tr.removeClass('warning');
+		}
+
+		Backend.elements.$chooseStageAction.prop('disabled', Backend.markedRecordsForMassAction.length === 0);
+		Backend.elements.$chooseSelectionAction.prop('disabled', Backend.markedRecordsForMassAction.length === 0);
+		Backend.elements.$chooseMassAction.prop('disabled', Backend.markedRecordsForMassAction.length > 0);
+	};
+
+	/**
+	 * Generates the diff view of a record
+	 *
+	 * @param {Object} diff
+	 * @return {$}
+	 */
+	Backend.generateDiffView = function(diff) {
+		var $diff = $('<div />', {class: 'diff'});
+
+		for (var i = 0; i < diff.length; ++i) {
+			$diff.append(
+				$('<div />', {class: 'diff-item'}).append(
+					$('<div />', {class: 'diff-item-title'}).text(diff[i].label),
+					$('<div />', {class: 'diff-item-result diff-item-result-inline'}).html(diff[i].content)
+				)
+			);
+		}
+		return $diff;
+	};
+
+	/**
+	 * Generates the comments view of a record
+	 *
+	 * @param {Object} comments
+	 * @return {$}
+	 */
+	Backend.generateCommentView = function(comments) {
+		var $comments = $('<div />');
+
+		for (var i = 0; i < comments.length; ++i) {
+			var $panel = $('<div />', {class: 'panel panel-default'});
+
+			if (comments[i].user_comment.length > 0) {
+				$panel.append(
+					$('<div />', {class: 'panel-body'}).html(comments[i].user_comment)
+				);
+			}
+
+			$panel.append(
+				$('<div />', {class: 'panel-footer'}).append(
+					$('<span />', {class: 'label label-success'}).text(comments[i].stage_title),
+					$('<span />', {class: 'label label-info'}).text(comments[i].tstamp)
+				)
+			);
+
+			$comments.append(
+				$('<div />', {class: 'media'}).append(
+					$('<div />', {class: 'media-left text-center'}).text(comments[i].user_username).prepend(
+						$('<div />').html(comments[i].user_avatar)
+					),
+					$('<div />', {class: 'media-body'}).append($panel)
+				)
+			);
+		}
+
+		return $comments;
+	};
+
+	/**
+	 * Sends a record to a stage
+	 *
+	 * @param {Object} $row
+	 * @param {String} direction
+	 */
+	Backend.sendToStage = function($row, direction) {
+		var nextStage,
+			stageWindowAction,
+			stageExecuteAction;
+
+		if (direction === 'next') {
+			nextStage = $row.data('nextStage');
+			stageWindowAction = 'sendToNextStageWindow';
+			stageExecuteAction = 'sendToNextStageExecute';
+		} else if (direction === 'prev') {
+			nextStage = $row.data('prevStage');
+			stageWindowAction = 'sendToPrevStageWindow';
+			stageExecuteAction = 'sendToPrevStageExecute';
+		} else {
+			throw 'Invalid direction given.';
+		}
+
+		Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectActionsPayload(stageWindowAction, [
+				$row.data('uid'), $row.data('table'), $row.data('t3ver_oid')
+			])
+		).done(function(response) {
+			var $modal = Workspaces.renderSendToStageWindow(response);
+			$modal.on('button.clicked', function(e) {
+				if (e.target.name === 'ok') {
+					var $form = $(e.currentTarget).find('form'),
+						serializedForm = $form.serializeObject();
+
+					serializedForm.affects = {
+						table: $row.data('table'),
+						nextStage: nextStage,
+						t3ver_oid: $row.data('t3ver_oid'),
+						uid: $row.data('uid'),
+						elements: []
+					};
+
+					Workspaces.sendExtDirectRequest([
+						Workspaces.generateExtDirectActionsPayload(stageExecuteAction, [serializedForm]),
+						Workspaces.generateExtDirectPayload('getWorkspaceInfos', Backend.settings)
+					]).done(function(response) {
+						$modal.modal('hide');
+						Backend.renderWorkspaceInfos(response[1].result);
+						Backend.refreshPageTree();
+					});
+				}
+			});
+		});
+	};
+
+	/**
+	 * Loads the workspace components, like available stage actions and items of the workspace
+	 */
+	Backend.loadWorkspaceComponents = function() {
+		Workspaces.sendExtDirectRequest([
+			Workspaces.generateExtDirectPayload('getWorkspaceInfos', Backend.settings),
+			Workspaces.generateExtDirectPayload('getStageActions', {}),
+			Workspaces.generateExtDirectMassActionsPayload('getMassStageActions', {}),
+			Workspaces.generateExtDirectPayload('getSystemLanguages', {})
+		]).done(function(response) {
+			Backend.elements.$depthSelector.prop('disabled', false);
+
+			// Records
+			Backend.renderWorkspaceInfos(response[0].result);
+
+			// Stage actions
+			var stageActions = response[1].result.data,
+				i;
+			for (i = 0; i < stageActions.length; ++i) {
+				Backend.elements.$chooseStageAction.append(
+					$('<option />').val(stageActions[i].uid).text(stageActions[i].title)
+				);
+			}
+
+			// Mass actions
+			var massActions = response[2].result.data;
+			for (i = 0; i < massActions.length; ++i) {
+				Backend.elements.$chooseSelectionAction.append(
+					$('<option />').val(massActions[i].action).text(massActions[i].title)
+				);
+
+				Backend.elements.$chooseMassAction.append(
+					$('<option />').val(massActions[i].action).text(massActions[i].title)
+				);
+			}
+
+			// Languages
+			var languages = response[3].result.data;
+			for (i = 0; i < languages.length; ++i) {
+				var $option = $('<option />').val(languages[i].uid).text(languages[i].title).data('icon', languages[i].icon);
+				if (String(languages[i].uid) === String(TYPO3.settings.Workspaces.language)) {
+					$option.prop('selected', true);
+					Backend.elements.$languageSelector.prev().html(languages[i].icon);
+				}
+				Backend.elements.$languageSelector.append($option);
+			}
+			Backend.elements.$languageSelector.prop('disabled', false);
+		});
+	};
+
+	/**
+	 * Gets the workspace infos
+	 *
+	 * @return {Promise}
+	 * @protected
+	 */
+	Backend.getWorkspaceInfos = function() {
+		Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectPayload('getWorkspaceInfos', Backend.settings)
+		).done(function(response) {
+			Backend.renderWorkspaceInfos(response[0].result);
+		});
+	};
+
+	/**
+	 * Renders fetched workspace informations
+	 *
+	 * @param {Object} result
+	 */
+	Backend.renderWorkspaceInfos = function(result) {
+		Backend.elements.$tableBody.children().remove();
+		Backend.allToggled = false;
+		Backend.elements.$chooseStageAction.prop('disabled', true);
+		Backend.elements.$chooseSelectionAction.prop('disabled', true);
+		Backend.elements.$chooseMassAction.prop('disabled', result.data.length === 0);
+
+		Backend.buildPagination(result.total);
+
+		for (var i = 0; i < result.data.length; ++i) {
+			var item = result.data[i],
+				$actions = $('<div />', {class: 'btn-group'}),
+				$integrityIcon = '';
+
+			$actions.append(
+				Backend.getAction(item.Workspaces_CollectionChildren > 0 && item.Workspaces_CollectionCurrent !== '', 'expand', 'apps-pagetree-collapse').attr('title', TYPO3.lang['tooltip.swap']).attr('data-target', '[data-collection="' + item.Workspaces_CollectionCurrent + '"]').attr('data-toggle', 'collapse'),
+				$('<button />', {class: 'btn btn-default', 'data-action': 'changes', 'data-toggle': 'tooltip', title: TYPO3.lang['tooltip.showChanges']}).append(Backend.getPreRenderedIcon('actions-document-info')),
+				Backend.getAction(item.allowedAction_swap && item.Workspaces_CollectionParent === '', 'swap', 'actions-version-swap-version').attr('title', TYPO3.lang['tooltip.swap']),
+				Backend.getAction(item.allowedAction_view, 'preview', 'actions-version-workspace-preview').attr('title', TYPO3.lang['tooltip.viewElementAction']),
+				$('<button />', {class: 'btn btn-default', 'data-action': 'open', 'data-toggle': 'tooltip', title: TYPO3.lang['tooltip.editElementAction']}).append(Backend.getPreRenderedIcon('actions-open')),
+				$('<button />', {class: 'btn btn-default', 'data-action': 'version', 'data-toggle': 'tooltip', title: TYPO3.lang['tooltip.openPage']}).append(Backend.getPreRenderedIcon('actions-version-page-open')),
+				Backend.getAction(item.allowedAction_delete, 'remove', 'actions-version-document-remove').attr('title', TYPO3.lang['tooltip.discardVersion']),
+				$('<label />', {class: 'btn btn-default btn-checkbox'}).append(
+					$('<input />', {type: 'checkbox'}),
+					$('<span />', {class: 't3-icon fa'})
+				)
+			);
+
+			if (item.integrity.messages !== '') {
+				$integrityIcon = $(TYPO3.settings.Workspaces.icons[item.integrity.status]);
+				$integrityIcon
+					.attr('data-toggle', 'tooltip')
+					.attr('data-placement', 'top')
+					.attr('data-html', true)
+					.attr('title', item.integrity.messages);
+			}
+
+			if (Backend.latestPath !== item.path_Workspace) {
+				Backend.latestPath = item.path_Workspace;
+				Backend.elements.$tableBody.append(
+					$('<tr />').append(
+						$('<th />', {colspan: 6}).text(Backend.latestPath)
+					)
+				);
+			}
+
+			var rowConfiguration = {
+				'data-uid': item.uid,
+				'data-pid': item.livepid,
+				'data-t3ver_oid': item.t3ver_oid,
+				'data-t3ver_wsid': item.t3ver_wsid,
+				'data-table': item.table,
+				'data-next-stage': item.value_nextStage,
+				'data-prev-stage': item.value_prevStage,
+				'data-stage': item.stage
+			};
+
+			if (item.Workspaces_CollectionParent !== '') {
+				rowConfiguration['data-collection'] = item.Workspaces_CollectionParent;
+				rowConfiguration['class'] = 'collapse';
+			}
+
+			Backend.elements.$tableBody.append(
+				$('<tr />', rowConfiguration).append(
+					$('<td />', {class: 't3js-title-workspace'}).html(item.icon_Workspace + '&nbsp;' + '<a href="#" data-action="changes"><span class="item-state-' + item.state_Workspace + '">' + item.label_Workspace + '</span></a>'),
+					$('<td />', {class: 't3js-title-live'}).html(item.icon_Live + '&nbsp;' + item.label_Live),
+					$('<td />').text(item.label_Stage),
+					$('<td />').html($integrityIcon),
+					$('<td />').html(item.language.icon),
+					$('<td />', {class: 'text-right', nowrap: 'nowrap'}).append($actions)
+				)
+			);
+
+			Tooltip.initialize('[data-toggle="tooltip"]', {
+				delay: {
+					show: 500,
+					hide: 100
+				},
+				trigger: 'hover',
+				container: 'body'
+			});
+		}
+	};
+
+	/**
+	 * Renders the pagination
+	 *
+	 * @param {Number} totalItems
+	 */
+	Backend.buildPagination = function(totalItems) {
+		if (totalItems === 0) {
+			Backend.elements.$pagination.contents().remove();
+			return;
+		}
+
+		Backend.paging.totalItems = totalItems;
+		Backend.paging.totalPages = Math.ceil(totalItems / Backend.settings.limit);
+
+		if (Backend.paging.totalPages === 1) {
+			// early abort if only one page is available
+			Backend.elements.$pagination.contents().remove();
+			return;
+		}
+
+		var $ul = $('<ul />', {class: 'pagination pagination-block'}),
+			liElements = [],
+			$controlFirstPage = $('<li />').append(
+				$('<a />', {'data-action': 'previous'}).append(
+					$('<span />', {class: 't3-icon fa fa-arrow-left'})
+				)
+			),
+			$controlLastPage = $('<li />').append(
+				$('<a />', {'data-action': 'next'}).append(
+					$('<span />', {class: 't3-icon fa fa-arrow-right'})
+				)
+			);
+
+		if (Backend.paging.currentPage === 1) {
+			$controlFirstPage.disablePagingAction();
+		}
+
+		if (Backend.paging.currentPage === Backend.paging.totalPages) {
+			$controlLastPage.disablePagingAction();
+		}
+
+		for (var i = 1; i <= Backend.paging.totalPages; i++) {
+			var $li = $('<li />', {class: Backend.paging.currentPage === i ? 'active' : ''});
+			$li.append(
+				$('<a />', {'data-action': 'page', 'data-page': i}).append(
+					$('<span />').text(i)
+				)
+			);
+			liElements.push($li);
+		}
+
+		$ul.append($controlFirstPage, liElements, $controlLastPage);
+		Backend.elements.$pagination.html($ul);
+	};
+
+	/**
+	 * View changes of a record
+	 *
+	 * @param {Event} e
+	 */
+	Backend.viewChanges = function(e) {
+		e.preventDefault();
+
+		var $tr = $(e.target).closest('tr');
+
+		Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectPayload('getRowDetails', {
+				stage: $tr.data('stage'),
+				t3ver_oid: $tr.data('t3ver_oid'),
+				table: $tr.data('table'),
+				uid: $tr.data('uid')
+			})
+		).done(function(response) {
+			var item = response[0].result.data[0],
+				$content = $('<div />'),
+				$tabsNav = $('<ul />', {class: 'nav nav-tabs', role: 'tablist'}),
+				$tabsContent = $('<div />', {class: 'tab-content'}),
+				modalButtons = [];
+
+			$content.append(
+				$('<p />').html(TYPO3.lang['path'].replace('{0}', item.path_Live)),
+				$('<p />').html(TYPO3.lang['current_step'].replace('{0}', item.label_Stage).replace('{1}', item.stage_position).replace('{2}', item.stage_count))
+			);
+
+			if (item.diff.length > 0) {
+				$tabsNav.append(
+					$('<li />', {role: 'presentation'}).append(
+						$('<a />', {href: '#workspace-changes', 'aria-controls': 'workspace-changes', role: 'tab', 'data-toggle': 'tab'}).text(TYPO3.lang['window.recordChanges.tabs.changeSummary'])
+					)
+				);
+				$tabsContent.append(
+					$('<div />', {role: 'tabpanel', class: 'tab-pane', id: 'workspace-changes'}).append(
+						$('<div />', {class: 'form-section'}).append(
+							Backend.generateDiffView(item.diff)
+						)
+					)
+				);
+			}
+
+			if (item.comments.length > 0) {
+				$tabsNav.append(
+					$('<li />', {role: 'presentation'}).append(
+						$('<a />', {href: '#workspace-comments', 'aria-controls': 'workspace-comments', role: 'tab', 'data-toggle': 'tab'}).html(TYPO3.lang['window.recordChanges.tabs.comments'] + '&nbsp;').append(
+							$('<span />', {class: 'badge'}).text(item.comments.length)
+						)
+					)
+				);
+				$tabsContent.append(
+					$('<div />', {role: 'tabpanel', class: 'tab-pane', id: 'workspace-comments'}).append(
+						$('<div />', {class: 'form-section'}).append(
+							Backend.generateCommentView(item.comments)
+						)
+					)
+				);
+			}
+
+			if (item.history.total > 0) {
+				$tabsNav.append(
+					$('<li />', {role: 'presentation'}).append(
+						$('<a />', {href: '#workspace-history', 'aria-controls': 'workspace-history', role: 'tab', 'data-toggle': 'tab'}).text(TYPO3.lang['window.recordChanges.tabs.history'])
+					)
+				);
+
+				$tabsContent.append(
+					$('<div />', {role: 'tabpanel', class: 'tab-pane', id: 'workspace-history'}).append(
+						$('<div />', {class: 'form-section'}).append(
+							Backend.generateHistoryView(item.history.data)
+						)
+					)
+				);
+			}
+
+			// Mark the first tab and pane as active
+			$tabsNav.find('li').first().addClass('active');
+			$tabsContent.find('.tab-pane').first().addClass('active');
+
+			// Attach tabs
+			$content.append(
+				$('<div />').append(
+					$tabsNav,
+					$tabsContent
+				)
+			);
+
+			if ($tr.data('stage') !== $tr.data('prevStage')) {
+				modalButtons.push({
+					text: item.label_PrevStage.title,
+					active: true,
+					btnClass: 'btn-default',
+					name: 'prevstage',
+					trigger: function () {
+						Modal.currentModal.trigger('modal-dismiss');
+						Backend.sendToStage($(e.target).closest('tr'), 'prev');
+					}
+				});
+			}
+
+			modalButtons.push({
+				text: item.label_NextStage.title,
+				active: true,
+				btnClass: 'btn-default',
+				name: 'nextstage',
+				trigger: function () {
+					Modal.currentModal.trigger('modal-dismiss');
+					Backend.sendToStage($(e.target).closest('tr'), 'next');
+				}
+			});
+			modalButtons.push({
+				text: TYPO3.lang['close'],
+				active: true,
+				btnClass: 'btn-info',
+				name: 'cancel',
+				trigger: function () {
+					Modal.currentModal.trigger('modal-dismiss');
+				}
+			});
+
+			Modal.show(
+				TYPO3.lang['window.recordInformation'].replace('{0}', $.trim($tr.find('.t3js-title-live').text())),
+				$content,
+				Severity.info,
+				modalButtons
+			);
+		});
+	};
+
+	/**
+	 * Opens a record in a preview window
+	 *
+	 * @param {Event} e
+	 */
+	Backend.openPreview = function(e) {
+		var $tr = $(e.target).closest('tr');
+
+		Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectActionsPayload('viewSingleRecord', [
+				$tr.data('table'), $tr.data('uid')
+			])
+		).done(function(response) {
+			eval(response[0].result);
+		});
+	};
+
+	/**
+	 * Renders the record's history
+	 *
+	 * @param {Object} data
+	 */
+	Backend.generateHistoryView = function(data) {
+		var $history = $('<div />');
+
+		for (var i = 0; i < data.length; ++i) {
+			var $panel = $('<div />', {class: 'panel panel-default'}),
+				$diff;
+
+			if (typeof data[i].differences === 'object') {
+				if (data[i].differences.length === 0) {
+					// Somehow here are no differences. What a pity, skip that record
+					continue;
+				}
+				$diff = $('<div />', {class: 'diff'});
+
+				for (var j = 0; j < data[i].differences.length; ++j) {
+					$diff.append(
+						$('<div />', {class: 'diff-item'}).append(
+							$('<div />', {class: 'diff-item-title'}).text(data[i].differences[j].label),
+							$('<div />', {class: 'diff-item-result diff-item-result-inline'}).html(data[i].differences[j].html)
+						)
+					);
+				}
+
+				$panel.append(
+					$('<div />').append($diff)
+				);
+			} else {
+				$panel.append(
+					$('<div />', {class: 'panel-body'}).text(data[i].differences)
+				);
+			}
+			$panel.append(
+				$('<div />', {class: 'panel-footer'}).append(
+					$('<span />', {class: 'label label-info'}).text(data[i].datetime)
+				)
+			);
+
+			$history.append(
+				$('<div />', {class: 'media'}).append(
+					$('<div />', {class: 'media-left text-center'}).text(data[i].user).prepend(
+						$('<div />').html(data[i].user_avatar)
+					),
+					$('<div />', {class: 'media-body'}).append($panel)
+				)
+			);
+		}
+
+		return $history;
+	};
+
+	/**
+	 * Shows a confirmation modal and deletes the selected record from workspace.
+	 *
+	 * @param {Event} e
+	 */
+	Backend.confirmDeleteRecordFromWorkspace = function(e) {
+		var $tr = $(e.target).closest('tr');
+		var $modal = Modal.confirm(
+			TYPO3.lang['window.discard.title'],
+			TYPO3.lang['window.discard.message'],
+			Severity.warning,
+			[
+				{
+					text: TYPO3.lang['cancel'],
+					active: true,
+					btnClass: 'btn-default',
+					name: 'cancel',
+					trigger: function() {
+						$modal.modal('hide');
+					}
+				}, {
+					text: TYPO3.lang['ok'],
+					btnClass: 'btn-warning',
+					name: 'ok'
+				}
+			]
+		);
+		$modal.on('button.clicked', function(e) {
+			if (e.target.name === 'ok') {
+				Workspaces.sendExtDirectRequest([
+					Workspaces.generateExtDirectActionsPayload('deleteSingleRecord', [
+						$tr.data('table'),
+						$tr.data('uid')
+					])
+				]).done(function() {
+					$modal.modal('hide');
+					Backend.getWorkspaceInfos();
+					Backend.refreshPageTree();
+				});
+			}
+		});
+	};
+
+	/**
+	 * Runs a mass action
+	 */
+	Backend.runSelectionAction = function() {
+		var selectedAction = Backend.elements.$chooseSelectionAction.val(),
+			integrityCheckRequired = selectedAction !== 'discard';
+
+		if (selectedAction.length === 0) {
+			// Don't do anything if that value is empty
+			return;
+		}
+
+		var affectedRecords = [];
+		for (var i = 0; i < Backend.markedRecordsForMassAction.length; ++i) {
+			var affected = Backend.markedRecordsForMassAction[i].split(':');
+			affectedRecords.push({
+				table: affected[0],
+				liveId: affected[2],
+				versionId: affected[1]
+			});
+		}
+
+		if (!integrityCheckRequired) {
+			Wizard.setup.forceSelection = false;
+			Backend.renderSelectionActionWizard(selectedAction, affectedRecords);
+		} else {
+			Workspaces.checkIntegrity(
+				{
+					selection: affectedRecords,
+					type: 'selection'
+				}
+			).done(function(response) {
+				Wizard.setup.forceSelection = false;
+				if (response[0].result.result === 'warning') {
+					Backend.addIntegrityCheckWarningToWizard();
+				}
+				Backend.renderSelectionActionWizard(selectedAction, affectedRecords);
+			});
+		}
+	};
+
+	/**
+	 * Adds a slide to the wizard concerning an integrity check warning.
+	 */
+	Backend.addIntegrityCheckWarningToWizard = function() {
+		Wizard.addSlide(
+			'integrity-warning',
+			'Warning',
+			TYPO3.lang['integrity.hasIssuesDescription'] + '<br>' + TYPO3.lang['integrity.hasIssuesQuestion'],
+			Severity.warning
+		);
+	};
+
+	/**
+	 * Renders the wizard for selection actions
+	 *
+	 * @param {String} selectedAction
+	 * @param {Object} affectedRecords
+	 */
+	Backend.renderSelectionActionWizard = function(selectedAction, affectedRecords) {
+		Wizard.addSlide(
+			'mass-action-confirmation',
+			TYPO3.lang['window.selectionAction.title'],
+			$('<p />').text(TYPO3.lang['tooltip.' + selectedAction + 'Selected']),
+			Severity.warning
+		);
+		Wizard.addFinalProcessingSlide(function() {
+			Workspaces.sendExtDirectRequest(
+				Workspaces.generateExtDirectActionsPayload('executeSelectionAction', {
+					action: selectedAction,
+					selection: affectedRecords
+				})
+			).done(function() {
+				Backend.getWorkspaceInfos();
+				Wizard.dismiss();
+				Backend.refreshPageTree();
+			});
+		}).done(function() {
+			Wizard.show();
+
+			Wizard.getComponent().on('wizard-dismissed', function() {
+				Backend.elements.$chooseSelectionAction.val('');
+			});
+		});
+	};
+
+	/**
+	 * Runs a mass action
+	 */
+	Backend.runMassAction = function() {
+		var selectedAction = Backend.elements.$chooseMassAction.val(),
+			integrityCheckRequired = selectedAction !== 'discard';
+
+		if (selectedAction.length === 0) {
+			// Don't do anything if that value is empty
+			return;
+		}
+
+		if (!integrityCheckRequired) {
+			Wizard.setup.forceSelection = false;
+			Backend.renderMassActionWizard(selectedAction);
+		} else {
+			Workspaces.checkIntegrity(
+				{
+					language: Backend.settings.language,
+					type: selectedAction
+				}
+			).done(function(response) {
+				Wizard.setup.forceSelection = false;
+				if (response[0].result.result === 'warning') {
+					Backend.addIntegrityCheckWarningToWizard();
+				}
+				Backend.renderMassActionWizard(selectedAction);
+			});
+		}
+	};
+
+	/**
+	 * Renders the wizard for mass actions
+	 *
+	 * @param {String} selectedAction
+	 */
+	Backend.renderMassActionWizard = function(selectedAction) {
+		var massAction,
+			doSwap = false;
+
+		switch (selectedAction) {
+			case 'publish':
+				massAction = 'publishWorkspace';
+				break;
+			case 'swap':
+				massAction = 'publishWorkspace';
+				doSwap = true;
+				break;
+			case 'discard':
+				massAction = 'flushWorkspace';
+				break;
+		}
+
+		if (massAction === null) {
+			throw 'Invalid mass action ' + selectedAction + ' called.';
+		}
+
+		Wizard.setup.forceSelection = false;
+		Wizard.addSlide(
+			'mass-action-confirmation',
+			TYPO3.lang['window.massAction.title'],
+			$('<p />').html(TYPO3.lang['tooltip.' + selectedAction + 'All'] + '<br><br>' + TYPO3.lang['tooltip.affectWholeWorkspace']),
+			Severity.warning
+		);
+		Wizard.addFinalProcessingSlide(function() {
+			Workspaces.sendExtDirectRequest(
+				Workspaces.generateExtDirectMassActionsPayload(massAction, {
+					init: true,
+					total: 0,
+					processed: 0,
+					language: Backend.settings.language,
+					swap: doSwap
+				})
+			).done(function(response) {
+				var payload = response[0].result;
+				Workspaces.sendExtDirectRequest(
+					Workspaces.generateExtDirectMassActionsPayload(massAction, payload)
+				).done(function() {
+					Backend.getWorkspaceInfos();
+					Wizard.dismiss();
+				});
+			});
+		}).done(function() {
+			Wizard.show();
+
+			Wizard.getComponent().on('wizard-dismissed', function() {
+				Backend.elements.$chooseMassAction.val('');
+			});
+		});
+	};
+
+	/**
+	 * Sends marked records to a stage
+	 *
+	 * @param {Event} e
+	 */
+	Backend.sendToSpecificStageAction = function(e) {
+		var affectedRecords = [],
+			stage = $(e.currentTarget).val();
+		for (var i = 0; i < Backend.markedRecordsForMassAction.length; ++i) {
+			var affected = Backend.markedRecordsForMassAction[i].split(':');
+			affectedRecords.push({
+				table: affected[0],
+				uid: affected[1],
+				t3ver_oid: affected[2]
+			});
+		}
+		Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectActionsPayload('sendToSpecificStageWindow', [
+				stage, affectedRecords
+			])
+		).done(function(response) {
+			var $modal = Workspaces.renderSendToStageWindow(response);
+			$modal.on('button.clicked', function(e) {
+				if (e.target.name === 'ok') {
+					var $form = $(e.currentTarget).find('form'),
+						serializedForm = $form.serializeObject();
+
+					serializedForm.affects = {
+						elements: affectedRecords,
+						nextStage: stage
+					};
+
+					Workspaces.sendExtDirectRequest([
+						Workspaces.generateExtDirectActionsPayload('sendToSpecificStageExecute', [serializedForm]),
+						Workspaces.generateExtDirectPayload('getWorkspaceInfos', Backend.settings)
+					]).done(function(response) {
+						$modal.modal('hide');
+						Backend.renderWorkspaceInfos(response[1].result);
+						Backend.refreshPageTree();
+					});
+				}
+			}).on('modal-destroyed', function() {
+				Backend.elements.$chooseStageAction.val('');
+			});
+		});
+	};
+
+	/**
+	 * Reloads the page tree
+	 */
+	Backend.refreshPageTree = function() {
+		if (top.TYPO3 && top.TYPO3.Backend && top.TYPO3.Backend.NavigationContainer && top.TYPO3.Backend.NavigationContainer.PageTree) {
+			top.TYPO3.Backend.NavigationContainer.PageTree.refreshTree();
+		}
+	};
+
+	/**
+	 * Renders the action button based on the user's permission.
+	 * This method is intended to be dropped once we don't the ExtDirect stuff anymore.
+	 *
+	 * @returns {$}
+	 * @private
+	 */
+	Backend.getAction = function(condition, action, iconIdentifier) {
+		if (condition) {
+			return $('<button />', {class: 'btn btn-default', 'data-action': action, 'data-toggle': 'tooltip'}).append(Backend.getPreRenderedIcon(iconIdentifier))
+		}
+		return $('<span />', {class: 'btn btn-default disabled'}).append(Backend.getPreRenderedIcon('empty-empty'));
+	};
+
+	/**
+	 * Fetches and renders available preview links
+	 */
+	Backend.generatePreviewLinks = function() {
+		Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectActionsPayload('generateWorkspacePreviewLinksForAllLanguages', [
+				Backend.settings.id
+			])
+		).done(function(response) {
+			var result = response[0].result,
+				$list = $('<dl />');
+
+			$.each(result, function(language, url) {
+				$list.append(
+					$('<dt />').text(language),
+					$('<dd />').append(
+						$('<a />', {href: url, target: '_blank'}).text(url)
+					)
+				);
+			});
+
+			Modal.show(
+				TYPO3.lang['previewLink'],
+				$list,
+				Severity.info,
+				[{
+					text: TYPO3.lang['ok'],
+					active: true,
+					btnClass: 'btn-info',
+					name: 'ok',
+					trigger: function() {
+						Modal.currentModal.trigger('modal-dismiss');
+					}
+				}]
+			);
+		});
+	};
+
+	/**
+	 * Gets the pre-rendered icon
+	 * This method is intended to be dropped once we use Fluid's StandaloneView.
+	 *
+	 * @param {String} identifier
+	 * @returns {$}
+	 */
+	Backend.getPreRenderedIcon = function(identifier) {
+		return Backend.elements.$actionIcons.find('[data-identifier="' + identifier + '"]').clone();
+	};
+
+	/**
+	 * Serialize a form to a JavaScript object
+	 *
+	 * @see http://stackoverflow.com/a/1186309/4828813
+	 * @return {Object}
+	 */
+	$.fn.serializeObject = function() {
+		var o = {};
+		var a = this.serializeArray();
+		$.each(a, function() {
+			if (typeof o[this.name] !== 'undefined') {
+				if (!o[this.name].push) {
+					o[this.name] = [o[this.name]];
+				}
+				o[this.name].push(this.value || '');
+			} else {
+				o[this.name] = this.value || '';
+			}
+		});
+		return o;
+	};
+
+	/**
+	 * Changes the markup of a pagination action being disabled
+	 */
+	$.fn.disablePagingAction = function() {
+		$(this).addClass('disabled').find('.t3-icon').unwrap().wrap($('<span />'));
+	};
+
+	$(Backend.initialize);
+});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowDetailTemplate.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowDetailTemplate.js
deleted file mode 100644
index 0a33cc61500b..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowDetailTemplate.js
+++ /dev/null
@@ -1,10 +0,0 @@
-Ext.ns('TYPO3.Workspaces.Component');
-
-TYPO3.Workspaces.Component.RowDetailTemplate = Ext.extend(Ext.XTemplate, {
-	exists: function(o, name) {
-		return typeof o != 'undefined' && o != null && o!='';
-	},
-	hasComments: function(comments){
-		return comments.length>0;
-	}
-});
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowExpander.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowExpander.js
deleted file mode 100644
index 25d644ab0100..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/RowExpander.js
+++ /dev/null
@@ -1,318 +0,0 @@
-Ext.ns('TYPO3.Workspaces.Component');
-
-TYPO3.Workspaces.Component.RowExpander = Ext.extend(Ext.grid.RowExpander, {
-	menuDisabled: true,
-	hideable: false,
-
-	rowDetailTemplate: [
-		'<div class="t3-workspaces-foldoutWrapper">',
-		'<tpl for=".">',
-			'<tpl>',
-				'<table class="char_select_template" width="100%">',
-					'<tr class="header">',
-						'<th class="char_select_profile_titleLeft">',
-							'{icon_Workspace} {[TYPO3.l10n.localize(\'workspace_version\')]}',
-						'</th>',
-						'<th class="char_select_profile_titleRight">',
-							'{icon_Live} {[TYPO3.l10n.localize(\'live_workspace\')]}',
-						'</th>',
-					'</tr>',
-					'<tr>',
-						'<td class="t3-workspaces-foldout-subheaderLeft">',
-							'{[String.format(TYPO3.l10n.localize(\'current_step\'), values.label_Stage, values.stage_position, values.stage_count)]}',
-						'</td>',
-						'<td class="t3-workspaces-foldout-subheaderRight">',
-							'{[String.format(TYPO3.l10n.localize(\'path\'), values.path_Live)]}',
-						'</td>',
-					'</tr>',
-					'<tr>',
-						'<td class="t3-workspaces-foldout-td-contentDiffLeft">',
-							'<div class="t3-workspaces-foldout-contentDiff-container">',
-								'<table class="t3-workspaces-foldout-contentDiff">',
-									'<tpl for="diff">',
-										'<tr><th>{label}</th><td class="content">',
-											'<tpl if="this.exists(content)">',
-												'{content}',
-											'</tpl>',
-										'</td></tr>',
-									'</tpl>',
-								'</table>',
-							'</div>',
-						'</td>',
-						'<td class="t3-workspaces-foldout-td-contentDiffRight">',
-							'<div class="t3-workspaces-foldout-contentDiff-container">',
-								'<table class="t3-workspaces-foldout-contentDiff">',
-									'<tpl for="live_record">',
-										'<tr><th>{label}</th><td class="content">',
-											'<tpl if="this.exists(content)">',
-												'{content}',
-											'</tpl>',
-										'</td></tr>',
-									'</tpl>',
-								'</table>',
-							'</div>',
-						'</td>',
-					'</tr>',
-					'<tpl if="this.hasComments(comments)">',
-					'<tr>',
-						'<td class="t3-workspaces-foldout-subheaderLeft">',
-							'<div class="t3-workspaces-foldout-subheader-container">',
-								'{[String.format(TYPO3.l10n.localize(\'comments\'), values.stage_position, values.label_Stage)]}',
-							'</div>',
-						'</td>',
-						'<td class="t3-workspaces-foldout-subheaderRight">',
-							'&nbsp;',
-						'</td>',
-					'</tr>',
-					'<tr>',
-						'<td class="char_select_profile_stats">',
-							'<div class="t3-workspaces-comments">',
-							'<tpl for="comments">',
-								'<div class="t3-workspaces-comments-singleComment">',
-									'<div class="t3-workspaces-comments-singleComment-author">',
-										'{user_username}',
-									'</div>',
-									'<div class="t3-workspaces-comments-singleComment-content-wrapper"><div class="t3-workspaces-comments-singleComment-content">',
-										'<span class="t3-workspaces-comments-singleComment-content-date">{tstamp}</span>',
-										'<div class="t3-workspaces-comments-singleComment-content-title">@ {[String.format(TYPO3.l10n.localize(\'stage\'), values.stage_title)]}</div>',
-										'<div class="t3-workspaces-comments-singleComment-content-text">{user_comment}</div>',
-									'</div></div>',
-								'</div>',
-							'</tpl>',
-							'</div>',
-						'</td>',
-						'<td class="char_select_profile_title">',
-							'&nbsp;',
-						'</td>',
-						'</tpl>',
-					'</tr>',
-				'</table>',
-			'</tpl>',
-		'</tpl>',
-		'</div>',
-		'<div class="x-clear"></div>'
-	],
-
-	detailStoreConfiguration: {
-		xtype : 'directstore',
-		storeId : 'rowDetailService',
-		root : 'data',
-		totalProperty : 'total',
-		idProperty : 'id',
-		fields : [
-			{name : 'uid'},
-			{name : 't3ver_oid'},
-			{name : 'table'},
-			{name : 'stage'},
-			{name : 'diff'},
-			{name : 'path_Live'},
-			{name : 'label_Stage'},
-			{name : 'stage_position'},
-			{name : 'stage_count'},
-			{name : 'live_record'},
-			{name : 'comments'},
-			{name : 'icon_Live'},
-			{name : 'icon_Workspace'},
-			{name : 'languageValue'},
-			{name : 'integrity'}
-		]
-	},
-
-	detailStore: null,
-
-	init : function(grid) {
-		TYPO3.Workspaces.Component.RowExpander.superclass.init.call(this, grid);
-		this.detailStore = Ext.create(this.detailStoreConfiguration);
-
-		this.addEvents({
-			beforeExpandCollection: true,
-			beforeExpandCollectionChild: true,
-			beforeCollapseCollection: true,
-			beforeCollapseCollectionChild: true
-		})
-	},
-
-	getRowClass : function(record, rowIndex, p, ds) {
-		var cls = [];
-
-		cls.push(Ext.grid.RowExpander.prototype.getRowClass.call(this, record, rowIndex, p, ds));
-
-		if (record.json.Workspaces_CollectionChildren > 0) {
-			// @todo Extend by new nodeState check
-			cls.push('typo3-workspaces-collection-parent-collapsed');
-		}
-		if (record.json.Workspaces_CollectionParent) {
-			// @todo Extend by new nodeState check
-			cls.push('typo3-workspaces-collection-child-collapsed');
-		}
-		if (!record.json.allowedAction_nextStage && !record.json.allowedAction_prevStage && !record.json.allowedAction_swap) {
-			cls.push('typo3-workspaces-row-disabled');
-		}
-
-		return cls.join(' ');
-	},
-	renderer : function(v, p, record) {
-		var html;
-		html = Ext.grid.RowExpander.prototype.renderer.call(this, v, p, record);
-		return html;
-	},
-	remoteDataMethod : function (record, index) {
-		this.detailStore.baseParams = {
-			uid: record.json.uid,
-			table: record.json.table,
-			stage: record.json.stage,
-			t3ver_oid: record.json.t3ver_oid,
-			path_Live: record.json.path_Live,
-			label_Stage: record.json.label_Stage
-		};
-		this.detailStore.load({
-			callback: function(r, options, success) {
-				TYPO3.Workspaces.RowExpander.expandRow(index);
-			}
-		});
-		new Ext.ux.TYPO3.Workspace.RowPanel({
-			renderTo: 'remData' + index,
-			items: [{
-				xtype: 'dataview',
-				store: this.detailStore,
-				tpl: new TYPO3.Workspaces.Component.RowDetailTemplate(this.rowDetailTemplate)
-			}]
-		});
-	},
-	onMouseDown : function(e, t) {
-		tObject = Ext.get(t);
-		if (tObject.hasClass('x-grid3-row-expander')) {
-			e.stopEvent();
-			row = e.getTarget('.x-grid3-row');
-			this.toggleRow(row);
-		} else if (tObject.hasClass('typo3-workspaces-collection-level-node')) {
-			e.stopEvent();
-			row = e.getTarget('.x-grid3-row');
-			this.toggleCollection(row);
-		}
-	},
-	toggleRow : function(row) {
-		this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'beforeExpand' : 'collapseRow'](row);
-	},
-	beforeExpand : function(row) {
-		if (typeof row == 'number') {
-			row = this.grid.view.getRow(row);
-		}
-		var record = this.grid.store.getAt(row.rowIndex);
-		var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
-
-		if (this.fireEvent('beforexpand', this, record, body, row.rowIndex) !== false) {
-			this.tpl = new Ext.Template("<div id=\"remData" + row.rowIndex + "\" class=\"rem-data-expand\"><\div>");
-			if (this.tpl && this.lazyRender) {
-				body.innerHTML = this.getBodyContent(record, row.rowIndex);
-			}
-		}
-			// toggle remoteData loading
-		this.remoteDataMethod(record, row.rowIndex);
-		return true;
-	},
-	expandRow : function(row) {
-		if (typeof row == 'number') {
-			row = this.grid.view.getRow(row);
-		}
-		var record = this.grid.store.getAt(row.rowIndex);
-		var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
-		this.state[record.id] = true;
-		Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded');
-		this.fireEvent('expand', this, record, body, row.rowIndex);
-		var i;
-		for(i = 0; i < this.grid.store.getCount(); i++) {
-			if(i != row.rowIndex) {
-				this.collapseRow(i);
-			}
-		}
-	},
-	collapseRow : function(row) {
-		if (typeof row == 'number') {
-			row = this.grid.view.getRow(row);
-		}
-		var record = this.grid.store.getAt(row.rowIndex);
-		var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
-		if (this.fireEvent('beforcollapse', this, record, body, row.rowIndex) !== false) {
-			this.state[record.id] = false;
-			Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed');
-			this.fireEvent('collapse', this, record, body, row.rowIndex);
-		}
-	},
-
-	toggleCollection : function(row) {
-		if (Ext.fly(row).hasClass('typo3-workspaces-collection-parent-collapsed')) {
-			this.expandCollection(row);
-		} else {
-			this.collapseCollection(row);
-		}
-	},
-	expandCollection : function(row) {
-		var record, body, child, i;
-
-		if (typeof row === 'number') {
-			row = this.grid.view.getRow(row);
-		}
-
-		record = this.grid.store.getAt(row.rowIndex);
-		body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
-		if (this.fireEvent('beforeExpandCollection', this, record, body, row.rowIndex) !== false) {
-			for(i = 0; i < this.grid.store.getCount(); i++) {
-				child = this.grid.store.getAt(i);
-				if (child.json.Workspaces_CollectionParent === record.json.Workspaces_CollectionCurrent) {
-					this.expandCollectionChild(i);
-				}
-			}
-			Ext.fly(row).replaceClass('typo3-workspaces-collection-parent-collapsed', 'typo3-workspaces-collection-parent-expanded');
-		}
-	},
-	expandCollectionChild : function(row) {
-		var record, body;
-
-		if (typeof row === 'number') {
-			row = this.grid.view.getRow(row);
-		}
-
-		record = this.grid.store.getAt(row.rowIndex);
-		body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
-		if (this.fireEvent('beforeCollapseCollectionChild', this, record, body, row.rowIndex) !== false) {
-			Ext.fly(row).replaceClass('typo3-workspaces-collection-child-collapsed', 'typo3-workspaces-collection-child-expanded');
-		}
-	},
-	collapseCollection : function(row) {
-		var record, body, child, i;
-
-		if (typeof row === 'number') {
-			row = this.grid.view.getRow(row);
-		}
-
-		record = this.grid.store.getAt(row.rowIndex);
-		body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
-		if (this.fireEvent('beforeCollapseCollectionChild', this, record, body, row.rowIndex) !== false) {
-			for(i = 0; i < this.grid.store.getCount(); i++) {
-				child = this.grid.store.getAt(i);
-				if (child.json.Workspaces_CollectionParent === record.json.Workspaces_CollectionCurrent) {
-					// Delegate collapsing to child if it has children as well
-					if (child.json.Workspaces_CollectionChildren > 0) {
-						this.collapseCollection(i);
-					}
-					this.collapseCollectionChild(i);
-				}
-			}
-			Ext.fly(row).replaceClass('typo3-workspaces-collection-parent-expanded', 'typo3-workspaces-collection-parent-collapsed');
-		}
-	},
-	collapseCollectionChild : function(row) {
-		var record, body;
-
-		if (typeof row === 'number') {
-			row = this.grid.view.getRow(row);
-		}
-
-		record = this.grid.store.getAt(row.rowIndex);
-		body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
-		if (this.fireEvent('beforeCollapseCollection', this, record, body, row.rowIndex) !== false) {
-			Ext.fly(row).replaceClass('typo3-workspaces-collection-child-expanded', 'typo3-workspaces-collection-child-collapsed');
-		}
-	}
-});
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/TabPanel.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/TabPanel.js
deleted file mode 100644
index 635b47d1ed33..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/Component/TabPanel.js
+++ /dev/null
@@ -1,159 +0,0 @@
-Ext.ns('TYPO3.Workspaces.Component');
-
-TYPO3.Workspaces.Component.TabPanel = Ext.extend(Ext.TabPanel, {
-	menuRight: null,
-	tabMenu: null,
-
-	menuItems: [],
-	menuItemTemplate: null,
-
-	listeners: {
-		beforetabchange: function(panel, newTab, currentTab) {
-			if (typeof currentTab !== 'undefined' && newTab.triggerUrl) {
-				this.handleTriggerUrl(newTab);
-			}
-		},
-		afterrender: function() {
-			this.createMenu();
-			this.arrangeTabsAfterRender();
-			this.updateMenu();
-		}
-	},
-
-	initComponent: function() {
-		TYPO3.Workspaces.Component.TabPanel.superclass.initComponent.call(this);
-		Ext.EventManager.onWindowResize(this.handleResize, this);
-
-		this.menuItemTemplate = new Ext.XTemplate(
-			'<a id="{id}" class="{cls} x-unselectable" hidefocus="true" unselectable="on" href="{href}"',
-				'<tpl if="hrefTarget">',
-					' target="{hrefTarget}"',
-				'</tpl>',
-			'>',
-				'<span class="x-menu-item-text">{text}</span>',
-			'</a>'
-		);
-	},
-
-	getParentPanel: function() {
-		return this.findParentByType('panel');
-	},
-
-	createMenu : function() {
-		var position = this.tabPosition=='bottom' ? this.footer : this.header;
-		var h = this.stripWrap.dom.offsetHeight;
-		var menuRight = position.insertFirst({
-			cls:'x-tab-menu-right'
-		});
-		menuRight.hide();
-		menuRight.setHeight(h);
-		menuRight.addClassOnOver('x-tab-menu-right-over');
-		menuRight.on('click', this.showMenu, this);
-		this.menuRight = menuRight;
-	},
-
-	updateMenu: function() {
-		if (this.menuItems.length) {
-			this.menuRight.show();
-		} else {
-			this.menuRight.hide();
-		}
-	},
-
-	showMenu: function(event) {
-		if (this.tabMenu) {
-			this.tabMenu.destroy();
-			this.un('destroy', this.tabMenu.destroy, this.tabMenu);
-			this.tabMenu = null;
-		}
-
-		this.tabMenu =  new Ext.menu.Menu({
-			cls: 'typo3-workspaces-menu'
-		});
-		this.on('destroy', this.tabMenu.destroy, this.tabMenu);
-
-		this.addMenuItems();
-
-		var target = Ext.get(event.getTarget());
-		var xy = target.getXY();
-		xy[1] += this.menuRight.getHeight() - 1;
-
-		this.tabMenu.showAt(xy);
-	},
-
-	addMenuItems: function() {
-		Ext.each(this.menuItems, function(cmp) {
-			menuItem = new Ext.menu.Item({
-				itemTpl: this.menuItemTemplate,
-				text      : cmp.title,
-				handler   : this.handleTriggerUrl,
-				scope     : this,
-				triggerUrl: cmp.triggerUrl
-				//iconCls   : item.iconCls
-			});
-			this.tabMenu.add(menuItem);
-		}, this);
-	},
-
-	handleTriggerUrl: function(item) {
-		location.href = item.triggerUrl;
-	},
-
-	handleResize: function(width, height) {
-		this.setWidth(width);
-		this.arrangeTabsAfterResize();
-		this.updateMenu();
-	},
-
-	arrangeTabsAfterRender: function() {
-		var i, cmp, moveItems = [], width = 0;
-		var lastIndex = this.items.items.length;
-		var tabPanelWidth = this.getParentPanel().getWidth();
-
-		for (i = 0; i < lastIndex; i++) {
-			cmp = this.getComponent(i);
-			width += Ext.get(cmp.tabEl).getWidth() + this.tabMargin;
-			if (width > tabPanelWidth - this.menuRight.getWidth()) {
-				moveItems.push(cmp);
-			}
-		}
-
-		Ext.each(moveItems, function(cmp) {
-			this.remove(cmp);
-			this.menuItems.push(cmp);
-		}, this);
-	},
-
-	arrangeTabsAfterResize: function() {
-		var i, cmp, moveItems = [], width = 0;
-		var lastIndex = this.items.items.length;
-		var tabPanelWidth = this.getParentPanel().getWidth();
-
-		for (i = 0; i < lastIndex; i++) {
-			cmp = this.getComponent(i);
-			width += Ext.get(cmp.tabEl).getWidth() + this.tabMargin;
-			if (width > tabPanelWidth - this.menuRight.getWidth()) {
-				moveItems.unshift(cmp);
-			}
-		}
-
-		if (moveItems.length) {
-			Ext.each(moveItems, function(cmp) {
-				this.remove(cmp);
-				this.menuItems.unshift(cmp);
-			}, this);
-		} else {
-			while (this.menuItems.length) {
-				cmp = this.menuItems[0];
-				this.add(cmp);
-				width += Ext.get(cmp.tabEl).getWidth() + this.tabMargin;
-				if (width > tabPanelWidth - this.menuRight.getWidth()) {
-					this.remove(cmp);
-					break;
-				}
-				this.menuItems.shift();
-			}
-		}
-	}
-});
-Ext.reg('WorkspacesTabPanel', TYPO3.Workspaces.Component.TabPanel);
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Ext.ux.plugins.TabStripContainer.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Ext.ux.plugins.TabStripContainer.js
deleted file mode 100644
index 67a3fe16268f..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/Ext.ux.plugins.TabStripContainer.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * Ext.ux.plugins.TabStripContainer
- * @date	December 19, 2010
- *
- * @class Ext.ux.plugins.TabStripContainer
- * @extends Object
- */
-
-Ext.ns('Ext.ux.plugins');
-
-Ext.ux.plugins.TabStripContainer = Ext.extend(Object, {
-
-	/**
-	 * @hide	private
-	 *
-	 * Tab panel we are plugged in.
-	 */
-	tabPanel : null,
-
-	/**
-	 * @hide	private
-	 *
-	 * items for the panel
-	 */
-	items: [],
-
-	/**
-	 * @hide	private
-	 *
-	 * Cached tab panel's strip wrap element container, i.e. panel's header or footer element.
-	 */
-	headerFooterEl : null,
-
-
-	/**
-	 * @constructor
-	 */
-	constructor : function(config) {
-		Ext.apply(this, config);
-	},
-
-	/**
-	 * Initializes plugin
-	 */
-	init : function(tabPanel) {
-		this.tabPanel = tabPanel;
-		tabPanel.on(
-			'afterrender',
-			this.onTabPanelAfterRender,
-			this,
-			{
-				delay: 10
-			}
-		);
-	},
-
-	/**
-	 * Adds the panel to the tab header/footer
-	 *
-	 * @param tabPanel
-	 */
-	onTabPanelAfterRender: function(tabPanel) {
-		var height, panelDiv, stripTarget, config;
-		// Getting and caching strip wrap element parent, i.e. tab panel footer or header.
-		this.headerFooterEl =
-				this.tabPanel.tabPosition == 'bottom'
-					? this.tabPanel.footer
-					: this.tabPanel.header;
-		height = this.headerFooterEl.getComputedHeight();
-		stripTarget = tabPanel[tabPanel.stripTarget];
-		stripTarget.applyStyles('position: relative;');
-
-		panelDiv = this.headerFooterEl.createChild({
-			tag : 'div',
-			id: this.id || Ext.id(),
-			style : {
-				position : 'absolute',
-				right: 0,
-				top: '1px'
-			}
-		});
-		panelDiv.setSize(this.width, height, false);
-		config = Ext.applyIf({
-			layout: 'hbox',
-			height: height,
-			width: this.width,
-			renderTo: panelDiv
-		}, this.panelConfig);
-		this.panelContainer = new Ext.Panel(config);
-		this.panelContainer.add(this.items);
-		this.panelContainer.doLayout();
-	},
-
-	doLayout: function () {
-		this.panelContainer.doLayout();
-	}
-
-});
-Ext.preg('Ext.ux.plugins.TabStripContainer', Ext.ux.plugins.TabStripContainer);
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Preview.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Preview.js
new file mode 100644
index 000000000000..1c1113430bba
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Public/JavaScript/Preview.js
@@ -0,0 +1,305 @@
+/*
+/*
+ * 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!
+ */
+
+/**
+ * RequireJS module for workspace preview
+ */
+define([
+	'jquery',
+	'TYPO3/CMS/Workspaces/Workspaces',
+	'TYPO3/CMS/Backend/Severity',
+	'TYPO3/CMS/Backend/Modal',
+	'twbs/bootstrap-slider'
+], function($, Workspaces, Severity, Modal) {
+	'use strict';
+
+	var Preview = {
+		identifiers: {
+			topbar: '#typo3-topbar',
+			workspacePanel: '.workspace-panel',
+			liveView: '#live-view',
+			workspaceTabs: '.t3js-workspace-tabs [data-toggle="tab"]',
+			workspaceActions: '.t3js-workspace-actions',
+			stageSlider: '#workspace-stage-slider',
+			workspaceView: '#workspace-view',
+			workspaceList: '#workspace-list',
+			sendToStageAction: '[data-action="send-to-stage"]',
+			discardAction: '[data-action="discard"]',
+			stageButtonsContainer: '.t3js-stage-buttons',
+			previewModeContainer: '.t3js-preview-mode',
+			activePreviewMode: '.t3js-active-preview-mode',
+			workspacePreview: '.t3js-workspace-preview'
+		},
+		currentSlidePosition: 100,
+		elements: {} // filled in Preview.getElements()
+	};
+
+	/**
+	 * Initializes the preview module
+	 */
+	Preview.initialize = function() {
+		Preview.getElements();
+		Preview.resizeViews();
+
+		Preview.adjustPreviewModeSelectorWidth();
+		Preview.elements.$stageSlider.slider();
+
+		Preview.registerEvents();
+	};
+
+	/**
+	 * Fetches and stores often required elements
+	 */
+	Preview.getElements = function() {
+		Preview.elements.$liveView = $(Preview.identifiers.liveView);
+		Preview.elements.$workspacePanel = $(Preview.identifiers.workspacePanel);
+		Preview.elements.$workspaceTabs = $(Preview.identifiers.workspaceTabs);
+		Preview.elements.$workspaceActions = $(Preview.identifiers.workspaceActions);
+		Preview.elements.$stageSlider = $(Preview.identifiers.stageSlider);
+		Preview.elements.$workspaceView = $(Preview.identifiers.workspaceView);
+		Preview.elements.$workspaceList = $(Preview.identifiers.workspaceList);
+		Preview.elements.$stageButtonsContainer = $(Preview.identifiers.stageButtonsContainer);
+		Preview.elements.$previewModeContainer = $(Preview.identifiers.previewModeContainer);
+		Preview.elements.$activePreviewMode = $(Preview.identifiers.activePreviewMode);
+		Preview.elements.$workspacePreview = $(Preview.identifiers.workspacePreview);
+	};
+
+	/**
+	 * Registers the events
+	 */
+	Preview.registerEvents = function() {
+		$(window).on('resize', function() {
+			Preview.resizeViews();
+		});
+		$(document)
+			.on('click', Preview.identifiers.discardAction, Preview.renderDiscardWindow)
+			.on('click', Preview.identifiers.sendToStageAction, Preview.renderSendPageToStageWindow)
+		;
+
+		Preview.elements.$workspaceTabs.on('show.bs.tab', function() {
+			Preview.elements.$workspaceActions.toggle($(this).data('actions'));
+		});
+		Preview.elements.$stageSlider.on('change', Preview.updateSlidePosition);
+		Preview.elements.$previewModeContainer.find('[data-preview-mode]').on('click', Preview.changePreviewMode);
+	};
+
+	/**
+	 * Renders the staging buttons
+	 *
+	 * @param {String} buttons
+	 */
+	Preview.renderStageButtons = function(buttons) {
+		Preview.elements.$stageButtonsContainer.html(buttons);
+	};
+
+	/**
+	 * Calculate the available space based on the viewport height
+	 *
+	 * @returns {Number}
+	 */
+	Preview.getAvailableSpace = function() {
+		var $viewportHeight = $(window).height(),
+			$topbarHeight = $(Preview.identifiers.topbar).outerHeight();
+
+		return $viewportHeight - $topbarHeight;
+	};
+
+	/**
+	 * Updates the position of the comparison slider
+	 *
+	 * @param {Event} e
+	 */
+	Preview.updateSlidePosition = function(e) {
+		Preview.currentSlidePosition = e.value.newValue;
+		Preview.resizeViews();
+	};
+
+	/**
+	 * Resize the views based on the current viewport height and slider position
+	 */
+	Preview.resizeViews = function() {
+		var availableSpace = Preview.getAvailableSpace(),
+			relativeHeightOfLiveView = (Preview.currentSlidePosition - 100) * -1,
+			absoluteHeightOfLiveView = Math.round(Math.abs(availableSpace * relativeHeightOfLiveView / 100)),
+			outerHeightDifference = Preview.elements.$liveView.outerHeight() - Preview.elements.$liveView.height();
+
+		Preview.elements.$workspacePreview.height(availableSpace);
+
+		if (Preview.elements.$activePreviewMode.data('activePreviewMode') === 'slider') {
+			Preview.elements.$liveView.height(absoluteHeightOfLiveView - outerHeightDifference);
+		}
+		Preview.elements.$workspaceList.height(availableSpace);
+	};
+
+	/**
+	 * Renders the discard window
+	 *
+	 * @private
+	 */
+	Preview.renderDiscardWindow = function() {
+		var $modal = Modal.confirm(
+			TYPO3.lang['window.discardAll.title'],
+			TYPO3.lang['window.discardAll.message'],
+			Severity.warning,
+			[
+				{
+					text: TYPO3.lang['cancel'],
+					active: true,
+					btnClass: 'btn-default',
+					name: 'cancel',
+					trigger: function() {
+						$modal.modal('hide');
+					}
+				}, {
+				text: TYPO3.lang['ok'],
+				btnClass: 'btn-warning',
+				name: 'ok'
+			}
+			]
+		);
+		$modal.on('button.clicked', function(e) {
+			if (e.target.name === 'ok') {
+				Workspaces.sendExtDirectRequest([
+					Workspaces.generateExtDirectActionsPayload('discardStagesFromPage', [TYPO3.settings.Workspaces.id]),
+					Workspaces.generateExtDirectActionsPayload('updateStageChangeButtons', [TYPO3.settings.Workspaces.id])
+				]).done(function(response) {
+					$modal.modal('hide');
+					Preview.renderStageButtons(response[1].result);
+					// Reloading live view and and workspace list view IFRAME
+					Preview.elements.$workspaceView.attr('src', Preview.elements.$workspaceView.attr('src'));
+					Preview.elements.$workspaceList.attr('src', Preview.elements.$workspaceList.attr('src'));
+				});
+			}
+		});
+	};
+
+	/**
+	 * Adjusts the width of the preview mode selector to avoid jumping around due to different widths of the labels
+	 */
+	Preview.adjustPreviewModeSelectorWidth = function() {
+		var $btnGroup = Preview.elements.$previewModeContainer.find('.btn-group'),
+			maximumWidth = 0;
+
+		$btnGroup.addClass('open');
+		Preview.elements.$previewModeContainer.find('li > a > span').each(function(_, el) {
+			var width = $(el).width();
+			if (maximumWidth < width) {
+				maximumWidth = width;
+			}
+		});
+		$btnGroup.removeClass('open');
+		Preview.elements.$activePreviewMode.width(maximumWidth);
+	};
+
+	/**
+	 * Renders the "send page to stage" window
+	 *
+	 * @private
+	 */
+	Preview.renderSendPageToStageWindow = function() {
+		var $me = $(this),
+			direction = $me.data('direction'),
+			actionName;
+
+		if (direction === 'prev') {
+			actionName = 'sendPageToPreviousStage';
+		} else if (direction === 'next') {
+			actionName = 'sendPageToNextStage';
+		} else {
+			throw 'Invalid direction ' + direction + ' requested.';
+		}
+
+		Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectActionsPayload(actionName, [TYPO3.settings.Workspaces.id])
+		).done(function(response) {
+			var $modal = Workspaces.renderSendToStageWindow(response);
+			$modal.on('button.clicked', function (e) {
+				if (e.target.name === 'ok') {
+					var $form = $(e.currentTarget).find('form'),
+						serializedForm = $form.serializeObject();
+
+					serializedForm.affects = response[0].result.affects;
+					serializedForm.stageId = $me.data('stageId');
+
+					Workspaces.sendExtDirectRequest([
+						Workspaces.generateExtDirectActionsPayload('sentCollectionToStage', [serializedForm]),
+						Workspaces.generateExtDirectActionsPayload('updateStageChangeButtons', [TYPO3.settings.Workspaces.id])
+					]).done(function(response) {
+						$modal.modal('hide');
+
+						Preview.renderStageButtons(response[1].result);
+					});
+				}
+			});
+		});
+	};
+
+	/**
+	 * Changes the preview mode
+	 *
+	 * @param {Event} e
+	 */
+	Preview.changePreviewMode = function(e) {
+		e.preventDefault();
+
+		var $trigger = $(this),
+			currentPreviewMode = Preview.elements.$activePreviewMode.data('activePreviewMode'),
+			newPreviewMode = $trigger.data('previewMode');
+
+		Preview.elements.$activePreviewMode.text($trigger.text()).data('activePreviewMode', newPreviewMode);
+		Preview.elements.$workspacePreview.parent()
+			.removeClass('preview-mode-' + currentPreviewMode)
+			.addClass('preview-mode-' + newPreviewMode);
+
+		if (newPreviewMode === 'slider') {
+			Preview.elements.$stageSlider.parent().toggle(true);
+			Preview.resizeViews();
+		} else {
+			Preview.elements.$stageSlider.parent().toggle(false);
+
+			if (newPreviewMode === 'vbox') {
+				Preview.elements.$liveView.height('100%');
+			} else {
+				Preview.elements.$liveView.height('50%');
+			}
+		}
+
+	};
+
+	/**
+	 * Serialize a form to a JavaScript object
+	 *
+	 * @see http://stackoverflow.com/a/1186309/4828813
+	 * @return {Object}
+	 */
+	$.fn.serializeObject = function() {
+		var o = {};
+		var a = this.serializeArray();
+		$.each(a, function() {
+			if (typeof o[this.name] !== 'undefined') {
+				if (!o[this.name].push) {
+					o[this.name] = [o[this.name]];
+				}
+				o[this.name].push(this.value || '');
+			} else {
+				o[this.name] = this.value || '';
+			}
+		});
+		return o;
+	};
+
+	$(document).ready(function() {
+		Preview.initialize();
+	});
+});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Store/mainstore.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Store/mainstore.js
deleted file mode 100644
index b66d1200b521..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/Store/mainstore.js
+++ /dev/null
@@ -1,85 +0,0 @@
-Ext.ns('TYPO3.Workspaces.Configuration');
-
-TYPO3.Workspaces.Configuration.StoreFieldArray = [
-	{name : 'Workspaces_Collection', type : 'int'},
-	{name : 'Workspaces_CollectionLevel', type : 'int'},
-	{name : 'Workspaces_CollectionParent'},
-	{name : 'Workspaces_CollectionCurrent'},
-	{name : 'Workspaces_CollectionChildren', type : 'int'},
-	{name : 'table'},
-	{name : 'uid', type : 'int'},
-	{name : 't3ver_oid', type : 'int'},
-	{name : 't3ver_wsid', type : 'int'},
-	{name : 'livepid', type : 'int'},
-	{name : 'stage', type: 'int'},
-	{name : 'change',type : 'int'},
-	{name : 'languageValue'},
-	{name : 'language'},
-	{name : 'integrity'},
-	{name : 'label_Live'},
-	{name : 'label_Workspace'},
-	{name : 'label_Stage'},
-	{name : 'label_nextStage'},
-	{name : 'label_prevStage'},
-	{name : 'workspace_Title'},
-	{name : 'actions'},
-	{name : 'icon_Workspace'},
-	{name : 'icon_Live'},
-	{name : 'path_Live'},
-	{name : 'path_Workspace'},
-	{name : 'state_Workspace'},
-	{name : 'workspace_Tstamp'},
-	{name : 'workspace_Formated_Tstamp'},
-	{name : 'allowedAction_nextStage'},
-	{name : 'allowedAction_prevStage'},
-	{name : 'allowedAction_swap'},
-	{name : 'allowedAction_delete'},
-	{name : 'allowedAction_edit'},
-	{name : 'allowedAction_editVersionedPage'},
-	{name : 'allowedAction_view'}
-].concat(TYPO3.settings.Workspaces.extension.AdditionalColumn.Definition);
-
-TYPO3.Workspaces.MainStore = new Ext.data.GroupingStore({
-	storeId : 'workspacesMainStore',
-	reader : new Ext.data.JsonReader({
-		idProperty : 'id',
-		root : 'data',
-		totalProperty : 'total'
-	}, TYPO3.Workspaces.Configuration.StoreFieldArray),
-	groupField: 'path_Workspace',
-	paramsAsHash : true,
-	sortInfo : {
-		field : 'label_Live',
-		direction : "ASC"
-	},
-	remoteSort : true,
-	baseParams: {
-		depth : 990,
-		id: TYPO3.settings.Workspaces.id,
-		language: TYPO3.settings.Workspaces.language,
-		query: '',
-		start: 0,
-		limit: 30
-	},
-
-	showAction : false,
-	listeners : {
-		beforeload : function() {},
-		load : function(store, records) {
-			var defaultColumn = TYPO3.Workspaces.WorkspaceGrid.colModel.getColumnById('label_Workspace');
-			if (defaultColumn) {
-				defaultColumn.width = defaultColumn.defaultWidth + this.getMaximumCollectionLevel() * defaultColumn.levelWidth;
-			}
-		},
-		datachanged : function(store) {}
-	},
-	getMaximumCollectionLevel: function() {
-		var maximumCollectionLevel = 0;
-		Ext.each(this.data.items, function(item) {
-			if (item.json.Workspaces_CollectionLevel > maximumCollectionLevel) {
-				maximumCollectionLevel = item.json.Workspaces_CollectionLevel;
-			}
-		});
-		return maximumCollectionLevel;
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/Workspaces.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/Workspaces.js
new file mode 100644
index 000000000000..60e20ef72782
--- /dev/null
+++ b/typo3/sysext/workspaces/Resources/Public/JavaScript/Workspaces.js
@@ -0,0 +1,214 @@
+/*
+/*
+ * 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!
+ */
+
+/**
+ * RequireJS module for Workspaces
+ */
+define([
+	'jquery',
+	'TYPO3/CMS/Backend/Severity',
+	'TYPO3/CMS/Backend/Modal'
+], function($, Severity, Modal) {
+	'use strict';
+
+	var Workspaces = {};
+
+	/**
+	 * Renders the send to stage window
+	 * @param {Object} response
+	 * @return {$}
+	 */
+	Workspaces.renderSendToStageWindow = function(response) {
+		var result = response[0].result,
+			$form = $('<form />');
+
+		if (typeof result.sendMailTo !== 'undefined' && result.sendMailTo.length > 0) {
+			$form.append(
+				$('<label />', {class: 'control-label'}).text(TYPO3.lang['window.sendToNextStageWindow.itemsWillBeSentTo'])
+			);
+
+			for (var i = 0; i < result.sendMailTo.length; ++i) {
+				var recipient = result.sendMailTo[i];
+
+				$form.append(
+					$('<div />', {class: 'checkbox'}).append(
+						$('<label />').text(recipient.label).prepend(
+							$('<input />', {type: 'checkbox', name: 'recipients', id: recipient.name, value: recipient.value}).prop('checked', recipient.checked).prop('disabled', recipient.disabled)
+						)
+					)
+				);
+			}
+		}
+
+		if (typeof result.additional !== 'undefined') {
+			$form.append(
+				$('<div />', {class: 'form-group'}).append(
+					$('<label />', {class: 'control-label', 'for': 'additional'}).text(TYPO3.lang['window.sendToNextStageWindow.additionalRecipients']),
+					$('<textarea />', {class: 'form-control', name: 'additional', id: 'additional'}).text(result.additional.value),
+					$('<span />', {class: 'help-block'}).text(TYPO3.lang['window.sendToNextStageWindow.additionalRecipients.hint'])
+				)
+			);
+		}
+
+		$form.append(
+			$('<div />', {class: 'form-group'}).append(
+				$('<label />', {class: 'control-label', 'for': 'comments'}).text(TYPO3.lang['window.sendToNextStageWindow.comments']),
+				$('<textarea />', {class: 'form-control', name: 'comments', id: 'comments'}).text(result.comments.value)
+			)
+		);
+
+		var $modal = Modal.show(
+			TYPO3.lang['actionSendToStage'],
+			$form,
+			Severity.info,
+			[
+				{
+					text: TYPO3.lang['cancel'],
+					active: true,
+					btnClass: 'btn-default',
+					name: 'cancel',
+					trigger: function() {
+						$modal.modal('hide');
+					}
+				}, {
+				text: TYPO3.lang['ok'],
+				btnClass: 'btn-info',
+				name: 'ok'
+			}
+			]
+		);
+
+		return $modal;
+	};
+
+	/**
+	 * Checks the integrity of a record
+	 *
+	 * @param {Array} payload
+	 * @return {$}
+	 */
+	Workspaces.checkIntegrity = function(payload) {
+		return Workspaces.sendExtDirectRequest(
+			Workspaces.generateExtDirectPayload('checkIntegrity', payload)
+		);
+	};
+
+	/**
+	 * Sends an AJAX request compatible to ExtDirect
+	 * This method is intended to be dropped once we don't the ExtDirect stuff anymore.
+	 *
+	 * @param {Object} payload
+	 * @return {$}
+	 */
+	Workspaces.sendExtDirectRequest = function(payload) {
+		return $.ajax({
+			url: TYPO3.settings.ajaxUrls['ext_direct_route'] + '&namespace=TYPO3.Workspaces',
+			method: 'POST',
+			contentType: 'application/json; charset=utf-8',
+			dataType: 'json',
+			data: JSON.stringify(payload)
+		});
+	};
+
+	/**
+	 * Generates the payload for ExtDirect
+	 *
+	 * @param {String} method
+	 * @param {Object} data
+	 * @return {{action, data, method, type}}
+	 */
+	Workspaces.generateExtDirectPayload = function(method, data) {
+		if (typeof data === 'undefined') {
+			data = {};
+		}
+		return Workspaces.generateExtDirectPayloadBody('ExtDirect', method, data);
+	};
+
+	/**
+	 * Generates the payload for ExtDirectMassActions
+	 *
+	 * @param {String} method
+	 * @param {Object} data
+	 * @return {{action, data, method, type}}
+	 */
+	Workspaces.generateExtDirectMassActionsPayload = function(method, data) {
+		if (typeof data === 'undefined') {
+			data = {};
+		}
+		return Workspaces.generateExtDirectPayloadBody('ExtDirectMassActions', method, data);
+	};
+
+	/**
+	 * Generates the payload for ExtDirectActions
+	 *
+	 * @param {String} method
+	 * @param {Object} data
+	 * @return {{action, data, method, type}}
+	 */
+	Workspaces.generateExtDirectActionsPayload = function(method, data) {
+		if (typeof data === 'undefined') {
+			data = [];
+		}
+		return Workspaces.generateExtDirectPayloadBody('ExtDirectActions', method, data);
+	};
+
+	/**
+	 * Generates the payload body
+	 *
+	 * @param {String} action
+	 * @param {String} method
+	 * @param {Object} data
+	 * @return {{action: String, data: Object, method: String, type: string}}
+	 */
+	Workspaces.generateExtDirectPayloadBody = function(action, method, data) {
+		if (data instanceof Array) {
+			data.push(TYPO3.settings.Workspaces.token);
+		} else {
+			data = [
+				data,
+				TYPO3.settings.Workspaces.token
+			];
+		}
+		return {
+			action: action,
+			data: data,
+			method: method,
+			type: 'rpc'
+		};
+	};
+
+	/**
+	 * Serialize a form to a JavaScript object
+	 *
+	 * @see http://stackoverflow.com/a/1186309/4828813
+	 * @return {Object}
+	 */
+	$.fn.serializeObject = function() {
+		var o = {};
+		var a = this.serializeArray();
+		$.each(a, function() {
+			if (typeof o[this.name] !== 'undefined') {
+				if (!o[this.name].push) {
+					o[this.name] = [o[this.name]];
+				}
+				o[this.name].push(this.value || '');
+			} else {
+				o[this.name] = this.value || '';
+			}
+		});
+		return o;
+	};
+
+	return Workspaces;
+});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js
deleted file mode 100644
index 13e2ecdbd935..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/actions.js
+++ /dev/null
@@ -1,403 +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!
- */
-
-
-Ext.ns('TYPO3.Workspaces');
-
-TYPO3.Workspaces.Actions = {
-
-	runningMassAction: null,
-	currentSendToMode: 'next',
-
-	checkIntegrity: function(parameters, callbackFunction, callbackArguments) {
-		TYPO3.Workspaces.ExtDirect.checkIntegrity(
-				parameters,
-				function (response) {
-					switch (response.result) {
-						case 'error':
-							top.TYPO3.Dialog.ErrorDialog({
-								minWidth: 400,
-								title: 'Error',
-								msg: '<div class="scope">' + TYPO3.l10n.localize('integrity.hasIssuesDescription') + '</div>'
-							});
-							break;
-						case 'warning':
-							top.TYPO3.Dialog.QuestionDialog({
-								minWidth: 400,
-								title: 'Warning',
-								msg: '<div class="scope">' + TYPO3.l10n.localize('integrity.hasIssuesDescription') + '</div>' +
-									'<div class="question">' + TYPO3.l10n.localize('integrity.hasIssuesQuestion') + '</div>',
-								fn: function(result) {
-									if (result == 'yes') {
-										callbackFunction.call(this, callbackArguments)
-									}
-								}
-							});
-							break;
-						default:
-							callbackFunction.call(this, callbackArguments);
-					}
-				}
-		)
-	},
-
-	triggerMassAction: function(action, language) {
-		switch (action) {
-			case 'publish':
-			case 'swap':
-				this.runningMassAction = TYPO3.Workspaces.ExtDirectMassActions.publishWorkspace;
-				break;
-			case 'discard':
-				this.runningMassAction = TYPO3.Workspaces.ExtDirectMassActions.flushWorkspace;
-				break;
-		}
-
-		// Publishing large amount of changes may require a longer timeout
-		Ext.Ajax.timeout = 3600000;
-
-		this.runMassAction({
-			init: true,
-			total:0,
-			processed:0,
-			language: language,
-			swap: (action == 'swap')
-		});
-	},
-
-	runMassAction: function(parameters) {
-		if (parameters.init) {
-			top.Ext.getCmp('executeMassActionForm').hide();
-			top.Ext.getCmp('executeMassActionProgressBar').show();
-			top.Ext.getCmp('executeMassActionOkButton').disable();
-		}
-
-		var progress = parameters.total > 0 ? parameters.processed / parameters.total : 0;
-		var label = parameters.total > 0 ? parameters.processed + '/' + parameters.total : TYPO3.l10n.localize('runMassAction.init');
-		top.Ext.getCmp('executeMassActionProgressBar').updateProgress(progress, label, true);
-
-		this.runningMassAction(parameters, TYPO3.Workspaces.Actions.runMassActionCallback);
-	},
-
-	runMassActionCallback: function(response) {
-		if (response.error) {
-			top.Ext.getCmp('executeMassActionProgressBar').hide();
-			top.Ext.getCmp('executeMassActionOkButton').hide();
-			top.Ext.getCmp('executeMassActionCancelButton').setText(TYPO3.l10n.localize('close'));
-			top.Ext.getCmp('executeMassActionForm').show();
-			top.Ext.getCmp('executeMassActionForm').update(response.error);
-			TYPO3.Workspaces.Helpers.refreshPageTree();
-		} else {
-			if (response.total > response.processed) {
-				TYPO3.Workspaces.Actions.runMassAction(response);
-			} else {
-				top.Ext.getCmp('executeMassActionProgressBar').hide();
-				top.Ext.getCmp('executeMassActionOkButton').hide();
-				top.Ext.getCmp('executeMassActionCancelButton').setText(TYPO3.l10n.localize('close'));
-				top.Ext.getCmp('executeMassActionForm').show();
-				top.Ext.getCmp('executeMassActionForm').update(TYPO3.l10n.localize('runMassAction.done').replace('%d', response.total));
-				TYPO3.Workspaces.Helpers.refreshPageTree();
-			}
-		}
-	},
-	generateWorkspacePreviewLink: function() {
-		TYPO3.Workspaces.ExtDirectActions.generateWorkspacePreviewLink(TYPO3.settings.Workspaces.id, function(response) {
-			top.TYPO3.Dialog.InformationDialog({
-				title: TYPO3.l10n.localize('previewLink'),
-				msg: String.format('<a href="{0}" target="_blank">{0}</a>', response)
-			});
-		});
-	},
-	swapSingleRecord: function(table, t3ver_oid, orig_uid) {
-		TYPO3.Workspaces.ExtDirectActions.swapSingleRecord(table, t3ver_oid, orig_uid, function(response) {
-			TYPO3.Workspaces.MainStore.load();
-		});
-	},
-	deleteSingleRecord: function(table, uid) {
-		TYPO3.Workspaces.ExtDirectActions.deleteSingleRecord(table, uid, function(response) {
-			TYPO3.Workspaces.Helpers.refreshPageTree();
-			TYPO3.Workspaces.MainStore.load();
-		});
-	},
-	viewSingleRecord: function(table, uid) {
-		TYPO3.Workspaces.ExtDirectActions.viewSingleRecord(table, uid, function(response) {
-			eval(response);
-		});
-	},
-	sendToStageWindow: function(response, selection) {
-		if (Ext.isObject(response.error)) {
-			TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction(response);
-		} else {
-			var dialog = TYPO3.Workspaces.Helpers.getSendToStageWindow({
-				title: response.title,
-				items: response.items,
-				executeHandler: function(event) {
-					var values = top.Ext.getCmp('sendToStageForm').getForm().getValues();
-					affects = response.affects;
-					affects.elements = TYPO3.Workspaces.Helpers.getElementsArrayOfSelection(selection);
-					var parameters = {
-						affects: affects,
-						receipients: TYPO3.Workspaces.Helpers.getElementIdsFromFormValues(values, 'receipients'),
-						additional: values.additional,
-						comments: values.comments
-					};
-
-					TYPO3.Workspaces.Actions.sendToStageExecute(parameters);
-					top.TYPO3.Windows.close('sendToStageWindow');
-					TYPO3.Workspaces.MainStore.reload();
-					TYPO3.Workspaces.Helpers.refreshPageTree();
-				}
-			});
-		}
-	},
-	sendToNextStageWindow: function(table, uid, t3ver_oid) {
-		TYPO3.Workspaces.ExtDirectActions.sendToNextStageWindow(uid, table, t3ver_oid, function(response) {
-			TYPO3.Workspaces.Actions.currentSendToMode = 'next';
-			TYPO3.Workspaces.Actions.sendToStageWindow(response);
-		});
-	},
-	sendToPrevStageWindow: function(table, uid) {
-		TYPO3.Workspaces.ExtDirectActions.sendToPrevStageWindow(uid, table, function(response) {
-			TYPO3.Workspaces.Actions.currentSendToMode = 'prev';
-			TYPO3.Workspaces.Actions.sendToStageWindow(response);
-		});
-	},
-	sendToSpecificStageWindow: function(selection, nextStage) {
-		var elements = [];
-
-		Ext.each(selection, function(row) {
-			elements.push({table: row.json.table, uid: row.json.uid})
-		});
-
-		TYPO3.Workspaces.ExtDirectActions.sendToSpecificStageWindow(nextStage, elements, function(response) {
-			TYPO3.Workspaces.Actions.currentSendToMode = 'specific';
-			TYPO3.Workspaces.Actions.sendToStageWindow(response, selection);
-		});
-	},
-	sendToStageExecute: function (parameters) {
-		switch (TYPO3.Workspaces.Actions.currentSendToMode) {
-			case 'next':
-				TYPO3.Workspaces.ExtDirectActions.sendToNextStageExecute(parameters, TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction);
-			break;
-			case 'prev':
-				TYPO3.Workspaces.ExtDirectActions.sendToPrevStageExecute(parameters, TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction);
-			break;
-			case 'specific':
-				TYPO3.Workspaces.ExtDirectActions.sendToSpecificStageExecute(parameters, TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction);
-			break;
-		}
-
-	},
-	updateColModel: function(colModel) {
-		var dataArray = [];
-		for (var i = 0; i < colModel.config.length; i++) {
-			if (colModel.config[i].dataIndex !== '') {
-				dataArray.push({
-					'position': i,
-					'column': colModel.config[i].dataIndex,
-					'hidden': colModel.config[i].hidden ? 1 : 0
-				});
-			}
-		}
-		TYPO3.Workspaces.ExtDirectActions.saveColumnModel(dataArray);
-	},
-	loadColModel: function(grid) {
-		TYPO3.Workspaces.ExtDirectActions.loadColumnModel(function(response) {
-			var colModel = grid.getColumnModel();
-			for (var field in response) {
-				var colIndex = colModel.getIndexById(field);
-				if (colIndex != -1) {
-					colModel.setHidden(colModel.getIndexById(field), (response[field].hidden == 1 ? true : false));
-					colModel.moveColumn(colModel.getIndexById(field), response[field].position);
-				}
-			}
-		});
-	},
-	handlerResponseOnExecuteAction: function(response) {
-		if (!Ext.isObject(response)) {
-			response = { error: { message: TYPO3.l10n.localize('error.noResponse') }};
-		}
-
-		if (Ext.isObject(response.error)) {
-			var error = response.error;
-			var code = (error.code ? ' #' + error.code : '');
-			top.TYPO3.Dialog.ErrorDialog({ title: 'Error' + code, msg: error.message });
-		}
-	},
-
-	/**
-	 * Process "send to next stage" action.
-	 *
-	 * This method is used in the split frontend preview part.
-	 *
-	 * @return void
-	 */
-	sendPageToNextStage: function () {
-		TYPO3.Workspaces.ExtDirectActions.sendPageToNextStage(TYPO3.settings.Workspaces.id, function (response) {
-			if (Ext.isObject(response.error)) {
-				TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction(response);
-			} else {
-				var dialog = TYPO3.Workspaces.Helpers.getSendToStageWindow({
-					title: TYPO3.l10n.localize('nextStage'),
-					items: response.items.items,
-					executeHandler: function(event) {
-						var values = top.Ext.getCmp('sendToStageForm').getForm().getValues();
-						affects = response.affects;
-						var parameters = {
-							affects: affects,
-							receipients: TYPO3.Workspaces.Helpers.getElementIdsFromFormValues(values, 'receipients'),
-							additional: values.additional,
-							comments: values.comments,
-							stageId: response.stageId
-						};
-						TYPO3.Workspaces.ExtDirectActions.sentCollectionToStage(parameters, function (response) {
-							TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction(response);
-							TYPO3.Workspaces.ExtDirectActions.updateStageChangeButtons(TYPO3.settings.Workspaces.id, TYPO3.Workspaces.Actions.updateStageChangeButtons);
-
-							if (response.refreshLivePanel == true) {
-								Ext.getCmp('livePanel').refresh();
-								Ext.getCmp('livePanel-hbox').refresh();
-								Ext.getCmp('livePanel-vbox').refresh();
-							}
-						});
-						top.TYPO3.Windows.close('sendToStageWindow');
-					}
-				});
-			}
-		});
-	},
-
-	/**
-	 * Process "send to previous stage" action.
-	 *
-	 * This method is used in the split frontend preview part.
-	 *
-	 * @return void
-	 */
-	sendPageToPrevStage: function () {
-		TYPO3.Workspaces.ExtDirectActions.sendPageToPreviousStage(TYPO3.settings.Workspaces.id, function (response) {
-			if (Ext.isObject(response.error)) {
-				TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction(response);
-			} else {
-				var dialog = TYPO3.Workspaces.Helpers.getSendToStageWindow({
-					title: TYPO3.l10n.localize('nextStage'),
-					items: response.items.items,
-					executeHandler: function(event) {
-						var values = top.Ext.getCmp('sendToStageForm').getForm().getValues();
-
-						affects = response.affects;
-						var parameters = {
-							affects: affects,
-							receipients: TYPO3.Workspaces.Helpers.getElementIdsFromFormValues(values, 'receipients'),
-							additional: values.additional,
-							comments: values.comments,
-							stageId: response.stageId
-						};
-						TYPO3.Workspaces.ExtDirectActions.sentCollectionToStage(parameters, function (response) {
-							TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction(response);
-							TYPO3.Workspaces.ExtDirectActions.updateStageChangeButtons(TYPO3.settings.Workspaces.id, TYPO3.Workspaces.Actions.updateStageChangeButtons);
-						});
-						top.TYPO3.Windows.close('sendToStageWindow');
-					}
-				});
-			}
-		});
-	},
-
-	/**
-	 * Update the visible state for the buttons "next stage", "prev stage" and "discard".
-	 *
-	 * This method is used in the split frontend preview part.
-	 *
-	 * @param object response
-	 * @return void
-	 */
-	updateStageChangeButtons: function (response) {
-
-		if (Ext.isObject(response.error)) {
-				TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction(response);
-		} else {
-			for (componentId in response) {
-				if (response[componentId].visible) {
-					if (!top.Ext.getCmp(componentId).isVisible()) {
-						top.Ext.getCmp(componentId).show();
-					}
-					top.Ext.getCmp(componentId).setText(response[componentId].text.substr(0, 35));
-					top.Ext.getCmp(componentId).setTooltip(response[componentId].text);
-				} else {
-					if (top.Ext.getCmp(componentId).isVisible()) {
-						top.Ext.getCmp(componentId).hide();
-					}
-				}
-			}
-				// force doLayout on each plugin containing the preview panel
-			Ext.getCmp('preview').plugins.each(function (item, index) {
-				if (Ext.isFunction(item.doLayout)) {
-					item.doLayout();
-				}
-			});
-		}
-	},
-
-	/**
-	 * Process the discard all items from current page action.
-	 *
-	 * This method is used in the split frontend preview part.
-	 *
-	 * @return void
-	 */
-	discardPage: function () {
-		var configuration = {
-			title: TYPO3.l10n.localize('window.discardAll.title'),
-			msg: TYPO3.l10n.localize('window.discardAll.message'),
-			fn: function(result) {
-				if (result == 'yes') {
-					TYPO3.Workspaces.ExtDirectActions.discardStagesFromPage(TYPO3.settings.Workspaces.id, function (response) {
-						TYPO3.Workspaces.Actions.handlerResponseOnExecuteAction(response);
-						TYPO3.Workspaces.ExtDirectActions.updateStageChangeButtons(TYPO3.settings.Workspaces.id, TYPO3.Workspaces.Actions.updateStageChangeButtons);
-						Ext.getCmp('wsPanel').refresh();
-						Ext.getCmp('wsPanel-hbox').refresh();
-						Ext.getCmp('wsPanel-vbox').refresh();
-					});
-				}
-			}
-		};
-
-		top.TYPO3.Dialog.QuestionDialog(configuration);
-	},
-
-	/**
-	 * Generate workspace preview links for all available languages of a page
-	 *
-	 * @return {void}
-	 */
-	generateWorkspacePreviewLinksForAllLanguages: function() {
-		TYPO3.Workspaces.ExtDirectActions.generateWorkspacePreviewLinksForAllLanguages(TYPO3.settings.Workspaces.id, function(response) {
-
-			var msg = '<ul>';
-
-			for (language in response) {
-				var url = response[language];
-
-				msg += String.format('<li style="margin: 0 0 8px;"><strong>{1}</strong><br /><a href="{0}" target="_blank">{0}</a></li>', url, language);
-			}
-
-			msg += '</ul>';
-
-			top.TYPO3.Dialog.InformationDialog({
-				title: TYPO3.l10n.localize('previewLink'),
-				minWidth: '400',
-				msg: msg
-			});
-		});
-	}
-};
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/component.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/component.js
deleted file mode 100644
index 1e1e8ff5b86b..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/component.js
+++ /dev/null
@@ -1,44 +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!
- */
-
-
-Ext.ns('TYPO3.Workspaces');
-
-Ext.override(Ext.grid.GroupingView, {
-	constructId : function(value, field, idx) {
-		var cfg = this.cm.config[idx],
-			groupRenderer = cfg.groupRenderer || cfg.renderer,
-			val = (this.groupMode == 'value') ? value : this.getGroup(value, {data:{}}, groupRenderer, 0, idx, this.ds);
-
-		var id = this.getPrefix(field) + val;
-		id = id.replace(/[^a-zA-Z0-9_]/g, '');
-		return id;
-	}
-});
-
-Ext.ns('Ext.ux.TYPO3.Workspace');
-Ext.ux.TYPO3.Workspace.RowPanel = Ext.extend(Ext.Panel, {
-	constructor: function(config) {
-		config = config || {
-			frame:true,
-			width:'100%',
-			autoHeight:true,
-			layout:'fit',
-			title: TYPO3.l10n.localize('rowDetails')
-		};
-		Ext.apply(this, config);
-		Ext.ux.TYPO3.Workspace.RowPanel.superclass.constructor.call(this, config);
-	}
-});
-
-TYPO3.Workspaces.RowExpander = new TYPO3.Workspaces.Component.RowExpander();
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/configuration.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/configuration.js
deleted file mode 100644
index f790a00d3e37..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/configuration.js
+++ /dev/null
@@ -1,400 +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!
- */
-
-Ext.ns('TYPO3.Workspaces');
-TYPO3.Workspaces.Configuration = {};
-
-TYPO3.Workspaces.Configuration.GridFilters = new Ext.ux.grid.GridFilters({
-	encode : false, // json encode the filter query
-	local : true, // defaults to false (remote filtering)
-	filters : [
-		{
-			type : 'numeric',
-			dataIndex : 'uid'
-		},
-		{
-			type : 'string',
-			dataIndex : 'workspace_Title'
-		},
-		{
-			type : 'numeric',
-			dataIndex : 'languageValue'
-		},
-		{
-			type : 'string',
-			dataIndex : 'label_Live'
-		},
-		{
-			type : 'string',
-			dataIndex : 'label_Workspace'
-		},
-		{
-			type : 'numeric',
-			dataIndex : 'change'
-		}
-	]
-});
-
-TYPO3.Workspaces.Configuration.Integrity = new Ext.grid.Column({
-	width: 24,
-	hideable: true,
-	sortable: false,
-	header: TYPO3.settings.Workspaces.icons.integrity + '&nbsp;',
-	renderer: function(value, meta, record) {
-		if (record.json.integrity.status !== 'success') {
-			var icon = TYPO3.settings.Workspaces.icons[record.json.integrity.status];
-			var title = TYPO3.l10n.localize('status.' + record.json.integrity.status);
-			var message = record.json.integrity.messages;
-
-			return '<span ext:qtitle="' + title + '" ext:qtip="' + message + '">' + icon + '&nbsp;</span>';
-		}
-	}
-});
-TYPO3.Workspaces.Configuration.WsPath = {
-	id: 'path_Workspace',
-	dataIndex : 'path_Workspace',
-	width: 120,
-	hidden: true,
-	hideable: false,
-	sortable: true,
-	header : TYPO3.l10n.localize('column.wsPath'),
-	renderer: function(value, metaData, record, rowIndex, colIndex, store) {
-		var path = record.json.path_Workspace;
-		return path;
-	},
-	filter : {type: 'string'}
-};
-
-TYPO3.Workspaces.Configuration.LivePath = {
-	id: 'path_Live',
-	dataIndex : 'path_Live',
-	width: 120,
-	hidden: true,
-	hideable: true,
-	sortable: true,
-	header : TYPO3.l10n.localize('column.livePath'),
-	renderer: function(value, metaData, record, rowIndex, colIndex, store) {
-		var path = record.json.path_Live;
-		return path;
-	},
-	filter : {type: 'string'}
-};
-
-TYPO3.Workspaces.Configuration.WsTitleWithIcon = {
-	id: 'label_Workspace',
-	dataIndex : 'label_Workspace',
-	// basic definition
-	defaultWidth: 120,
-	// width is extended depending on collection levels
-	// the value is set in addition to this.defaultWidth
-	width: 120,
-	// additional width used for each collection level
-	levelWidth: 18,
-	hideable: false,
-	sortable: true,
-	header : TYPO3.l10n.localize('column.wsTitle'),
-	renderer: function(value, metaData, record, rowIndex, colIndex, store) {
-		var dekoClass = 'item-state-' + record.json.state_Workspace;
-		value = "<span class=\"" + dekoClass + "\">" + value + "</span>";
-		// Prepend icon
-		if (record.json.icon_Live !== record.json.icon_Workspace) {
-			value = record.json.icon_Workspace + "&nbsp;" + value;
-		}
-		// Prepend nested collection level
-		var levelStyle = 'margin-left: ' + record.json.Workspaces_CollectionLevel * this.levelWidth + 'px;';
-		if (record.json.Workspaces_CollectionChildren > 0) {
-			value = '<div class="typo3-workspaces-collection-level-node" style="' + levelStyle + '">&#160;</div>' + value;
-		} else if (record.json.Workspaces_CollectionLevel > 0) {
-			value = '<div class="typo3-workspaces-collection-level-leaf" style="' + levelStyle + '">&#160;</div>' + value;
-		} else {
-			value = '<div class="typo3-workspaces-collection-level-none" style="' + levelStyle + '">&#160;</div>' + value;
-		}
-		return value;
-	},
-	filter : {type: 'string'}
-};
-
-TYPO3.Workspaces.Configuration.Language = {
-	id: 'language',
-	dataIndex: 'languageValue',
-	width: 30,
-	hideable: true,
-	sortable: true,
-	header: TYPO3.settings.Workspaces.icons.language,
-	filter: { type: 'string '},
-	renderer: function(value, metaData, record) {
-		return record.json.language.icon;
-	}
-};
-
-TYPO3.Workspaces.Configuration.TitleWithIcon = {
-	id: 'label_Live',
-	dataIndex : 'label_Live',
-	width: 120,
-	hideable: false,
-	sortable: true,
-	header : TYPO3.l10n.localize('column.liveTitle'),
-	renderer: function(value, metaData, record, rowIndex, colIndex, store) {
-		var dekoClass = '';
-		if (record.json.state_Workspace == 'unhidden') {
-			dekoClass = 'item-state-hidden';
-		}
-
-		value = "<span class=\"" + dekoClass + "\">" + value + "</span>";
-		return record.json.icon_Live + "&nbsp;" + value;
-	},
-	filter : {type: 'string'}
-};
-
-TYPO3.Workspaces.Configuration.ChangeDate = {
-	id: 'workspace_Tstamp',
-	dataIndex : 'workspace_Tstamp',
-	width: 120,
-	sortable: true,
-	header : TYPO3.l10n.localize('column.changeDate'),
-	renderer: function(value, metaData, record, rowIndex, colIndex, store) {
-		return record.json.workspace_Formated_Tstamp;
-	},
-	hidden: true,
-	filter : {type : 'string'}
-};
-
-TYPO3.Workspaces.Configuration.SendToPrevStageButton = {
-	xtype: 'actioncolumn',
-	header:'',
-	width: 18,
-	hidden: false,
-	items:[
-		{
-			iconCls: 't3-icon t3-icon-extensions t3-icon-extensions-workspaces t3-icon-workspaces-sendtoprevstage',
-			tooltip: TYPO3.l10n.localize('tooltip.sendToPrevStage'),
-			handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				TYPO3.Workspaces.Actions.sendToPrevStageWindow(record.json.table, record.json.uid);
-			}
-		}
-	]
-};
-
-TYPO3.Workspaces.Configuration.SendToNextStageButton = {
-	xtype: 'actioncolumn',
-	header:'',
-	width: 18,
-	hidden: false,
-	items: [
-		{},{	// empty dummy important!!!!
-			iconCls: 't3-icon t3-icon-extensions t3-icon-extensions-workspaces t3-icon-workspaces-sendtonextstage',
-			tooltip: TYPO3.l10n.localize('tooltip.sendToNextStage'),
-			handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				TYPO3.Workspaces.Actions.sendToNextStageWindow(record.json.table, record.json.uid, record.json.t3ver_oid);
-			}
-		}
-	]
-};
-
-TYPO3.Workspaces.Configuration.Stage = {
-	id: 'label_Stage',
-	dataIndex : 'label_Stage',
-	width: 80,
-	sortable: true,
-	header : TYPO3.l10n.localize('column.stage'),
-	hidden: false,
-	filter : {
-		type : 'string'
-	},
-	renderer: function(value, metaData, record, rowIndex, colIndex, store) {
-		var returnCode = '';
-		if (record.json.allowedAction_prevStage) {
-			var tempTooltip = TYPO3.Workspaces.Configuration.SendToPrevStageButton.items[0].tooltip;
-			TYPO3.Workspaces.Configuration.SendToPrevStageButton.items[0].tooltip += ' &quot;'+ record.json.label_prevStage + '&quot;';
-			var prevButton = new Ext.grid.ActionColumn(TYPO3.Workspaces.Configuration.SendToPrevStageButton);
-			returnCode += prevButton.renderer(1, metaData, record, rowIndex, 1, store);
-			TYPO3.Workspaces.Configuration.SendToPrevStageButton.items[0].tooltip = tempTooltip;
-		} else {
-			returnCode += "<span class=\"t3-icon t3-icon-empty t3-icon-empty-empty\">&nbsp;</span>";
-		}
-		returnCode += record.json.label_Stage;
-		if (record.json.allowedAction_nextStage) {
-			var tempTooltip = TYPO3.Workspaces.Configuration.SendToNextStageButton.items[1].tooltip;
-			TYPO3.Workspaces.Configuration.SendToNextStageButton.items[1].tooltip += ' &quot;'+ record.json.label_nextStage + '&quot;';
-			var nextButton = new Ext.grid.ActionColumn(TYPO3.Workspaces.Configuration.SendToNextStageButton);
-			returnCode += nextButton.renderer(2, metaData, record, rowIndex, 2, store);
-			TYPO3.Workspaces.Configuration.SendToNextStageButton.items[1].tooltip = tempTooltip;
-		} else {
-			returnCode += "<span class=\"t3-icon t3-icon-empty t3-icon-empty-empty\">&nbsp;</span>";
-		}
-		return returnCode;
-	},
-	processEvent : function(name, e, grid, rowIndex, colIndex){
-		var m = e.getTarget().className.match(/x-action-col-(\d+)/);
-		if(m && m[1] == 0) {
-			TYPO3.Workspaces.Configuration.SendToPrevStageButton.items[0].handler(grid, rowIndex, colIndex);
-			return false;
-		} else if (m && m[1] == 1 ) {
-			TYPO3.Workspaces.Configuration.SendToNextStageButton.items[1].handler(grid, rowIndex, colIndex);
-			return false;
-		}
-		return Ext.grid.ActionColumn.superclass.processEvent.apply(this, arguments);
-	}
-}
-
-TYPO3.Workspaces.Configuration.RowButtons = {
-	xtype: 'actioncolumn',
-	header: TYPO3.l10n.localize('column.actions'),
-	width: 80,
-	hideable: false,
-	hidden: false,
-	menuDisabled: true,
-	items: [
-		{
-			iconCls:'t3-icon t3-icon-actions t3-icon-actions-version t3-icon-version-workspace-preview'
-			,tooltip: TYPO3.l10n.localize('tooltip.viewElementAction')
-			,handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				TYPO3.Workspaces.Actions.viewSingleRecord(record.json.table, record.json.uid);
-			},
-			getClass: function(v, meta, rec) {
-				if(!rec.json.allowedAction_view) {
-					return 'icon-hidden';
-				} else {
-					return '';
-				}
-			}
-		},
-		{
-			iconCls:'t3-icon t3-icon-actions t3-icon-actions-document t3-icon-document-open',
-			tooltip: TYPO3.l10n.localize('tooltip.editElementAction'),
-			handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				var newUrl = TYPO3.settings.FormEngine.moduleUrl + '&returnUrl=' + encodeURIComponent(document.location.href) + '&id=' + TYPO3.settings.Workspaces.id + '&edit[' + record.json.table + '][' + record.json.uid + ']=edit';
-				// Append workspace of record in all-workspaces view
-				if (TYPO3.settings.Workspaces.allView) {
-					newUrl += '&workspace=' + record.json.t3ver_wsid;
-				}
-				window.location.href = newUrl;
-			},
-			getClass: function(v, meta, rec) {
-				if(!rec.json.allowedAction_edit) {
-					return 'icon-hidden';
-				} else {
-					return '';
-				}
-			}
-		},
-		{
-			iconCls:'t3-icon t3-icon-actions t3-icon-actions-system t3-icon-system-pagemodule-open',
-			tooltip: TYPO3.l10n.localize('tooltip.openPage'),
-			handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				if (record.json.table == 'pages') {
-					top.loadEditId(record.json.t3ver_oid);
-				} else {
-					top.loadEditId(record.json.livepid);
-				}
-			},
-			getClass: function(v, meta, rec) {
-				if(!rec.json.allowedAction_editVersionedPage || !TYPO3.Workspaces.Helpers.isDefined('top.TYPO3.configuration.pageModule') || !top.TYPO3.configuration.pageModule) {
-					return 'icon-hidden';
-				} else {
-					return '';
-				}
-			}
-		},
-		{
-			iconCls:'t3-icon t3-icon-actions t3-icon-actions-version t3-icon-version-document-remove',
-			tooltip: TYPO3.l10n.localize('tooltip.discardVersion'),
-			handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				var configuration = {
-					title: TYPO3.l10n.localize('window.discard.title'),
-					msg: TYPO3.l10n.localize('window.discard.message'),
-					fn: function(result) {
-						if (result == 'yes') {
-							TYPO3.Workspaces.Actions.deleteSingleRecord(record.json.table, record.json.uid);
-						}
-					}
-				};
-
-				top.TYPO3.Dialog.QuestionDialog(configuration);
-			},
-			getClass: function(v, meta, rec) {
-				if(!rec.json.allowedAction_delete) {
-					return 'icon-hidden';
-				} else {
-					return '';
-				}
-			}
-		},
-		{
-			iconCls: 't3-icon t3-icon-actions t3-icon-actions-document t3-icon-document-history-open',
-			tooltip: TYPO3.l10n.localize('tooltip.showHistory'),
-			handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				TYPO3.Workspaces.Helpers.getHistoryWindow({
-					table: record.json.table,
-					liveId: record.json.t3ver_oid,
-					versionId: record.json.uid
-				});
-			}
-		}
-	]
-};
-
-TYPO3.Workspaces.Configuration.SwapButton = {
-	xtype: 'actioncolumn',
-	header: '',
-	id: 'wsSwapColumn',
-	width: 18,
-	menuDisabled: true,
-	sortable: false,
-	hidden: false,
-	items: [
-		{
-			iconCls:'t3-icon t3-icon-actions t3-icon-actions-version t3-icon-version-swap-workspace'
-			,tooltip: TYPO3.l10n.localize('tooltip.swap')
-			,handler: function(grid, rowIndex, colIndex) {
-				var record = TYPO3.Workspaces.MainStore.getAt(rowIndex);
-				var parameters = {
-					type: 'selection',
-					selection: [{
-						table: record.json.table,
-						versionId: record.json.uid,
-						liveId: record.json.t3ver_oid
-					}]
-				};
-
-				var configuration = {
-					title: TYPO3.l10n.localize('window.swap.title'),
-					msg: TYPO3.l10n.localize('window.swap.message'),
-					fn: function(result) {
-						if (result == 'yes') {
-							TYPO3.Workspaces.Actions.swapSingleRecord(record.json.table, record.json.t3ver_oid, record.json.uid);
-						}
-					}
-				};
-
-				TYPO3.Workspaces.Actions.checkIntegrity(parameters, function() {
-					top.TYPO3.Dialog.QuestionDialog(configuration);
-				});
-			},
-			getClass: function(v, meta, rec) {
-				if(!rec.json.allowedAction_swap) {
-					return 'icon-hidden';
-				} else {
-					return '';
-				}
-			}
-		}
-	]
-};
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/grid.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/grid.js
deleted file mode 100644
index be493f0faa11..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/grid.js
+++ /dev/null
@@ -1,153 +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!
- */
-
-Ext.ns('TYPO3.Workspaces');
-
-Ext.override(Ext.grid.GridView, {
-	beforeColMenuShow : function() {
-		var colModel = this.cm,
-			colCount = colModel.getColumnCount(),
-			colMenu = this.colMenu,
-			i, text;
-
-		colMenu.removeAll();
-
-		for (i = 0; i < colCount; i++) {
-			if (colModel.config[i].hideable !== false) {
-				text = colModel.getColumnHeader(i);
-				if (colModel.getColumnId(i) === 'wsSwapColumn') {
-					text = TYPO3.l10n.localize('column.wsSwapColumn');
-				}
-				colMenu.add(new Ext.menu.CheckItem({
-					text: text,
-					itemId: 'col-' + colModel.getColumnId(i),
-					checked: !colModel.isHidden(i),
-					disabled: colModel.config[i].hideable === false,
-					hideOnClick: false
-				}));
-			}
-		}
-	}
-});
-
-/** override mousedown for grid to select checkbox respecting singleSelect */
-Ext.override(Ext.grid.CheckboxSelectionModel, {
-	handleMouseDown: function(g, rowIndex, e) {
-		e.stopEvent();
-		if (this.isSelected(rowIndex)) {
-			this.deselectRow(rowIndex);
-		} else {
-			this.selectRow(rowIndex, true);
-			this.grid.getView().focusRow(rowIndex);
-		}
-	}
-});
-
-TYPO3.Workspaces.SelectionModel = new Ext.grid.CheckboxSelectionModel({
-	singleSelect: false,
-	hidden: true,
-	listeners: {
-		beforerowselect : function (selection, rowIndex, keep, rec) {
-			if (rec.json.allowedAction_nextStage || rec.json.allowedAction_prevStage || rec.json.allowedAction_swap) {
-				return true;
-			} else {
-				return false;
-			}
-		},
-		selectionchange: function (selection) {
-			var record = selection.grid.getSelectionModel().getSelections();
-			if (record.length > 0) {
-				TYPO3.Workspaces.Toolbar.selectStateActionCombo.setDisabled(false);
-				TYPO3.Workspaces.Toolbar.selectionActionCombo.setDisabled(false);
-				TYPO3.Workspaces.Toolbar.selectStateMassActionCombo.setDisabled(true);
-			} else {
-				TYPO3.Workspaces.Toolbar.selectStateActionCombo.setDisabled(true);
-				TYPO3.Workspaces.Toolbar.selectionActionCombo.setDisabled(true);
-				TYPO3.Workspaces.Toolbar.selectStateMassActionCombo.setDisabled(false);
-			}
-		}
-	}
-});
-
-TYPO3.Workspaces.WorkspaceGrid = new Ext.grid.GridPanel({
-	initColModel: function() {
-		if (TYPO3.settings.Workspaces.isLiveWorkspace) {
-			this.colModel = new Ext.grid.ColumnModel({
-				columns: [
-					TYPO3.Workspaces.RowExpander,
-					{id: 'uid', dataIndex : 'uid', width: 40, sortable: true, header : TYPO3.l10n.localize('column.uid'), hidden: true, filterable : true },
-					{id: 't3ver_oid', dataIndex : 't3ver_oid', width: 40, sortable: true, header : TYPO3.l10n.localize('column.oid'), hidden: true, filterable : true },
-					{id: 'workspace_Title', dataIndex : 'workspace_Title', width: 120, sortable: true, header : TYPO3.l10n.localize('column.workspaceName'), hidden: true, filter : {type : 'string'}},
-					TYPO3.Workspaces.Configuration.WsPath,
-					TYPO3.Workspaces.Configuration.LivePath,
-					TYPO3.Workspaces.Configuration.WsTitleWithIcon,
-					TYPO3.Workspaces.Configuration.TitleWithIcon,
-					TYPO3.Workspaces.Configuration.ChangeDate,
-					TYPO3.Workspaces.Configuration.Integrity,
-					TYPO3.Workspaces.Configuration.Language
-				].concat(TYPO3.Workspaces.Helpers.getAdditionalColumnHandler()),
-				listeners: {
-					columnmoved: TYPO3.Workspaces.Actions.updateColModel,
-					hiddenchange: TYPO3.Workspaces.Actions.updateColModel
-				}
-			});
-		} else {
-				this.colModel = new Ext.grid.ColumnModel({
-				columns: [
-					TYPO3.Workspaces.SelectionModel,
-					TYPO3.Workspaces.RowExpander,
-					{id: 'uid', dataIndex : 'uid', width: 40, sortable: true, header : TYPO3.l10n.localize('column.uid'), hidden: true, filterable : true },
-					{id: 't3ver_oid', dataIndex : 't3ver_oid', width: 40, sortable: true, header : TYPO3.l10n.localize('column.oid'), hidden: true, filterable : true },
-					{id: 'workspace_Title', dataIndex : 'workspace_Title', width: 120, sortable: true, header : TYPO3.l10n.localize('column.workspaceName'), hidden: true, filter : {type : 'string'}},
-					TYPO3.Workspaces.Configuration.WsPath,
-					TYPO3.Workspaces.Configuration.LivePath,
-					TYPO3.Workspaces.Configuration.WsTitleWithIcon,
-					TYPO3.Workspaces.Configuration.SwapButton,
-					TYPO3.Workspaces.Configuration.TitleWithIcon,
-					TYPO3.Workspaces.Configuration.ChangeDate,
-					TYPO3.Workspaces.Configuration.Stage,
-					TYPO3.Workspaces.Configuration.RowButtons,
-					TYPO3.Workspaces.Configuration.Integrity,
-					TYPO3.Workspaces.Configuration.Language
-				].concat(TYPO3.Workspaces.Helpers.getAdditionalColumnHandler()),
-				listeners: {
-					columnmoved: TYPO3.Workspaces.Actions.updateColModel,
-					hiddenchange: TYPO3.Workspaces.Actions.updateColModel
-				}
-			});
-		}
-	},
-	border : true,
-	store : TYPO3.Workspaces.MainStore,
-	colModel : null,
-	sm: TYPO3.Workspaces.SelectionModel,
-	loadMask : true,
-	height: 630,
-	stripeRows: true,
-		// below the grid we need 40px space for the legend
-	heightOffset: 40,
-	plugins : [
-		TYPO3.Workspaces.RowExpander,
-		TYPO3.Workspaces.Configuration.GridFilters,
-		new Ext.ux.plugins.FitToParent()
-	],
-	view : new Ext.grid.GroupingView({
-		forceFit: true,
-		groupTextTpl : '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "' + TYPO3.l10n.localize('items') + '" : "' + TYPO3.l10n.localize('item') + '"]})',
-		enableGroupingMenu: false,
-  		enableNoGroups: false,
-		hideGroupedColumn: true
-	}),
-	bbar : TYPO3.Workspaces.Toolbar.FullBottomBar,
-	tbar : TYPO3.Workspaces.Toolbar.FullTopToolbar
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/GridFilters.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/GridFilters.js
deleted file mode 100644
index 07dbfe339635..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/GridFilters.js
+++ /dev/null
@@ -1,740 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-Ext.namespace('Ext.ux.grid');
-
-/**
- * @class Ext.ux.grid.GridFilters
- * @extends Ext.util.Observable
- * <p>GridFilter is a plugin (<code>ptype='gridfilters'</code>) for grids that
- * allow for a slightly more robust representation of filtering than what is
- * provided by the default store.</p>
- * <p>Filtering is adjusted by the user using the grid's column header menu
- * (this menu can be disabled through configuration). Through this menu users
- * can configure, enable, and disable filters for each column.</p>
- * <p><b><u>Features:</u></b></p>
- * <div class="mdetail-params"><ul>
- * <li><b>Filtering implementations</b> :
- * <div class="sub-desc">
- * Default filtering for Strings, Numeric Ranges, Date Ranges, Lists (which can
- * be backed by a Ext.data.Store), and Boolean. Additional custom filter types
- * and menus are easily created by extending Ext.ux.grid.filter.Filter.
- * </div></li>
- * <li><b>Graphical indicators</b> :
- * <div class="sub-desc">
- * Columns that are filtered have {@link #filterCls a configurable css class}
- * applied to the column headers.
- * </div></li>
- * <li><b>Paging</b> :
- * <div class="sub-desc">
- * If specified as a plugin to the grid's configured PagingToolbar, the current page
- * will be reset to page 1 whenever you update the filters.
- * </div></li>
- * <li><b>Automatic Reconfiguration</b> :
- * <div class="sub-desc">
- * Filters automatically reconfigure when the grid 'reconfigure' event fires.
- * </div></li>
- * <li><b>Stateful</b> :
- * Filter information will be persisted across page loads by specifying a
- * <code>stateId</code> in the Grid configuration.
- * <div class="sub-desc">
- * The filter collection binds to the
- * <code>{@link Ext.grid.GridPanel#beforestaterestore beforestaterestore}</code>
- * and <code>{@link Ext.grid.GridPanel#beforestatesave beforestatesave}</code>
- * events in order to be stateful.
- * </div></li>
- * <li><b>Grid Changes</b> :
- * <div class="sub-desc"><ul>
- * <li>A <code>filters</code> <i>property</i> is added to the grid pointing to
- * this plugin.</li>
- * <li>A <code>filterupdate</code> <i>event</i> is added to the grid and is
- * fired upon onStateChange completion.</li>
- * </ul></div></li>
- * <li><b>Server side code examples</b> :
- * <div class="sub-desc"><ul>
- * <li><a href="http://www.vinylfox.com/extjs/grid-filter-php-backend-code.php">PHP</a> - (Thanks VinylFox)</li>
- * <li><a href="http://extjs.com/forum/showthread.php?p=77326#post77326">Ruby on Rails</a> - (Thanks Zyclops)</li>
- * <li><a href="http://extjs.com/forum/showthread.php?p=176596#post176596">Ruby on Rails</a> - (Thanks Rotomaul)</li>
- * <li><a href="http://www.debatablybeta.com/posts/using-extjss-grid-filtering-with-django/">Python</a> - (Thanks Matt)</li>
- * <li><a href="http://mcantrell.wordpress.com/2008/08/22/extjs-grids-and-grails/">Grails</a> - (Thanks Mike)</li>
- * </ul></div></li>
- * </ul></div>
- * <p><b><u>Example usage:</u></b></p>
- * <pre><code>
-var store = new Ext.data.GroupingStore({
-	...
-});
-
-var filters = new Ext.ux.grid.GridFilters({
-	autoReload: false, //don&#39;t reload automatically
-	local: true, //only filter locally
-	// filters may be configured through the plugin,
-	// or in the column definition within the column model configuration
-	filters: [{
-		type: 'numeric',
-		dataIndex: 'id'
-	}, {
-		type: 'string',
-		dataIndex: 'name'
-	}, {
-		type: 'numeric',
-		dataIndex: 'price'
-	}, {
-		type: 'date',
-		dataIndex: 'dateAdded'
-	}, {
-		type: 'list',
-		dataIndex: 'size',
-		options: ['extra small', 'small', 'medium', 'large', 'extra large'],
-		phpMode: true
-	}, {
-		type: 'boolean',
-		dataIndex: 'visible'
-	}]
-});
-var cm = new Ext.grid.ColumnModel([{
-	...
-}]);
-
-var grid = new Ext.grid.GridPanel({
-	 ds: store,
-	 cm: cm,
-	 view: new Ext.grid.GroupingView(),
-	 plugins: [filters],
-	 height: 400,
-	 width: 700,
-	 bbar: new Ext.PagingToolbar({
-		 store: store,
-		 pageSize: 15,
-		 plugins: [filters] //reset page to page 1 if filters change
-	 })
- });
-
-store.load({params: {start: 0, limit: 15}});
-
-// a filters property is added to the grid
-grid.filters
- * </code></pre>
- */
-Ext.ux.grid.GridFilters = Ext.extend(Ext.util.Observable, {
-	/**
-	 * @cfg {Boolean} autoReload
-	 * Defaults to true, reloading the datasource when a filter change happens.
-	 * Set this to false to prevent the datastore from being reloaded if there
-	 * are changes to the filters.  See <code>{@link updateBuffer}</code>.
-	 */
-	autoReload : true,
-	/**
-	 * @cfg {Boolean} encode
-	 * Specify true for {@link #buildQuery} to use Ext.util.JSON.encode to
-	 * encode the filter query parameter sent with a remote request.
-	 * Defaults to false.
-	 */
-	/**
-	 * @cfg {Array} filters
-	 * An Array of filters config objects. Refer to each filter type class for
-	 * configuration details specific to each filter type. Filters for Strings,
-	 * Numeric Ranges, Date Ranges, Lists, and Boolean are the standard filters
-	 * available.
-	 */
-	/**
-	 * @cfg {String} filterCls
-	 * The css class to be applied to column headers with active filters.
-	 * Defaults to <tt>'ux-filterd-column'</tt>.
-	 */
-	filterCls : 'ux-filtered-column',
-	/**
-	 * @cfg {Boolean} local
-	 * <tt>true</tt> to use Ext.data.Store filter functions (local filtering)
-	 * instead of the default (<tt>false</tt>) server side filtering.
-	 */
-	local : false,
-	/**
-	 * @cfg {String} menuFilterText
-	 * defaults to <tt>'Filters'</tt>.
-	 */
-	menuFilterText : 'Filters',
-	/**
-	 * @cfg {String} paramPrefix
-	 * The url parameter prefix for the filters.
-	 * Defaults to <tt>'filter'</tt>.
-	 */
-	paramPrefix : 'filter',
-	/**
-	 * @cfg {Boolean} showMenu
-	 * Defaults to true, including a filter submenu in the default header menu.
-	 */
-	showMenu : true,
-	/**
-	 * @cfg {String} stateId
-	 * Name of the value to be used to store state information.
-	 */
-	stateId : undefined,
-	/**
-	 * @cfg {Integer} updateBuffer
-	 * Number of milliseconds to defer store updates since the last filter change.
-	 */
-	updateBuffer : 500,
-
-	/** @private */
-	constructor : function (config) {
-		config = config || {};
-		this.deferredUpdate = new Ext.util.DelayedTask(this.reload, this);
-		this.filters = new Ext.util.MixedCollection();
-		this.filters.getKey = function (o) {
-			return o ? o.dataIndex : null;
-		};
-		this.addFilters(config.filters);
-		delete config.filters;
-		Ext.apply(this, config);
-	},
-
-	/** @private */
-	init : function (grid) {
-		if (grid instanceof Ext.grid.GridPanel) {
-			this.grid = grid;
-
-			this.bindStore(this.grid.getStore(), true);
-			// assumes no filters were passed in the constructor, so try and use ones from the colModel
-			if(this.filters.getCount() == 0){
-				this.addFilters(this.grid.getColumnModel());
-			}
-
-			this.grid.filters = this;
-
-			this.grid.addEvents({'filterupdate': true});
-
-			grid.on({
-				scope: this,
-				beforestaterestore: this.applyState,
-				beforestatesave: this.saveState,
-				beforedestroy: this.destroy,
-				reconfigure: this.onReconfigure
-			});
-
-			if (grid.rendered){
-				this.onRender();
-			} else {
-				grid.on({
-					scope: this,
-					single: true,
-					render: this.onRender
-				});
-			}
-
-		} else if (grid instanceof Ext.PagingToolbar) {
-			this.toolbar = grid;
-		}
-	},
-
-	/**
-	 * @private
-	 * Handler for the grid's beforestaterestore event (fires before the state of the
-	 * grid is restored).
-	 * @param {Object} grid The grid object
-	 * @param {Object} state The hash of state values returned from the StateProvider.
-	 */
-	applyState : function (grid, state) {
-		var key, filter;
-		this.applyingState = true;
-		this.clearFilters();
-		if (state.filters) {
-			for (key in state.filters) {
-				filter = this.filters.get(key);
-				if (filter) {
-					filter.setValue(state.filters[key]);
-					filter.setActive(true);
-				}
-			}
-		}
-		this.deferredUpdate.cancel();
-		if (this.local) {
-			this.reload();
-		}
-		delete this.applyingState;
-		delete state.filters;
-	},
-
-	/**
-	 * Saves the state of all active filters
-	 * @param {Object} grid
-	 * @param {Object} state
-	 * @return {Boolean}
-	 */
-	saveState : function (grid, state) {
-		var filters = {};
-		this.filters.each(function (filter) {
-			if (filter.active) {
-				filters[filter.dataIndex] = filter.getValue();
-			}
-		});
-		return (state.filters = filters);
-	},
-
-	/**
-	 * @private
-	 * Handler called when the grid is rendered
-	 */
-	onRender : function () {
-		this.grid.getView().on('refresh', this.onRefresh, this);
-		this.createMenu();
-	},
-
-	/**
-	 * @private
-	 * Handler called by the grid 'beforedestroy' event
-	 */
-	destroy : function () {
-		this.removeAll();
-		this.purgeListeners();
-
-		if(this.filterMenu){
-			Ext.menu.MenuMgr.unregister(this.filterMenu);
-			this.filterMenu.destroy();
-			 this.filterMenu = this.menu.menu = null;
-		}
-	},
-
-	/**
-	 * Remove all filters, permanently destroying them.
-	 */
-	removeAll : function () {
-		if(this.filters){
-			Ext.destroy.apply(Ext, this.filters.items);
-			// remove all items from the collection
-			this.filters.clear();
-		}
-	},
-
-
-	/**
-	 * Changes the data store bound to this view and refreshes it.
-	 * @param {Store} store The store to bind to this view
-	 */
-	bindStore : function(store, initial){
-		if(!initial && this.store){
-			if (this.local) {
-				store.un('load', this.onLoad, this);
-			} else {
-				store.un('beforeload', this.onBeforeLoad, this);
-			}
-		}
-		if(store){
-			if (this.local) {
-				store.on('load', this.onLoad, this);
-			} else {
-				store.on('beforeload', this.onBeforeLoad, this);
-			}
-		}
-		this.store = store;
-	},
-
-	/**
-	 * @private
-	 * Handler called when the grid reconfigure event fires
-	 */
-	onReconfigure : function () {
-		this.bindStore(this.grid.getStore());
-		this.store.clearFilter();
-		this.removeAll();
-		this.addFilters(this.grid.getColumnModel());
-		this.updateColumnHeadings();
-	},
-
-	createMenu : function () {
-		var view = this.grid.getView(),
-			hmenu = view.hmenu;
-
-		if (this.showMenu && hmenu) {
-
-			this.sep  = hmenu.addSeparator();
-			this.filterMenu = new Ext.menu.Menu({
-				id: this.grid.id + '-filters-menu'
-			});
-			this.menu = hmenu.add({
-				checked: false,
-				itemId: 'filters',
-				text: this.menuFilterText,
-				menu: this.filterMenu
-			});
-
-			this.menu.on({
-				scope: this,
-				checkchange: this.onCheckChange,
-				beforecheckchange: this.onBeforeCheck
-			});
-			hmenu.on('beforeshow', this.onMenu, this);
-		}
-		this.updateColumnHeadings();
-	},
-
-	/**
-	 * @private
-	 * Get the filter menu from the filters MixedCollection based on the clicked header
-	 */
-	getMenuFilter : function () {
-		var view = this.grid.getView();
-		if (!view || view.hdCtxIndex === undefined) {
-			return null;
-		}
-		return this.filters.get(
-			view.cm.config[view.hdCtxIndex].dataIndex
-		);
-	},
-
-	/**
-	 * @private
-	 * Handler called by the grid's hmenu beforeshow event
-	 */
-	onMenu : function (filterMenu) {
-		var filter = this.getMenuFilter();
-
-		if (filter) {
-/*
-TODO: lazy rendering
-			if (!filter.menu) {
-				filter.menu = filter.createMenu();
-			}
-*/
-			this.menu.menu = filter.menu;
-			this.menu.setChecked(filter.active, false);
-			// disable the menu if filter.disabled explicitly set to true
-			this.menu.setDisabled(filter.disabled === true);
-		}
-
-		this.menu.setVisible(filter !== undefined);
-		this.sep.setVisible(filter !== undefined);
-	},
-
-	/** @private */
-	onCheckChange : function (item, value) {
-		this.getMenuFilter().setActive(value);
-	},
-
-	/** @private */
-	onBeforeCheck : function (check, value) {
-		return !value || this.getMenuFilter().isActivatable();
-	},
-
-	/**
-	 * @private
-	 * Handler for all events on filters.
-	 * @param {String} event Event name
-	 * @param {Object} filter Standard signature of the event before the event is fired
-	 */
-	onStateChange : function (event, filter) {
-		if (event === 'serialize') {
-			return;
-		}
-
-		if (filter == this.getMenuFilter()) {
-			this.menu.setChecked(filter.active, false);
-		}
-
-		if ((this.autoReload || this.local) && !this.applyingState) {
-			this.deferredUpdate.delay(this.updateBuffer);
-		}
-		this.updateColumnHeadings();
-
-		if (!this.applyingState) {
-			this.grid.saveState();
-		}
-		this.grid.fireEvent('filterupdate', this, filter);
-	},
-
-	/**
-	 * @private
-	 * Handler for store's beforeload event when configured for remote filtering
-	 * @param {Object} store
-	 * @param {Object} options
-	 */
-	onBeforeLoad : function (store, options) {
-		options.params = options.params || {};
-		this.cleanParams(options.params);
-		var params = this.buildQuery(this.getFilterData());
-		Ext.apply(options.params, params);
-	},
-
-	/**
-	 * @private
-	 * Handler for store's load event when configured for local filtering
-	 * @param {Object} store
-	 * @param {Object} options
-	 */
-	onLoad : function (store, options) {
-		store.filterBy(this.getRecordFilter());
-	},
-
-	/**
-	 * @private
-	 * Handler called when the grid's view is refreshed
-	 */
-	onRefresh : function () {
-		this.updateColumnHeadings();
-	},
-
-	/**
-	 * Update the styles for the header row based on the active filters
-	 */
-	updateColumnHeadings : function () {
-		var view = this.grid.getView(),
-			i, len, filter;
-		if (view.mainHd) {
-			for (i = 0, len = view.cm.config.length; i < len; i++) {
-				filter = this.getFilter(view.cm.config[i].dataIndex);
-				Ext.fly(view.getHeaderCell(i))[filter && filter.active ? 'addClass' : 'removeClass'](this.filterCls);
-			}
-		}
-	},
-
-	/** @private */
-	reload : function () {
-		if (this.local) {
-			this.grid.store.clearFilter(true);
-			this.grid.store.filterBy(this.getRecordFilter());
-		} else {
-			var start,
-				store = this.grid.store;
-			this.deferredUpdate.cancel();
-			if (this.toolbar) {
-				start = store.paramNames.start;
-				if (store.lastOptions && store.lastOptions.params && store.lastOptions.params[start]) {
-					store.lastOptions.params[start] = 0;
-				}
-			}
-			store.reload();
-		}
-	},
-
-	/**
-	 * Method factory that generates a record validator for the filters active at the time
-	 * of invokation.
-	 * @private
-	 */
-	getRecordFilter : function () {
-		var f = [], len, i;
-		this.filters.each(function (filter) {
-			if (filter.active) {
-				f.push(filter);
-			}
-		});
-
-		len = f.length;
-		return function (record) {
-			for (i = 0; i < len; i++) {
-				if (!f[i].validateRecord(record)) {
-					return false;
-				}
-			}
-			return true;
-		};
-	},
-
-	/**
-	 * Adds a filter to the collection and observes it for state change.
-	 * @param {Object/Ext.ux.grid.filter.Filter} config A filter configuration or a filter object.
-	 * @return {Ext.ux.grid.filter.Filter} The existing or newly created filter object.
-	 */
-	addFilter : function (config) {
-		var Cls = this.getFilterClass(config.type),
-			filter = config.menu ? config : (new Cls(config));
-		this.filters.add(filter);
-
-		Ext.util.Observable.capture(filter, this.onStateChange, this);
-		return filter;
-	},
-
-	/**
-	 * Adds filters to the collection.
-	 * @param {Array/Ext.grid.ColumnModel} filters Either an Array of
-	 * filter configuration objects or an Ext.grid.ColumnModel.  The columns
-	 * of a passed Ext.grid.ColumnModel will be examined for a <code>filter</code>
-	 * property and, if present, will be used as the filter configuration object.
-	 */
-	addFilters : function (filters) {
-		if (filters) {
-			var i, len, filter, cm = false, dI;
-			if (filters instanceof Ext.grid.ColumnModel) {
-				filters = filters.config;
-				cm = true;
-			}
-			for (i = 0, len = filters.length; i < len; i++) {
-				filter = false;
-				if (cm) {
-					dI = filters[i].dataIndex;
-					filter = filters[i].filter || filters[i].filterable;
-					if (filter){
-						filter = (filter === true) ? {} : filter;
-						Ext.apply(filter, {dataIndex:dI});
-						// filter type is specified in order of preference:
-						//     filter type specified in config
-						//     type specified in store's field's type config
-						filter.type = filter.type || this.store.fields.get(dI).type.type;
-					}
-				} else {
-					filter = filters[i];
-				}
-				// if filter config found add filter for the column
-				if (filter) {
-					this.addFilter(filter);
-				}
-			}
-		}
-	},
-
-	/**
-	 * Returns a filter for the given dataIndex, if one exists.
-	 * @param {String} dataIndex The dataIndex of the desired filter object.
-	 * @return {Ext.ux.grid.filter.Filter}
-	 */
-	getFilter : function (dataIndex) {
-		return this.filters.get(dataIndex);
-	},
-
-	/**
-	 * Turns all filters off. This does not clear the configuration information
-	 * (see {@link #removeAll}).
-	 */
-	clearFilters : function () {
-		this.filters.each(function (filter) {
-			filter.setActive(false);
-		});
-	},
-
-	/**
-	 * Returns an Array of the currently active filters.
-	 * @return {Array} filters Array of the currently active filters.
-	 */
-	getFilterData : function () {
-		var filters = [], i, len;
-
-		this.filters.each(function (f) {
-			if (f.active) {
-				var d = [].concat(f.serialize());
-				for (i = 0, len = d.length; i < len; i++) {
-					filters.push({
-						field: f.dataIndex,
-						data: d[i]
-					});
-				}
-			}
-		});
-		return filters;
-	},
-
-	/**
-	 * Function to take the active filters data and build it into a query.
-	 * The format of the query depends on the <code>{@link #encode}</code>
-	 * configuration:
-	 * <div class="mdetail-params"><ul>
-	 *
-	 * <li><b><tt>false</tt></b> : <i>Default</i>
-	 * <div class="sub-desc">
-	 * Flatten into query string of the form (assuming <code>{@link #paramPrefix}='filters'</code>:
-	 * <pre><code>
-filters[0][field]="someDataIndex"&
-filters[0][data][comparison]="someValue1"&
-filters[0][data][type]="someValue2"&
-filters[0][data][value]="someValue3"&
-	 * </code></pre>
-	 * </div></li>
-	 * <li><b><tt>true</tt></b> :
-	 * <div class="sub-desc">
-	 * JSON encode the filter data
-	 * <pre><code>
-filters[0][field]="someDataIndex"&
-filters[0][data][comparison]="someValue1"&
-filters[0][data][type]="someValue2"&
-filters[0][data][value]="someValue3"&
-	 * </code></pre>
-	 * </div></li>
-	 * </ul></div>
-	 * Override this method to customize the format of the filter query for remote requests.
-	 * @param {Array} filters A collection of objects representing active filters and their configuration.
-	 *    Each element will take the form of {field: dataIndex, data: filterConf}. dataIndex is not assured
-	 *    to be unique as any one filter may be a composite of more basic filters for the same dataIndex.
-	 * @return {Object} Query keys and values
-	 */
-	buildQuery : function (filters) {
-		var p = {}, i, f, root, dataPrefix, key, tmp,
-			len = filters.length;
-
-		if (!this.encode){
-			for (i = 0; i < len; i++) {
-				f = filters[i];
-				root = [this.paramPrefix, '[', i, ']'].join('');
-				p[root + '[field]'] = f.field;
-
-				dataPrefix = root + '[data]';
-				for (key in f.data) {
-					p[[dataPrefix, '[', key, ']'].join('')] = f.data[key];
-				}
-			}
-		} else {
-			tmp = [];
-			for (i = 0; i < len; i++) {
-				f = filters[i];
-				tmp.push(Ext.apply(
-					{},
-					{field: f.field},
-					f.data
-				));
-			}
-			// only build if there is active filter
-			if (tmp.length > 0){
-				p[this.paramPrefix] = Ext.util.JSON.encode(tmp);
-			}
-		}
-		return p;
-	},
-
-	/**
-	 * Removes filter related query parameters from the provided object.
-	 * @param {Object} p Query parameters that may contain filter related fields.
-	 */
-	cleanParams : function (p) {
-		// if encoding just delete the property
-		if (this.encode) {
-			delete p[this.paramPrefix];
-		// otherwise scrub the object of filter data
-		} else {
-			var regex, key;
-			regex = new RegExp('^' + this.paramPrefix + '\[[0-9]+\]');
-			for (key in p) {
-				if (regex.test(key)) {
-					delete p[key];
-				}
-			}
-		}
-	},
-
-	/**
-	 * Function for locating filter classes, overwrite this with your favorite
-	 * loader to provide dynamic filter loading.
-	 * @param {String} type The type of filter to load ('Filter' is automatically
-	 * appended to the passed type; eg, 'string' becomes 'StringFilter').
-	 * @return {Class} The Ext.ux.grid.filter.Class
-	 */
-	getFilterClass : function (type) {
-		// map the supported Ext.data.Field type values into a supported filter
-		switch(type) {
-			case 'auto':
-			  type = 'string';
-			  break;
-			case 'int':
-			case 'float':
-			  type = 'numeric';
-			  break;
-			case 'bool':
-			  type = 'boolean';
-			  break;
-		}
-		return Ext.ux.grid.filter[type.substr(0, 1).toUpperCase() + type.substr(1) + 'Filter'];
-	}
-});
-
-// register ptype
-Ext.preg('gridfilters', Ext.ux.grid.GridFilters);
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/GridFilters.css b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/GridFilters.css
deleted file mode 100644
index 0d1057866ad5..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/GridFilters.css
+++ /dev/null
@@ -1,53 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/**
- * GridFilters Styles
- **/
-/*
-.x-grid3-hd-row .ux-filtered-column {
-	border-left:  1px solid #C7E3B4;
-	border-right: 1px solid #C7E3B4;
-}
-
-.x-grid3-hd-row .ux-filtered-column .x-grid3-hd-inner {
-	background-image: url(../images/header_bg.gif);
-}
-
-.ux-filtered-column .x-grid3-hd-btn {
-	background-image: url(../images/hd-btn.gif);
-}
-*/
-.x-grid3-hd-row td.ux-filtered-column {
-	font-style: italic;
-	font-weight: bold;
-}
-
-.ux-filtered-column.sort-asc .x-grid3-sort-icon {
-	background-image: url(../images/sort_filtered_asc.gif) !important;
-}
-
-.ux-filtered-column.sort-desc .x-grid3-sort-icon {
-	background-image: url(../images/sort_filtered_desc.gif) !important;
-}
-
-.ux-gridfilter-text-icon {
-	background-image: url(../images/find.png) !important;
-}
-
-/* Temporary Patch for Bug ??? */
-.x-menu-list-item-indent .x-menu-item-icon {
-	position: relative;
-	top: 3px;
-	left: 3px;
-	margin-right: 10px;
-}
-li.x-menu-list-item-indent {
-	padding-left:0px;
-}
-li.x-menu-list-item div {
-	display: block;
-}
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/RangeMenu.css b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/RangeMenu.css
deleted file mode 100644
index 9495126e2e86..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/css/RangeMenu.css
+++ /dev/null
@@ -1,20 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/**
- * RangeMenu Styles
- **/
-.ux-rangemenu-gt {
-	background-image: url(../images/greater_than.png) !important;
-}
-
-.ux-rangemenu-lt {
-	background-image: url(../images/less_than.png) !important;
-}
-
-.ux-rangemenu-eq {
-	background-image: url(../images/equals.png) !important;
-}
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/BooleanFilter.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/BooleanFilter.js
deleted file mode 100644
index 3d9af5baf737..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/BooleanFilter.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/** 
- * @class Ext.ux.grid.filter.BooleanFilter
- * @extends Ext.ux.grid.filter.Filter
- * Boolean filters use unique radio group IDs (so you can have more than one!)
- * <p><b><u>Example Usage:</u></b></p>
- * <pre><code>    
-var filters = new Ext.ux.grid.GridFilters({
-	...
-	filters: [{
-		// required configs
-		type: 'boolean',
-		dataIndex: 'visible'
-
-		// optional configs
-		defaultValue: null, // leave unselected (false selected by default)
-		yesText: 'Yes',     // default
-		noText: 'No'        // default
-	}]
-});
- * </code></pre>
- */
-Ext.ux.grid.filter.BooleanFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
-	/**
-	 * @cfg {Boolean} defaultValue
-	 * Set this to null if you do not want either option to be checked by default. Defaults to false.
-	 */
-	defaultValue : false,
-	/**
-	 * @cfg {String} yesText
-	 * Defaults to 'Yes'.
-	 */
-	yesText : 'Yes',
-	/**
-	 * @cfg {String} noText
-	 * Defaults to 'No'.
-	 */
-	noText : 'No',
-
-	/**
-	 * @private
-	 * Template method that is to initialize the filter and install required menu items.
-	 */
-	init : function (config) {
-		var gId = Ext.id();
-		this.options = [
-			new Ext.menu.CheckItem({text: this.yesText, group: gId, checked: this.defaultValue === true}),
-			new Ext.menu.CheckItem({text: this.noText, group: gId, checked: this.defaultValue === false})];
-
-		this.menu.add(this.options[0], this.options[1]);
-
-		for(var i=0; i<this.options.length; i++){
-			this.options[i].on('click', this.fireUpdate, this);
-			this.options[i].on('checkchange', this.fireUpdate, this);
-		}
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return the value of the filter.
-	 * @return {String} The value of this filter
-	 */
-	getValue : function () {
-		return this.options[0].checked;
-	},
-
-	/**
-	 * @private
-	 * Template method that is to set the value of the filter.
-	 * @param {Object} value The value to set the filter
-	 */
-	setValue : function (value) {
-		this.options[value ? 0 : 1].setChecked(true);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return serialized filter data for
-	 * transmission to the server.
-	 * @return {Object/Array} An object or collection of objects containing
-	 * key value pairs representing the current configuration of the filter.
-	 */
-	getSerialArgs : function () {
-		var args = {type: 'boolean', value: this.getValue()};
-		return args;
-	},
-
-	/**
-	 * Template method that is to validate the provided Ext.data.Record
-	 * against the filters configuration.
-	 * @param {Ext.data.Record} record The record to validate
-	 * @return {Boolean} true if the record is valid within the bounds
-	 * of the filter, false otherwise.
-	 */
-	validateRecord : function (record) {
-		return record.get(this.dataIndex) == this.getValue();
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/DateFilter.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/DateFilter.js
deleted file mode 100644
index af8e3f128298..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/DateFilter.js
+++ /dev/null
@@ -1,313 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/** 
- * @class Ext.ux.grid.filter.DateFilter
- * @extends Ext.ux.grid.filter.Filter
- * Filter by a configurable Ext.menu.DateMenu
- * <p><b><u>Example Usage:</u></b></p>
- * <pre><code>    
-var filters = new Ext.ux.grid.GridFilters({
-	...
-	filters: [{
-		// required configs
-		type: 'date',
-		dataIndex: 'dateAdded',
-
-		// optional configs
-		dateFormat: 'm/d/Y',  // default
-		beforeText: 'Before', // default
-		afterText: 'After',   // default
-		onText: 'On',         // default
-		pickerOpts: {
-			// any DateMenu configs
-		},
-
-		active: true // default is false
-	}]
-});
- * </code></pre>
- */
-Ext.ux.grid.filter.DateFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
-	/**
-	 * @cfg {String} afterText
-	 * Defaults to 'After'.
-	 */
-	afterText : 'After',
-	/**
-	 * @cfg {String} beforeText
-	 * Defaults to 'Before'.
-	 */
-	beforeText : 'Before',
-	/**
-	 * @cfg {Object} compareMap
-	 * Map for assigning the comparison values used in serialization.
-	 */
-	compareMap : {
-		before: 'lt',
-		after:  'gt',
-		on:     'eq'
-	},
-	/**
-	 * @cfg {String} dateFormat
-	 * The date format to return when using getValue.
-	 * Defaults to 'm/d/Y'.
-	 */
-	dateFormat : 'm/d/Y',
-
-	/**
-	 * @cfg {Date} maxDate
-	 * Allowable date as passed to the Ext.DatePicker
-	 * Defaults to undefined.
-	 */
-	/**
-	 * @cfg {Date} minDate
-	 * Allowable date as passed to the Ext.DatePicker
-	 * Defaults to undefined.
-	 */
-	/**
-	 * @cfg {Array} menuItems
-	 * The items to be shown in this menu
-	 * Defaults to:<pre>
-	 * menuItems : ['before', 'after', '-', 'on'],
-	 * </pre>
-	 */
-	menuItems : ['before', 'after', '-', 'on'],
-
-	/**
-	 * @cfg {Object} menuItemCfgs
-	 * Default configuration options for each menu item
-	 */
-	menuItemCfgs : {
-		selectOnFocus: true,
-		width: 125
-	},
-
-	/**
-	 * @cfg {String} onText
-	 * Defaults to 'On'.
-	 */
-	onText : 'On',
-
-	/**
-	 * @cfg {Object} pickerOpts
-	 * Configuration options for the date picker associated with each field.
-	 */
-	pickerOpts : {},
-
-	/**
-	 * @private
-	 * Template method that is to initialize the filter and install required menu items.
-	 */
-	init : function (config) {
-		var menuCfg, i, len, item, cfg, Cls;
-
-		menuCfg = Ext.apply(this.pickerOpts, {
-			minDate: this.minDate,
-			maxDate: this.maxDate,
-			format:  this.dateFormat,
-			listeners: {
-				scope: this,
-				select: this.onMenuSelect
-			}
-		});
-
-		this.fields = {};
-		for (i = 0, len = this.menuItems.length; i < len; i++) {
-			item = this.menuItems[i];
-			if (item !== '-') {
-				cfg = {
-					itemId: 'range-' + item,
-					text: this[item + 'Text'],
-					menu: new Ext.menu.DateMenu(
-						Ext.apply(menuCfg, {
-							itemId: item
-						})
-					),
-					listeners: {
-						scope: this,
-						checkchange: this.onCheckChange
-					}
-				};
-				Cls = Ext.menu.CheckItem;
-				item = this.fields[item] = new Cls(cfg);
-			}
-			//this.add(item);
-			this.menu.add(item);
-		}
-	},
-
-	onCheckChange : function () {
-		this.setActive(this.isActivatable());
-		this.fireEvent('update', this);
-	},
-
-	/**
-	 * @private
-	 * Handler method called when there is a keyup event on an input
-	 * item of this menu.
-	 */
-	onInputKeyUp : function (field, e) {
-		var k = e.getKey();
-		if (k == e.RETURN && field.isValid()) {
-			e.stopEvent();
-			this.menu.hide(true);
-			return;
-		}
-	},
-
-	/**
-	 * Handler for when the menu for a field fires the 'select' event
-	 * @param {Object} date
-	 * @param {Object} menuItem
-	 * @param {Object} value
-	 * @param {Object} picker
-	 */
-	onMenuSelect : function (menuItem, value, picker) {
-		var fields = this.fields,
-			field = this.fields[menuItem.itemId];
-
-		field.setChecked(true);
-
-		if (field == fields.on) {
-			fields.before.setChecked(false, true);
-			fields.after.setChecked(false, true);
-		} else {
-			fields.on.setChecked(false, true);
-			if (field == fields.after && fields.before.menu.picker.value < value) {
-				fields.before.setChecked(false, true);
-			} else if (field == fields.before && fields.after.menu.picker.value > value) {
-				fields.after.setChecked(false, true);
-			}
-		}
-		this.fireEvent('update', this);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return the value of the filter.
-	 * @return {String} The value of this filter
-	 */
-	getValue : function () {
-		var key, result = {};
-		for (key in this.fields) {
-			if (this.fields[key].checked) {
-				result[key] = this.fields[key].menu.picker.getValue();
-			}
-		}
-		return result;
-	},
-
-	/**
-	 * @private
-	 * Template method that is to set the value of the filter.
-	 * @param {Object} value The value to set the filter
-	 * @param {Boolean} preserve true to preserve the checked status
-	 * of the other fields.  Defaults to false, unchecking the
-	 * other fields
-	 */
-	setValue : function (value, preserve) {
-		var key;
-		for (key in this.fields) {
-			if(value[key]){
-				this.fields[key].menu.picker.setValue(value[key]);
-				this.fields[key].setChecked(true);
-			} else if (!preserve) {
-				this.fields[key].setChecked(false);
-			}
-		}
-		this.fireEvent('update', this);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to return <tt>true</tt> if the filter
-	 * has enough configuration information to be activated.
-	 * @return {Boolean}
-	 */
-	isActivatable : function () {
-		var key;
-		for (key in this.fields) {
-			if (this.fields[key].checked) {
-				return true;
-			}
-		}
-		return false;
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return serialized filter data for
-	 * transmission to the server.
-	 * @return {Object/Array} An object or collection of objects containing
-	 * key value pairs representing the current configuration of the filter.
-	 */
-	getSerialArgs : function () {
-		var args = [];
-		for (var key in this.fields) {
-			if(this.fields[key].checked){
-				args.push({
-					type: 'date',
-					comparison: this.compareMap[key],
-					value: this.getFieldValue(key).format(this.dateFormat)
-				});
-			}
-		}
-		return args;
-	},
-
-	/**
-	 * Get and return the date menu picker value
-	 * @param {String} item The field identifier ('before', 'after', 'on')
-	 * @return {Date} Gets the current selected value of the date field
-	 */
-	getFieldValue : function(item){
-		return this.fields[item].menu.picker.getValue();
-	},
-
-	/**
-	 * Gets the menu picker associated with the passed field
-	 * @param {String} item The field identifier ('before', 'after', 'on')
-	 * @return {Object} The menu picker
-	 */
-	getPicker : function(item){
-		return this.fields[item].menu.picker;
-	},
-
-	/**
-	 * Template method that is to validate the provided Ext.data.Record
-	 * against the filters configuration.
-	 * @param {Ext.data.Record} record The record to validate
-	 * @return {Boolean} true if the record is valid within the bounds
-	 * of the filter, false otherwise.
-	 */
-	validateRecord : function (record) {
-		var key,
-			pickerValue,
-			val = record.get(this.dataIndex);
-
-		if(!Ext.isDate(val)){
-			return false;
-		}
-		val = val.clearTime(true).getTime();
-
-		for (key in this.fields) {
-			if (this.fields[key].checked) {
-				pickerValue = this.getFieldValue(key).clearTime(true).getTime();
-				if (key == 'before' && pickerValue <= val) {
-					return false;
-				}
-				if (key == 'after' && pickerValue >= val) {
-					return false;
-				}
-				if (key == 'on' && pickerValue != val) {
-					return false;
-				}
-			}
-		}
-		return true;
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/Filter.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/Filter.js
deleted file mode 100644
index 79f7883bcb74..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/Filter.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-Ext.namespace('Ext.ux.grid.filter');
-
-/** 
- * @class Ext.ux.grid.filter.Filter
- * @extends Ext.util.Observable
- * Abstract base class for filter implementations.
- */
-Ext.ux.grid.filter.Filter = Ext.extend(Ext.util.Observable, {
-	/**
-	 * @cfg {Boolean} active
-	 * Indicates the initial status of the filter (defaults to false).
-	 */
-	active : false,
-	/**
-	 * True if this filter is active.  Use setActive() to alter after configuration.
-	 * @type Boolean
-	 * @property active
-	 */
-	/**
-	 * @cfg {String} dataIndex
-	 * The {@link Ext.data.Store} dataIndex of the field this filter represents.
-	 * The dataIndex does not actually have to exist in the store.
-	 */
-	dataIndex : null,
-	/**
-	 * The filter configuration menu that will be installed into the filter submenu of a column menu.
-	 * @type Ext.menu.Menu
-	 * @property
-	 */
-	menu : null,
-	/**
-	 * @cfg {Number} updateBuffer
-	 * Number of milliseconds to wait after user interaction to fire an update. Only supported
-	 * by filters: 'list', 'numeric', and 'string'. Defaults to 500.
-	 */
-	updateBuffer : 500,
-
-	constructor : function (config) {
-		Ext.apply(this, config);
-
-		this.addEvents(
-			/**
-			 * @event activate
-			 * Fires when an inactive filter becomes active
-			 * @param {Ext.ux.grid.filter.Filter} this
-			 */
-			'activate',
-			/**
-			 * @event deactivate
-			 * Fires when an active filter becomes inactive
-			 * @param {Ext.ux.grid.filter.Filter} this
-			 */
-			'deactivate',
-			/**
-			 * @event serialize
-			 * Fires after the serialization process. Use this to attach additional parameters to serialization
-			 * data before it is encoded and sent to the server.
-			 * @param {Array/Object} data A map or collection of maps representing the current filter configuration.
-			 * @param {Ext.ux.grid.filter.Filter} filter The filter being serialized.
-			 */
-			'serialize',
-			/**
-			 * @event update
-			 * Fires when a filter configuration has changed
-			 * @param {Ext.ux.grid.filter.Filter} this The filter object.
-			 */
-			'update'
-		);
-		Ext.ux.grid.filter.Filter.superclass.constructor.call(this);
-
-		this.menu = new Ext.menu.Menu();
-		this.init(config);
-		if(config && config.value){
-			this.setValue(config.value);
-			this.setActive(config.active !== false, true);
-			delete config.value;
-		}
-	},
-
-	/**
-	 * Destroys this filter by purging any event listeners, and removing any menus.
-	 */
-	destroy : function(){
-		if (this.menu){
-			this.menu.destroy();
-		}
-		this.purgeListeners();
-	},
-
-	/**
-	 * Template method to be implemented by all subclasses that is to
-	 * initialize the filter and install required menu items.
-	 * Defaults to Ext.emptyFn.
-	 */
-	init : Ext.emptyFn,
-
-	/**
-	 * Template method to be implemented by all subclasses that is to
-	 * get and return the value of the filter.
-	 * Defaults to Ext.emptyFn.
-	 * @return {Object} The 'serialized' form of this filter
-	 * @methodOf Ext.ux.grid.filter.Filter
-	 */
-	getValue : Ext.emptyFn,
-
-	/**
-	 * Template method to be implemented by all subclasses that is to
-	 * set the value of the filter and fire the 'update' event.
-	 * Defaults to Ext.emptyFn.
-	 * @param {Object} data The value to set the filter
-	 * @methodOf Ext.ux.grid.filter.Filter
-	 */
-	setValue : Ext.emptyFn,
-
-	/**
-	 * Template method to be implemented by all subclasses that is to
-	 * return <tt>true</tt> if the filter has enough configuration information to be activated.
-	 * Defaults to <tt>return true</tt>.
-	 * @return {Boolean}
-	 */
-	isActivatable : function(){
-		return true;
-	},
-
-	/**
-	 * Template method to be implemented by all subclasses that is to
-	 * get and return serialized filter data for transmission to the server.
-	 * Defaults to Ext.emptyFn.
-	 */
-	getSerialArgs : Ext.emptyFn,
-
-	/**
-	 * Template method to be implemented by all subclasses that is to
-	 * validates the provided Ext.data.Record against the filters configuration.
-	 * Defaults to <tt>return true</tt>.
-	 * @param {Ext.data.Record} record The record to validate
-	 * @return {Boolean} true if the record is valid within the bounds
-	 * of the filter, false otherwise.
-	 */
-	validateRecord : function(){
-		return true;
-	},
-
-	/**
-	 * Returns the serialized filter data for transmission to the server
-	 * and fires the 'serialize' event.
-	 * @return {Object/Array} An object or collection of objects containing
-	 * key value pairs representing the current configuration of the filter.
-	 * @methodOf Ext.ux.grid.filter.Filter
-	 */
-	serialize : function(){
-		var args = this.getSerialArgs();
-		this.fireEvent('serialize', args, this);
-		return args;
-	},
-
-	/** @private */
-	fireUpdate : function(){
-		if (this.active) {
-			this.fireEvent('update', this);
-		}
-		this.setActive(this.isActivatable());
-	},
-
-	/**
-	 * Sets the status of the filter and fires the appropriate events.
-	 * @param {Boolean} active        The new filter state.
-	 * @param {Boolean} suppressEvent True to prevent events from being fired.
-	 * @methodOf Ext.ux.grid.filter.Filter
-	 */
-	setActive : function(active, suppressEvent){
-		if(this.active != active){
-			this.active = active;
-			if (suppressEvent !== true) {
-				this.fireEvent(active ? 'activate' : 'deactivate', this);
-			}
-		}
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/ListFilter.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/ListFilter.js
deleted file mode 100644
index 234e9e575126..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/ListFilter.js
+++ /dev/null
@@ -1,176 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/** 
- * @class Ext.ux.grid.filter.ListFilter
- * @extends Ext.ux.grid.filter.Filter
- * <p>List filters are able to be preloaded/backed by an Ext.data.Store to load
- * their options the first time they are shown. ListFilter utilizes the
- * {@link Ext.ux.menu.ListMenu} component.</p>
- * <p>Although not shown here, this class accepts all configuration options
- * for {@link Ext.ux.menu.ListMenu}.</p>
- * 
- * <p><b><u>Example Usage:</u></b></p>
- * <pre><code>    
-var filters = new Ext.ux.grid.GridFilters({
-	...
-	filters: [{
-		type: 'list',
-		dataIndex: 'size',
-		phpMode: true,
-		// options will be used as data to implicitly creates an ArrayStore
-		options: ['extra small', 'small', 'medium', 'large', 'extra large']
-	}]
-});
- * </code></pre>
- * 
- */
-Ext.ux.grid.filter.ListFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
-
-	/**
-	 * @cfg {Array} options
-	 * <p><code>data</code> to be used to implicitly create a data store
-	 * to back this list when the data source is <b>local</b>. If the
-	 * data for the list is remote, use the <code>{@link #store}</code>
-	 * config instead.</p>
-	 * <br><p>Each item within the provided array may be in one of the
-	 * following formats:</p>
-	 * <div class="mdetail-params"><ul>
-	 * <li><b>Array</b> :
-	 * <pre><code>
-options: [
-	[11, 'extra small'],
-	[18, 'small'],
-	[22, 'medium'],
-	[35, 'large'],
-	[44, 'extra large']
-]
-	 * </code></pre>
-	 * </li>
-	 * <li><b>Object</b> :
-	 * <pre><code>
-labelField: 'name', // override default of 'text'
-options: [
-	{id: 11, name:'extra small'},
-	{id: 18, name:'small'},
-	{id: 22, name:'medium'},
-	{id: 35, name:'large'},
-	{id: 44, name:'extra large'}
-]
-	 * </code></pre>
-	 * </li>
-	 * <li><b>String</b> :
-	 * <pre><code>
-	 * options: ['extra small', 'small', 'medium', 'large', 'extra large']
-	 * </code></pre>
-	 * </li>
-	 */
-	/**
-	 * @cfg {Boolean} phpMode
-	 * <p>Adjust the format of this filter. Defaults to false.</p>
-	 * <br><p>When GridFilters <code>@cfg encode = false</code> (default):</p>
-	 * <pre><code>
-// phpMode == false (default):
-filter[0][data][type] list
-filter[0][data][value] value1
-filter[0][data][value] value2
-filter[0][field] prod 
-
-// phpMode == true:
-filter[0][data][type] list
-filter[0][data][value] value1, value2
-filter[0][field] prod 
-	 * </code></pre>
-	 * When GridFilters <code>@cfg encode = true</code>:
-	 * <pre><code>
-// phpMode == false (default):
-filter : [{"type":"list","value":["small","medium"],"field":"size"}]
-
-// phpMode == true:
-filter : [{"type":"list","value":"small,medium","field":"size"}]
-	 * </code></pre>
-	 */
-	phpMode : false,
-	/**
-	 * @cfg {Ext.data.Store} store
-	 * The {@link Ext.data.Store} this list should use as its data source
-	 * when the data source is <b>remote</b>. If the data for the list
-	 * is local, use the <code>{@link #options}</code> config instead.
-	 */
-
-	/**
-	 * @private
-	 * Template method that is to initialize the filter and install required menu items.
-	 * @param {Object} config
-	 */
-	init : function (config) {
-		this.dt = new Ext.util.DelayedTask(this.fireUpdate, this);
-
-		// if a menu already existed, do clean up first
-		if (this.menu){
-			this.menu.destroy();
-		}
-		this.menu = new Ext.ux.menu.ListMenu(config);
-		this.menu.on('checkchange', this.onCheckChange, this);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return the value of the filter.
-	 * @return {String} The value of this filter
-	 */
-	getValue : function () {
-		return this.menu.getSelected();
-	},
-	/**
-	 * @private
-	 * Template method that is to set the value of the filter.
-	 * @param {Object} value The value to set the filter
-	 */
-	setValue : function (value) {
-		this.menu.setSelected(value);
-		this.fireEvent('update', this);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to return <tt>true</tt> if the filter
-	 * has enough configuration information to be activated.
-	 * @return {Boolean}
-	 */
-	isActivatable : function () {
-		return this.getValue().length > 0;
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return serialized filter data for
-	 * transmission to the server.
-	 * @return {Object/Array} An object or collection of objects containing
-	 * key value pairs representing the current configuration of the filter.
-	 */
-	getSerialArgs : function () {
-		var args = {type: 'list', value: this.phpMode ? this.getValue().join(',') : this.getValue()};
-		return args;
-	},
-
-	/** @private */
-	onCheckChange : function(){
-		this.dt.delay(this.updateBuffer);
-	},
-
-
-	/**
-	 * Template method that is to validate the provided Ext.data.Record
-	 * against the filters configuration.
-	 * @param {Ext.data.Record} record The record to validate
-	 * @return {Boolean} true if the record is valid within the bounds
-	 * of the filter, false otherwise.
-	 */
-	validateRecord : function (record) {
-		return this.getValue().indexOf(record.get(this.dataIndex)) > -1;
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/NumericFilter.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/NumericFilter.js
deleted file mode 100644
index 181af8dca268..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/NumericFilter.js
+++ /dev/null
@@ -1,202 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/** 
- * @class Ext.ux.grid.filter.NumericFilter
- * @extends Ext.ux.grid.filter.Filter
- * Filters using an Ext.ux.menu.RangeMenu.
- * <p><b><u>Example Usage:</u></b></p>
- * <pre><code>    
-var filters = new Ext.ux.grid.GridFilters({
-	...
-	filters: [{
-		type: 'numeric',
-		dataIndex: 'price'
-	}]
-});
- * </code></pre> 
- */
-Ext.ux.grid.filter.NumericFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
-
-	/**
-	 * @cfg {Object} fieldCls
-	 * The Class to use to construct each field item within this menu
-	 * Defaults to:<pre>
-	 * fieldCls : Ext.form.NumberField
-	 * </pre>
-	 */
-	fieldCls : Ext.form.NumberField,
-	/**
-	 * @cfg {Object} fieldCfg
-	 * The default configuration options for any field item unless superseded
-	 * by the <code>{@link #fields}</code> configuration.
-	 * Defaults to:<pre>
-	 * fieldCfg : {}
-	 * </pre>
-	 * Example usage:
-	 * <pre><code>
-fieldCfg : {
-	width: 150,
-},
-	 * </code></pre>
-	 */
-	/**
-	 * @cfg {Object} fields
-	 * The field items may be configured individually
-	 * Defaults to <tt>undefined</tt>.
-	 * Example usage:
-	 * <pre><code>
-fields : {
-	gt: { // override fieldCfg options
-		width: 200,
-		fieldCls: Ext.ux.form.CustomNumberField // to override default {@link #fieldCls}
-	}
-},
-	 * </code></pre>
-	 */
-	/**
-	 * @cfg {Object} iconCls
-	 * The iconCls to be applied to each comparator field item.
-	 * Defaults to:<pre>
-iconCls : {
-	gt : 'ux-rangemenu-gt',
-	lt : 'ux-rangemenu-lt',
-	eq : 'ux-rangemenu-eq'
-}
-	 * </pre>
-	 */
-	iconCls : {
-		gt : 'ux-rangemenu-gt',
-		lt : 'ux-rangemenu-lt',
-		eq : 'ux-rangemenu-eq'
-	},
-
-	/**
-	 * @cfg {Object} menuItemCfgs
-	 * Default configuration options for each menu item
-	 * Defaults to:<pre>
-menuItemCfgs : {
-	emptyText: 'Enter Filter Text...',
-	selectOnFocus: true,
-	width: 125
-}
-	 * </pre>
-	 */
-	menuItemCfgs : {
-		emptyText: 'Enter Filter Text...',
-		selectOnFocus: true,
-		width: 125
-	},
-
-	/**
-	 * @cfg {Array} menuItems
-	 * The items to be shown in this menu.  Items are added to the menu
-	 * according to their position within this array. Defaults to:<pre>
-	 * menuItems : ['lt','gt','-','eq']
-	 * </pre>
-	 */
-	menuItems : ['lt', 'gt', '-', 'eq'],
-
-	/**
-	 * @private
-	 * Template method that is to initialize the filter and install required menu items.
-	 */
-	init : function (config) {
-		// if a menu already existed, do clean up first
-		if (this.menu){
-			this.menu.destroy();
-		}
-		this.menu = new Ext.ux.menu.RangeMenu(Ext.apply(config, {
-			// pass along filter configs to the menu
-			fieldCfg : this.fieldCfg || {},
-			fieldCls : this.fieldCls,
-			fields : this.fields || {},
-			iconCls: this.iconCls,
-			menuItemCfgs: this.menuItemCfgs,
-			menuItems: this.menuItems,
-			updateBuffer: this.updateBuffer
-		}));
-		// relay the event fired by the menu
-		this.menu.on('update', this.fireUpdate, this);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return the value of the filter.
-	 * @return {String} The value of this filter
-	 */
-	getValue : function () {
-		return this.menu.getValue();
-	},
-
-	/**
-	 * @private
-	 * Template method that is to set the value of the filter.
-	 * @param {Object} value The value to set the filter
-	 */
-	setValue : function (value) {
-		this.menu.setValue(value);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to return <tt>true</tt> if the filter
-	 * has enough configuration information to be activated.
-	 * @return {Boolean}
-	 */
-	isActivatable : function () {
-		var values = this.getValue();
-		for (key in values) {
-			if (values[key] !== undefined) {
-				return true;
-			}
-		}
-		return false;
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return serialized filter data for
-	 * transmission to the server.
-	 * @return {Object/Array} An object or collection of objects containing
-	 * key value pairs representing the current configuration of the filter.
-	 */
-	getSerialArgs : function () {
-		var key,
-			args = [],
-			values = this.menu.getValue();
-		for (key in values) {
-			args.push({
-				type: 'numeric',
-				comparison: key,
-				value: values[key]
-			});
-		}
-		return args;
-	},
-
-	/**
-	 * Template method that is to validate the provided Ext.data.Record
-	 * against the filters configuration.
-	 * @param {Ext.data.Record} record The record to validate
-	 * @return {Boolean} true if the record is valid within the bounds
-	 * of the filter, false otherwise.
-	 */
-	validateRecord : function (record) {
-		var val = record.get(this.dataIndex),
-			values = this.getValue();
-		if (values.eq !== undefined && val != values.eq) {
-			return false;
-		}
-		if (values.lt !== undefined && val >= values.lt) {
-			return false;
-		}
-		if (values.gt !== undefined && val <= values.gt) {
-			return false;
-		}
-		return true;
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/StringFilter.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/StringFilter.js
deleted file mode 100644
index d1af8e2edd20..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/filter/StringFilter.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-/** 
- * @class Ext.ux.grid.filter.StringFilter
- * @extends Ext.ux.grid.filter.Filter
- * Filter by a configurable Ext.form.TextField
- * <p><b><u>Example Usage:</u></b></p>
- * <pre><code>    
-var filters = new Ext.ux.grid.GridFilters({
-	...
-	filters: [{
-		// required configs
-		type: 'string',
-		dataIndex: 'name',
-
-		// optional configs
-		value: 'foo',
-		active: true, // default is false
-		iconCls: 'ux-gridfilter-text-icon' // default
-		// any Ext.form.TextField configs accepted
-	}]
-});
- * </code></pre>
- */
-Ext.ux.grid.filter.StringFilter = Ext.extend(Ext.ux.grid.filter.Filter, {
-
-	/**
-	 * @cfg {String} iconCls
-	 * The iconCls to be applied to the menu item.
-	 * Defaults to <tt>'ux-gridfilter-text-icon'</tt>.
-	 */
-	iconCls : 'ux-gridfilter-text-icon',
-
-	emptyText: 'Enter Filter Text...',
-	selectOnFocus: true,
-	width: 125,
-
-	/**
-	 * @private
-	 * Template method that is to initialize the filter and install required menu items.
-	 */
-	init : function (config) {
-		Ext.applyIf(config, {
-			enableKeyEvents: true,
-			iconCls: this.iconCls,
-			listeners: {
-				scope: this,
-				keyup: this.onInputKeyUp
-			}
-		});
-
-		this.inputItem = new Ext.form.TextField(config);
-		this.menu.add(this.inputItem);
-		this.updateTask = new Ext.util.DelayedTask(this.fireUpdate, this);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return the value of the filter.
-	 * @return {String} The value of this filter
-	 */
-	getValue : function () {
-		return this.inputItem.getValue();
-	},
-
-	/**
-	 * @private
-	 * Template method that is to set the value of the filter.
-	 * @param {Object} value The value to set the filter
-	 */
-	setValue : function (value) {
-		this.inputItem.setValue(value);
-		this.fireEvent('update', this);
-	},
-
-	/**
-	 * @private
-	 * Template method that is to return <tt>true</tt> if the filter
-	 * has enough configuration information to be activated.
-	 * @return {Boolean}
-	 */
-	isActivatable : function () {
-		return this.inputItem.getValue().length > 0;
-	},
-
-	/**
-	 * @private
-	 * Template method that is to get and return serialized filter data for
-	 * transmission to the server.
-	 * @return {Object/Array} An object or collection of objects containing
-	 * key value pairs representing the current configuration of the filter.
-	 */
-	getSerialArgs : function () {
-		return {type: 'string', value: this.getValue()};
-	},
-
-	/**
-	 * Template method that is to validate the provided Ext.data.Record
-	 * against the filters configuration.
-	 * @param {Ext.data.Record} record The record to validate
-	 * @return {Boolean} true if the record is valid within the bounds
-	 * of the filter, false otherwise.
-	 */
-	validateRecord : function (record) {
-		var val = record.get(this.dataIndex);
-
-		if(typeof val != 'string') {
-			return (this.getValue().length === 0);
-		}
-
-		return val.toLowerCase().indexOf(this.getValue().toLowerCase()) > -1;
-	},
-
-	/**
-	 * @private
-	 * Handler method called when there is a keyup event on this.inputItem
-	 */
-	onInputKeyUp : function (field, e) {
-		var k = e.getKey();
-		if (k == e.RETURN && field.isValid()) {
-			e.stopEvent();
-			this.menu.hide(true);
-			return;
-		}
-		// restart the timer
-		this.updateTask.delay(this.updateBuffer);
-	}
-});
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/equals.png b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/equals.png
deleted file mode 100644
index 4769cb1583178d094a4385f475486de77f3e4099..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 106
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9>;M1%jg5^hLV6|wMHowh
z{DK)Ap4~_Ta)dlx978ywlM@_RKiSXNuqly&!Q6+*xaot#5}+)Dr>mdKI;Vst0Hr1x
AWB>pF

diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/find.png b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/find.png
deleted file mode 100644
index ccb710716d7b55ac0272b7dbaab86fbc08acc9a5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 638
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47<~hLLR|m<{~sEgx?s)Disn8+
zVNo`A_6c)WPg%IWxqnXIlI;pgszCK^ljaxIwgW|gY#>N0sPqeskyTI@5fhh`kz-_J
z1Pb~DMKQCmSlPRpSlX#->hSRky7>g_8Jh!5;O6Gx;N;TK)>l+fmynhPYEe?v0O|#*
z$tbF+?VQ>=aW2q`f~wZFI}WYeaoEE@3}{GpY5lIlXHxSkwDpa1%bQkhIgnq`oKw~y
zCLsm1u5b2=+TQtH)0cG5Se8{%H+jLj^up>z>vmb#I;G^67go0cU1eZm33Lh2QfXO*
z>WQm(`S_P?*b|$U$I8mq)HhpHToUNE%9aV%j&3eq0YFd1XB0-{G}TUA7M<JNIDLbo
zyRVv--n7LVb&brt0wYRVrWjk;0>dgixzNGQCn>umIyq;`@?D%<+`vEs`aLea;Mt^~
z6M>G?DhcunX1K-ih>4Nq;gerH%&Z=d{;{(Dd}^@u9n;|l%U7&8{O9V`sy{y&-|=6O
zx_$qu%~YVSZJsWUAr*1GCk~gfI5MzaFyA70d*!Na$IX&&|N5Wmr(d*b?(RJ^{7Q}l
zr1t$U=sd5$`agcpR1NjVTMwP)b~Jy`BeP*z$t>CU7(1`matB_omOl1Cxgd5=)xyt;
z3TNJlT&meWb<>ic!rjcBDUTm|`Y$!!x%lwIGdc~Hex|3pBdo;E95P~96Y=WiPpxYe
zj;nKT6eh2X$}P^G%_TMSM&Y4um!0=-E-hWO<?RIPs_obB-~RvS*SY70t?_Q!@+yng
SUHcF80fVQjpUXO@geCwQQ2I*%

diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/greater_than.png b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/greater_than.png
deleted file mode 100644
index e2d4ae150d3c241f2c80273c09a092e311d3dcf6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 213
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!S%6Q7>;M1%jY$U`53hlY6f6ny
z3ubs_W2|@gZ^ySkK0n|6diw8+uH4h#KuKFq7sn8Z%X52o3NjdQ9By#<*Z+6A?^`ui
ztx~Jm8Xo#hi%k3!TIO!_oa4Lkrk%meeRaxNlKHO;ZFYugo@4HQ%*dbM@oOv4AO=rY
KKbLh*2~7Y63q;5O

diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/less_than.png b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/less_than.png
deleted file mode 100644
index 19a38fbb05d6ea291a349333de0617c227c58c60..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 215
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!S%6Q7>;M1%jY$U`53hlY6f6ny
z3udr+Wqeof@3)RGzyAGv`sbZbyQJb@prpO0i(`m{<lKYX85;})m>oRdyO`|%ziCRx
zwekbIZkbz5TYR`BYUPgr%|mZ2ncto1F4$_qDl=6n=7rpkhZP%Mu=WWs^0S@k@&Fpe
N;OXk;vd$@?2>|;3N7euU

diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/sort_filtered_asc.gif b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/sort_filtered_asc.gif
deleted file mode 100644
index 8e33691a0a7c72e72e063474971f28dc8736c1e9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 209
zcmZ?wbhEHb<Yi!G_{hNU^7Esf%_aZ;|7T!eQ2fsw;Txdfl30=mq?_$43KEmEQx&KP
zxbT_91+}n5AvG_>R;gUc-i|@>CkrDx0~3P|(0L3XCp$3lPZ3?t^mbps3{9yl)w!z~
G7_0$AkSzxQ

diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/sort_filtered_desc.gif b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/images/sort_filtered_desc.gif
deleted file mode 100644
index ad58af86d85ad657184ed6e5e1b1fc1a71546a46..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 209
zcmZ?wbhEHb<Yi!G_{hNU^7Esf%_aZ;|7T!eQ2fsw;Txdfl30=mq?_$43KEmEQx&KP
zxbT_91+}n5AvG_>R;gUc-i|@>CkrDx0~3P|(0L3XCp$3lyYw+0I{SK&Wq_LK?3L>n
G7_0$GS}m;r

diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/ListMenu.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/ListMenu.js
deleted file mode 100644
index c5162a4d5014..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/ListMenu.js
+++ /dev/null
@@ -1,177 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-Ext.namespace('Ext.ux.menu');
-
-/** 
- * @class Ext.ux.menu.ListMenu
- * @extends Ext.menu.Menu
- * This is a supporting class for {@link Ext.ux.grid.filter.ListFilter}.
- * Although not listed as configuration options for this class, this class
- * also accepts all configuration options from {@link Ext.ux.grid.filter.ListFilter}.
- */
-Ext.ux.menu.ListMenu = Ext.extend(Ext.menu.Menu, {
-	/**
-	 * @cfg {String} labelField
-	 * Defaults to 'text'.
-	 */
-	labelField :  'text',
-	/**
-	 * @cfg {String} paramPrefix
-	 * Defaults to 'Loading...'.
-	 */
-	loadingText : 'Loading...',
-	/**
-	 * @cfg {Boolean} loadOnShow
-	 * Defaults to true.
-	 */
-	loadOnShow : true,
-	/**
-	 * @cfg {Boolean} single
-	 * Specify true to group all items in this list into a single-select
-	 * radio button group. Defaults to false.
-	 */
-	single : false,
-
-	constructor : function (cfg) {
-		this.selected = [];
-		this.addEvents(
-			/**
-			 * @event checkchange
-			 * Fires when there is a change in checked items from this list
-			 * @param {Object} item Ext.menu.CheckItem
-			 * @param {Object} checked The checked value that was set
-			 */
-			'checkchange'
-		);
-
-		Ext.ux.menu.ListMenu.superclass.constructor.call(this, cfg = cfg || {});
-
-		if(!cfg.store && cfg.options){
-			var options = [];
-			for(var i=0, len=cfg.options.length; i<len; i++){
-				var value = cfg.options[i];
-				switch(Ext.type(value)){
-					case 'array':  options.push(value); break;
-					case 'object': options.push([value.id, value[this.labelField]]); break;
-					case 'string': options.push([value, value]); break;
-				}
-			}
-
-			this.store = new Ext.data.Store({
-				reader: new Ext.data.ArrayReader({id: 0}, ['id', this.labelField]),
-				data:   options,
-				listeners: {
-					'load': this.onLoad,
-					scope:  this
-				}
-			});
-			this.loaded = true;
-		} else {
-			this.add({text: this.loadingText, iconCls: 'loading-indicator'});
-			this.store.on('load', this.onLoad, this);
-		}
-	},
-
-	destroy : function () {
-		if (this.store) {
-			this.store.destroy();
-		}
-		Ext.ux.menu.ListMenu.superclass.destroy.call(this);
-	},
-
-	/**
-	 * Lists will initially show a 'loading' item while the data is retrieved from the store.
-	 * In some cases the loaded data will result in a list that goes off the screen to the
-	 * right (as placement calculations were done with the loading item). This adapter will
-	 * allow show to be called with no arguments to show with the previous arguments and
-	 * thus recalculate the width and potentially hang the menu from the left.
-	 */
-	show : function () {
-		var lastArgs = null;
-		return function(){
-			if(arguments.length === 0){
-				Ext.ux.menu.ListMenu.superclass.show.apply(this, lastArgs);
-			} else {
-				lastArgs = arguments;
-				if (this.loadOnShow && !this.loaded) {
-					this.store.load();
-				}
-				Ext.ux.menu.ListMenu.superclass.show.apply(this, arguments);
-			}
-		};
-	}(),
-
-	/** @private */
-	onLoad : function (store, records) {
-		var visible = this.isVisible();
-		this.hide(false);
-
-		this.removeAll(true);
-
-		var gid = this.single ? Ext.id() : null;
-		for(var i=0, len=records.length; i<len; i++){
-			var item = new Ext.menu.CheckItem({
-				text:    records[i].get(this.labelField),
-				group:   gid,
-				checked: this.selected.indexOf(records[i].id) > -1,
-				hideOnClick: false});
-
-			item.itemId = records[i].id;
-			item.on('checkchange', this.checkChange, this);
-
-			this.add(item);
-		}
-
-		this.loaded = true;
-
-		if (visible) {
-			this.show();
-		}
-		this.fireEvent('load', this, records);
-	},
-
-	/**
-	 * Get the selected items.
-	 * @return {Array} selected
-	 */
-	getSelected : function () {
-		return this.selected;
-	},
-
-	/** @private */
-	setSelected : function (value) {
-		value = this.selected = [].concat(value);
-
-		if (this.loaded) {
-			this.items.each(function(item){
-				item.setChecked(false, true);
-				for (var i = 0, len = value.length; i < len; i++) {
-					if (item.itemId == value[i]) {
-						item.setChecked(true, true);
-					}
-				}
-			}, this);
-		}
-	},
-
-	/**
-	 * Handler for the 'checkchange' event from an check item in this menu
-	 * @param {Object} item Ext.menu.CheckItem
-	 * @param {Object} checked The checked value that was set
-	 */
-	checkChange : function (item, checked) {
-		var value = [];
-		this.items.each(function(item){
-			if (item.checked) {
-				value.push(item.itemId);
-			}
-		},this);
-		this.selected = value;
-
-		this.fireEvent('checkchange', item, checked);
-	}
-});
\ No newline at end of file
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/RangeMenu.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/RangeMenu.js
deleted file mode 100644
index 539281a92fdb..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/gridfilters/menu/RangeMenu.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-Ext.ns('Ext.ux.menu');
-
-/** 
- * @class Ext.ux.menu.RangeMenu
- * @extends Ext.menu.Menu
- * Custom implementation of Ext.menu.Menu that has preconfigured
- * items for gt, lt, eq.
- * <p><b><u>Example Usage:</u></b></p>
- * <pre><code>    
-
- * </code></pre> 
- */
-Ext.ux.menu.RangeMenu = Ext.extend(Ext.menu.Menu, {
-
-	constructor : function (config) {
-
-		Ext.ux.menu.RangeMenu.superclass.constructor.call(this, config);
-
-		this.addEvents(
-			/**
-			 * @event update
-			 * Fires when a filter configuration has changed
-			 * @param {Ext.ux.grid.filter.Filter} this The filter object.
-			 */
-			'update'
-		);
-
-		this.updateTask = new Ext.util.DelayedTask(this.fireUpdate, this);
-
-		var i, len, item, cfg, Cls;
-
-		for (i = 0, len = this.menuItems.length; i < len; i++) {
-			item = this.menuItems[i];
-			if (item !== '-') {
-				// defaults
-				cfg = {
-					itemId: 'range-' + item,
-					enableKeyEvents: true,
-					iconCls: this.iconCls[item] || 'no-icon',
-					listeners: {
-						scope: this,
-						keyup: this.onInputKeyUp
-					}
-				};
-				Ext.apply(
-					cfg,
-					// custom configs
-					Ext.applyIf(this.fields[item] || {}, this.fieldCfg[item]),
-					// configurable defaults
-					this.menuItemCfgs
-				);
-				Cls = cfg.fieldCls || this.fieldCls;
-				item = this.fields[item] = new Cls(cfg);
-			}
-			this.add(item);
-		}
-	},
-
-	/**
-	 * @private
-	 * called by this.updateTask
-	 */
-	fireUpdate : function () {
-		this.fireEvent('update', this);
-	},
-
-	/**
-	 * Get and return the value of the filter.
-	 * @return {String} The value of this filter
-	 */
-	getValue : function () {
-		var result = {}, key, field;
-		for (key in this.fields) {
-			field = this.fields[key];
-			if (field.isValid() && String(field.getValue()).length > 0) {
-				result[key] = field.getValue();
-			}
-		}
-		return result;
-	},
-
-	/**
-	 * Set the value of this menu and fires the 'update' event.
-	 * @param {Object} data The data to assign to this menu
-	 */
-	setValue : function (data) {
-		var key;
-		for (key in this.fields) {
-			this.fields[key].setValue(data[key] !== undefined ? data[key] : '');
-		}
-		this.fireEvent('update', this);
-	},
-
-	/**
-	 * @private
-	 * Handler method called when there is a keyup event on an input
-	 * item of this menu.
-	 */
-	onInputKeyUp : function (field, e) {
-		var k = e.getKey();
-		if (k == e.RETURN && field.isValid()) {
-			e.stopEvent();
-			this.hide(true);
-			return;
-		}
-
-		if (field == this.fields.eq) {
-			if (this.fields.gt) {
-				this.fields.gt.setValue(null);
-			}
-			if (this.fields.lt) {
-				this.fields.lt.setValue(null);
-			}
-		}
-		else {
-			this.fields.eq.setValue(null);
-		}
-
-		// restart the timer
-		this.updateTask.delay(this.updateBuffer);
-	}
-});
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/helpers.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/helpers.js
deleted file mode 100644
index 345049c172d0..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/helpers.js
+++ /dev/null
@@ -1,212 +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!
- */
-
-Ext.ns('TYPO3.Workspaces');
-
-TYPO3.Workspaces.Helpers = {
-	/**
-	 * Gets an form values object like {'element-1':on, 'element-2':on} and returns
-	 * the checked results in an array like ['1', '2'].
-	 *
-	 * @param object values
-	 * @param string elementPrefix
-	 * @return array
-	 */
-	getElementIdsFromFormValues: function(values, elementPrefix) {
-		var results = [];
-		var pattern = new RegExp('^' + elementPrefix + '-' + '(.+)$');
-
-		Ext.iterate(values, function(key, value) {
-			if (value == 'on' && pattern.test(key)) {
-				results.push(RegExp.$1);
-			}
-		});
-
-		return results;
-	},
-
-	getSendToStageWindow: function(configuration) {
-		top.TYPO3.Windows.close('sendToStageWindow');
-		return top.TYPO3.Windows.showWindow({
-			id: 'sendToStageWindow',
-			title: configuration.title,
-			items: [
-				{
-					xtype: 'form',
-					id: 'sendToStageForm',
-					width: '100%',
-					bodyStyle: 'padding: 5px 5px 3px 5px; border-width: 0; margin-bottom: 7px;',
-					items: configuration.items
-				}
-			],
-			buttons: [
-				{
-					text: TYPO3.l10n.localize('ok'),
-					handler: configuration.executeHandler
-				},
-				{
-					text: TYPO3.l10n.localize('cancel'),
-					handler: function(event) {
-						top.TYPO3.Windows.close('sendToStageWindow');
-					}
-				}
-			]
-		});
-	},
-
-	getElementsArrayOfSelection: function(selection) {
-		var elements = [];
-
-		Ext.each(selection, function(item) {
-			var element = {
-				table: item.data.table,
-				t3ver_oid: item.data.t3ver_oid,
-				uid: item.data.uid
-			}
-			elements.push(element);
-		});
-
-		return elements;
-	},
-
-	getElementsArrayOfSelectionForIntegrityCheck: function(selection) {
-		var elements = [];
-
-		Ext.each(selection, function(item) {
-			var element = {
-				table: item.data.table,
-				liveId: item.data.t3ver_oid,
-				versionId: item.data.uid
-			}
-			elements.push(element);
-		});
-
-		return elements;
-	},
-
-	getHistoryWindow: function(configuration) {
-		top.TYPO3.Windows.close('historyWindow');
-		return top.TYPO3.Windows.showWindow({
-			id: 'historyWindow',
-			title: 'Record History',
-			stateful: false,
-			modal: false,
-
-			autoHeight: true,
-			boxMaxHeight: 500,
-			width: 700,
-
-			buttons: [
-				{
-					text: TYPO3.l10n.localize('ok'),
-					handler: function(event) {
-						top.TYPO3.Windows.close('historyWindow');
-					}
-				}
-			],
-
-			items: [
-				{
-					xtype: 'grid',
-
-					border : false,
-					loadMask : true,
-					stripeRows: true,
-					autoHeight: true,
-					style: 'min-height: 100px',
-
-					viewConfig: {
-						forceFit: true
-					},
-
-					store: {
-						xtype: 'directstore',
-						autoLoad: true,
-						autoDestroy: true,
-						reader: new Ext.data.JsonReader({
-							idProperty : 'id',
-							root : 'data',
-							totalProperty : 'total',
-							fields: [
-								{ name: 'datetime' },
-								{ name: 'user' },
-								{ name: 'differences' }
-							]
-						}),
-						proxy: new Ext.data.DirectProxy({
-							directFn : TYPO3.Workspaces.ExtDirect.getHistory
-						}),
-						listeners: {
-							beforeload: function(store, options) {
-								store.setBaseParam('table', configuration.table);
-								store.setBaseParam('liveId', configuration.liveId);
-								store.setBaseParam('versionId', configuration.versionId);
-							}
-						}
-					},
-
-					colModel: new Ext.grid.ColumnModel({
-						columns: [
-							{ width: 30, id: 'datetime', header: 'Date' },
-							{ width: 20, id: 'user', header: 'User', dataIndex: 'user' },
-							{
-								id: 'differences',
-								header: 'Differences',
-								dataIndex: 'differences',
-								renderer: function(value, metaData, record, rowIndex, colIndex, store) {
-									if (typeof value === 'string') {
-										return value;
-									} else {
-										var template = new Ext.XTemplate(
-											'<tpl for=".">',
-												'<div style="display: block; padding: 3px 0;"><strong>{label}</strong> {html}</div>',
-											'</tpl>'
-										);
-										return template.apply(value);
-									}
-								}
-							}
-						]
-					})
-				}
-			]
-		});
-	},
-
-	getAdditionalColumnHandler: function() {
-		var handlers = [];
-		Ext.each(TYPO3.settings.Workspaces.extension.AdditionalColumn.Handler, function(objectName) {
-			handlers.push(eval(objectName));
-		});
-		return handlers;
-	},
-
-	isDefined: function(propertyName) {
-		var result = true;
-		var pointer = window;
-		Ext.each(propertyName.split('.'), function(item) {
-			if (typeof pointer[item] === 'undefined') {
-				result = false;
-				return false;
-			}
-			pointer = pointer[item];
-		});
-		return result;
-	},
-
-	refreshPageTree: function() {
-		if (TYPO3.Workspaces.Helpers.isDefined('top.TYPO3.Backend.NavigationContainer.PageTree')) {
-			top.TYPO3.Backend.NavigationContainer.PageTree.refreshTree();
-		}
-	}
-};
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/preview.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/preview.js
deleted file mode 100644
index 4af8b6401fcc..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/preview.js
+++ /dev/null
@@ -1,391 +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!
- */
-
-Ext.onReady(function() {
-
-	Ext.state.Manager.setProvider(new TYPO3.state.ExtDirectProvider({
-		key: 'moduleData.Workspaces.States',
-		autoRead: false
-	}));
-
-	if (Ext.isObject(TYPO3.settings.Workspaces.States)) {
-		Ext.state.Manager.getProvider().initState(TYPO3.settings.Workspaces.States);
-	}
-	// late binding of ExtDirect
-	TYPO3.Workspaces.MainStore.proxy = new Ext.data.DirectProxy({
-		directFn : TYPO3.Workspaces.ExtDirect.getWorkspaceInfos
-	});
-
-	var iconClsChecked = 't3-icon t3-icon-status t3-icon-status-status t3-icon-status-checked';
-	var iconClsEmpty = 't3-icon t3-icon-empty t3-icon-empty-empty t3-icon-empty';
-	var viewMode = 0;
-	var changePreviewMode = function(config, mode) {
-		var visual = Ext.getCmp('wsVisualWrap');
-		if ((typeof mode != 'undefined') && (mode != viewMode)) {
-			viewMode = mode;
-			visual.remove(0);
-			visual.add(Ext.apply(config, {}));
-		};
-		visual.doLayout();
-	}
-
-	var sliderSetup = {
-		layout: 'fit',
-		x: 0, y:0,
-		anchor: '100% 100%',
-		autoScroll: true,
-		items: [{
-			layout: 'absolute',
-			id: 'visualPanel',
-			items: [{
-				x: 0, y:0,
-				anchor: '100% 100%',
-				id: 'wsContainer',
-				layout: 'absolute',
-				autoScroll: false,
-				items:[{
-					xtype: 'iframePanel',
-					x: 0, y:0,
-					id: 'wsPanel',
-					showLoadingIndicator: false,
-					src: wsUrl,
-					autoScroll: false
-				}]
-			},{
-				x: 0, y:0,
-				anchor: '100% 0%',
-				id: 'liveContainer',
-				layout: 'absolute',
-				bodyStyle: 'height:0px;border-bottom: 2px solid red;',
-				autoScroll: false,
-				items:[{
-					xtype: 'iframePanel',
-					x: 0, y:0,
-					id: 'livePanel',
-					showLoadingIndicator: false,
-					src: liveUrl,
-					autoScroll: false
-				}]
-			}]
-		}]
-	};
-	var hboxSetup = {
-		layout: 'hbox',
-		x: 0, y:0,
-		anchor: '100% 100%',
-		layoutConfig: {
-			align : 'stretch',
-			pack  : 'start'
-		},
-		id: 'visualPanel-hbox',
-		items: [{
-			xtype: 'iframePanel',
-			x: 0, y:0,
-			id: 'wsPanel-hbox',
-			showLoadingIndicator: false,
-			src: wsUrl,
-			autoScroll: false,
-			flex: 1
-		},{
-			xtype: 'iframePanel',
-			x: 0, y:0,
-			id: 'livePanel-hbox',
-			showLoadingIndicator: false,
-			src: liveUrl,
-			autoScroll: false,
-			flex: 1
-		}]
-	};
-	var vboxSetup = {
-		layout: 'vbox',
-		x: 0, y:0,
-		anchor: '100% 100%',
-		layoutConfig: {
-			align : 'stretch',
-			pack  : 'start'
-		},
-		id: 'visualPanel-vbox',
-		items: [{
-			xtype: 'iframePanel',
-			x: 0, y:0,
-			id: 'wsPanel-vbox',
-			showLoadingIndicator: false,
-			src: wsUrl,
-			autoScroll: false,
-			flex: 1
-		},{
-			xtype: 'iframePanel',
-			x: 0, y:0,
-			id: 'livePanel-vbox',
-			showLoadingIndicator: false,
-			src: liveUrl,
-			autoScroll: false,
-			flex: 1
-		}]
-	};
-
-	var viewport = new Ext.Viewport({
-		layout: 'border',
-		items: [{
-			xtype: 'tabpanel',
-			region: 'center', // a center region is ALWAYS required for border layout
-			id: 'preview',
-			activeTab: 0,
-			plugins : [{
-				ptype : 'Ext.ux.plugins.TabStripContainer',
-				id: 'controls',
-				width: 930,
-				items: [
-					{
-						xtype: 'panel',
-						width: 360,
-						items: [{
-							xtype: 'panel',
-							id: 'slider',
-							layout: 'hbox',
-							items: [
-								{
-									xtype: 'button',
-									id: 'sizeSliderButtonLive',
-									cls: 'sliderButton',
-									text: TYPO3.l10n.localize('livePreview'),
-									tooltip: TYPO3.l10n.localize('livePreviewDetail'),
-									width: 100,
-									listeners: {
-										click: {
-											fn: function () {
-												Ext.getCmp('sizeSlider').setValue(0);
-											}
-										}
-									}
-								},
-								{
-									xtype: 'slider',
-									id: 'sizeSlider',
-									margins: '0 10 0 10',
-									maxValue: 100,
-									minValue: 0,
-									value: 100,
-									width: 150,
-									flex: 1,
-									listeners: {
-										change: {
-											fn: function resizeFromValue(slider, newValue, thumb) {
-												var height = Ext.getCmp('wsPanel').getHeight();
-												Ext.getCmp('liveContainer').setHeight(height * (100 - newValue) / 100);
-											}
-										}
-									}
-								},
-								{
-									xtype: 'button',
-									id: 'sizeSliderButtonWorkspace',
-									cls: 'sliderButton',
-									text: TYPO3.l10n.localize('workspacePreview'),
-									tooltip: TYPO3.l10n.localize('workspacePreviewDetail'),
-									width: 100,
-									listeners: {
-										click: {
-											fn: function () {
-												Ext.getCmp('sizeSlider').setValue(100);
-											}
-										}
-									}
-								}
-							]
-						}]
-					}, {
-						xtype: 'buttongroup',
-						id: 'stageButtonGroup',
-						columns: 4,
-						width: 400,
-						items: [{
-							text: TYPO3.l10n.localize('nextStage').substr(0, 35),
-							tooltip:  TYPO3.l10n.localize('nextStage'),
-							xtype: 'button',
-							iconCls: 'x-btn-text',
-							id: 'feToolbarButtonNextStage',
-							hidden: TYPO3.settings.Workspaces.disableNextStageButton,
-							listeners: {
-								click: {
-									fn: function () {
-										TYPO3.Workspaces.Actions.sendPageToNextStage();
-									}
-								}
-							}
-						}, {
-							text: TYPO3.l10n.localize('previousStage').substr(0, 35),
-							tooltip:  TYPO3.l10n.localize('previousStage'),
-							xtype: 'button',
-							iconCls: 'x-btn-text',
-							id: 'feToolbarButtonPreviousStage',
-							hidden: TYPO3.settings.Workspaces.disablePreviousStageButton,
-							listeners: {
-								click: {
-									fn: function () {
-										TYPO3.Workspaces.Actions.sendPageToPrevStage();
-									}
-								}
-							}
-						}, {
-							text: TYPO3.l10n.localize('discard'),
-							iconCls: 'x-btn-text',
-							xtype: 'button',
-							id: 'feToolbarButtonDiscardStage',
-							hidden: TYPO3.settings.Workspaces.disableDiscardStageButton,
-							listeners: {
-								click: {
-									fn: function () {
-										TYPO3.Workspaces.Actions.discardPage();
-									}
-								}
-							}
-						}, {
-							xtype: 'button',
-							iconCls: 'x-btn-icon t3-icon t3-icon-actions t3-icon-actions-system t3-icon-system-options-view',
-							id: 'visual-mode-options',
-							menu: {
-								id: 'visual-mode-selector',
-								stateful: true,
-								stateId: 'WorkspacePreviewModeSelect',
-								stateEvents: ['itemclick'],
-								items: [{
-									text: TYPO3.l10n.localize('modeSlider'),
-									id: 'visual-mode-selector-slider',
-									checked: false,
-									group: 'mode',
-									hidden: TYPO3.settings.Workspaces.SplitPreviewModes.indexOf('slider') == -1,
-									checkHandler: modeChange
-								},{
-									text: TYPO3.l10n.localize('modeVbox'),
-									id: 'visual-mode-selector-vbox',
-									checked: false,
-									group: 'mode',
-									hidden: TYPO3.settings.Workspaces.SplitPreviewModes.indexOf('vbox') == -1,
-									checkHandler: modeChange
-
-								},{
-									text: TYPO3.l10n.localize('modeHbox'),
-									id: 'visual-mode-selector-hbox',
-									checked: false,
-									group: 'mode',
-									hidden: TYPO3.settings.Workspaces.SplitPreviewModes.indexOf('hbox') == -1,
-									checkHandler: modeChange
-								}],
-								getState:function() {
-									return {viewMode: viewMode};
-								},
-								applyState: function(state) {
-									modeChange(null, true, viewMode);
-								}
-							}
-						}]
-					}
-				]
-			}],
-			items: [{
-				title: TYPO3.l10n.localize('visualPreview'),
-				id: 'wsVisual',
-				layout: 'fit',
-				anchor: '100% 100%',
-				listeners: {
-					activate: function () {
-						if (Ext.isObject(top.Ext.getCmp('slider'))) {
-							top.Ext.getCmp('slider').show();
-							top.Ext.getCmp('visual-mode-options').show();
-							TYPO3.Workspaces.ExtDirectActions.updateStageChangeButtons(TYPO3.settings.Workspaces.id, TYPO3.Workspaces.Actions.updateStageChangeButtons);
-						}
-					}
-				},
-				items: [{
-					id: 'wsVisualWrap',
-					layout: 'absolute',
-					anchor: '100% 100%',
-					x: 0, y:0,
-					items: [sliderSetup]
-				}]
-			},{
-				title: TYPO3.l10n.localize('listView'),
-				id: 'wsSettings',
-				layout: 'fit',
-				listeners: {
-					activate: function () {
-						top.Ext.getCmp('slider').hide();
-						top.Ext.getCmp('visual-mode-options').hide();
-						top.Ext.getCmp('feToolbarButtonNextStage').hide();
-						top.Ext.getCmp('feToolbarButtonPreviousStage').hide();
-						top.Ext.getCmp('feToolbarButtonDiscardStage').hide();
-					}
-				},
-				items:  [{
-					xtype: 'iframePanel',
-					id: 'settingsPanel',
-					showLoadingIndicator: false,
-					src: wsSettingsUrl
-				}]
-			}]
-		}]
-	});
-
-	function modeChange(item, checked, mode) {
-		if (checked) {
-			var id ,
-				ids = ['visual-mode-selector-slider', 'visual-mode-selector-hbox', 'visual-mode-selector-vbox'],
-				slider = Ext.getCmp('slider'),
-				itemSlider = Ext.getCmp('visual-mode-selector-slider'),
-				itemHbox = Ext.getCmp('visual-mode-selector-hbox'),
-				itemVbox = Ext.getCmp('visual-mode-selector-vbox');
-
-			if (item) {
-				mode = ids.indexOf(item.id);
-			}
-
-			Ext.select('#visual-mode-selector ul li a img.t3-icon-status-checked').removeClass(iconClsChecked.split(" "));
-
-			var splitPreviewModes = TYPO3.settings.Workspaces.SplitPreviewModes;
-			if (splitPreviewModes.length == 1) {
-				Ext.getCmp('visual-mode-options').hide();
-			}
-
-			if (splitPreviewModes.indexOf('vbox') == -1 && mode === 2) {
-				mode = 0
-			}
-			if (splitPreviewModes.indexOf('slider') == -1 && mode === 0) {
-				mode = 1
-			}
-			if (splitPreviewModes.indexOf('hbox') == -1 && mode === 1) {
-				mode = 2
-			}
-
-			if (mode === 0) {
-				changePreviewMode(sliderSetup, mode);
-				slider.show();
-				itemSlider.setIconClass(iconClsChecked);
-				itemHbox.setIconClass(iconClsEmpty);
-				itemVbox.setIconClass(iconClsEmpty);
-			} else if (mode === 1) {
-				changePreviewMode(vboxSetup, mode);
-				slider.hide();
-				itemSlider.setIconClass(iconClsEmpty);
-				itemHbox.setIconClass(iconClsChecked);
-				itemVbox.setIconClass(iconClsEmpty);
-			} else if (mode === 2) {
-				changePreviewMode(hboxSetup, mode);
-				slider.hide();
-				itemSlider.setIconClass(iconClsEmpty);
-				itemHbox.setIconClass(iconClsEmpty);
-				itemVbox.setIconClass(iconClsChecked);
-			}
-		}
-	}
-});
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/toolbar.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/toolbar.js
deleted file mode 100644
index a3387ee664b3..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/toolbar.js
+++ /dev/null
@@ -1,407 +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!
- */
-
-Ext.ns('TYPO3.Workspaces');
-
-TYPO3.Workspaces.Toolbar = {};
-
-TYPO3.Workspaces.Toolbar.search =  new Ext.app.SearchField({
-	store: TYPO3.Workspaces.MainStore,
-	trigger1Class : 't3-icon t3-icon-actions t3-icon-actions-input t3-icon-input-clear t3-tceforms-input-clearer',
-	trigger2Class : 't3-icon t3-icon-actions t3-icon-actions-system t3-icon-system-tree-search-open',
-	width: 200
-});
-
-TYPO3.Workspaces.Toolbar.selectActionStore = new Ext.data.DirectStore({
-	storeId : 'stagesService',
-	root : 'data',
-	totalProperty : 'total',
-	idProperty : 'uid',
-	fields : [
-		{name : 'uid'},
-		{name : 'title'}
-	],
-	listeners : {
-		load : function(store, records) {
-			if (records.length == 0) {
-				TYPO3.Workspaces.Toolbar.selectStateActionCombo.hide();
-			} else {
-				TYPO3.Workspaces.Toolbar.selectStateActionCombo.show();
-				TYPO3.Workspaces.WorkspaceGrid.colModel.setHidden(0, false);
-			}
-		}
-	}
-});
-
-TYPO3.Workspaces.Toolbar.selectStateActionCombo = new Ext.form.ComboBox({
-	width: 150,
-	listWidth: 350,
-	lazyRender: true,
-	valueField: 'uid',
-	displayField: 'title',
-	mode: 'local',
-	emptyText: TYPO3.l10n.localize('chooseAction'),
-	selectOnFocus: true,
-	disabled : true,
-	hidden : true,	 // we hide it by default and show it in case there are any actions available
-	triggerAction: 'all',
-	editable: false,
-	forceSelection: true,
-	store: TYPO3.Workspaces.Toolbar.selectActionStore,
-	listeners: {
-		'select' : function () {
-			var selection = TYPO3.Workspaces.WorkspaceGrid.getSelectionModel().getSelections();
-			var nextStage = this.getValue();
-
-			// Use integrity check since "publish execute" stage is effective
-			if (nextStage == -20) {
-				var parameters = {
-					type: 'selection',
-					selection: TYPO3.Workspaces.Helpers.getElementsArrayOfSelectionForIntegrityCheck(selection)
-				};
-
-				TYPO3.Workspaces.Actions.checkIntegrity(parameters, function() {
-					TYPO3.Workspaces.Actions.sendToSpecificStageWindow(selection, nextStage);
-				});
-			} else {
-				TYPO3.Workspaces.Actions.sendToSpecificStageWindow(selection, nextStage);
-			}
-		}
-	}
-});
-
-TYPO3.Workspaces.Toolbar.selectMassActionStore = new Ext.data.DirectStore({
-	storeId : 'stagesService',
-	root : 'data',
-	totalProperty : 'total',
-	idProperty : 'action',
-	fields : [
-		{name : 'action'},
-		{name : 'title'}
-	],
-	listeners : {
-		load : function(store, records) {
-			if (records.length == 0 || TYPO3.settings.Workspaces.singleView === '1') {
-				TYPO3.Workspaces.Toolbar.selectionActionCombo.hide();
-				TYPO3.Workspaces.Toolbar.selectStateMassActionCombo.hide();
-			} else {
-				TYPO3.Workspaces.Toolbar.selectionActionCombo.show();
-				TYPO3.Workspaces.Toolbar.selectStateMassActionCombo.show();
-			}
-		}
-	}
-});
-
-TYPO3.Workspaces.Toolbar.selectionActionCombo = new Ext.form.ComboBox({
-	width: 150,
-	lazyRender: true,
-	valueField: 'action',
-	displayField: 'title',
-	mode: 'local',
-	emptyText: 'choose selection action',
-	selectOnFocus: true,
-	triggerAction: 'all',
-	editable: false,
-	disabled : true, // disabled per default, enabled if selections are done in the grid
-	hidden : true, // hidden per default, shown if actions are available
-	forceSelection: true,
-	store: TYPO3.Workspaces.Toolbar.selectMassActionStore,
-	listeners: {
-		'select' : function(combo, record) {
-			var label;
-			var checkIntegrity = false;
-			var selection = TYPO3.Workspaces.Helpers.getElementsArrayOfSelectionForIntegrityCheck(
-				TYPO3.Workspaces.WorkspaceGrid.getSelectionModel().getSelections()
-			);
-
-			switch (record.data.action) {
-				case 'publish':
-					label = TYPO3.l10n.localize('tooltip.publishSelected');
-					checkIntegrity = true;
-					break;
-				case 'swap':
-					label = TYPO3.l10n.localize('tooltip.swapSelected');
-					checkIntegrity = true;
-					break;
-				case 'discard':
-					label = TYPO3.l10n.localize('tooltip.discardSelected');
-					break;
-			}
-
-			top.TYPO3.Windows.close('executeSelectionActionWindow');
-
-			var configuration = {
-				id: 'executeSelectionActionWindow',
-				title: TYPO3.l10n.localize('window.selectionAction.title'),
-				items: [
-					{
-						xtype: 'form',
-						id: 'executeSelectionActionForm',
-						width: '100%',
-						html: label,
-						bodyStyle: 'padding: 5px 5px 3px 5px; border-width: 0; margin-bottom: 7px;'
-					}
-				],
-				buttons: [
-					{
-						id: 'executeSelectionActionOkButton',
-						data: { action: record.data.action, selection: selection },
-						scope: this,
-						text: TYPO3.l10n.localize('ok'),
-						disabled:false,
-						handler: function(event) {
-							top.Ext.getCmp('executeSelectionActionForm').update('Working...');
-							top.Ext.getCmp('executeSelectionActionOkButton').disable();
-							TYPO3.Workspaces.ExtDirectActions.executeSelectionAction(event.data, function(response) {
-								top.Ext.getCmp('executeSelectionActionOkButton').hide();
-								top.Ext.getCmp('executeSelectionActionCancelButton').setText(TYPO3.lang.close);
-								if (response.error) {
-									top.Ext.getCmp('executeSelectionActionForm').update('<strong>' + TYPO3.l10n.localize('status.error') + ':</strong> ' + response.error);
-								} else {
-									top.Ext.getCmp('executeSelectionActionForm').update(TYPO3.l10n.localize('runMassAction.done').replace('%d', response.total));
-									top.TYPO3.Backend.NavigationContainer.PageTree.refreshTree();
-								}
-							});
-						}
-					},
-					{
-						id: 'executeSelectionActionCancelButton',
-						scope: this,
-						text: TYPO3.l10n.localize('cancel'),
-						handler: function() {
-							top.TYPO3.Windows.close('executeSelectionActionWindow');
-							top.TYPO3.ModuleMenu.App.reloadFrames();
-						}
-					}
-				]
-			};
-
-			if (checkIntegrity) {
-				var parameters = {
-					type: 'selection',
-					selection: selection
-				};
-
-				TYPO3.Workspaces.Actions.checkIntegrity(parameters, function() {
-					top.TYPO3.Windows.showWindow(configuration);
-				});
-			} else {
-				top.TYPO3.Windows.showWindow(configuration);
-			}
-		}
-	}
-});
-
-TYPO3.Workspaces.Toolbar.selectStateMassActionCombo = new Ext.form.ComboBox({
-	width: 150,
-	lazyRender: true,
-	valueField: 'action',
-	displayField: 'title',
-	mode: 'local',
-	emptyText: TYPO3.l10n.localize('chooseMassAction'),
-	selectOnFocus: true,
-	triggerAction: 'all',
-	editable: false,
-	hidden : true,	 // we hide it by default and show it in case there are any actions available
-	forceSelection: true,
-	store: TYPO3.Workspaces.Toolbar.selectMassActionStore,
-	listeners: {
-		'select' : function (combo, record) {
-			var label = '';
-			var affectWholeWorkspaceWarning = TYPO3.l10n.localize('tooltip.affectWholeWorkspace');
-			var language = TYPO3.Workspaces.MainStore.baseParams.language;
-			var checkIntegrity = false;
-
-			switch (record.data.action) {
-				case 'publish':
-					label = TYPO3.l10n.localize('tooltip.publishAll');
-					checkIntegrity = true;
-					break;
-				case 'swap':
-					label = TYPO3.l10n.localize('tooltip.swapAll');
-					checkIntegrity = true;
-					break;
-				case 'discard':
-					label = TYPO3.l10n.localize('tooltip.discardAll');
-					break;
-			}
-			top.TYPO3.Windows.close('executeMassActionWindow');
-
-			var configuration = {
-				id: 'executeMassActionWindow',
-				title: TYPO3.l10n.localize('window.massAction.title'),
-				items: [
-					{
-						xtype: 'form',
-						id: 'executeMassActionForm',
-						width: '100%',
-						html: label + '<br /><br />' + affectWholeWorkspaceWarning,
-						bodyStyle: 'padding: 5px 5px 3px 5px; border-width: 0; margin-bottom: 7px;'
-					},
-					{
-						xtype: 'progress',
-						id: 'executeMassActionProgressBar',
-						autoWidth: true,
-						autoHeight: true,
-						hidden: true,
-						value: 0
-					}
-				],
-				buttons: [
-					{
-						id: 'executeMassActionOkButton',
-						data: record.data,
-						scope: this,
-						text: TYPO3.l10n.localize('ok'),
-						disabled:false,
-						handler: function(event) {
-							TYPO3.Workspaces.Actions.triggerMassAction(
-								event.data.action,
-								language
-							);
-						}
-					},
-					{
-						id: 'executeMassActionCancelButton',
-						scope: this,
-						text: TYPO3.l10n.localize('cancel'),
-						handler: function() {
-							top.TYPO3.Windows.close('executeMassActionWindow');
-							// if clicks during action - this also interrupts the running process -- not the nices way but efficient
-							top.TYPO3.ModuleMenu.App.reloadFrames();
-						}
-					}
-				]
-			};
-
-			if (checkIntegrity && language != 'all') {
-				var parameters = {
-					type: 'all',
-					language: language
-				};
-				TYPO3.Workspaces.Actions.checkIntegrity(parameters, function() {
-					top.TYPO3.Windows.showWindow(configuration);
-				});
-			} else {
-				top.TYPO3.Windows.showWindow(configuration);
-			}
-		}
-	}
-});
-
-TYPO3.Workspaces.Toolbar.Pager = new Ext.PagingToolbar({
-	store :  TYPO3.Workspaces.MainStore,
-	pageSize : 30,
-	displayInfo: false,
-	plugins : [ TYPO3.Workspaces.Configuration.GridFilters ]
-});
-
-/****************************************************
- * Depth menu
- ****************************************************/
-TYPO3.Workspaces.Toolbar.depthFilter = new Ext.form.ComboBox({
-	width: 150,
-	lazyRender: true,
-	valueField: 'depth',
-	displayField: 'label',
-	id: 'depthSelector',
-	mode: 'local',
-	emptyText: TYPO3.l10n.localize('depth'),
-	selectOnFocus: true,
-	triggerAction: 'all',
-	editable: false,
-	forceSelection: true,
-	hidden: (TYPO3.settings.Workspaces.singleView === '1'),
-	store: new Ext.data.SimpleStore({
-		autoLoad: true,
-		fields: ['depth','label'],
-		data : [
-			['0', TYPO3.l10n.localize('depth_0')],
-			['1', TYPO3.l10n.localize('depth_1')],
-			['2', TYPO3.l10n.localize('depth_2')],
-			['3', TYPO3.l10n.localize('depth_3')],
-			['4', TYPO3.l10n.localize('depth_4')],
-			['999', TYPO3.l10n.localize('depth_infi')]
-		]
-	}),
-	value: 999,
-	listeners: {
-		'select': {
-			fn: function(cmp, rec, index) {
-				var depth = rec.get('depth');
-				TYPO3.Workspaces.MainStore.setBaseParam('depth', depth);
-				TYPO3.Workspaces.MainStore.load({
-					params: {
-						wsId: 0
-					}
-				});
-			}
-		}
-	}
-});
-
-TYPO3.Workspaces.Toolbar.LanguageSelector = new Ext.form.ComboBox({
-	width: 150,
-	listWidth: 350,
-	lazyRender: true,
-	valueField: 'uid',
-	displayField: 'title',
-	mode: 'local',
-	emptyText: TYPO3.l10n.localize('language.selectLanguage'),
-	selectOnFocus: true,
-	triggerAction: 'all',
-	editable: false,
-	forceSelection: true,
-	tpl: '<tpl for="."><div class="x-combo-list-item">{icon} {title}</div></tpl>',
-	store: new Ext.data.DirectStore({
-		storeId: 'languages',
-		root: 'data',
-		totalProperty: 'total',
-		idProperty: 'uid',
-		fields: [
-			{name : 'uid'},
-			{name : 'title'},
-			{name : 'icon'}
-		],
-		listeners: {
-			load: function() {
-				TYPO3.Workspaces.Toolbar.LanguageSelector.setValue(TYPO3.settings.Workspaces.language);
-			}
-		}
-	}),
-	listeners: {
-		select: function (comboBox, record, index) {
-			TYPO3.Workspaces.ExtDirectActions.saveLanguageSelection(this.getValue());
-			TYPO3.Workspaces.MainStore.setBaseParam('language', this.getValue());
-			TYPO3.Workspaces.MainStore.load();
-		}
-	}
-});
-
-TYPO3.Workspaces.Toolbar.FullTopToolbar = [
-	TYPO3.Workspaces.Toolbar.depthFilter,
-	'-',
-	TYPO3.Workspaces.Toolbar.LanguageSelector,
-	{xtype: 'tbfill'},
-	TYPO3.Workspaces.Toolbar.search
-];
-
-TYPO3.Workspaces.Toolbar.FullBottomBar = [
-	(TYPO3.settings.Workspaces.isLiveWorkspace == true || TYPO3.settings.Workspaces.allView) ? {hidden: true} : TYPO3.Workspaces.Toolbar.selectStateActionCombo,
-	(TYPO3.settings.Workspaces.isLiveWorkspace == true || TYPO3.settings.Workspaces.allView) ? {hidden: true} : '-',
-	(TYPO3.settings.Workspaces.isLiveWorkspace == true || TYPO3.settings.Workspaces.allView) ? {hidden: true} : TYPO3.Workspaces.Toolbar.selectionActionCombo,
-	(TYPO3.settings.Workspaces.isLiveWorkspace == true || TYPO3.settings.Workspaces.allView) ? {hidden: true} : '-',
-	(TYPO3.settings.Workspaces.isLiveWorkspace == true || TYPO3.settings.Workspaces.allView) ? {hidden: true} : TYPO3.Workspaces.Toolbar.selectStateMassActionCombo,
-	{xtype: 'tbfill'},
-	TYPO3.Workspaces.Toolbar.Pager
-];
diff --git a/typo3/sysext/workspaces/Resources/Public/JavaScript/workspaces.js b/typo3/sysext/workspaces/Resources/Public/JavaScript/workspaces.js
deleted file mode 100644
index 3f792ac839f6..000000000000
--- a/typo3/sysext/workspaces/Resources/Public/JavaScript/workspaces.js
+++ /dev/null
@@ -1,90 +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!
- */
-
-Ext.ns('TYPO3.Workspaces');
-
-TYPO3.Workspaces.App = {
-
-	init : function() {
-		// With a large amount of unpublished changes, the workspace grid requires a longer Ajax timeout
-		Ext.Ajax.timeout = 120000;
-
-		TYPO3.Workspaces.WorkspaceGrid.initColModel();
-		TYPO3.Workspaces.WorkspaceGrid.render('workspacegrid');
-
-		TYPO3.Workspaces.MainStore.load();
-		TYPO3.Workspaces.Toolbar.selectActionStore.load();
-		TYPO3.Workspaces.Toolbar.selectMassActionStore.load();
-		TYPO3.Workspaces.Toolbar.LanguageSelector.getStore().load();
-	}
-};
-
-Ext.onReady(function() {
-	Ext.state.Manager.setProvider(new TYPO3.state.ExtDirectProvider({
-		key: 'moduleData.Workspaces.States',
-		autoRead: false
-	}));
-
-	if (Ext.isObject(TYPO3.settings.Workspaces.States)) {
-		Ext.state.Manager.getProvider().initState(TYPO3.settings.Workspaces.States);
-	}
-
-	// Quicktips initialisieren
-	Ext.QuickTips.init();
-
-	// rearrange columns in grid
-	TYPO3.Workspaces.Actions.loadColModel(TYPO3.Workspaces.WorkspaceGrid);
-
-	// late binding of ExtDirect
-	TYPO3.Workspaces.Toolbar.selectMassActionStore.proxy = new Ext.data.DirectProxy({
-		directFn : TYPO3.Workspaces.ExtDirectMassActions.getMassStageActions
-	});
-	// late binding of ExtDirect
-	TYPO3.Workspaces.Toolbar.selectActionStore.proxy = new Ext.data.DirectProxy({
-		directFn : TYPO3.Workspaces.ExtDirect.getStageActions
-	});
-	// late binding of ExtDirect
-	TYPO3.Workspaces.Toolbar.LanguageSelector.getStore().proxy = new Ext.data.DirectProxy({
-		directFn : TYPO3.Workspaces.ExtDirect.getSystemLanguages
-	});
-
-	TYPO3.Workspaces.RowExpander.detailStore.proxy = new Ext.data.DirectProxy({
-		directFn: TYPO3.Workspaces.ExtDirect.getRowDetails
-	});
-	// late binding of ExtDirect
-	TYPO3.Workspaces.MainStore.proxy = new Ext.data.DirectProxy({
-		directFn : TYPO3.Workspaces.ExtDirect.getWorkspaceInfos
-	});
-
-	// Workspace Tabs are not used in
-	// frontend list preview
-	if (Ext.get('workspacetabs')) {
-		TYPO3.Workspaces.Tabs = new Ext.Panel({
-			renderTo: 'workspacetabs',
-			autoWidth: true,
-			layout: 'fit',
-			items: [
-				{
-					xtype: 'WorkspacesTabPanel',
-					unstyled: true,
-					items: TYPO3.settings.Workspaces.workspaceTabs,
-					activeTab: 'workspace-' + TYPO3.settings.Workspaces.activeWorkspaceId
-				}
-			]
-		});
-	}
-
-	// fire grid
-	var WS = new TYPO3.Workspaces.App.init();
-
-});
diff --git a/typo3/sysext/workspaces/Tests/Functional/ActionHandler/ActionHandlerTest.php b/typo3/sysext/workspaces/Tests/Functional/ActionHandler/ActionHandlerTest.php
index f5dc344ed54a..ddd3d0cd8add 100644
--- a/typo3/sysext/workspaces/Tests/Functional/ActionHandler/ActionHandlerTest.php
+++ b/typo3/sysext/workspaces/Tests/Functional/ActionHandler/ActionHandlerTest.php
@@ -49,7 +49,7 @@ class ActionHandlerTest extends \TYPO3\CMS\Core\Tests\FunctionalTestCase
         // Prepare parameter
         $parameter = new \stdClass();
         $parameter->additional = '';
-        $parameter->receipients = array();
+        $parameter->recipients = array();
         $parameter->comments = '';
 
         // Send to LIVE
-- 
GitLab