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:
Mads Rasmussen
2017-09-10 18:04:59 +02:00
committed by GitHub
27 changed files with 569 additions and 617 deletions

View File

@@ -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

View File

@@ -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)">&nbsp;</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);

View File

@@ -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;
});

View File

@@ -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;
}

View File

@@ -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 {

View File

@@ -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 = "";
}
});

View File

@@ -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;

View File

@@ -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;

View File

@@ -48,7 +48,7 @@
<div ng-hide="searchInfo.showSearch">
<umb-tree
section="content"
hideheader="false"
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"

View File

@@ -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"

View File

@@ -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) {

View File

@@ -27,7 +27,7 @@
<div ng-hide="miniListView">
<umb-tree
section="media"
hideheader="false"
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"