Much better tree syncing
Is now pluggable, without those directive watches, and only active when used from external controllers, so dialog trees become much lighter
This commit is contained in:
@@ -87,10 +87,10 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
|
||||
//mimic the API of the legacy tree
|
||||
var tree = {
|
||||
setActiveTreeType : function(treeType){
|
||||
navService.syncTree(null, treeType, null);
|
||||
navService.setActiveTreeType(treeType);
|
||||
},
|
||||
syncTree : function(path,forceReload){
|
||||
navService.syncPath(path);
|
||||
navService.syncPath(path, forceReload);
|
||||
},
|
||||
getActionNode: function () {
|
||||
//need to replicate the legacy tree node
|
||||
|
||||
@@ -13,6 +13,14 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
|
||||
scope.maxSections = 7;
|
||||
scope.overflowingSections = 0;
|
||||
scope.sections = [];
|
||||
scope.nav = navigationService;
|
||||
|
||||
|
||||
/*
|
||||
scope.$watch("currentSection", function (newVal, oldVal) {
|
||||
scope.currentSection = newVal;
|
||||
});
|
||||
*/
|
||||
|
||||
function loadSections(){
|
||||
sectionResource.getSections()
|
||||
|
||||
@@ -14,8 +14,6 @@ angular.module("umbraco.directives")
|
||||
scope: {
|
||||
section: '@',
|
||||
treealias: '@',
|
||||
path: '@',
|
||||
activetree: '@',
|
||||
showoptions: '@',
|
||||
showheader: '@',
|
||||
cachekey: '@',
|
||||
@@ -26,7 +24,7 @@ angular.module("umbraco.directives")
|
||||
//config
|
||||
var hideheader = (attrs.showheader === 'false') ? true : false;
|
||||
var hideoptions = (attrs.showoptions === 'false') ? "hide-options" : "";
|
||||
|
||||
|
||||
var template = '<ul class="umb-tree ' + hideoptions + '">' +
|
||||
'<li class="root">';
|
||||
|
||||
@@ -37,7 +35,7 @@ angular.module("umbraco.directives")
|
||||
'</div>';
|
||||
}
|
||||
template += '<ul>' +
|
||||
'<umb-tree-item ng-repeat="child in tree.root.children" eventhandler="eventhandler" path="{{path}}" activetree="{{activetree}}" node="child" tree="child" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
|
||||
'<umb-tree-item ng-repeat="child in tree.root.children" eventhandler="eventhandler" path="{{path}}" activetree="{{activetree}}" node="child" current-node="currentNode" tree="child" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
|
||||
'</ul>' +
|
||||
'</li>' +
|
||||
'</ul>';
|
||||
@@ -53,6 +51,9 @@ angular.module("umbraco.directives")
|
||||
// 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.
|
||||
var lastSection = "";
|
||||
|
||||
//keeps track of the currently active tree being called by editors syncing
|
||||
var activeTree;
|
||||
|
||||
//flag to enable/disable delete animations
|
||||
var enableDeleteAnimations = false;
|
||||
@@ -64,10 +65,36 @@ angular.module("umbraco.directives")
|
||||
}
|
||||
}
|
||||
|
||||
function setupExternalEvents() {
|
||||
if (scope.eventhandler) {
|
||||
|
||||
scope.eventhandler.clearCache = function(treeAlias){
|
||||
treeService.clearCache(treeAlias);
|
||||
};
|
||||
|
||||
scope.eventhandler.syncPath = function(path, forceReload){
|
||||
if(!angular.isArray(path)){
|
||||
path = path.split(',');
|
||||
}
|
||||
|
||||
path = _.filter(path, function(item){ return (item !== "init" && item !== "-1"); });
|
||||
|
||||
//if we have a active tree, we sync based on that.
|
||||
var root = activeTree ? activeTree : scope.tree.root;
|
||||
|
||||
//tell the tree to sync the children below the root
|
||||
syncTree(root, path, forceReload);
|
||||
};
|
||||
|
||||
scope.eventhandler.setActiveTreeType = function(treeAlias){
|
||||
activeTree = _.find(scope.tree.root.children, function(node){ return node.metaData.treeAlias === treeAlias; });
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** Method to load in the tree data */
|
||||
function loadTree() {
|
||||
if (!scope.loading && scope.section) {
|
||||
|
||||
scope.loading = true;
|
||||
|
||||
//anytime we want to load the tree we need to disable the delete animations
|
||||
@@ -94,6 +121,31 @@ angular.module("umbraco.directives")
|
||||
}
|
||||
}
|
||||
|
||||
function syncTree(node, array, forceReload) {
|
||||
if(!node || !array || array.length === 0){
|
||||
return;
|
||||
}
|
||||
|
||||
scope.loadChildren(node, forceReload)
|
||||
.then(function(children){
|
||||
var next = _.where(children, {id: array[0]});
|
||||
if(next && next.length > 0){
|
||||
|
||||
if(array.length > 0){
|
||||
array.splice(0,1);
|
||||
}else{
|
||||
|
||||
}
|
||||
|
||||
if(array.length === 0){
|
||||
scope.currentNode = next[0];
|
||||
}
|
||||
|
||||
syncTree(next[0], array, forceReload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** method to set the current animation for the node.
|
||||
* This changes dynamically based on if we are changing sections or just loading normal tree data.
|
||||
* When changing sections we don't want all of the tree-ndoes to do their 'leave' animations.
|
||||
@@ -107,6 +159,35 @@ angular.module("umbraco.directives")
|
||||
}
|
||||
};
|
||||
|
||||
/* helper to force reloading children of a tree node */
|
||||
scope.loadChildren = function(node, forceReload){
|
||||
var deferred = $q.defer();
|
||||
|
||||
//emit treeNodeExpanding event, if a callback object is set on the tree
|
||||
emitEvent("treeNodeExpanding", {tree: scope.tree, node: node });
|
||||
|
||||
if (node.hasChildren && (forceReload || !node.children || (angular.isArray(node.children) && node.children.length === 0))) {
|
||||
//get the children from the tree service
|
||||
treeService.loadNodeChildren({ node: node, section: scope.section })
|
||||
.then(function(data) {
|
||||
//emit expanded event
|
||||
emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: data });
|
||||
enableDeleteAnimations = true;
|
||||
|
||||
deferred.resolve(data);
|
||||
});
|
||||
}
|
||||
else {
|
||||
emitEvent("treeNodeExpanded", {tree: scope.tree, node: node, children: node.children });
|
||||
node.expanded = true;
|
||||
enableDeleteAnimations = true;
|
||||
|
||||
deferred.resolve(node.children);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
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
|
||||
@@ -115,7 +196,7 @@ angular.module("umbraco.directives")
|
||||
scope.options = function (e, n, ev) {
|
||||
emitEvent("treeOptionsClick", { element: e, 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
|
||||
@@ -132,7 +213,7 @@ angular.module("umbraco.directives")
|
||||
|
||||
//watch for section changes
|
||||
scope.$watch("section", function (newVal, oldVal) {
|
||||
|
||||
|
||||
if(!scope.tree){
|
||||
loadTree();
|
||||
}
|
||||
@@ -146,28 +227,10 @@ angular.module("umbraco.directives")
|
||||
loadTree();
|
||||
|
||||
//store the new section to be loaded as the last section
|
||||
//clear any active trees to reset lookups
|
||||
lastSection = newVal;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//watch for path changes
|
||||
scope.$watch("path", function (newVal, oldVal) {
|
||||
|
||||
//resetting the path destroys the tree
|
||||
if(newVal && newVal !== oldVal){
|
||||
scope.tree = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//watch for active tree changes
|
||||
scope.$watch("activetree", function (newVal, oldVal) {
|
||||
|
||||
if (newVal && newVal !== oldVal) {
|
||||
scope.tree = null;
|
||||
//only reload the tree data and Dom if the newval is different from the old one
|
||||
}
|
||||
activeTree = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
//When the user logs in
|
||||
@@ -176,6 +239,8 @@ angular.module("umbraco.directives")
|
||||
if (data.lastUserId !== data.user.id) {
|
||||
treeService.clearCache();
|
||||
scope.tree = null;
|
||||
|
||||
setupExternalEvents();
|
||||
loadTree();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -27,15 +27,14 @@ angular.module("umbraco.directives")
|
||||
section: '@',
|
||||
cachekey: '@',
|
||||
eventhandler: '=',
|
||||
path: '@',
|
||||
currentNode:'=',
|
||||
node:'=',
|
||||
activetree:'@',
|
||||
tree:'='
|
||||
},
|
||||
|
||||
template: '<li ng-swipe-right="options(this, node, $event)"><div ng-style="setTreePadding(node)" class="{{node.stateCssClass}}" ng-class="{\'loading\': node.loading}">' +
|
||||
template: '<li ng-class="{\'current\': (node == currentNode)}"><div ng-style="setTreePadding(node)" class="{{node.stateCssClass}}" ng-class="{\'loading\': node.loading}" ng-swipe-right="options(this, node, $event)" >' +
|
||||
'<ins ng-hide="node.hasChildren" style="background:none;width:18px;"></ins>' +
|
||||
'<ins ng-show="node.hasChildren" ng-class="{\'icon-navigation-right\': !node.expanded, \'icon-navigation-down\': node.expanded}" ng-click="load(this, node)"></ins>' +
|
||||
'<ins ng-show="node.hasChildren" ng-class="{\'icon-navigation-right\': !node.expanded, \'icon-navigation-down\': node.expanded}" ng-click="load(node)"></ins>' +
|
||||
'<i title="#{{node.routePath}}" class="{{node.cssClass}}" style="{{node.style}}"></i>' +
|
||||
'<a href ng-click="select(this, node, $event)" on-right-click="altSelect(this, node, $event)" >{{node.name}}</a>' +
|
||||
'<a href class="umb-options" ng-hide="!node.menuUrl" ng-click="options(this, node, $event)"><i></i><i></i><i></i></a>' +
|
||||
@@ -103,33 +102,33 @@ angular.module("umbraco.directives")
|
||||
takes the arrow DOM element and node data as parameters
|
||||
emits treeNodeCollapsing event if already expanded and treeNodeExpanding if collapsed
|
||||
*/
|
||||
scope.load = function(arrow, node) {
|
||||
scope.load = function(node) {
|
||||
if (node.expanded) {
|
||||
enableDeleteAnimations = false;
|
||||
emitEvent("treeNodeCollapsing", { element: arrow, tree: scope.tree, node: node });
|
||||
emitEvent("treeNodeCollapsing", {tree: scope.tree, node: node });
|
||||
node.expanded = false;
|
||||
}
|
||||
else {
|
||||
scope.loadChildren(arrow, node, false);
|
||||
scope.loadChildren(node, false);
|
||||
}
|
||||
};
|
||||
|
||||
/* helper to force reloading children of a tree node */
|
||||
scope.loadChildren = function(arrow, node, forceReload){
|
||||
scope.loadChildren = function(node, forceReload){
|
||||
//emit treeNodeExpanding event, if a callback object is set on the tree
|
||||
emitEvent("treeNodeExpanding", { element: arrow, tree: scope.tree, node: node });
|
||||
emitEvent("treeNodeExpanding", { tree: scope.tree, node: node });
|
||||
|
||||
if (node.hasChildren && (forceReload || !node.children || (angular.isArray(node.children) && node.children.length === 0))) {
|
||||
//get the children from the tree service
|
||||
treeService.loadNodeChildren({ node: node, section: scope.section })
|
||||
.then(function(data) {
|
||||
//emit expanded event
|
||||
emitEvent("treeNodeExpanded", { element: arrow, tree: scope.tree, node: node, children: data });
|
||||
emitEvent("treeNodeExpanded", {tree: scope.tree, node: node, children: data });
|
||||
enableDeleteAnimations = true;
|
||||
});
|
||||
}
|
||||
else {
|
||||
emitEvent("treeNodeExpanded", { element: arrow, tree: scope.tree, node: node, children: node.children });
|
||||
emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: node.children });
|
||||
node.expanded = true;
|
||||
enableDeleteAnimations = true;
|
||||
}
|
||||
@@ -159,7 +158,7 @@ angular.module("umbraco.directives")
|
||||
scope.expandActivePath(scope.node, scope.activetree, scope.path);
|
||||
scope.node.stateCssClass = scope.node.cssClasses.join(" ");
|
||||
|
||||
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" eventhandler="eventhandler" activetree="{{activetree}}" path="{{path}}" tree="tree" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
|
||||
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" eventhandler="eventhandler" activetree="{{activetree}}" tree="tree" current-node="currentNode" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
|
||||
var newElement = angular.element(template);
|
||||
$compile(newElement)(scope);
|
||||
element.append(newElement);
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
*/
|
||||
|
||||
angular.module('umbraco.services')
|
||||
.factory('navigationService', function ($rootScope, $routeParams, $log, $location, $q, $timeout, dialogService, treeService, notificationsService) {
|
||||
.factory('navigationService', function ($rootScope, $routeParams, $log, $location, $q, $timeout, dialogService, treeService, notificationsService, historyService) {
|
||||
|
||||
//Define all sub-properties for the UI object here
|
||||
var ui = {
|
||||
tablet: false,
|
||||
showNavigation: false,
|
||||
showContextMenu: false,
|
||||
showContextMenuDialog: false,
|
||||
@@ -30,16 +31,23 @@ angular.module('umbraco.services')
|
||||
currentSection: undefined,
|
||||
currentPath: undefined,
|
||||
currentTree: undefined,
|
||||
treeEventHandler: undefined,
|
||||
currentNode: undefined,
|
||||
actions: undefined,
|
||||
currentDialog: undefined,
|
||||
dialogTitle: undefined,
|
||||
|
||||
//a string/name reference for the currently set ui mode
|
||||
currentMode: "default"
|
||||
};
|
||||
|
||||
$rootScope.$on("closeDialogs", function(){});
|
||||
|
||||
function setTreeMode() {
|
||||
ui.tablet = ($(window).width() <= 1000);
|
||||
ui.showNavigation = !ui.tablet;
|
||||
}
|
||||
|
||||
function setMode(mode) {
|
||||
switch (mode) {
|
||||
case 'tree':
|
||||
@@ -82,12 +90,16 @@ angular.module('umbraco.services')
|
||||
break;
|
||||
default:
|
||||
ui.currentMode = "default";
|
||||
ui.showNavigation = false;
|
||||
ui.showContextMenu = false;
|
||||
ui.showContextMenuDialog = false;
|
||||
ui.showSearchResults = false;
|
||||
ui.stickyNavigation = false;
|
||||
ui.showTray = false;
|
||||
|
||||
if(ui.tablet){
|
||||
ui.showNavigation = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -98,6 +110,18 @@ angular.module('umbraco.services')
|
||||
userDialog: undefined,
|
||||
ui: ui,
|
||||
|
||||
init: function(){
|
||||
|
||||
//TODO: detect tablet mode, subscribe to window resizing
|
||||
//for now we just hardcode it to non-tablet mode
|
||||
setTreeMode();
|
||||
this.ui.currentSection = $routeParams.section;
|
||||
|
||||
$(window).bind("resize", function () {
|
||||
setTreeMode();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.navigationService#load
|
||||
@@ -144,7 +168,13 @@ angular.module('umbraco.services')
|
||||
*/
|
||||
showTree: function (sectionAlias, treeAlias, path) {
|
||||
if (sectionAlias !== this.ui.currentSection) {
|
||||
this.syncTree(sectionAlias, treeAlias, path);
|
||||
this.ui.currentSection = sectionAlias;
|
||||
if(treeAlias){
|
||||
this.setActiveTreeType(treeAlias);
|
||||
}
|
||||
if(path){
|
||||
this.syncpath(path, true);
|
||||
}
|
||||
}
|
||||
setMode("tree");
|
||||
},
|
||||
@@ -156,6 +186,80 @@ angular.module('umbraco.services')
|
||||
hideTray: function () {
|
||||
ui.showTray = false;
|
||||
},
|
||||
|
||||
//adding this to get clean global access to the main tree directive
|
||||
//there will only ever be one main tree event handler
|
||||
//we need to pass in the current scope for binding these actions
|
||||
setupTreeEvents: function(treeEventHandler, scope){
|
||||
this.ui.treeEventHandler = treeEventHandler;
|
||||
|
||||
//this reacts to the options item in the tree
|
||||
this.ui.treeEventHandler.bind("treeOptionsClick", function (ev, args) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
scope.currentNode = args.node;
|
||||
args.scope = scope;
|
||||
|
||||
if(args.event && args.event.altKey){
|
||||
args.skipDefault = true;
|
||||
}
|
||||
|
||||
service.showMenu(ev, args);
|
||||
});
|
||||
|
||||
this.ui.treeEventHandler.bind("treeNodeAltSelect", function (ev, args) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
scope.currentNode = args.node;
|
||||
args.scope = scope;
|
||||
|
||||
args.skipDefault = true;
|
||||
service.showMenu(ev, args);
|
||||
});
|
||||
|
||||
//this reacts to tree items themselves being clicked
|
||||
//the tree directive should not contain any handling, simply just bubble events
|
||||
this.ui.treeEventHandler.bind("treeNodeSelect", function (ev, args) {
|
||||
var n = args.node;
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
|
||||
if (n.metaData && n.metaData["jsClickCallback"] && angular.isString(n.metaData["jsClickCallback"]) && n.metaData["jsClickCallback"] !== "") {
|
||||
//this is a legacy tree node!
|
||||
var jsPrefix = "javascript:";
|
||||
var js;
|
||||
if (n.metaData["jsClickCallback"].startsWith(jsPrefix)) {
|
||||
js = n.metaData["jsClickCallback"].substr(jsPrefix.length);
|
||||
}
|
||||
else {
|
||||
js = n.metaData["jsClickCallback"];
|
||||
}
|
||||
try {
|
||||
var func = eval(js);
|
||||
//this is normally not necessary since the eval above should execute the method and will return nothing.
|
||||
if (func != null && (typeof func === "function")) {
|
||||
func.call();
|
||||
}
|
||||
}
|
||||
catch(ex) {
|
||||
$log.error("Error evaluating js callback from legacy tree node: " + ex);
|
||||
}
|
||||
}
|
||||
else if(n.routePath){
|
||||
//add action to the history service
|
||||
historyService.add({ name: n.name, link: n.routePath, icon: n.icon });
|
||||
//not legacy, lets just set the route value and clear the query string if there is one.
|
||||
$location.path(n.routePath).search("");
|
||||
} else if(args.element.section){
|
||||
$location.path(args.element.section).search("");
|
||||
}
|
||||
|
||||
service.hideNavigation();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.navigationService#syncTree
|
||||
@@ -163,42 +267,24 @@ angular.module('umbraco.services')
|
||||
*
|
||||
* @description
|
||||
* Syncs the tree with a given section alias and a given path
|
||||
* The path format is: ["treeAlias","itemId","itemId"], and so on
|
||||
* The path format is: ["itemId","itemId"], and so on
|
||||
* so to sync to a specific document type node do:
|
||||
* <pre>
|
||||
* navigationService.syncTree("content", "nodeTypes", [-1,1023,3453]);
|
||||
* navigationService.syncPath(["-1","123d"], true);
|
||||
* </pre>
|
||||
* @param {string} sectionAlias The alias of the section the tree should load data from
|
||||
* @param {string} treeAlias The alias of tree to auto-expand
|
||||
* @param {array} path array of ascendant ids, ex: [,1023,1243] (loads a specific document type into the settings tree)
|
||||
* @param {array} path array of ascendant ids, ex: ["1023","1243"] (loads a specific document type into the settings tree)
|
||||
* @param {bool} forceReload forces a reload of data from the server
|
||||
*/
|
||||
syncTree: function (sectionAlias, treeAlias, path) {
|
||||
//TODO: investicate if we need to halt watch triggers
|
||||
//and instead pause them and then manually tell the tree to digest path changes
|
||||
//as this might be a bit heavy loading
|
||||
if(sectionAlias){
|
||||
this.ui.currentSection = sectionAlias;
|
||||
}
|
||||
if(treeAlias){
|
||||
this.ui.currentTree = treeAlias;
|
||||
}
|
||||
if(path){
|
||||
this.ui.currentPath = path;
|
||||
}
|
||||
syncPath: function (path, forceReload) {
|
||||
if(this.ui.treeEventHandler){
|
||||
this.ui.treeEventHandler.syncPath(path,forceReload);
|
||||
}
|
||||
},
|
||||
|
||||
/* this is to support the legacy ways to sync the tree, so you can do it in 2 steps
|
||||
For all new operations, its recommend to just use syncTree()
|
||||
*/
|
||||
syncPath: function (path) {
|
||||
//TODO: investicate if we need to halt watch triggers
|
||||
//and instead pause them and then manually tell the tree to digest path changes
|
||||
//as this might be a bit heavy loading
|
||||
if(!angular.isArray(path)){
|
||||
path = path.split(",");
|
||||
}
|
||||
|
||||
this.ui.currentPath = path;
|
||||
setActiveTreeType: function (treeAlias) {
|
||||
if(this.ui.treeEventHandler){
|
||||
this.ui.treeEventHandler.setActiveTreeType(treeAlias);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -249,10 +335,13 @@ angular.module('umbraco.services')
|
||||
* Hides the tree by hiding the containing dom element
|
||||
*/
|
||||
hideTree: function () {
|
||||
if (!this.ui.stickyNavigation) {
|
||||
this.ui.currentSection = "";
|
||||
|
||||
if (this.ui.tablet && !this.ui.stickyNavigation) {
|
||||
//reset it to whatever is in the url
|
||||
this.ui.currentSection = $routeParams.section;
|
||||
setMode("default-hidesectiontree");
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -552,7 +641,7 @@ angular.module('umbraco.services')
|
||||
*/
|
||||
hideNavigation: function () {
|
||||
this.ui.actions = [];
|
||||
this.ui.currentNode = undefined;
|
||||
//this.ui.currentNode = undefined;
|
||||
setMode("default");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,113 +16,49 @@ function NavigationController($scope,$rootScope, $location, $log, $routeParams,
|
||||
// when we create a dialog we pass in this scope to be used for the dialog's scope instead of creating a new one.
|
||||
$scope.nav = navigationService;
|
||||
|
||||
//wire up the screensize and tree mode detection
|
||||
$scope.nav.init();
|
||||
|
||||
//the tree event handler i used to subscribe to the main tree click events
|
||||
$scope.treeEventHandler = $({});
|
||||
$scope.nav.setupTreeEvents($scope.treeEventHandler, $scope);
|
||||
|
||||
//keep track of
|
||||
$scope.$watch(function () {
|
||||
//watch the route parameters section
|
||||
return $routeParams.section;
|
||||
}, function(newVal, oldVal) {
|
||||
$scope.currentSection = newVal;
|
||||
$scope.nav.ui.currentSection = newVal;
|
||||
});
|
||||
|
||||
|
||||
//trigger search with a hotkey:
|
||||
keyboardService.bind("ctrl+shift+s", function(){
|
||||
$scope.nav.showSearch();
|
||||
});
|
||||
|
||||
//the tree event handler i used to subscribe to the main tree click events
|
||||
$scope.treeEventHandler = $({});
|
||||
$scope.selectedId = navigationService.currentId;
|
||||
|
||||
|
||||
//This reacts to clicks passed to the body element which emits a global call to close all dialogs
|
||||
$rootScope.$on("closeDialogs", function (event) {
|
||||
if (navigationService.ui.stickyNavigation) {
|
||||
navigationService.hideNavigation();
|
||||
navigationService.hideNavigation();
|
||||
angularHelper.safeApply($scope);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//this reacts to the options item in the tree
|
||||
$scope.treeEventHandler.bind("treeOptionsClick", function (ev, args) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
$scope.currentNode = args.node;
|
||||
args.scope = $scope;
|
||||
|
||||
if(args.event && args.event.altKey){
|
||||
args.skipDefault = true;
|
||||
}
|
||||
|
||||
navigationService.showMenu(ev, args);
|
||||
});
|
||||
|
||||
$scope.treeEventHandler.bind("treeNodeAltSelect", function (ev, args) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
$scope.currentNode = args.node;
|
||||
args.scope = $scope;
|
||||
|
||||
args.skipDefault = true;
|
||||
navigationService.showMenu(ev, args);
|
||||
});
|
||||
|
||||
|
||||
//this reacts to the options item in the tree
|
||||
$scope.searchShowMenu = function (ev, args) {
|
||||
|
||||
//todo, migrate to nav service
|
||||
$scope.searchShowMenu = function (ev, args) {
|
||||
$scope.currentNode = args.node;
|
||||
args.scope = $scope;
|
||||
|
||||
//always skip default
|
||||
args.skipDefault = true;
|
||||
|
||||
navigationService.showMenu(ev, args);
|
||||
};
|
||||
|
||||
//this reacts to tree items themselves being clicked
|
||||
//the tree directive should not contain any handling, simply just bubble events
|
||||
$scope.treeEventHandler.bind("treeNodeSelect", function (ev, args) {
|
||||
var n = args.node;
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
|
||||
if (n.metaData && n.metaData["jsClickCallback"] && angular.isString(n.metaData["jsClickCallback"]) && n.metaData["jsClickCallback"] !== "") {
|
||||
//this is a legacy tree node!
|
||||
var jsPrefix = "javascript:";
|
||||
var js;
|
||||
if (n.metaData["jsClickCallback"].startsWith(jsPrefix)) {
|
||||
js = n.metaData["jsClickCallback"].substr(jsPrefix.length);
|
||||
}
|
||||
else {
|
||||
js = n.metaData["jsClickCallback"];
|
||||
}
|
||||
try {
|
||||
var func = eval(js);
|
||||
//this is normally not necessary since the eval above should execute the method and will return nothing.
|
||||
if (func != null && (typeof func === "function")) {
|
||||
func.call();
|
||||
}
|
||||
}
|
||||
catch(ex) {
|
||||
$log.error("Error evaluating js callback from legacy tree node: " + ex);
|
||||
}
|
||||
}
|
||||
else if(n.routePath){
|
||||
//add action to the history service
|
||||
historyService.add({ name: n.name, link: n.routePath, icon: n.icon });
|
||||
//not legacy, lets just set the route value and clear the query string if there is one.
|
||||
$location.path(n.routePath).search("");
|
||||
} else if(args.element.section){
|
||||
$location.path(args.element.section).search("");
|
||||
}
|
||||
|
||||
navigationService.hideNavigation();
|
||||
});
|
||||
|
||||
|
||||
/** Opens a dialog but passes in this scope instance to be used for the dialog */
|
||||
$scope.openDialog = function (currentNode, action, currentSection) {
|
||||
navigationService.showDialog({
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<div id="leftcolumn" ng-controller="Umbraco.NavigationController"
|
||||
ng-mouseleave="nav.leaveTree($event)" ng-mouseenter="nav.enterTree($event)">
|
||||
|
||||
<umb-sections sections="sections" current-section="currentSection"></umb-sections>
|
||||
<umb-sections sections="sections">
|
||||
</umb-sections>
|
||||
|
||||
<!-- navigation container -->
|
||||
<div id="navigation" ng-show="nav.ui.showNavigation" class="fill shadow umb-modalcolumn" ng-animate="'slide'">
|
||||
@@ -11,6 +12,8 @@
|
||||
<!-- the search -->
|
||||
<div id="search-form">
|
||||
<div class="umb-modalcolumn-header">
|
||||
|
||||
{{nav.ui.currentSection}}
|
||||
<form class="form-search" ng-controller="Umbraco.SearchController" novalidate>
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
<div>
|
||||
<div style="position:absolute; top: 1; background: red">
|
||||
{{overflowingSections}} {{maxSections}} {{totalSections}}
|
||||
</div>
|
||||
<div id="applications" ng-class="{faded:nav.ui.stickyNavigation}">
|
||||
<ul class="sections">
|
||||
<li class="avatar">
|
||||
@@ -9,7 +6,7 @@
|
||||
<img ng-src="{{avatar}}" />
|
||||
</a>
|
||||
</li>
|
||||
<li ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">
|
||||
<li ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == nav.ui.currentSection}">
|
||||
<a href="#/{{section.alias}}"
|
||||
ng-dblclick="sectionDblClick(section)"
|
||||
ng-click="sectionClick(section)"
|
||||
|
||||
Reference in New Issue
Block a user