The easiest way to do this is to simply modify the MNTP property editor and have it show the extra data. It is however not really recommended to modify these files since it will be reverted every time you upgrade your Umbraco site.
There is a bit of a hacky workaround to achieve what you want however;
Angular has something called interceptors, allowing you to intercept and modify requests being made. By registrering an interceptor you could intercept the requests to contentpicker.html
and redirect it to a contentpicker.html
file located somewhere else - this means you will be able to just copy this file somewhere else and not modify the one in the umbraco
folder being overwritten by upgrades.
Unfortunately in this case it isn't enough to just override the view being sent to the browser, since the document type alias is not actually available to that view - so the view would never be able to show the alias even if we modified it.
To work around that, you could create a copy of the contentpicker.controller.js
file and create a modified version of that to use in your custom contentpicker.html
view. This modified ContentPickerController would make sure to include the contentTypeAlias
in the model being used in rendering the view.
All of this can be wrapped up as a "package" in the App_Plugins
folder and it will be nicely separated away from being overwritten when you upgrade Umbraco, while being automatically loaded via the package.manifest
file. The only caveat is that in case something is updated in the content picker code, you would have to manually merge those updates over into your custom content picker files - fortunately the content picker is rarely updated.
Place the following files in App_Plugins/CustomContentPicker/
folder and you should have what you want without actually modifying the core code:
package.manifest
{
"javascript": [
"~/App_Plugins/CustomContentPicker/customcontentpicker.controller.js"
]
}
customcontentpicker.html
<div ng-controller="Umbraco.PropertyEditors.CustomContentPickerController" class="umb-editor umb-contentpicker">
<ng-form name="contentPickerForm">
<ul class="unstyled list-icons"
ui-sortable
ng-model="renderModel">
<li ng-repeat="node in renderModel" ng-attr-title="{{model.config.showPathOnHover && 'Path: ' + node.path || undefined}}">
<i class="icon icon-navigation handle"></i>
<a href="#" prevent-default ng-click="remove($index)">
<i class="icon icon-delete red hover-show"></i>
<i class="{{node.icon}} hover-hide"></i>
{{node.name}}<br />
({{node.contentTypeAlias}})
</a>
<div ng-if="!dialogEditor && ((model.config.showOpenButton && allowOpenButton) || (model.config.showEditButton && allowEditButton))">
<small ng-if="model.config.showOpenButton && allowOpenButton"><a href ng-click="showNode($index)"><localize key="open">Open</localize></a></small>
<small ng-if="model.config.showEditButton && allowEditButton"><a href umb-launch-mini-editor="node"><localize key="edit">Edit</localize></a></small>
</div>
</li>
</ul>
<ul class="unstyled list-icons" ng-show="model.config.multiPicker === true || renderModel.length === 0">
<li>
<i class="icon icon-add blue"></i>
<a href="#" ng-click="openContentPicker()" prevent-default>
<localize key="general_add">Add</localize>
</a>
</li>
</ul>
<input type="hidden" name="minCount" ng-model="renderModel" />
<input type="hidden" name="maxCount" ng-model="renderModel" />
<div class="help-inline" val-msg-for="minCount" val-toggle-msg="minCount">
You need to add at least {{model.config.minNumber}} items
</div>
<div class="help-inline" val-msg-for="maxCount" val-toggle-msg="maxCount">
You can only have {{model.config.maxNumber}} items selected
</div>
</ng-form>
<umb-overlay
ng-if="contentPickerOverlay.show"
model="contentPickerOverlay"
view="contentPickerOverlay.view"
position="right">
</umb-overlay>
</div>
customcontentpicker.controller.js
angular.module('umbraco.services').config([
'$httpProvider',
function ($httpProvider) {
$httpProvider.interceptors.push(function ($q) {
return {
'request': function (request) {
var url = 'views/propertyeditors/contentpicker/contentpicker.html';
if (request.url.indexOf(url) !== -1) {
request.url = request.url.replace(url, '/App_Plugins/CustomContentPicker/customcontentpicker.html');
}
return request || $q.when(request);
}
};
});
}]);
function customContentPickerController($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams, fileManager, contentEditingHelper, angularHelper, navigationService, $location) {
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
return str.replace(rgxtrim, '');
}
function startWatch() {
$scope.$watch(function () {
return _.map($scope.renderModel, function (i) {
return i.id;
}).join();
}, function (newVal) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
}
else {
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
}
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
}
else {
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
}
});
}
$scope.renderModel = [];
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
var defaultConfig = {
multiPicker: false,
showOpenButton: false,
showEditButton: false,
showPathOnHover: false,
startNode: {
query: "",
type: "content",
id: $scope.model.config.startNodeId ? $scope.model.config.startNodeId : -1
}
};
if ($scope.model.config) {
$scope.model.config = angular.extend(defaultConfig, $scope.model.config);
}
$scope.model.config.multiPicker = ($scope.model.config.multiPicker === "1" ? true : false);
$scope.model.config.showOpenButton = ($scope.model.config.showOpenButton === "1" ? true : false);
$scope.model.config.showEditButton = ($scope.model.config.showEditButton === "1" ? true : false);
$scope.model.config.showPathOnHover = ($scope.model.config.showPathOnHover === "1" ? true : false);
var entityType = $scope.model.config.startNode.type === "member"
? "Member"
: $scope.model.config.startNode.type === "media"
? "Media"
: "Document";
$scope.allowOpenButton = entityType === "Document" || entityType === "Media";
$scope.allowEditButton = entityType === "Document";
var dialogOptions = {
multiPicker: $scope.model.config.multiPicker,
entityType: entityType,
filterCssClass: "not-allowed not-published",
startNodeId: null,
callback: function (data) {
if (angular.isArray(data)) {
_.each(data, function (item, i) {
$scope.add(item);
});
} else {
$scope.clear();
$scope.add(data);
}
angularHelper.getCurrentForm($scope).$setDirty();
},
treeAlias: $scope.model.config.startNode.type,
section: $scope.model.config.startNode.type
};
angular.extend(dialogOptions, $scope.model.config);
if (entityType === "Member") {
dialogOptions.filterCssClass = "not-allowed";
var currFilter = dialogOptions.filter;
dialogOptions.filter = function (i) {
if (i.metaData.isContainer) {
return true;
}
if (!currFilter) {
return false;
}
var filterItem = currFilter.toLowerCase().split(',');
var found = filterItem.indexOf(i.metaData.contentType.toLowerCase()) >= 0;
if (!currFilter.startsWith("!") && !found || currFilter.startsWith("!") && found) {
return true;
}
return false;
}
}
if ($scope.model.config.startNode.query) {
var rootId = $routeParams.id;
entityResource.getByQuery($scope.model.config.startNode.query, rootId, "Document").then(function (ent) {
dialogOptions.startNodeId = ent.id;
});
} else {
dialogOptions.startNodeId = $scope.model.config.startNode.id;
}
$scope.openContentPicker = function () {
$scope.contentPickerOverlay = dialogOptions;
$scope.contentPickerOverlay.view = "treepicker";
$scope.contentPickerOverlay.show = true;
$scope.contentPickerOverlay.submit = function (model) {
if (angular.isArray(model.selection)) {
_.each(model.selection, function (item, i) {
$scope.add(item);
});
}
$scope.contentPickerOverlay.show = false;
$scope.contentPickerOverlay = null;
}
$scope.contentPickerOverlay.close = function (oldModel) {
$scope.contentPickerOverlay.show = false;
$scope.contentPickerOverlay = null;
}
};
$scope.remove = function (index) {
$scope.renderModel.splice(index, 1);
angularHelper.getCurrentForm($scope).$setDirty();
};
$scope.showNode = function (index) {
var item = $scope.renderModel[index];
var id = item.id;
var section = $scope.model.config.startNode.type.toLowerCase();
entityResource.getPath(id, entityType).then(function (path) {
navigationService.changeSection(section);
navigationService.showTree(section, {
tree: section, path: path, forceReload: false, activate: true
});
var routePath = section + "/" + section + "/edit/" + id.toString();
$location.path(routePath).search("");
});
}
$scope.add = function (item) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
if (currIds.indexOf(item.id) < 0) {
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon, path: item.path, contentTypeAlias: item.metaData.ContentTypeAlias });
}
};
$scope.clear = function () {
$scope.renderModel = [];
};
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
});
$scope.$on('$destroy', function () {
unsubscribe();
});
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
entityResource.getByIds(modelIds, entityType).then(function (data) {
_.each(modelIds, function (id, i) {
var entity = _.find(data, function (d) {
return d.id == id;
});
if (entity) {
entity.icon = iconHelper.convertFromLegacyIcon(entity.icon);
$scope.renderModel.push({ name: entity.name, id: entity.id, icon: entity.icon, path: entity.path, contentTypeAlias: entity.metaData.ContentTypeAlias });
}
});
startWatch();
});
}
angular.module('umbraco').controller("Umbraco.PropertyEditors.CustomContentPickerController", customContentPickerController);