* Add visuallyHiddenTexts area and keys to swedish Translations contributed by @plannero * Add missing localizations. * Revert prettier formatting * Format in visual studio * Change default UpgradeUnattended value to true (#13281) * add labels to default en.xml + small glitch fix
This commit is contained in:
@@ -2520,6 +2520,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
|
||||
<key alias="addImageCaption">Add image caption</key>
|
||||
<key alias="searchContentTree">Search content tree</key>
|
||||
<key alias="maxAmount">Maximum amount</key>
|
||||
<key alias="expandChildItems">Expand child items for</key>
|
||||
<key alias="openContextNode">Open context node for</key>
|
||||
</area>
|
||||
<area alias="references">
|
||||
<key alias="tabName">References</key>
|
||||
|
||||
@@ -2624,6 +2624,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
|
||||
<key alias="addImageCaption">Add image caption</key>
|
||||
<key alias="searchContentTree">Search content tree</key>
|
||||
<key alias="maxAmount">Maximum amount</key>
|
||||
<key alias="expandChildItems">Expand child items for</key>
|
||||
<key alias="openContextNode">Open context node for</key>
|
||||
</area>
|
||||
<area alias="references">
|
||||
<key alias="tabName">References</key>
|
||||
|
||||
@@ -240,6 +240,60 @@
|
||||
<key alias="memberIntro">Komma igång</key>
|
||||
<key alias="formsInstall">Installera Umbraco Forms</key>
|
||||
</area>
|
||||
<area alias="visuallyHiddenTexts">
|
||||
<key alias="goBack">Backa</key>
|
||||
<key alias="activeListLayout">Aktiv layout:</key>
|
||||
<key alias="jumpTo">Hoppa till</key>
|
||||
<key alias="group">grupp</key>
|
||||
<key alias="passed">godkänd</key>
|
||||
<key alias="warning">varning</key>
|
||||
<key alias="failed">underkänd</key>
|
||||
<key alias="suggestion">förslag</key>
|
||||
<key alias="checkPassed">Godkänd</key>
|
||||
<key alias="checkFailed">Underkänd</key>
|
||||
<key alias="openBackofficeSearch">Öppna sökfunktion (backoffice)</key>
|
||||
<key alias="openCloseBackofficeHelp">Öppna/stäng hjälpfunktion</key>
|
||||
<key alias="openCloseBackofficeProfileOptions">Öppna/stäng personliga inställningar</key>
|
||||
<key alias="assignDomainDescription">Redigera språk och värdnamn för %0%</key>
|
||||
<key alias="createDescription">Skapa en ny nod under %0%</key>
|
||||
<key alias="protectDescription">Ändra behörigheter för %0%</key>
|
||||
<key alias="rightsDescription">Redigera behörigheter för %0%</key>
|
||||
<key alias="sortDescription">Ändra sortering av %0%</key>
|
||||
<key alias="createblueprintDescription">Skapa innehållsmall baserad på %0%</key>
|
||||
<key alias="openContextMenu">Öppna kontextmeny för </key>
|
||||
<key alias="currentLanguage">Aktuellt språk</key>
|
||||
<key alias="switchLanguage">Byt språk till</key>
|
||||
<key alias="createNewFolder">Skapa ny mapp</key>
|
||||
<key alias="newPartialView">Del av vy</key>
|
||||
<key alias="newPartialViewMacro">Del av vy (makro)</key>
|
||||
<key alias="newMember">Medlem</key>
|
||||
<key alias="newDataType">Datatyp</key>
|
||||
<key alias="redirectDashboardSearchLabel">Sök bland omdirigeringar</key>
|
||||
<key alias="userGroupSearchLabel">Sök bland användargrupper</key>
|
||||
<key alias="userSearchLabel">Sök bland användare</key>
|
||||
<key alias="createItem">Skapa post</key>
|
||||
<key alias="create">Skapa</key>
|
||||
<key alias="edit">Redigera</key>
|
||||
<key alias="name">Namn</key>
|
||||
<key alias="addNewRow">Lägg till ny rad</key>
|
||||
<key alias="tabExpand">Visa fler alternativ</key>
|
||||
<key alias="searchOverlayTitle">Sök i Umbraco backoffice</key>
|
||||
<key alias="searchOverlayDescription">Sök efter innehåll, media etc i hela Umbraco.</key>
|
||||
<key alias="searchInputDescription">När det finns automatförslag, använd pil upp eller ner, eller använd tabbtangenten. Använd enter för att välja.
|
||||
</key>
|
||||
<key alias="path">Sökväg:</key>
|
||||
<key alias="foundIn">Hittad i</key>
|
||||
<key alias="hasTranslation">Har översättning</key>
|
||||
<key alias="noTranslation">Saknar översättning</key>
|
||||
<key alias="dictionaryListCaption">Post i ordlista</key>
|
||||
<key alias="contextMenuDescription">Välj ett av alternativen för att redigera noden.</key>
|
||||
<key alias="contextDialogDescription">Utför %0% på noden %1%</key>
|
||||
<key alias="addImageCaption">Lägg till bildtext</key>
|
||||
<key alias="searchContentTree">Sök i innehållsträdet</key>
|
||||
<key alias="maxAmount">Maximalt värde</key>
|
||||
<key alias="expandChildItems">Visa underliggande noder för</key>
|
||||
<key alias="openContextNode">Öppna kontext för</key>
|
||||
</area>
|
||||
<area alias="prompt">
|
||||
<key alias="stay">Stanna</key>
|
||||
<key alias="discardChanges">Ignorera ändringar</key>
|
||||
|
||||
@@ -3,406 +3,415 @@
|
||||
* @name umbraco.directives.directive:umbTree
|
||||
* @restrict E
|
||||
**/
|
||||
function umbTreeDirective($q, treeService, notificationsService) {
|
||||
function umbTreeDirective($q, treeService, notificationsService, localizationService) {
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
terminal: false,
|
||||
templateUrl: 'views/components/tree/umb-tree.html',
|
||||
scope: {
|
||||
section: '@',
|
||||
treealias: '@',
|
||||
hideoptions: '@',
|
||||
hideheader: '@',
|
||||
cachekey: '@',
|
||||
isdialog: '@',
|
||||
onlyInitialized: '@',
|
||||
//Custom query string arguments to pass in to the tree as a string, example: "startnodeid=123&something=value"
|
||||
customtreeparams: '@',
|
||||
enablecheckboxes: '@',
|
||||
enablelistviewsearch: '@',
|
||||
enablelistviewexpand: '@',
|
||||
api: '=?',
|
||||
onInit: '&?'
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
terminal: false,
|
||||
templateUrl: 'views/components/tree/umb-tree.html',
|
||||
scope: {
|
||||
section: '@',
|
||||
treealias: '@',
|
||||
hideoptions: '@',
|
||||
hideheader: '@',
|
||||
cachekey: '@',
|
||||
isdialog: '@',
|
||||
onlyInitialized: '@',
|
||||
//Custom query string arguments to pass in to the tree as a string, example: "startnodeid=123&something=value"
|
||||
customtreeparams: '@',
|
||||
enablecheckboxes: '@',
|
||||
enablelistviewsearch: '@',
|
||||
enablelistviewexpand: '@',
|
||||
api: '=?',
|
||||
onInit: '&?'
|
||||
},
|
||||
controller: function ($scope, $element) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
var registeredCallbacks = {
|
||||
treeNodeExpanded: [],
|
||||
treeNodeSelect: [],
|
||||
treeLoaded: [],
|
||||
treeSynced: [],
|
||||
treeOptionsClick: [],
|
||||
treeNodeAltSelect: []
|
||||
};
|
||||
|
||||
//this is the API exposed by this directive, for either hosting controllers or for other directives
|
||||
vm.callbacks = {
|
||||
treeNodeExpanded: function (f) {
|
||||
registeredCallbacks.treeNodeExpanded.push(f);
|
||||
},
|
||||
controller: function ($scope, $element) {
|
||||
treeNodeSelect: function (f) {
|
||||
registeredCallbacks.treeNodeSelect.push(f);
|
||||
},
|
||||
treeLoaded: function (f) {
|
||||
registeredCallbacks.treeLoaded.push(f);
|
||||
},
|
||||
treeSynced: function (f) {
|
||||
registeredCallbacks.treeSynced.push(f);
|
||||
},
|
||||
treeOptionsClick: function (f) {
|
||||
registeredCallbacks.treeOptionsClick.push(f);
|
||||
},
|
||||
treeNodeAltSelect: function (f) {
|
||||
registeredCallbacks.treeNodeAltSelect.push(f);
|
||||
}
|
||||
};
|
||||
vm.emitEvent = emitEvent;
|
||||
vm.load = load;
|
||||
vm.reloadNode = reloadNode;
|
||||
vm.syncTree = syncTree;
|
||||
vm.loadChildren = loadChildren;
|
||||
vm.hasTree = hasTree;
|
||||
|
||||
var vm = this;
|
||||
$scope.labels = {
|
||||
openContextNode: "Open context node for"
|
||||
};
|
||||
|
||||
var registeredCallbacks = {
|
||||
treeNodeExpanded: [],
|
||||
treeNodeSelect: [],
|
||||
treeLoaded: [],
|
||||
treeSynced: [],
|
||||
treeOptionsClick: [],
|
||||
treeNodeAltSelect: []
|
||||
};
|
||||
//wire up the exposed api object for hosting controllers
|
||||
if ($scope.api) {
|
||||
$scope.api.callbacks = vm.callbacks;
|
||||
$scope.api.load = vm.load;
|
||||
$scope.api.reloadNode = vm.reloadNode;
|
||||
$scope.api.syncTree = vm.syncTree;
|
||||
$scope.api.hasTree = vm.hasTree;
|
||||
}
|
||||
|
||||
//this is the API exposed by this directive, for either hosting controllers or for other directives
|
||||
vm.callbacks = {
|
||||
treeNodeExpanded: function (f) {
|
||||
registeredCallbacks.treeNodeExpanded.push(f);
|
||||
},
|
||||
treeNodeSelect: function (f) {
|
||||
registeredCallbacks.treeNodeSelect.push(f);
|
||||
},
|
||||
treeLoaded: function (f) {
|
||||
registeredCallbacks.treeLoaded.push(f);
|
||||
},
|
||||
treeSynced: function (f) {
|
||||
registeredCallbacks.treeSynced.push(f);
|
||||
},
|
||||
treeOptionsClick: function (f) {
|
||||
registeredCallbacks.treeOptionsClick.push(f);
|
||||
},
|
||||
treeNodeAltSelect: function (f) {
|
||||
registeredCallbacks.treeNodeAltSelect.push(f);
|
||||
}
|
||||
};
|
||||
vm.emitEvent = emitEvent;
|
||||
vm.load = load;
|
||||
vm.reloadNode = reloadNode;
|
||||
vm.syncTree = syncTree;
|
||||
vm.loadChildren = loadChildren;
|
||||
vm.hasTree = hasTree;
|
||||
//flag to track the last loaded section when the tree 'un-loads'. We use this to determine if we should
|
||||
// re-load the tree again. For example, if we hover over 'content' the content tree is shown. Then we hover
|
||||
// outside of the tree and the tree 'un-loads'. When we re-hover over 'content', we don't want to re-load the
|
||||
// entire tree again since we already still have it in memory. Of course if the section is different we will
|
||||
// reload it. This saves a lot on processing if someone is navigating in and out of the same section many times
|
||||
// since it saves on data retreival and DOM processing.
|
||||
// TODO: This isn't used!?
|
||||
var lastSection = "";
|
||||
|
||||
//wire up the exposed api object for hosting controllers
|
||||
if ($scope.api) {
|
||||
$scope.api.callbacks = vm.callbacks;
|
||||
$scope.api.load = vm.load;
|
||||
$scope.api.reloadNode = vm.reloadNode;
|
||||
$scope.api.syncTree = vm.syncTree;
|
||||
$scope.api.hasTree = vm.hasTree;
|
||||
}
|
||||
|
||||
//flag to track the last loaded section when the tree 'un-loads'. We use this to determine if we should
|
||||
// re-load the tree again. For example, if we hover over 'content' the content tree is shown. Then we hover
|
||||
// outside of the tree and the tree 'un-loads'. When we re-hover over 'content', we don't want to re-load the
|
||||
// entire tree again since we already still have it in memory. Of course if the section is different we will
|
||||
// reload it. This saves a lot on processing if someone is navigating in and out of the same section many times
|
||||
// since it saves on data retreival and DOM processing.
|
||||
// TODO: This isn't used!?
|
||||
var lastSection = "";
|
||||
|
||||
/** Helper function to emit tree events */
|
||||
function emitEvent(eventName, args) {
|
||||
if (registeredCallbacks[eventName] && Utilities.isArray(registeredCallbacks[eventName])) {
|
||||
// call it
|
||||
registeredCallbacks[eventName].forEach(c => c(args));
|
||||
}
|
||||
}
|
||||
/** Helper function to emit tree events */
|
||||
function emitEvent(eventName, args) {
|
||||
if (registeredCallbacks[eventName] && Utilities.isArray(registeredCallbacks[eventName])) {
|
||||
// call it
|
||||
registeredCallbacks[eventName].forEach(c => c(args));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Re-loads the tree with the updated parameters
|
||||
* @param {any} args either a string representing the 'section' or an object containing: 'section', 'treeAlias', 'customTreeParams', 'cacheKey'
|
||||
*/
|
||||
function load(args) {
|
||||
if (Utilities.isString(args)) {
|
||||
$scope.section = args;
|
||||
}
|
||||
else if (args) {
|
||||
if (args.section) {
|
||||
$scope.section = args.section;
|
||||
}
|
||||
if (args.customTreeParams) {
|
||||
$scope.customtreeparams = args.customTreeParams;
|
||||
}
|
||||
if (args.treeAlias) {
|
||||
$scope.treealias = args.treeAlias;
|
||||
}
|
||||
if (args.cacheKey) {
|
||||
$scope.cachekey = args.cacheKey;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Re-loads the tree with the updated parameters
|
||||
* @param {any} args either a string representing the 'section' or an object containing: 'section', 'treeAlias', 'customTreeParams', 'cacheKey'
|
||||
*/
|
||||
function load(args) {
|
||||
if (Utilities.isString(args)) {
|
||||
$scope.section = args;
|
||||
}
|
||||
else if (args) {
|
||||
if (args.section) {
|
||||
$scope.section = args.section;
|
||||
}
|
||||
if (args.customTreeParams) {
|
||||
$scope.customtreeparams = args.customTreeParams;
|
||||
}
|
||||
if (args.treeAlias) {
|
||||
$scope.treealias = args.treeAlias;
|
||||
}
|
||||
if (args.cacheKey) {
|
||||
$scope.cachekey = args.cacheKey;
|
||||
}
|
||||
}
|
||||
|
||||
return loadTree();
|
||||
}
|
||||
return loadTree();
|
||||
}
|
||||
|
||||
function reloadNode(node) {
|
||||
function reloadNode(node) {
|
||||
|
||||
if (!node) {
|
||||
node = $scope.currentNode;
|
||||
}
|
||||
if (!node) {
|
||||
node = $scope.currentNode;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
return $scope.loadChildren(node, true);
|
||||
}
|
||||
if (node) {
|
||||
return $scope.loadChildren(node, true);
|
||||
}
|
||||
|
||||
return $q.reject();
|
||||
}
|
||||
return $q.reject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to do the tree syncing
|
||||
* @param {any} args
|
||||
* @returns a promise with an object containing 'node' and 'activate'
|
||||
*/
|
||||
function syncTree(args) {
|
||||
if (!args) {
|
||||
throw "args cannot be null";
|
||||
}
|
||||
if (!args.path) {
|
||||
throw "args.path cannot be null";
|
||||
}
|
||||
/**
|
||||
* Used to do the tree syncing
|
||||
* @param {any} args
|
||||
* @returns a promise with an object containing 'node' and 'activate'
|
||||
*/
|
||||
function syncTree(args) {
|
||||
if (!args) {
|
||||
throw "args cannot be null";
|
||||
}
|
||||
if (!args.path) {
|
||||
throw "args.path cannot be null";
|
||||
}
|
||||
|
||||
if (Utilities.isString(args.path)) {
|
||||
args.path = args.path.replace('"', '').split(',');
|
||||
}
|
||||
if (Utilities.isString(args.path)) {
|
||||
args.path = args.path.replace('"', '').split(',');
|
||||
}
|
||||
|
||||
//Filter the path for root node ids (we don't want to pass in -1 or 'init')
|
||||
//Filter the path for root node ids (we don't want to pass in -1 or 'init')
|
||||
|
||||
args.path = _.filter(args.path, function (item) { return (item !== "init" && item !== "-1"); });
|
||||
args.path = _.filter(args.path, function (item) { return (item !== "init" && item !== "-1"); });
|
||||
|
||||
var treeNode = loadActiveTree(args.tree);
|
||||
var treeNode = loadActiveTree(args.tree);
|
||||
|
||||
return treeService.syncTree({
|
||||
node: treeNode,
|
||||
path: args.path,
|
||||
forceReload: args.forceReload
|
||||
}).then(function (data) {
|
||||
return treeService.syncTree({
|
||||
node: treeNode,
|
||||
path: args.path,
|
||||
forceReload: args.forceReload
|
||||
}).then(function (data) {
|
||||
|
||||
if (args.activate === undefined || args.activate === true) {
|
||||
$scope.currentNode = data;
|
||||
}
|
||||
if (args.activate === undefined || args.activate === true) {
|
||||
$scope.currentNode = data;
|
||||
}
|
||||
|
||||
emitEvent("treeSynced", { node: data, activate: args.activate });
|
||||
emitEvent("treeSynced", { node: data, activate: args.activate });
|
||||
|
||||
return $q.when({ node: data, activate: args.activate });
|
||||
}, function (data) {
|
||||
return $q.reject(data);
|
||||
}, function (data) {
|
||||
//on notification
|
||||
if (data.type === "treeNodeExpanded") {
|
||||
//raise the event
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: data.node, children: data.children });
|
||||
}
|
||||
});
|
||||
return $q.when({ node: data, activate: args.activate });
|
||||
}, function (data) {
|
||||
return $q.reject(data);
|
||||
}, function (data) {
|
||||
//on notification
|
||||
if (data.type === "treeNodeExpanded") {
|
||||
//raise the event
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: data.node, children: data.children });
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** This will check the section tree loaded and return all actual root nodes based on a tree type (non group nodes, non section groups) */
|
||||
function getTreeRootNodes() {
|
||||
var roots;
|
||||
if ($scope.tree.root.containsGroups) {
|
||||
//all children in this case are group nodes, so we want the children of these children
|
||||
roots = _.reduce(
|
||||
//get the array of array of children
|
||||
_.map($scope.tree.root.children, function (n) {
|
||||
return n.children
|
||||
}), function (m, p) {
|
||||
//combine the arrays to one array
|
||||
return m.concat(p)
|
||||
});
|
||||
}
|
||||
else {
|
||||
roots = [$scope.tree.root].concat($scope.tree.root.children);
|
||||
}
|
||||
|
||||
return _.filter(roots, function (node) {
|
||||
return node && node.metaData && node.metaData.treeAlias;
|
||||
});
|
||||
}
|
||||
|
||||
//given a tree alias, this will search the current section tree for the specified tree alias and set the current active tree to it's root node
|
||||
function hasTree(treeAlias) {
|
||||
|
||||
if (!$scope.tree) {
|
||||
throw "Err in umbtree.directive.loadActiveTree, $scope.tree is null";
|
||||
}
|
||||
|
||||
if (!treeAlias) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var treeRoots = getTreeRootNodes();
|
||||
var foundTree = _.find(treeRoots, function (node) {
|
||||
return node.metaData.treeAlias.toUpperCase() === treeAlias.toUpperCase();
|
||||
});
|
||||
|
||||
return foundTree !== undefined;
|
||||
}
|
||||
|
||||
//given a tree alias, this will search the current section tree for the specified tree alias and set the current active tree to it's root node
|
||||
function loadActiveTree(treeAlias) {
|
||||
|
||||
if (!$scope.tree) {
|
||||
throw "Err in umbtree.directive.loadActiveTree, $scope.tree is null";
|
||||
}
|
||||
|
||||
//if its not specified, it should have been specified before
|
||||
if (!treeAlias) {
|
||||
if (!$scope.activeTree) {
|
||||
throw "Err in umbtree.directive.loadActiveTree, $scope.activeTree is null";
|
||||
}
|
||||
return $scope.activeTree;
|
||||
}
|
||||
|
||||
var treeRoots = getTreeRootNodes();
|
||||
$scope.activeTree = _.find(treeRoots, function (node) {
|
||||
return node.metaData.treeAlias.toUpperCase() === treeAlias.toUpperCase();
|
||||
});
|
||||
|
||||
if (!$scope.activeTree) {
|
||||
throw "Could not find the tree " + treeAlias;
|
||||
}
|
||||
|
||||
emitEvent("activeTreeLoaded", { tree: $scope.activeTree });
|
||||
|
||||
return $scope.activeTree;
|
||||
}
|
||||
|
||||
/** Method to load in the tree data */
|
||||
function loadTree() {
|
||||
if ($scope.section) {
|
||||
|
||||
//default args
|
||||
var args = { section: $scope.section, tree: $scope.treealias, cacheKey: $scope.cachekey, isDialog: $scope.isdialog ? $scope.isdialog : false };
|
||||
|
||||
//add the extra query string params if specified
|
||||
if ($scope.customtreeparams) {
|
||||
args["queryString"] = $scope.customtreeparams;
|
||||
}
|
||||
|
||||
return treeService.getTree(args)
|
||||
.then(function (data) {
|
||||
//Only use the tree data, if we are still on the correct section
|
||||
if(data.alias !== $scope.section){
|
||||
return $q.reject();
|
||||
}
|
||||
|
||||
//set the data once we have it
|
||||
$scope.tree = data;
|
||||
|
||||
//set the root as the current active tree
|
||||
$scope.activeTree = $scope.tree.root;
|
||||
|
||||
emitEvent("treeLoaded", { tree: $scope.tree });
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: $scope.tree.root, children: $scope.tree.root.children });
|
||||
|
||||
return $q.when(data);
|
||||
}, function (reason) {
|
||||
notificationsService.error("Tree Error", reason);
|
||||
return $q.reject(reason);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return $q.reject();
|
||||
}
|
||||
}
|
||||
|
||||
function loadChildren(node, forceReload) {
|
||||
//emit treeNodeExpanding event, if a callback object is set on the tree
|
||||
emitEvent("treeNodeExpanding", { tree: $scope.tree, node: node });
|
||||
|
||||
//standardising
|
||||
if (!node.children) {
|
||||
node.children = [];
|
||||
}
|
||||
|
||||
if (forceReload || (node.hasChildren && node.children.length === 0)) {
|
||||
//get the children from the tree service
|
||||
return treeService.loadNodeChildren({ node: node, section: $scope.section, isDialog: $scope.isdialog })
|
||||
.then(function (data) {
|
||||
//emit expanded event
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: data });
|
||||
|
||||
return $q.when(data);
|
||||
});
|
||||
}
|
||||
else {
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: node.children });
|
||||
node.expanded = true;
|
||||
|
||||
return $q.when(node.children);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
node.cssClasses.forEach(c => css.push(c));
|
||||
}
|
||||
|
||||
return css.join(" ");
|
||||
};
|
||||
|
||||
$scope.selectEnabledNodeClass = node =>
|
||||
node && node.selected ? 'icon sprTree icon-check green temporary' : '-hidden';
|
||||
|
||||
/* helper to force reloading children of a tree node */
|
||||
$scope.loadChildren = (node, forceReload) => loadChildren(node, forceReload);
|
||||
|
||||
/**
|
||||
Method called when the options button next to the root node is called.
|
||||
The tree doesnt know about this, so it raises an event to tell the parent controller
|
||||
about it.
|
||||
*/
|
||||
$scope.options = function (n, ev) {
|
||||
emitEvent("treeOptionsClick", { element: $element, node: n, event: ev });
|
||||
};
|
||||
|
||||
/**
|
||||
Method called when an item is clicked in the tree, this passes the
|
||||
DOM element, the tree node object and the original click
|
||||
and emits it as a treeNodeSelect element if there is a callback object
|
||||
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
|
||||
$scope.currentNode = null;
|
||||
|
||||
emitEvent("treeNodeSelect", { element: $element, node: n, event: ev });
|
||||
};
|
||||
|
||||
$scope.altSelect = function (n, ev) {
|
||||
emitEvent("treeNodeAltSelect", { element: $element, tree: $scope.tree, node: n, event: ev });
|
||||
};
|
||||
|
||||
//call the onInit method, if the result is a promise then load the tree after that resolves (if it's not a promise this will just resolve automatically).
|
||||
//NOTE: The promise cannot be rejected, else the tree won't be loaded and we'll get exceptions if some API calls syncTree or similar.
|
||||
$q.when($scope.onInit(), function (args) {
|
||||
|
||||
//the promise resolution can pass in parameters
|
||||
if (args) {
|
||||
if (args.section) {
|
||||
$scope.section = args.section;
|
||||
}
|
||||
if (args.cacheKey) {
|
||||
$scope.cachekey = args.cacheKey;
|
||||
}
|
||||
if (args.customTreeParams) {
|
||||
$scope.customtreeparams = args.customTreeParams;
|
||||
}
|
||||
}
|
||||
|
||||
//load the tree
|
||||
loadTree().then(function () {
|
||||
//because angular doesn't return a promise for the resolve method, we need to resort to some hackery, else
|
||||
//like normal JS promises we could do resolve(...).then()
|
||||
if (args && args.onLoaded && Utilities.isFunction(args.onLoaded)) {
|
||||
args.onLoaded();
|
||||
}
|
||||
});
|
||||
/** This will check the section tree loaded and return all actual root nodes based on a tree type (non group nodes, non section groups) */
|
||||
function getTreeRootNodes() {
|
||||
var roots;
|
||||
if ($scope.tree.root.containsGroups) {
|
||||
//all children in this case are group nodes, so we want the children of these children
|
||||
roots = _.reduce(
|
||||
//get the array of array of children
|
||||
_.map($scope.tree.root.children, function (n) {
|
||||
return n.children
|
||||
}), function (m, p) {
|
||||
//combine the arrays to one array
|
||||
return m.concat(p)
|
||||
});
|
||||
}
|
||||
};
|
||||
else {
|
||||
roots = [$scope.tree.root].concat($scope.tree.root.children);
|
||||
}
|
||||
|
||||
return _.filter(roots, function (node) {
|
||||
return node && node.metaData && node.metaData.treeAlias;
|
||||
});
|
||||
}
|
||||
|
||||
//given a tree alias, this will search the current section tree for the specified tree alias and set the current active tree to it's root node
|
||||
function hasTree(treeAlias) {
|
||||
|
||||
if (!$scope.tree) {
|
||||
throw "Err in umbtree.directive.loadActiveTree, $scope.tree is null";
|
||||
}
|
||||
|
||||
if (!treeAlias) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var treeRoots = getTreeRootNodes();
|
||||
var foundTree = _.find(treeRoots, function (node) {
|
||||
return node.metaData.treeAlias.toUpperCase() === treeAlias.toUpperCase();
|
||||
});
|
||||
|
||||
return foundTree !== undefined;
|
||||
}
|
||||
|
||||
//given a tree alias, this will search the current section tree for the specified tree alias and set the current active tree to it's root node
|
||||
function loadActiveTree(treeAlias) {
|
||||
|
||||
if (!$scope.tree) {
|
||||
throw "Err in umbtree.directive.loadActiveTree, $scope.tree is null";
|
||||
}
|
||||
|
||||
//if its not specified, it should have been specified before
|
||||
if (!treeAlias) {
|
||||
if (!$scope.activeTree) {
|
||||
throw "Err in umbtree.directive.loadActiveTree, $scope.activeTree is null";
|
||||
}
|
||||
return $scope.activeTree;
|
||||
}
|
||||
|
||||
var treeRoots = getTreeRootNodes();
|
||||
$scope.activeTree = _.find(treeRoots, function (node) {
|
||||
return node.metaData.treeAlias.toUpperCase() === treeAlias.toUpperCase();
|
||||
});
|
||||
|
||||
if (!$scope.activeTree) {
|
||||
throw "Could not find the tree " + treeAlias;
|
||||
}
|
||||
|
||||
emitEvent("activeTreeLoaded", { tree: $scope.activeTree });
|
||||
|
||||
return $scope.activeTree;
|
||||
}
|
||||
|
||||
/** Method to load in the tree data */
|
||||
function loadTree() {
|
||||
if ($scope.section) {
|
||||
|
||||
//default args
|
||||
var args = { section: $scope.section, tree: $scope.treealias, cacheKey: $scope.cachekey, isDialog: $scope.isdialog ? $scope.isdialog : false };
|
||||
|
||||
//add the extra query string params if specified
|
||||
if ($scope.customtreeparams) {
|
||||
args["queryString"] = $scope.customtreeparams;
|
||||
}
|
||||
|
||||
return treeService.getTree(args)
|
||||
.then(function (data) {
|
||||
//Only use the tree data, if we are still on the correct section
|
||||
if (data.alias !== $scope.section) {
|
||||
return $q.reject();
|
||||
}
|
||||
|
||||
//set the data once we have it
|
||||
$scope.tree = data;
|
||||
|
||||
//set the root as the current active tree
|
||||
$scope.activeTree = $scope.tree.root;
|
||||
|
||||
emitEvent("treeLoaded", { tree: $scope.tree });
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: $scope.tree.root, children: $scope.tree.root.children });
|
||||
|
||||
return $q.when(data);
|
||||
}, function (reason) {
|
||||
notificationsService.error("Tree Error", reason);
|
||||
return $q.reject(reason);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return $q.reject();
|
||||
}
|
||||
}
|
||||
|
||||
function loadChildren(node, forceReload) {
|
||||
//emit treeNodeExpanding event, if a callback object is set on the tree
|
||||
emitEvent("treeNodeExpanding", { tree: $scope.tree, node: node });
|
||||
|
||||
//standardising
|
||||
if (!node.children) {
|
||||
node.children = [];
|
||||
}
|
||||
|
||||
if (forceReload || (node.hasChildren && node.children.length === 0)) {
|
||||
//get the children from the tree service
|
||||
return treeService.loadNodeChildren({ node: node, section: $scope.section, isDialog: $scope.isdialog })
|
||||
.then(function (data) {
|
||||
//emit expanded event
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: data });
|
||||
|
||||
return $q.when(data);
|
||||
});
|
||||
}
|
||||
else {
|
||||
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: node.children });
|
||||
node.expanded = true;
|
||||
|
||||
return $q.when(node.children);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
node.cssClasses.forEach(c => css.push(c));
|
||||
}
|
||||
|
||||
return css.join(" ");
|
||||
};
|
||||
|
||||
$scope.selectEnabledNodeClass = node =>
|
||||
node && node.selected ? 'icon sprTree icon-check green temporary' : '-hidden';
|
||||
|
||||
/* helper to force reloading children of a tree node */
|
||||
$scope.loadChildren = (node, forceReload) => loadChildren(node, forceReload);
|
||||
|
||||
/**
|
||||
Method called when the options button next to the root node is called.
|
||||
The tree doesnt know about this, so it raises an event to tell the parent controller
|
||||
about it.
|
||||
*/
|
||||
$scope.options = function (n, ev) {
|
||||
emitEvent("treeOptionsClick", { element: $element, node: n, event: ev });
|
||||
};
|
||||
|
||||
/**
|
||||
Method called when an item is clicked in the tree, this passes the
|
||||
DOM element, the tree node object and the original click
|
||||
and emits it as a treeNodeSelect element if there is a callback object
|
||||
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
|
||||
$scope.currentNode = null;
|
||||
|
||||
emitEvent("treeNodeSelect", { element: $element, node: n, event: ev });
|
||||
};
|
||||
|
||||
$scope.altSelect = function (n, ev) {
|
||||
emitEvent("treeNodeAltSelect", { element: $element, tree: $scope.tree, node: n, event: ev });
|
||||
};
|
||||
|
||||
//call the onInit method, if the result is a promise then load the tree after that resolves (if it's not a promise this will just resolve automatically).
|
||||
//NOTE: The promise cannot be rejected, else the tree won't be loaded and we'll get exceptions if some API calls syncTree or similar.
|
||||
$q.when($scope.onInit(), function (args) {
|
||||
|
||||
//the promise resolution can pass in parameters
|
||||
if (args) {
|
||||
if (args.section) {
|
||||
$scope.section = args.section;
|
||||
}
|
||||
if (args.cacheKey) {
|
||||
$scope.cachekey = args.cacheKey;
|
||||
}
|
||||
if (args.customTreeParams) {
|
||||
$scope.customtreeparams = args.customTreeParams;
|
||||
}
|
||||
}
|
||||
|
||||
//load the tree
|
||||
loadTree().then(function () {
|
||||
//because angular doesn't return a promise for the resolve method, we need to resort to some hackery, else
|
||||
//like normal JS promises we could do resolve(...).then()
|
||||
if (args && args.onLoaded && Utilities.isFunction(args.onLoaded)) {
|
||||
args.onLoaded();
|
||||
}
|
||||
});
|
||||
|
||||
localizationService.localize("visuallyHiddenTexts_openContextNode").then((value) => {
|
||||
$scope.labels.openContextNode = value;
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module("umbraco.directives").directive('umbTree', umbTreeDirective);
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
<li class="umb-tree-item" data-element="tree-item-{{::node.dataElement}}" ng-class="getNodeCssClass(node)" on-right-click="altSelect(node, $event)">
|
||||
<div class="umb-tree-item__inner" ng-swipe-right="options(node, $event)" ng-dblclick="load(node, $event)" tabindex="-1">
|
||||
<button data-element="tree-item-expand"
|
||||
class="umb-tree-item__arrow umb-outline btn-reset"
|
||||
ng-style="{'visibility': (scope.enablelistviewexpand === 'true' || node.hasChildren && (!node.metaData.isContainer || isDialog)) ? 'visible' : 'hidden'}"
|
||||
ng-click="load(node, $event)">
|
||||
<umb-icon icon="{{(node.expanded && !node.metaData.isContainer) ? 'icon-navigation-down' : 'icon-navigation-right'}}"></umb-icon>
|
||||
<!-- TODO: Use localization for this text -->
|
||||
<span class="sr-only">Expand child items for {{node.name}}</span>
|
||||
</button>
|
||||
<li class="umb-tree-item" data-element="tree-item-{{::node.dataElement}}" ng-class="getNodeCssClass(node)"
|
||||
on-right-click="altSelect(node, $event)">
|
||||
<div class="umb-tree-item__inner" ng-swipe-right="options(node, $event)" ng-dblclick="load(node, $event)"
|
||||
tabindex="-1">
|
||||
<button data-element="tree-item-expand" class="umb-tree-item__arrow umb-outline btn-reset"
|
||||
ng-style="{'visibility': (scope.enablelistviewexpand === 'true' || node.hasChildren && (!node.metaData.isContainer || isDialog)) ? 'visible' : 'hidden'}"
|
||||
ng-click="load(node, $event)">
|
||||
<umb-icon icon="{{(node.expanded && !node.metaData.isContainer) ? 'icon-navigation-down' : 'icon-navigation-right'}}"></umb-icon>
|
||||
<!-- TODO: Use localization for this text -->
|
||||
<span class="sr-only">
|
||||
<localize key="visuallyHiddenTexts_expandChildItems">Expand child items for</localize>
|
||||
{{node.name}}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<umb-icon icon="{{node.selected ? 'icon-check' : node.icon}}" class="icon umb-tree-icon sprTree" ng-class="node.cssClass" title="{{::node.title}}" ng-click="select(node, $event)" ng-style="::node.style" tabindex="-1"></umb-icon>
|
||||
<span class="umb-tree-item__annotation"></span>
|
||||
<a class="umb-tree-item__label" ng-href="#/{{::node.routePath}}" ng-click="select(node, $event)" title="{{::node.title}}">{{node.name}}</a>
|
||||
<umb-icon icon="{{node.selected ? 'icon-check' : node.icon}}" class="icon umb-tree-icon sprTree"
|
||||
ng-class="node.cssClass" title="{{::node.title}}" ng-click="select(node, $event)" ng-style="::node.style"
|
||||
tabindex="-1"></umb-icon>
|
||||
<span class="umb-tree-item__annotation"></span>
|
||||
<a class="umb-tree-item__label" ng-href="#/{{::node.routePath}}" ng-click="select(node, $event)"
|
||||
title="{{::node.title}}">{{node.name}}</a>
|
||||
|
||||
<!-- NOTE: These are the 'option' ellipsis -->
|
||||
<umb-button-ellipsis
|
||||
ng-if="::node.menuUrl"
|
||||
element="tree-item-options"
|
||||
action="options(node, $event)"
|
||||
text="{{optionsText}} {{node.name}}"
|
||||
state="hidden"
|
||||
class="umb-options">
|
||||
</umb-button-ellipsis>
|
||||
<!-- NOTE: These are the 'option' ellipsis -->
|
||||
<umb-button-ellipsis ng-if="::node.menuUrl" element="tree-item-options" action="options(node, $event)"
|
||||
text="{{optionsText}} {{node.name}}" state="hidden" class="umb-options">
|
||||
</umb-button-ellipsis>
|
||||
|
||||
<umb-loader ng-show="node.loading" position="bottom" class="umb-tree-item__loader"></umb-loader>
|
||||
</div>
|
||||
<umb-loader ng-show="node.loading" position="bottom" class="umb-tree-item__loader"></umb-loader>
|
||||
</div>
|
||||
|
||||
<ul ng-class="{collapsed: !node.expanded}">
|
||||
<umb-tree-item class="umb-animated" ng-repeat="child in node.children track by child.id" enablelistviewexpand="{{enablelistviewexpand}}" tree="tree" current-node="currentNode" node="child" is-dialog="isDialog" section="{{section}}"></umb-tree-item>
|
||||
</ul>
|
||||
<ul ng-class="{collapsed: !node.expanded}">
|
||||
<umb-tree-item class="umb-animated" ng-repeat="child in node.children track by child.id"
|
||||
enablelistviewexpand="{{enablelistviewexpand}}" tree="tree" current-node="currentNode" node="child"
|
||||
is-dialog="isDialog" section="{{section}}"></umb-tree-item>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -1,79 +1,57 @@
|
||||
<ul class="umb-tree" ng-class="{'hide-options': hideoptions === 'true'}">
|
||||
<li ng-if="!tree.root.containsGroups">
|
||||
<div class="umb-tree-root" data-element="tree-root" ng-class="getNodeCssClass(tree.root)"
|
||||
ng-if="hideheader !== 'true'" on-right-click="altSelect(tree.root, $event)">
|
||||
<h1>
|
||||
<a ng-href="#/{{section}}" ng-click="select(tree.root, $event)" class="umb-tree-root-link umb-outline"
|
||||
data-element="tree-root-link">
|
||||
<umb-icon icon="icon-check" class="umb-tree-icon" ng-class="selectEnabledNodeClass(tree.root)"
|
||||
ng-if="enablecheckboxes === 'true'">
|
||||
</umb-icon>
|
||||
{{tree.name}}
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<li ng-if="!tree.root.containsGroups">
|
||||
<div class="umb-tree-root" data-element="tree-root" ng-class="getNodeCssClass(tree.root)" ng-if="hideheader !== 'true'" on-right-click="altSelect(tree.root, $event)">
|
||||
<h1>
|
||||
<a ng-href="#/{{section}}" ng-click="select(tree.root, $event)" class="umb-tree-root-link umb-outline" data-element="tree-root-link">
|
||||
<umb-icon icon="icon-check"
|
||||
class="umb-tree-icon"
|
||||
ng-class="selectEnabledNodeClass(tree.root)"
|
||||
ng-if="enablecheckboxes === 'true'">
|
||||
</umb-icon>
|
||||
{{tree.name}}
|
||||
</a>
|
||||
</h1>
|
||||
<umb-button-ellipsis element="tree-item-options" action="options(tree.root, $event)"
|
||||
text="{{labels.openContextNode}} {{tree.name}}" state="hidden" class="umb-options"
|
||||
ng-hide="tree.root.isContainer || !tree.root.menuUrl" ng-swipe-right="options(tree.root, $event)">
|
||||
</umb-button-ellipsis>
|
||||
</div>
|
||||
|
||||
<umb-button-ellipsis element="tree-item-options"
|
||||
action="options(tree.root, $event)"
|
||||
text="Open context node for {{tree.name}}"
|
||||
state="hidden"
|
||||
class="umb-options"
|
||||
ng-hide="tree.root.isContainer || !tree.root.menuUrl"
|
||||
ng-swipe-right="options(tree.root, $event)">
|
||||
</umb-button-ellipsis>
|
||||
<ul ng-if="tree.root.children.length > 0">
|
||||
<umb-tree-item class="umb-animated" ng-repeat="child in tree.root.children"
|
||||
enablelistviewexpand="{{enablelistviewexpand}}" node="child" current-node="currentNode" tree="this"
|
||||
is-dialog="isdialog" section="{{section}}">
|
||||
</umb-tree-item>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</div>
|
||||
<!-- REPEAT for each group in the tree -->
|
||||
<li ng-if="tree.root.containsGroups" ng-repeat="group in tree.root.children">
|
||||
<div class="umb-tree-root" data-element="tree-root" ng-class="getNodeCssClass(group)"
|
||||
ng-hide="hideheader === 'true'" on-right-click="altSelect(group, $event)">
|
||||
<h1>
|
||||
<a ng-href="#/{{section}}" ng-click="select(group, $event)" class="umb-tree-root-link umb-outline"
|
||||
data-element="tree-root-link">
|
||||
<umb-icon icon="icon-check" class="umb-tree-icon" ng-class="selectEnabledNodeClass(group)"
|
||||
ng-if="enablecheckboxes === 'true'">
|
||||
</umb-icon>
|
||||
{{group.name}}
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<ul ng-if="tree.root.children.length > 0">
|
||||
<umb-tree-item class="umb-animated"
|
||||
ng-repeat="child in tree.root.children"
|
||||
enablelistviewexpand="{{enablelistviewexpand}}"
|
||||
node="child"
|
||||
current-node="currentNode"
|
||||
tree="this"
|
||||
is-dialog="isdialog"
|
||||
section="{{section}}">
|
||||
</umb-tree-item>
|
||||
</ul>
|
||||
</li>
|
||||
<umb-button-ellipsis element="tree-item-options" action="options(group, $event)"
|
||||
text="{{labels.openContextNode}} {{group.name}}" state="hidden" class="umb-options"
|
||||
ng-hide="group.isContainer || !group.menuUrl" ng-swipe-right="options(group, $event)">
|
||||
</umb-button-ellipsis>
|
||||
</div>
|
||||
|
||||
<!-- REPEAT for each group in the tree -->
|
||||
<li ng-if="tree.root.containsGroups"
|
||||
ng-repeat="group in tree.root.children">
|
||||
|
||||
<div class="umb-tree-root" data-element="tree-root" ng-class="getNodeCssClass(group)" ng-hide="hideheader === 'true'" on-right-click="altSelect(group, $event)">
|
||||
<h1>
|
||||
<a ng-href="#/{{section}}" ng-click="select(group, $event)" class="umb-tree-root-link umb-outline" data-element="tree-root-link">
|
||||
<umb-icon icon="icon-check"
|
||||
class="umb-tree-icon"
|
||||
ng-class="selectEnabledNodeClass(group)"
|
||||
ng-if="enablecheckboxes === 'true'">
|
||||
</umb-icon>
|
||||
{{group.name}}
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<umb-button-ellipsis element="tree-item-options"
|
||||
action="options(group, $event)"
|
||||
text="Open context node for {{group.name}}"
|
||||
state="hidden"
|
||||
class="umb-options"
|
||||
ng-hide="group.isContainer || !group.menuUrl"
|
||||
ng-swipe-right="options(group, $event)">
|
||||
</umb-button-ellipsis>
|
||||
</div>
|
||||
|
||||
<ul ng-if="group.children.length > 0">
|
||||
<umb-tree-item class="umb-animated"
|
||||
ng-repeat="child in group.children"
|
||||
enablelistviewexpand="{{enablelistviewexpand}}"
|
||||
node="child"
|
||||
current-node="currentNode"
|
||||
tree="this"
|
||||
is-dialog="isdialog"
|
||||
section="{{section}}">
|
||||
</umb-tree-item>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- END REPEAT -->
|
||||
<ul ng-if="group.children.length > 0">
|
||||
<umb-tree-item class="umb-animated" ng-repeat="child in group.children"
|
||||
enablelistviewexpand="{{enablelistviewexpand}}" node="child" current-node="currentNode" tree="this"
|
||||
is-dialog="isdialog" section="{{section}}">
|
||||
</umb-tree-item>
|
||||
</ul>
|
||||
</li>
|
||||
<!-- END REPEAT -->
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user