Fixes: #14486 - Some sr-only texts not localized (#14750)

* 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:
Johan Möller
2023-09-12 08:26:49 +02:00
committed by GitHub
parent 417e37ab1e
commit 916e495dc4
6 changed files with 522 additions and 473 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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