+ * contentResource.getRollbackVersions(id, culture)
+ * .then(function(versions) {
+ * alert('its here!');
+ * });
+ *
+ *
+ * @param {Int} id Id of node
+ * @param {Int} culture if provided, the results will be for this specific culture/variant
+ * @returns {Promise} resourcePromise object containing the versions
+ *
+ */
+ getRollbackVersions: function (contentId, culture) {
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "GetRollbackVersions", {
+ contentId: contentId,
+ culture: culture
+ })
+ ),
+ "Failed to get rollback versions for content item with id " + contentId
+ );
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.contentResource#getRollbackVersion
+ * @methodOf umbraco.resources.contentResource
+ *
+ * @description
+ * Returns a previous version of a content item
+ *
+ * ##usage
+ *
+ * contentResource.getRollbackVersion(versionId, culture)
+ * .then(function(version) {
+ * alert('its here!');
+ * });
+ *
+ *
+ * @param {Int} versionId The version Id
+ * @param {Int} culture if provided, the results will be for this specific culture/variant
+ * @returns {Promise} resourcePromise object containing the version
+ *
+ */
+ getRollbackVersion: function (versionId, culture) {
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "GetRollbackVersion", {
+ versionId: versionId,
+ culture: culture
+ })
+ ),
+ "Failed to get version for content item with id " + versionId
+ );
+ },
+
+ /**
+ * @ngdoc method
+ * @name umbraco.resources.contentResource#rollback
+ * @methodOf umbraco.resources.contentResource
+ *
+ * @description
+ * Roll backs a content item to a previous version
+ *
+ * ##usage
+ *
+ * contentResource.rollback(contentId, versionId, culture)
+ * .then(function() {
+ * alert('its here!');
+ * });
+ *
+ *
+ * @param {Int} id Id of node
+ * @param {Int} versionId The version Id
+ * @param {Int} culture if provided, the results will be for this specific culture/variant
+ * @returns {Promise} resourcePromise object
+ *
+ */
+ rollback: function (contentId, versionId, culture) {
+ return umbRequestHelper.resourcePromise(
+ $http.post(
+ umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostRollbackContent", {
+ contentId: contentId, versionId:versionId, culture:culture
+ })
+ ),
+ "Failed to roll back content item with id " + contentId
+ );
+ }
};
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
index eab167c2ec..7d1ef3e9b9 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
@@ -180,6 +180,25 @@
open(editor);
}
+ /**
+ * @ngdoc method
+ * @name umbraco.services.editorService#rollback
+ * @methodOf umbraco.services.editorService
+ *
+ * @description
+ * Opens a rollback editor in infinite editing.
+ * @param {String} editor.node The node to rollback
+ * @param {Callback} editor.submit Saves, submits, and closes the editor
+ * @param {Callback} editor.close Closes the editor
+ * @returns {Object} editor object
+ */
+
+ function rollback(editor) {
+ editor.view = "views/common/infiniteeditors/rollback/rollback.html";
+ editor.size = "small";
+ open(editor);
+ }
+
/**
* @ngdoc method
* @name umbraco.services.editorService#linkPicker
@@ -481,6 +500,7 @@
copy: copy,
move: move,
embed: embed,
+ rollback: rollback,
linkPicker: linkPicker,
mediaPicker: mediaPicker,
iconPicker: iconPicker,
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less
index 4b670ab781..d3f2fee5d5 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-button.less
@@ -104,7 +104,7 @@
}
.umb-button--xs {
- padding: 5px 16px;
+ padding: 5px 13px;
font-size: 14px;
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less
index f2cacc26b3..fb83504a1f 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less
@@ -8,6 +8,9 @@
.umb-box-header {
padding: 10px 20px;
border-bottom: 1px solid @gray-9;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
}
.umb-box-header-title {
diff --git a/src/Umbraco.Web.UI.Client/src/less/utilities/typography/_white-space.less b/src/Umbraco.Web.UI.Client/src/less/utilities/typography/_white-space.less
index b8fb5ca5db..5767b0b474 100644
--- a/src/Umbraco.Web.UI.Client/src/less/utilities/typography/_white-space.less
+++ b/src/Umbraco.Web.UI.Client/src/less/utilities/typography/_white-space.less
@@ -7,6 +7,8 @@
.ws-normal { white-space: normal; }
.nowrap { white-space: nowrap; }
.pre { white-space: pre; }
+.pre-wrap { white-space: pre-wrap; }
+.pre-line { white-space: pre-line; }
.truncate {
white-space: nowrap;
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.controller.js
new file mode 100644
index 0000000000..6b8462b583
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.controller.js
@@ -0,0 +1,177 @@
+(function () {
+ "use strict";
+
+ function RollbackController($scope, contentResource, localizationService, assetsService) {
+
+ var vm = this;
+
+ vm.rollback = rollback;
+ vm.changeLanguage = changeLanguage;
+ vm.changeVersion = changeVersion;
+ vm.submit = submit;
+ vm.close = close;
+
+ //////////
+
+ function onInit() {
+
+ vm.loading = true;
+ vm.variantVersions = [];
+ vm.diff = null;
+ vm.currentVersion = null;
+ vm.rollbackButtonDisabled = true;
+
+ // find the current version for invariant nodes
+ if($scope.model.node.variants.length === 1) {
+ vm.currentVersion = $scope.model.node.variants[0];
+ }
+
+ // find the current version for nodes with variants
+ if($scope.model.node.variants.length > 1) {
+ var active = _.find($scope.model.node.variants, function (v) {
+ return v.active;
+ });
+
+ // preselect the language in the dropdown
+ if(active) {
+ vm.selectedLanguage = active;
+ vm.currentVersion = active;
+ }
+ }
+
+ // set default title
+ if(!$scope.model.title) {
+ localizationService.localize("actions_rollback").then(function(value){
+ $scope.model.title = value;
+ });
+ }
+
+ // Load in diff library
+ assetsService.loadJs('lib/jsdiff/diff.min.js', $scope).then(function () {
+
+ getVersions().then(function(){
+ vm.loading = false;
+ });
+
+ });
+
+ }
+
+ function changeLanguage(language) {
+ vm.currentVersion = language;
+ getVersions();
+ }
+
+ function changeVersion(version) {
+
+ if(version && version.versionId) {
+
+ const culture = $scope.model.node.variants.length > 1 ? vm.currentVersion.language.culture : null;
+
+ contentResource.getRollbackVersion(version.versionId, culture)
+ .then(function(data){
+ vm.previousVersion = data;
+ vm.previousVersion.versionId = version.versionId;
+ createDiff(vm.currentVersion, vm.previousVersion);
+ vm.rollbackButtonDisabled = false;
+ });
+
+ } else {
+ vm.diff = null;
+ vm.rollbackButtonDisabled = true;
+ }
+ }
+
+ function getVersions() {
+
+ const nodeId = $scope.model.node.id;
+ const culture = $scope.model.node.variants.length > 1 ? vm.currentVersion.language.culture : null;
+
+ return contentResource.getRollbackVersions(nodeId, culture)
+ .then(function(data){
+ vm.previousVersions = data.map(version => {
+ version.displayValue = version.versionDate + " - " + version.versionAuthorName;
+ return version;
+ });
+ });
+ }
+
+ /**
+ * This will load in a new version
+ */
+ function createDiff(currentVersion, previousVersion) {
+
+ vm.diff = {};
+ vm.diff.properties = [];
+
+ // find diff in name
+ vm.diff.name = JsDiff.diffWords(currentVersion.name, previousVersion.name);
+
+ // extract all properties from the tabs and create new object for the diff
+ currentVersion.tabs.forEach((tab, tabIndex) => {
+ tab.properties.forEach((property, propertyIndex) => {
+ var oldProperty = previousVersion.tabs[tabIndex].properties[propertyIndex];
+
+ // we have to make properties storing values as object into strings (Grid, nested content, etc.)
+ if(property.value instanceof Object) {
+ property.value = JSON.stringify(property.value, null, 1);
+ property.isObject = true;
+ }
+
+ if(oldProperty.value instanceof Object) {
+ oldProperty.value = JSON.stringify(oldProperty.value, null, 1);
+ oldProperty.isObject = true;
+ }
+
+ // create new property object used in the diff table
+ var diffProperty = {
+ "alias": property.alias,
+ "label": property.label,
+ "diff": (property.value || oldProperty.value) ? JsDiff.diffWords(property.value, oldProperty.value) : "",
+ "isObject": (property.isObject || oldProperty.isObject) ? true : false
+ };
+
+ vm.diff.properties.push(diffProperty);
+
+ });
+ });
+
+ }
+
+ function rollback() {
+
+ vm.rollbackButtonState = "busy";
+
+ const nodeId = $scope.model.node.id;
+ const versionId = vm.previousVersion.versionId;
+ const culture = $scope.model.node.variants.length > 1 ? vm.currentVersion.language.culture : null;
+
+ return contentResource.rollback(nodeId, versionId, culture)
+ .then(data => {
+ vm.rollbackButtonState = "success";
+ submit();
+ }, error => {
+ vm.rollbackButtonState = "error";
+ });
+
+ }
+
+ function submit() {
+ if($scope.model.submit) {
+ $scope.model.submit($scope.model.submit);
+ }
+ }
+
+ function close() {
+ if($scope.model.close) {
+ $scope.model.close();
+ }
+ }
+
+ onInit();
+
+ }
+
+ angular.module("umbraco").controller("Umbraco.Editors.RollbackController", RollbackController);
+
+})();
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html
new file mode 100644
index 0000000000..f7ab78b7a0
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/rollback/rollback.html
@@ -0,0 +1,104 @@
+{{vm.currentVersion.name}} (Created: {{vm.currentVersion.createDate}})
+ +| Name | +
+
+ {{part.value}}
+ |
+
| {{property.label}} | +
+
+ {{part.value}}
+ |
+
{{vm.currentVersion.name}} (Created: {{vm.currentVersion.createDate}})
- -| Name | -
-
- {{part.value}}
- |
-
| {{property.label}} | -
-
- {{part.value}}
- |
-
-