Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bca29975dd | |||
| be8bd3d443 | |||
| 6a7b6f7267 | |||
| f738e6d7c7 |
+5
-5
@@ -955,12 +955,12 @@
|
||||
"dependencies": {
|
||||
"extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extendable": "0.1.1"
|
||||
},
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz"
|
||||
"is-extendable": "^0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1670,9 +1670,9 @@
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=",
|
||||
"dev": true,
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -158,6 +158,10 @@
|
||||
});
|
||||
contentApp.viewModel = variant;
|
||||
|
||||
// emit variant change event so content apps can update content
|
||||
var args = { "node": $scope.content, "variant": variant };
|
||||
eventsService.emit("editors.content.changeVariant", args);
|
||||
|
||||
return variant;
|
||||
}
|
||||
|
||||
|
||||
+47
-45
@@ -6,7 +6,7 @@
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
var evts = [];
|
||||
var isInfoTab = false;
|
||||
var isInfoApp = false;
|
||||
var labels = {};
|
||||
scope.publishStatus = [];
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
function onInit() {
|
||||
|
||||
//get the current variant
|
||||
scope.activeVariant = _.find(scope.node.variants, function (variant) {
|
||||
return variant.active;
|
||||
});
|
||||
|
||||
userService.getCurrentUser().then(function(user){
|
||||
// only allow change of media type if user has access to the settings sections
|
||||
angular.forEach(user.sections, function(section){
|
||||
@@ -42,7 +47,7 @@
|
||||
labels.publishedPendingChanges = data[3];
|
||||
labels.notCreated = data[4];
|
||||
|
||||
setNodePublishStatus(scope.node);
|
||||
setPublishState(scope.node, scope.activeVariant);
|
||||
|
||||
});
|
||||
|
||||
@@ -172,49 +177,40 @@
|
||||
});
|
||||
}
|
||||
|
||||
function setNodePublishStatus(node) {
|
||||
function setPublishState(node, variant) {
|
||||
|
||||
// deleted node
|
||||
if (node.trashed === true) {
|
||||
scope.publishStatus.push({
|
||||
label: labels.deleted,
|
||||
color: "danger"
|
||||
});
|
||||
var state = {};
|
||||
|
||||
if (node.trashed) {
|
||||
// deleted node
|
||||
state.label = labels.deleted;
|
||||
state.color = "danger";
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.variants) {
|
||||
for (var i = 0; i < node.variants.length; i++) {
|
||||
|
||||
var variant = node.variants[i];
|
||||
|
||||
var status = {
|
||||
culture: variant.language ? variant.language.culture : null
|
||||
};
|
||||
|
||||
if (variant.state === "NotCreated") {
|
||||
status.label = labels.notCreated;
|
||||
status.color = "gray";
|
||||
}
|
||||
else if (variant.state === "Draft") {
|
||||
// draft node
|
||||
status.label = labels.unpublished;
|
||||
status.color = "gray";
|
||||
}
|
||||
else if (variant.state === "Published") {
|
||||
// published node
|
||||
status.label = labels.published;
|
||||
status.color = "success";
|
||||
}
|
||||
else if (variant.state === "PublishedPendingChanges") {
|
||||
// published node with pending changes
|
||||
status.label = labels.publishedPendingChanges;
|
||||
status.color = "success";
|
||||
}
|
||||
|
||||
scope.publishStatus.push(status);
|
||||
}
|
||||
if (variant.state === "NotCreated") {
|
||||
// not created variant
|
||||
state.label = labels.notCreated;
|
||||
state.color = "gray";
|
||||
}
|
||||
else if (variant.state === "Draft") {
|
||||
// draft variant
|
||||
state.label = labels.unpublished;
|
||||
state.color = "gray";
|
||||
}
|
||||
else if (variant.state === "Published") {
|
||||
// published variant
|
||||
state.label = labels.published;
|
||||
state.color = "success";
|
||||
}
|
||||
else if (variant.state === "PublishedPendingChanges") {
|
||||
// published variant with pending changes
|
||||
state.label = labels.publishedPendingChanges;
|
||||
state.color = "success";
|
||||
}
|
||||
|
||||
scope.variantState = state;
|
||||
|
||||
}
|
||||
|
||||
function setPublishDate(date) {
|
||||
@@ -292,7 +288,7 @@
|
||||
function formatDatesToLocal() {
|
||||
// get current backoffice user and format dates
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
scope.node.createDateFormatted = dateHelper.getLocalDate(scope.node.createDate, currentUser.locale, 'LLL');
|
||||
scope.activeVariant.createDateFormatted = dateHelper.getLocalDate(scope.activeVariant.createDate, currentUser.locale, 'LLL');
|
||||
|
||||
scope.node.releaseDateYear = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'YYYY')) : null;
|
||||
scope.node.releaseDateMonth = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'MMMM')) : null;
|
||||
@@ -312,24 +308,30 @@
|
||||
evts.push(eventsService.on("app.tabChange", function (event, args) {
|
||||
$timeout(function(){
|
||||
if (args.alias === "info") {
|
||||
isInfoTab = true;
|
||||
isInfoApp = true;
|
||||
loadAuditTrail();
|
||||
} else {
|
||||
isInfoTab = false;
|
||||
isInfoApp = false;
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
// listen for variant change so we can update the content
|
||||
evts.push(eventsService.on("editors.content.changeVariant", function (event, args) {
|
||||
setPublishState(args.node, args.variant);
|
||||
formatDatesToLocal();
|
||||
}));
|
||||
|
||||
// watch for content updates - reload content when node is saved, published etc.
|
||||
scope.$watch('node.updateDate', function(newValue, oldValue){
|
||||
|
||||
if(!newValue) { return; }
|
||||
if(newValue === oldValue) { return; }
|
||||
if(newValue === oldValue) { return; }
|
||||
|
||||
if(isInfoTab) {
|
||||
loadAuditTrail();
|
||||
formatDatesToLocal();
|
||||
setNodePublishStatus(scope.node);
|
||||
setPublishState(scope.node);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -787,91 +787,9 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
),
|
||||
"Failed to create blueprint from content with id " + contentId
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.contentResource#getAvailableContentTypesToChangeTo
|
||||
* @methodOf umbraco.resources.contentResource
|
||||
*
|
||||
* @description
|
||||
* Returns a list of available content types that it can be changed by checking against a nodeID
|
||||
*
|
||||
* @param {Int} id id of content item to query for available ContentTypes to change to
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
getAvailableContentTypesToChangeTo: function (id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetAvailableContentTypesToChangeTo",
|
||||
[{ currentNodeId: id }])),
|
||||
'Failed to get available content types to change to for item ' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.contentResource#getAvailableProperties
|
||||
* @methodOf umbraco.resources.contentResource
|
||||
*
|
||||
* @description
|
||||
* Returns a list of available properties that a content types that it can be changed to
|
||||
*
|
||||
* @param {String} fromAlias alias of current ContentType
|
||||
* @param {String} toAlias alias of new ContentType changing to
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
getAvailableProperties: function (fromAlias, toAlias) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetAvailableProperties",
|
||||
[{ fromPropertyAlias: fromAlias}, { toPropertyAlias: toAlias }])),
|
||||
'Failed to get available propeties for item ' + fromAlias);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.contentResource#postContentTypeChange
|
||||
* @methodOf umbraco.resources.contentResource
|
||||
*
|
||||
* @description
|
||||
* Sorts all children below a given parent node id, based on a collection of node-ids
|
||||
*
|
||||
* @param {Object} args arguments object
|
||||
* @param {Int} args.contentNodeId the ID of the current node to change doctype
|
||||
* @param {Int} args.newContentTypeId the ID of the pew ContentType to change to
|
||||
* @param {Int} args.newTemplateId the ID of the new Template to change to
|
||||
* @param {Array} args.fieldMap array of node IDs as they should be sorted
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
postContentTypeChange: function (args) {
|
||||
if (!args) {
|
||||
throw "args cannot be null";
|
||||
}
|
||||
if (!args.contentNodeId) {
|
||||
throw "args.contentNodeId cannot be null";
|
||||
}
|
||||
if (!args.newContentTypeId) {
|
||||
throw "args.newContentTypeId cannot be null";
|
||||
}
|
||||
if (!args.newTemplateId) {
|
||||
throw "args.newTemplateId cannot be null";
|
||||
}
|
||||
if (!args.fieldMap) {
|
||||
throw "args.fieldMap cannot be null";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("contentApiBaseUrl", "PostContentTypeChange"),
|
||||
args),
|
||||
'Failed to change content type content');
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -519,25 +519,32 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
var allNewProps = this.getAllProps(savedVariant);
|
||||
|
||||
//check for changed properties of the content
|
||||
for (var p in allOrigProps) {
|
||||
var alias = allOrigProps[p].alias;
|
||||
for (var k = 0; k < allOrigProps.length; k++) {
|
||||
|
||||
var origProp = allOrigProps[k];
|
||||
var alias = origProp.alias;
|
||||
var newProp = getNewProp(alias, allNewProps);
|
||||
if (newProp && !_.isEqual(alias, newProp.value)) {
|
||||
if (newProp && !_.isEqual(origProp.value, newProp.value)) {
|
||||
|
||||
//they have changed so set the origContent prop to the new one
|
||||
var origVal = allOrigProps[p].value;
|
||||
allOrigProps[p].value = newProp.value;
|
||||
var origVal = origProp.value;
|
||||
|
||||
origProp.value = newProp.value;
|
||||
|
||||
//instead of having a property editor $watch their expression to check if it has
|
||||
// been updated, instead we'll check for the existence of a special method on their model
|
||||
// and just call it.
|
||||
if (angular.isFunction(allOrigProps[p].onValueChanged)) {
|
||||
if (angular.isFunction(origProp.onValueChanged)) {
|
||||
//send the newVal + oldVal
|
||||
allOrigProps[p].onValueChanged(allOrigProps[p].value, origVal);
|
||||
origProp.onValueChanged(origProp.value, origVal);
|
||||
}
|
||||
|
||||
changed.push(allOrigProps[p]);
|
||||
changed.push(origProp);
|
||||
}
|
||||
|
||||
}
|
||||
for (var p in allOrigProps) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,10 +159,18 @@ function formHelper(angularHelper, serverValidationManager, $timeout, notificati
|
||||
|
||||
//Check if this is for content properties - specific to content/media/member editors because those are special
|
||||
// user defined properties with custom controls.
|
||||
if (parts.length > 2 && parts[0] === "_Properties") {
|
||||
if (parts.length > 1 && parts[0] === "_Properties") {
|
||||
|
||||
var propertyAlias = parts[1];
|
||||
var culture = parts[2];
|
||||
|
||||
var culture = null;
|
||||
if (parts.length > 2) {
|
||||
culture = parts[2];
|
||||
//special check in case the string is formatted this way
|
||||
if (culture === "null") {
|
||||
culture = null;
|
||||
}
|
||||
}
|
||||
|
||||
//if it contains 3 '.' then we will wire it up to a property's html field
|
||||
if (parts.length > 3) {
|
||||
|
||||
@@ -140,8 +140,9 @@ function serverValidationManager($timeout) {
|
||||
}
|
||||
}
|
||||
else if (propertyAlias !== undefined) {
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
//don't add it if it already exists
|
||||
var exists2 = _.find(callbacks, function (item) {
|
||||
@@ -165,8 +166,9 @@ function serverValidationManager($timeout) {
|
||||
}
|
||||
else if (propertyAlias !== undefined) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
|
||||
//remove all callbacks for the content property
|
||||
@@ -192,8 +194,9 @@ function serverValidationManager($timeout) {
|
||||
*/
|
||||
getPropertyCallbacks: function (propertyAlias, culture, fieldName) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
|
||||
var found = _.filter(callbacks, function (item) {
|
||||
@@ -268,8 +271,9 @@ function serverValidationManager($timeout) {
|
||||
return;
|
||||
}
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
|
||||
//only add the item if it doesn't exist
|
||||
@@ -306,6 +310,12 @@ function serverValidationManager($timeout) {
|
||||
if (!propertyAlias) {
|
||||
return;
|
||||
}
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null;
|
||||
}
|
||||
|
||||
//remove the item
|
||||
this.items = _.reject(this.items, function (item) {
|
||||
return (item.propertyAlias === propertyAlias && item.culture === culture && (item.fieldName === fieldName || (fieldName === undefined || fieldName === "")));
|
||||
@@ -354,6 +364,12 @@ function serverValidationManager($timeout) {
|
||||
* Gets the error message for the content property
|
||||
*/
|
||||
getPropertyError: function (propertyAlias, culture, fieldName) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null;
|
||||
}
|
||||
|
||||
var err = _.find(this.items, function (item) {
|
||||
//return true if the property alias matches and if an empty field name is specified or the field name matches
|
||||
return (item.propertyAlias === propertyAlias && item.culture === culture && (item.fieldName === fieldName || (fieldName === undefined || fieldName === "")));
|
||||
@@ -388,6 +404,12 @@ function serverValidationManager($timeout) {
|
||||
* Checks if the content property + culture + field name combo has an error
|
||||
*/
|
||||
hasPropertyError: function (propertyAlias, culture, fieldName) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null;
|
||||
}
|
||||
|
||||
var err = _.find(this.items, function (item) {
|
||||
//return true if the property alias matches and if an empty field name is specified or the field name matches
|
||||
return (item.propertyAlias === propertyAlias && item.culture === culture && (item.fieldName === fieldName || (fieldName === undefined || fieldName === "")));
|
||||
|
||||
+1
-1
@@ -435,4 +435,4 @@ angular.module("umbraco")
|
||||
|
||||
onInit();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -169,16 +169,11 @@
|
||||
<umb-box-content class="block-form">
|
||||
|
||||
<umb-control-group data-element="node-info-status" label="@general_status">
|
||||
<div ng-repeat="status in publishStatus" style="margin-bottom: 5px;">
|
||||
<span ng-if="status.culture"><em>{{status.culture}}: </em></span>
|
||||
<umb-badge size="xs" color="{{status.color}}">
|
||||
{{status.label}}
|
||||
</umb-badge>
|
||||
</div>
|
||||
<umb-badge size="xs" color="{{variantState.color}}">{{variantState.label}}</umb-badge>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group data-element="node-info-create-date" label="@template_createdDate">
|
||||
{{node.createDateFormatted}} <localize key="general_by">by</localize> {{ node.owner.name }}
|
||||
{{activeVariant.createDateFormatted}} <localize key="general_by">by</localize> {{ node.owner.name }}
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group data-element="node-info-document-type" label="@content_documentType">
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
<div ng-controller="Umbraco.Editors.Content.ChangeDocTypeController as vm" ng-cloak>
|
||||
|
||||
<div class="umb-dialog-body with-footer">
|
||||
<div class="umb-pane">
|
||||
|
||||
<umb-load-indicator ng-show="vm.loading"></umb-load-indicator>
|
||||
|
||||
<div ng-if="!vm.loading">
|
||||
<div ng-if="vm.allowedContentTypes.length > 0" class="block-form">
|
||||
<p class="help"><localize key="changeDocType_changeDocTypeInstruction"></localize></p>
|
||||
|
||||
<div class="umb-el-wrap" style="margin-bottom: 15px;">
|
||||
<label class="control-label"><localize key="changeDocType_selectedContent"></localize></label>
|
||||
<div class="controls controls-row">{{ currentNode.name }}</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-el-wrap" style="margin-bottom: 15px;">
|
||||
<label class="control-label"><localize key="changeDocType_currentType"></localize></label>
|
||||
<div class="controls controls-row">{{ vm.currentContentType.name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Allowed Doctypes to switch to -->
|
||||
<div class="umb-el-wrap" style="margin-bottom: 15px;">
|
||||
<label class="control-label"><localize key="changeDocType_newType"></localize></label>
|
||||
<div class="controls controls-row">
|
||||
<select
|
||||
ng-change="vm.changeAllowedContentType(vm.newContentType)"
|
||||
ng-options="option.name for option in vm.allowedContentTypes"
|
||||
ng-model="vm.newContentType">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Allowed Templates to switch to -->
|
||||
<div ng-if="vm.allowedTemplates.length > 0" class="umb-el-wrap" style="margin-bottom: 15px;">
|
||||
<label class="control-label"><localize key="changeDocType_newTemplate"></localize></label>
|
||||
<div class="controls controls-row">
|
||||
<select
|
||||
ng-options="option.name for option in vm.allowedTemplates"
|
||||
ng-model="vm.newTemplate">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Map properties -->
|
||||
<table class="table table-condensed table-bordered" ng-if="vm.propertiesMap.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Current Property</th>
|
||||
<th>Map to Property</th>
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="currentProperty in vm.propertiesMap">
|
||||
<td>
|
||||
<span class="bold">{{currentProperty.name}}</span>
|
||||
</td>
|
||||
<td>
|
||||
<p ng-if="currentProperty.allowed.length === 0">None</p>
|
||||
<select
|
||||
ng-if="currentProperty.allowed.length > 0"
|
||||
style="margin-bottom: 0;"
|
||||
ng-options="option.alias as option.name for option in currentProperty.allowed"
|
||||
ng-model="selected"
|
||||
ng-change="vm.changeProperty(currentProperty, selected)">
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Display warning if no types available to swap to -->
|
||||
<umb-empty-state ng-if="vm.allowedContentTypes.length === 0" position="center">
|
||||
<localize key="changeDocType_docTypeCannotBeChanged"></localize>
|
||||
</umb-empty-state>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="link"
|
||||
action="nav.hideDialog()"
|
||||
label-key="general_cancel">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
ng-if="vm.allowedContentTypes.length > 0"
|
||||
type="button"
|
||||
action="vm.save()"
|
||||
state="vm.saveButtonState"
|
||||
button-style="success"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,84 +0,0 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function ChangeDocTypeController($scope, contentResource, navigationService) {
|
||||
|
||||
var vm = this;
|
||||
var id = $scope.currentNode.id;
|
||||
|
||||
vm.currentContentType = {};
|
||||
vm.allowedContentTypes = [];
|
||||
vm.allowedTemplates = [];
|
||||
vm.propertiesMap = [];
|
||||
|
||||
// the new models
|
||||
vm.newContentType = {};
|
||||
vm.newTemplate = {};
|
||||
|
||||
// bind function to view model
|
||||
vm.changeAllowedContentType = changeAllowedContentType;
|
||||
vm.changeProperty = changeProperty;
|
||||
vm.save = save;
|
||||
|
||||
function onInit() {
|
||||
vm.loading = true;
|
||||
contentResource.getAvailableContentTypesToChangeTo(id)
|
||||
.then(function(data){
|
||||
vm.currentContentType = data.currentContentType;
|
||||
vm.allowedContentTypes = data.contentTypes;
|
||||
vm.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function changeAllowedContentType(newContentType) {
|
||||
contentResource.getAvailableProperties(vm.currentContentType.alias, newContentType.alias)
|
||||
.then(function(data){
|
||||
vm.allowedTemplates = data.templates;
|
||||
vm.propertiesMap = data.currentProperties;
|
||||
});
|
||||
}
|
||||
|
||||
function changeProperty(currentProperty, selected) {
|
||||
currentProperty.selectedAlias = selected;
|
||||
}
|
||||
|
||||
function save() {
|
||||
|
||||
vm.saveButtonState = "busy";
|
||||
|
||||
var fieldMap = [];
|
||||
|
||||
angular.forEach(vm.propertiesMap, function(property) {
|
||||
if(property.selectedAlias) {
|
||||
var map = {};
|
||||
map.fromAlias = property.alias;
|
||||
map.toAlias = property.selectedAlias;
|
||||
fieldMap.push(map);
|
||||
}
|
||||
});
|
||||
|
||||
var args = {
|
||||
"contentNodeId": id,
|
||||
"newContentTypeId": vm.newContentType.id,
|
||||
"newTemplateId": vm.newTemplate.id,
|
||||
"fieldMap": fieldMap
|
||||
};
|
||||
|
||||
contentResource.postContentTypeChange(args).then(function(){
|
||||
|
||||
console.log('args', args);
|
||||
//Sync tree?
|
||||
//Reload node?
|
||||
vm.saveButtonState = "success";
|
||||
}, function(error) {
|
||||
vm.error = error;
|
||||
vm.saveButtonState = "error";
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
onInit();
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Content.ChangeDocTypeController", ChangeDocTypeController);
|
||||
})();
|
||||
@@ -123,7 +123,8 @@ describe('contentEditingHelper tests', function () {
|
||||
var allProps = contentEditingHelper.getAllProps(content);
|
||||
|
||||
//act
|
||||
formHelper.handleServerValidation({ "_Properties.bodyText.value": ["Required"] });
|
||||
//note the null, that's because culture is null
|
||||
formHelper.handleServerValidation({ "_Properties.bodyText.null.value": ["Required"] });
|
||||
|
||||
//assert
|
||||
expect(serverValidationManager.items.length).toBe(1);
|
||||
@@ -143,7 +144,8 @@ describe('contentEditingHelper tests', function () {
|
||||
{
|
||||
"Name": ["Required"],
|
||||
"UpdateDate": ["Invalid date"],
|
||||
"_Properties.bodyText.value": ["Required field"],
|
||||
//note the null, that's because culture is null
|
||||
"_Properties.bodyText.null.value": ["Required field"],
|
||||
"_Properties.textarea": ["Invalid format"]
|
||||
});
|
||||
|
||||
@@ -226,6 +228,7 @@ describe('contentEditingHelper tests', function () {
|
||||
//act
|
||||
var changed = contentEditingHelper.reBindChangedProperties(origContent, newContent);
|
||||
|
||||
|
||||
//assert
|
||||
expect(changed.length).toBe(2);
|
||||
expect(changed[0].alias).toBe("grid");
|
||||
|
||||
@@ -10,24 +10,39 @@ describe('file manager tests', function () {
|
||||
describe('file management', function () {
|
||||
|
||||
it('adding a file adds to the collection', function () {
|
||||
fileManager.setFiles('testProp', ["testFile"]);
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile"]
|
||||
});
|
||||
expect(fileManager.getFiles().length).toBe(1);
|
||||
});
|
||||
|
||||
it('adding a file with the same property id replaces the existing one', function () {
|
||||
fileManager.setFiles('testProp', ["testFile"]);
|
||||
fileManager.setFiles('testProp', ["testFile2"]);
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile"]
|
||||
});
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile2"]
|
||||
});
|
||||
expect(fileManager.getFiles().length).toBe(1);
|
||||
expect(fileManager.getFiles()[0].file).toBe("testFile2");
|
||||
});
|
||||
|
||||
it('clears all files', function () {
|
||||
fileManager.setFiles('testProp1', ["testFile"]);
|
||||
fileManager.setFiles('testProp2', ["testFile"]);
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile"]
|
||||
});
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp2',
|
||||
files: ["testFile"]
|
||||
});
|
||||
expect(fileManager.getFiles().length).toBe(2);
|
||||
fileManager.clearFiles();
|
||||
expect(fileManager.getFiles().length).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1539,196 +1539,5 @@ namespace Umbraco.Web.Editors
|
||||
Services.NotificationService.SetNotifications(Security.CurrentUser, content, notifyOptions);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public AvailableContentTypes GetAvailableContentTypesToChangeTo(int currentNodeId)
|
||||
{
|
||||
var content = Services.ContentService.GetById(currentNodeId);
|
||||
|
||||
// Start with all content types
|
||||
var contentTypes = Services.ContentTypeService.GetAll().ToArray();
|
||||
|
||||
//Remove invalid ones from list of potential alternatives
|
||||
//Remove CurrentDoctype
|
||||
contentTypes = contentTypes.Where(x => x.Id != content.ContentTypeId).ToArray();
|
||||
|
||||
//Remove Invalid Parent Doctypes
|
||||
if (content.ParentId == -1)
|
||||
{
|
||||
// Root content, only include those that have been selected as allowed at root
|
||||
contentTypes = contentTypes.Where(x => x.AllowedAsRoot).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Below root, so only include those allowed as sub-nodes for the parent
|
||||
var parentNode = Services.ContentService.GetById(content.ParentId);
|
||||
|
||||
contentTypes = contentTypes
|
||||
.Where(x => parentNode.ContentType.AllowedContentTypes
|
||||
.Select(y => y.Id.Value)
|
||||
.Contains(x.Id)).ToArray();
|
||||
}
|
||||
|
||||
//Remove invalid children doctypes
|
||||
var docTypeIdsOfChildren = content.Children(Services.ContentService)
|
||||
.Select(x => x.ContentType.Id)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
contentTypes = contentTypes
|
||||
.Where(x => x.AllowedContentTypes
|
||||
.Select(y => y.Id.Value)
|
||||
.ContainsAll(docTypeIdsOfChildren)).ToArray();
|
||||
|
||||
//Return a friendlier model down the wire
|
||||
var basicContentTypes = new List<ContentTypeBasic>();
|
||||
foreach (var type in contentTypes)
|
||||
{
|
||||
basicContentTypes.Add(Mapper.Map<IContentType, ContentTypeBasic>(type));
|
||||
}
|
||||
|
||||
return new AvailableContentTypes
|
||||
{
|
||||
ContentTypes = basicContentTypes,
|
||||
CurrentNodeName = content.Name,
|
||||
CurrentContentType = Mapper.Map<IContentType, ContentTypeBasic>(content.ContentType)
|
||||
};
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public AvailableProperties GetAvailableProperties(string fromPropertyAlias, string toPropertyAlias)
|
||||
{
|
||||
//Get the new property type we are changing to
|
||||
var newContentType = Services.ContentTypeService.Get(toPropertyAlias);
|
||||
|
||||
//Get the current property type that the content node is using
|
||||
var currentContentType = Services.ContentTypeService.Get(fromPropertyAlias);
|
||||
|
||||
var properties = new List<CurrentProperty>();
|
||||
|
||||
//Create a list of current properties the current doctype has
|
||||
//With each property in this list specifying what new properties from the doctype we are changing to
|
||||
//Ensuring they use the same underlying property editor alias
|
||||
foreach (var currentProp in currentContentType.PropertyTypes)
|
||||
{
|
||||
var propertyToAdd = new CurrentProperty
|
||||
{
|
||||
Name = currentProp.Name,
|
||||
Alias = currentProp.Alias
|
||||
};
|
||||
|
||||
var allowedProps = new List<NewProperty>();
|
||||
foreach (var newProp in newContentType.PropertyTypes.Where(x => x.PropertyEditorAlias == currentProp.PropertyEditorAlias))
|
||||
{
|
||||
var allowedProp = new NewProperty
|
||||
{
|
||||
Name = newProp.Name,
|
||||
Alias = newProp.Alias
|
||||
};
|
||||
|
||||
allowedProps.Add(allowedProp);
|
||||
}
|
||||
|
||||
propertyToAdd.Allowed = allowedProps;
|
||||
properties.Add(propertyToAdd);
|
||||
}
|
||||
|
||||
var templates = new List<TemplateDisplay>();
|
||||
foreach (var template in newContentType.AllowedTemplates)
|
||||
{
|
||||
templates.Add(Mapper.Map<ITemplate, TemplateDisplay>(template));
|
||||
}
|
||||
|
||||
return new AvailableProperties
|
||||
{
|
||||
Templates = templates,
|
||||
CurrentProperties = properties
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"contentNodeId": 1234,
|
||||
"newContentTypeId": 80,
|
||||
"newTemplateId": 40,
|
||||
"fieldMap": [
|
||||
{
|
||||
"fromAlias": "siteTitle",
|
||||
"toAlias": "newsTitle"
|
||||
},
|
||||
{
|
||||
"fromAlias": "bodyText",
|
||||
"toAlias": null
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
[HttpPost]
|
||||
public HttpResponseMessage PostContentTypeChange(ChangeContentType model)
|
||||
{
|
||||
var content = Services.ContentService.GetById(model.ContentNodeId);
|
||||
if (content == null)
|
||||
{
|
||||
//throw some ex
|
||||
return Request.CreateNotificationValidationErrorResponse("Content is null");
|
||||
}
|
||||
|
||||
//Check that field mappings (do not have something selected twice & is unique)
|
||||
if (model.FieldMap.GroupBy(x => x.ToAlias).Any(g => g.Count() > 1))
|
||||
{
|
||||
//Throw Error
|
||||
return Request.CreateNotificationValidationErrorResponse(Services.TextService.Localize("changeDocType/validationErrorPropertyWithMoreThanOneMapping"));
|
||||
}
|
||||
|
||||
// For all properties to be mapped, save the current values to a temporary list
|
||||
var propertyMappings = new List<FieldMapValue>();
|
||||
foreach (var map in model.FieldMap)
|
||||
{
|
||||
//If the ToAlias is not empty
|
||||
if (!string.IsNullOrEmpty(map.ToAlias))
|
||||
{
|
||||
// Mapping property, get current property value from alias
|
||||
var sourceAlias = map.FromAlias;
|
||||
var sourcePropertyValue = content.GetValue(sourceAlias);
|
||||
|
||||
// Add to list
|
||||
propertyMappings.Add(new FieldMapValue
|
||||
{
|
||||
ToAlias = map.ToAlias,
|
||||
CurrentValue = sourcePropertyValue
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Get flag for if content already published
|
||||
var wasPublished = content.Published;
|
||||
|
||||
// Change the document type passing flag to clear the properties
|
||||
var newContentType = Services.ContentTypeService.Get(model.NewContentTypeId);
|
||||
content.ChangeContentType(newContentType, true);
|
||||
|
||||
//Set the template if one has been selected
|
||||
content.Template = model.NewTemplateId > 0 ? Services.FileService.GetTemplate(model.NewTemplateId) : null;
|
||||
|
||||
// Port across the property values to the new properties
|
||||
foreach (var propertyMapping in propertyMappings)
|
||||
{
|
||||
content.SetValue(propertyMapping.ToAlias, propertyMapping.CurrentValue);
|
||||
}
|
||||
|
||||
// Save the changes
|
||||
var user = Security.CurrentUser;
|
||||
Services.ContentService.Save(content, user.Id);
|
||||
|
||||
// Publish if the content was already published
|
||||
if (wasPublished)
|
||||
{
|
||||
// no values to publish, really
|
||||
Services.ContentService.SaveAndPublish(content, userId: user.Id);
|
||||
}
|
||||
|
||||
//All OK - return a 200
|
||||
return Request.CreateNotificationSuccessResponse("DOCTYPE CHANGED");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
[DataContract(Name = "changeContentType", Namespace = "")]
|
||||
public class ChangeContentType
|
||||
{
|
||||
[DataMember(Name = "contentNodeId")]
|
||||
public int ContentNodeId { get; set; }
|
||||
|
||||
[DataMember(Name = "newContentTypeId")]
|
||||
public int NewContentTypeId { get; set; }
|
||||
|
||||
[DataMember(Name = "newTemplateId")]
|
||||
public int NewTemplateId { get; set; }
|
||||
|
||||
[DataMember(Name = "fieldMap")]
|
||||
public IEnumerable<FieldMap> FieldMap { get; set; }
|
||||
}
|
||||
|
||||
[DataContract(Name = "fieldMap", Namespace = "")]
|
||||
public class FieldMap
|
||||
{
|
||||
[DataMember(Name = "fromAlias")]
|
||||
public string FromAlias { get; set; }
|
||||
|
||||
[DataMember(Name = "toAlias")]
|
||||
public string ToAlias { get; set; }
|
||||
}
|
||||
|
||||
public class FieldMapValue
|
||||
{
|
||||
public string ToAlias { get; set; }
|
||||
|
||||
public object CurrentValue { get; set; }
|
||||
}
|
||||
|
||||
[DataContract(Name = "availableContentTypes", Namespace = "")]
|
||||
public class AvailableContentTypes
|
||||
{
|
||||
[DataMember(Name = "currentNodeName")]
|
||||
public string CurrentNodeName { get; set; }
|
||||
|
||||
[DataMember(Name = "currentContentType")]
|
||||
public ContentTypeBasic CurrentContentType { get; set; }
|
||||
|
||||
[DataMember(Name = "contentTypes")]
|
||||
public IEnumerable<ContentTypeBasic> ContentTypes { get; set; }
|
||||
}
|
||||
|
||||
[DataContract(Name = "availableProperties", Namespace = "")]
|
||||
public class AvailableProperties
|
||||
{
|
||||
[DataMember(Name = "templates")]
|
||||
public IEnumerable<TemplateDisplay> Templates { get; set; }
|
||||
|
||||
[DataMember(Name = "currentProperties")]
|
||||
public IEnumerable<CurrentProperty> CurrentProperties { get; set; }
|
||||
}
|
||||
|
||||
[DataContract(Name = "currentProperty", Namespace = "")]
|
||||
public class CurrentProperty
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[DataMember(Name = "allowed")]
|
||||
public IEnumerable<NewProperty> Allowed { get; set; }
|
||||
}
|
||||
|
||||
[DataContract(Name = "newProperty", Namespace = "")]
|
||||
public class NewProperty
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -226,7 +226,7 @@ namespace Umbraco.Web.Trees
|
||||
//need to ensure some of these are converted to the legacy system - until we upgrade them all to be angularized.
|
||||
AddActionNode<ActionMove>(item, menu, true);
|
||||
AddActionNode<ActionCopy>(item, menu);
|
||||
AddActionNode<ActionChangeDocType>(item, menu);
|
||||
AddActionNode<ActionChangeDocType>(item, menu, convert: true);
|
||||
|
||||
AddActionNode<ActionSort>(item, menu, true);
|
||||
|
||||
|
||||
@@ -211,43 +211,46 @@ namespace Umbraco.Web.Trees
|
||||
new LegacyUrlAction(
|
||||
"create.aspx?nodeId=" + nodeId + "&nodeType=" + nodeType + "&nodeName=" + nodeName + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/create")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionNewFolder()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"createFolder.aspx?nodeId=" + nodeId + "&nodeType=" + nodeType + "&nodeName=" + nodeName + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/create")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionProtect()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/protectPage.aspx?mode=cut&nodeId=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/protect")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionRollback()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/rollback.aspx?nodeId=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/rollback")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionNotify()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/notifications.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/notify")));
|
||||
case "UmbClientMgr.appActions().actionPublish()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/publish.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/publish")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionChangeDocType()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/ChangeDocType.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/changeDocType")));
|
||||
case "UmbClientMgr.appActions().actionToPublish()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/SendPublish.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/sendtopublish")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionRePublish()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/republish.aspx?rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/republish")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionSendToTranslate()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
|
||||
@@ -115,7 +115,6 @@
|
||||
<Compile Include="Editors\BackOfficeAssetsController.cs" />
|
||||
<Compile Include="Editors\BackOfficeModel.cs" />
|
||||
<Compile Include="Editors\BackOfficeServerVariables.cs" />
|
||||
<Compile Include="Models\ContentEditing\ChangeContentType.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentSavedState.cs" />
|
||||
<Compile Include="WebApi\HttpActionContextExtensions.cs" />
|
||||
<Compile Include="Models\ContentEditing\IContentSave.cs" />
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
return string.Format("{0}.actionChangeDocType()", ClientTools.Scripts.GetAppActions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user