Merge pull request #2163 from umbraco/temp-U4-10275
U4-10275 Render 'site' nodes for the content/media trees for users with non root access
This commit is contained in:
@@ -31,7 +31,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
//var showheader = (attrs.showheader !== 'false');
|
||||
var hideoptions = (attrs.hideoptions === 'true') ? "hide-options" : "";
|
||||
var template = '<ul class="umb-tree ' + hideoptions + '"><li class="root">';
|
||||
template += '<div ng-hide="hideheader" on-right-click="altSelect(tree.root, $event)">' +
|
||||
template += '<div ng-class="getNodeCssClass(tree.root)" ng-hide="hideheader" on-right-click="altSelect(tree.root, $event)">' +
|
||||
'<h5>' +
|
||||
'<a href="#/{{section}}" ng-click="select(tree.root, $event)" class="root-link"><i ng-if="enablecheckboxes == \'true\'" ng-class="selectEnabledNodeClass(tree.root)"></i> {{tree.name}}</a></h5>' +
|
||||
'<a class="umb-options" ng-hide="tree.root.isContainer || !tree.root.menuUrl" ng-click="options(tree.root, $event)" ng-swipe-right="options(tree.root, $event)"><i></i><i></i><i></i></a>' +
|
||||
@@ -310,6 +310,25 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
|
||||
}
|
||||
|
||||
/** Returns the css classses assigned to the node (div element) */
|
||||
scope.getNodeCssClass = function (node) {
|
||||
if (!node) {
|
||||
return '';
|
||||
}
|
||||
|
||||
//TODO: This is called constantly because as a method in a template it's re-evaluated pretty much all the time
|
||||
// it would be better if we could cache the processing. The problem is that some of these things are dynamic.
|
||||
|
||||
var css = [];
|
||||
if (node.cssClasses) {
|
||||
_.each(node.cssClasses, function (c) {
|
||||
css.push(c);
|
||||
});
|
||||
}
|
||||
|
||||
return css.join(" ");
|
||||
};
|
||||
|
||||
scope.selectEnabledNodeClass = function (node) {
|
||||
return node ?
|
||||
node.selected ?
|
||||
@@ -383,6 +402,12 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
defined on the tree
|
||||
*/
|
||||
scope.select = function (n, ev) {
|
||||
|
||||
if (n.metaData && n.metaData.noAccess === true) {
|
||||
ev.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
//on tree select we need to remove the current node -
|
||||
// whoever handles this will need to make sure the correct node is selected
|
||||
//reset current node selection
|
||||
|
||||
@@ -41,7 +41,7 @@ angular.module("umbraco.directives")
|
||||
//'<ins ng-if="tree.enablelistviewsearch && node.metaData.isContainer" class="umb-tree-node-search icon-search" ng-click="searchNode(node, $event)" alt="searchAltText"></ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded || node.metaData.isContainer, \'icon-navigation-down\': node.expanded && !node.metaData.isContainer}" ng-click="load(node)"> </ins>' +
|
||||
'<i class="icon umb-tree-icon sprTree" ng-click="select(node, $event)"></i>' +
|
||||
'<a href="#/{{node.routePath}}" ng-click="select(node, $event)"></a>' +
|
||||
'<a class="umb-tree-item__label" href="#/{{node.routePath}}" ng-click="select(node, $event)"></a>' +
|
||||
//NOTE: These are the 'option' elipses
|
||||
'<a class="umb-options" ng-click="options(node, $event)"><i></i><i></i><i></i></a>' +
|
||||
'<div ng-show="node.loading" class="l"><div></div></div>' +
|
||||
@@ -112,6 +112,10 @@ angular.module("umbraco.directives")
|
||||
if (!node) {
|
||||
return '';
|
||||
}
|
||||
|
||||
//TODO: This is called constantly because as a method in a template it's re-evaluated pretty much all the time
|
||||
// it would be better if we could cache the processing. The problem is that some of these things are dynamic.
|
||||
|
||||
var css = [];
|
||||
if (node.cssClasses) {
|
||||
_.each(node.cssClasses, function(c) {
|
||||
@@ -121,6 +125,7 @@ angular.module("umbraco.directives")
|
||||
if (node.selected) {
|
||||
css.push("umb-tree-node-checked");
|
||||
}
|
||||
|
||||
return css.join(" ");
|
||||
};
|
||||
|
||||
@@ -158,6 +163,11 @@ angular.module("umbraco.directives")
|
||||
return;
|
||||
}
|
||||
|
||||
if (n.metaData && n.metaData.noAccess === true) {
|
||||
ev.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
emitEvent("treeNodeSelect", { element: element, tree: scope.tree, node: n, event: ev });
|
||||
ev.preventDefault();
|
||||
};
|
||||
@@ -229,6 +239,12 @@ angular.module("umbraco.directives")
|
||||
|
||||
setupNodeDom(scope.node, scope.tree);
|
||||
|
||||
// load the children if the current user don't have access to the node
|
||||
// it is used to auto expand the tree to the start nodes the user has access to
|
||||
if(scope.node.hasChildren && scope.node.metaData.noAccess) {
|
||||
scope.loadChildren(scope.node);
|
||||
}
|
||||
|
||||
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" enablelistviewexpand="{{enablelistviewexpand}}" eventhandler="eventhandler" tree="tree" current-node="currentNode" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
|
||||
var newElement = angular.element(template);
|
||||
$compile(newElement)(scope);
|
||||
|
||||
@@ -44,7 +44,7 @@ angular.module('umbraco.services')
|
||||
|
||||
return entityResource.search(args.term, "Member", args.searchFrom).then(function (data) {
|
||||
_.each(data, function (item) {
|
||||
configureMemberResult(item);
|
||||
searchResultFormatter.configureMemberResult(item);
|
||||
});
|
||||
return data;
|
||||
});
|
||||
@@ -69,7 +69,7 @@ angular.module('umbraco.services')
|
||||
|
||||
return entityResource.search(args.term, "Document", args.searchFrom, args.canceler).then(function (data) {
|
||||
_.each(data, function (item) {
|
||||
configureContentResult(item);
|
||||
searchResultFormatter.configureContentResult(item);
|
||||
});
|
||||
return data;
|
||||
});
|
||||
@@ -94,7 +94,7 @@ angular.module('umbraco.services')
|
||||
|
||||
return entityResource.search(args.term, "Media", args.searchFrom).then(function (data) {
|
||||
_.each(data, function (item) {
|
||||
configureMediaResult(item);
|
||||
searchResultFormatter.configureMediaResult(item);
|
||||
});
|
||||
return data;
|
||||
});
|
||||
|
||||
@@ -44,52 +44,69 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
|
||||
if (!parentNode.section) {
|
||||
parentNode.section = section;
|
||||
}
|
||||
|
||||
if (parentNode.metaData && parentNode.metaData.noAccess === true) {
|
||||
if (!parentNode.cssClasses) {
|
||||
parentNode.cssClasses = [];
|
||||
}
|
||||
parentNode.cssClasses.push("no-access");
|
||||
}
|
||||
|
||||
//create a method outside of the loop to return the parent - otherwise jshint blows up
|
||||
var funcParent = function() {
|
||||
return parentNode;
|
||||
};
|
||||
for (var i = 0; i < treeNodes.length; i++) {
|
||||
|
||||
treeNodes[i].level = childLevel;
|
||||
var treeNode = treeNodes[i];
|
||||
|
||||
treeNode.level = childLevel;
|
||||
|
||||
//create a function to get the parent node, we could assign the parent node but
|
||||
// then we cannot serialize this entity because we have a cyclical reference.
|
||||
// Instead we just make a function to return the parentNode.
|
||||
treeNodes[i].parent = funcParent;
|
||||
treeNode.parent = funcParent;
|
||||
|
||||
//set the section for each tree node - this allows us to reference this easily when accessing tree nodes
|
||||
treeNodes[i].section = section;
|
||||
treeNode.section = section;
|
||||
|
||||
//if there is not route path specified, then set it automatically,
|
||||
//if this is a tree root node then we want to route to the section's dashboard
|
||||
if (!treeNodes[i].routePath) {
|
||||
if (!treeNode.routePath) {
|
||||
|
||||
if (treeNodes[i].metaData && treeNodes[i].metaData["treeAlias"]) {
|
||||
if (treeNode.metaData && treeNode.metaData["treeAlias"]) {
|
||||
//this is a root node
|
||||
treeNodes[i].routePath = section;
|
||||
treeNode.routePath = section;
|
||||
}
|
||||
else {
|
||||
var treeAlias = this.getTreeAlias(treeNodes[i]);
|
||||
treeNodes[i].routePath = section + "/" + treeAlias + "/edit/" + treeNodes[i].id;
|
||||
var treeAlias = this.getTreeAlias(treeNode);
|
||||
treeNode.routePath = section + "/" + treeAlias + "/edit/" + treeNode.id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//now, format the icon data
|
||||
if (treeNodes[i].iconIsClass === undefined || treeNodes[i].iconIsClass) {
|
||||
var converted = iconHelper.convertFromLegacyTreeNodeIcon(treeNodes[i]);
|
||||
treeNodes[i].cssClass = standardCssClass + " " + converted;
|
||||
if (treeNode.iconIsClass === undefined || treeNode.iconIsClass) {
|
||||
var converted = iconHelper.convertFromLegacyTreeNodeIcon(treeNode);
|
||||
treeNode.cssClass = standardCssClass + " " + converted;
|
||||
if (converted.startsWith('.')) {
|
||||
//its legacy so add some width/height
|
||||
treeNodes[i].style = "height:16px;width:16px;";
|
||||
treeNode.style = "height:16px;width:16px;";
|
||||
}
|
||||
else {
|
||||
treeNodes[i].style = "";
|
||||
treeNode.style = "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
treeNodes[i].style = "background-image: url('" + treeNodes[i].iconFilePath + "');";
|
||||
treeNode.style = "background-image: url('" + treeNode.iconFilePath + "');";
|
||||
//we need an 'icon-' class in there for certain styles to work so if it is image based we'll add this
|
||||
treeNodes[i].cssClass = standardCssClass + " legacy-custom-file";
|
||||
treeNode.cssClass = standardCssClass + " legacy-custom-file";
|
||||
}
|
||||
|
||||
if (treeNode.metaData && treeNode.metaData.noAccess === true) {
|
||||
if (!treeNode.cssClasses) {
|
||||
treeNode.cssClasses = [];
|
||||
}
|
||||
treeNode.cssClasses.push("no-access");
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -375,9 +392,10 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
|
||||
}
|
||||
|
||||
for (var i = 0; i < treeNode.children.length; i++) {
|
||||
if (treeNode.children[i].children && angular.isArray(treeNode.children[i].children) && treeNode.children[i].children.length > 0) {
|
||||
var child = treeNode.children[i];
|
||||
if (child.children && angular.isArray(child.children) && child.children.length > 0) {
|
||||
//recurse
|
||||
found = this.getDescendantNode(treeNode.children[i], id);
|
||||
found = this.getDescendantNode(child, id);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -377,6 +377,13 @@ div.locked:before{
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.umb-tree li div.no-access .umb-tree-icon,
|
||||
.umb-tree li div.no-access .root-link,
|
||||
.umb-tree li div.no-access .umb-tree-item__label {
|
||||
color: @gray-7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
// Tree context menu
|
||||
// -------------------------
|
||||
.umb-actions {
|
||||
|
||||
@@ -169,10 +169,10 @@ angular.module("umbraco")
|
||||
$scope.showPasswordFields = !$scope.showPasswordFields;
|
||||
}
|
||||
|
||||
function clearPasswordFields() {
|
||||
function clearPasswordFields() {
|
||||
$scope.changePasswordModel.value.oldPassword = "";
|
||||
$scope.changePasswordModel.value.newPassword = "";
|
||||
$scope.changePasswordModel.value.confirm = "";
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
|
||||
function ($scope, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
|
||||
function ($scope, userService, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
|
||||
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
var searchText = "Search...";
|
||||
@@ -18,6 +18,12 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
}
|
||||
$scope.treeModel = {
|
||||
hideHeader: false
|
||||
}
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
|
||||
});
|
||||
|
||||
var node = dialogOptions.currentNode;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
|
||||
function ($scope, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
|
||||
function ($scope, userService, eventsService, contentResource, navigationService, appState, treeService, localizationService, notificationsService) {
|
||||
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
var searchText = "Search...";
|
||||
@@ -15,7 +15,13 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
}
|
||||
}
|
||||
$scope.treeModel = {
|
||||
hideHeader: false
|
||||
}
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
|
||||
});
|
||||
|
||||
var node = dialogOptions.currentNode;
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<div ng-hide="searchInfo.showSearch">
|
||||
<umb-tree
|
||||
section="content"
|
||||
hideheader="false"
|
||||
hideheader="{{treeModel.hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
|
||||
@@ -47,9 +47,9 @@
|
||||
</umb-tree-search-results>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch">
|
||||
<umb-tree
|
||||
<umb-tree
|
||||
section="content"
|
||||
hideheader="false"
|
||||
hideheader="{{treeModel.hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
|
||||
function ($scope, eventsService, mediaResource, appState, treeService, navigationService) {
|
||||
function ($scope, userService, eventsService, mediaResource, appState, treeService, navigationService) {
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
var node = dialogOptions.currentNode;
|
||||
|
||||
$scope.treeModel = {
|
||||
hideHeader: false
|
||||
}
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.treeModel.hideHeader = userData.startMediaIds.length > 0 && userData.startMediaIds.indexOf(-1) == -1;
|
||||
});
|
||||
|
||||
function nodeSelectHandler(ev, args) {
|
||||
|
||||
if(args && args.event) {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<div ng-hide="miniListView">
|
||||
<umb-tree
|
||||
section="media"
|
||||
hideheader="false"
|
||||
hideheader="{{treeModel.hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
|
||||
Reference in New Issue
Block a user