Merge pull request #2590 from umbraco/temp-U4-11177

U4-11177 Update tree nodes with the new node names based on variant/language
This commit is contained in:
Robert
2018-04-19 08:35:01 +02:00
committed by GitHub
99 changed files with 1007 additions and 3011 deletions
@@ -90,11 +90,6 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
//mimic the API of the legacy tree
var tree = {
setActiveTreeType: function (treeType) {
angularHelper.safeApply($rootScope, function() {
navService._setActiveTreeType(treeType);
});
},
syncTree: function (path, forceReload) {
angularHelper.safeApply($rootScope, function() {
navService._syncPath(path, forceReload);
@@ -118,9 +113,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
});
},
refreshTree: function (treeAlias) {
angularHelper.safeApply($rootScope, function() {
navService._setActiveTreeType(treeAlias, true);
});
//no-op, just needs to be here for legacy reasons
},
moveNode: function (id, path) {
angularHelper.safeApply($rootScope, function() {
@@ -214,7 +214,7 @@ angular.module('umbraco.directives')
};
})
.directive('onRightClick',function(){
.directive('onRightClick',function($parse){
document.oncontextmenu = function (e) {
if(e.target.hasAttribute('on-right-click')) {
@@ -228,7 +228,10 @@ angular.module('umbraco.directives')
el.on('contextmenu',function(e){
e.preventDefault();
e.stopPropagation();
scope.$apply(attrs.onRightClick);
var fn = $parse(attrs.onRightClick);
scope.$apply(function () {
fn(scope, { $event: event });
});
return false;
});
};
@@ -20,10 +20,12 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
onlyinitialized: '@',
//Custom query string arguments to pass in to the tree as a string, example: "startnodeid=123&something=value"
customtreeparams: '@',
eventhandler: '=',
enablecheckboxes: '@',
enablelistviewsearch: '@',
enablelistviewexpand: '@'
enablelistviewexpand: '@',
api: '=?',
onInit: '&?'
},
compile: function (element, attrs) {
@@ -37,7 +39,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
'<a data-element="tree-item-options" class="umb-options" ng-hide="tree.root.isContainer || !tree.root.menuUrl" ng-click="options(tree.root, $event)" ng-swipe-right="options(tree.root, $event)"><i></i><i></i><i></i></a>' +
'</div>';
template += '<ul>' +
'<umb-tree-item ng-repeat="child in tree.root.children" enablelistviewexpand="{{enablelistviewexpand}}" eventhandler="eventhandler" node="child" current-node="currentNode" tree="this" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
'<umb-tree-item ng-repeat="child in tree.root.children" enablelistviewexpand="{{enablelistviewexpand}}" node="child" current-node="currentNode" tree="this" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
'</ul>' +
'</li>' +
'</ul>';
@@ -46,405 +48,384 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
return function (scope, elem, attr, controller) {
//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.
var lastSection = "";
};
},
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);
},
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;
//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;
}
//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.
var lastSection = "";
//flag to enable/disable delete animations
var deleteAnimations = false;
//setup a default internal handler
if (!scope.eventhandler) {
scope.eventhandler = $({});
/** Helper function to emit tree events */
function emitEvent(eventName, args) {
if (registeredCallbacks[eventName] && angular.isArray(registeredCallbacks[eventName])) {
_.each(registeredCallbacks[eventName], function (c) {
c(args);//call it
});
}
}
/** This will deleteAnimations to true after the current digest */
function enableDeleteAnimations() {
//do timeout so that it re-enables them after this digest
$timeout(function () {
//enable delete animations
deleteAnimations = true;
}, 0, false);
}
function clearCache(section) {
treeService.clearCache({ section: section });
}
function load(section) {
$scope.section = section;
return loadTree();
}
function reloadNode(node) {
if (!node) {
node = $scope.currentNode;
}
//flag to enable/disable delete animations
var deleteAnimations = false;
if (node) {
return $scope.loadChildren(node, true);
}
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";
}
var treeNode = loadActiveTree(args.tree);
if (angular.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')
/** Helper function to emit tree events */
function emitEvent(eventName, args) {
if (scope.eventhandler) {
$(scope.eventhandler).trigger(eventName, args);
args.path = _.filter(args.path, function (item) { return (item !== "init" && item !== "-1"); });
//Once those are filtered we need to check if the current user has a special start node id,
// if they do, then we're going to trim the start of the array for anything found from that start node
// and previous so that the tree syncs properly. The tree syncs from the top down and if there are parts
// of the tree's path in there that don't actually exist in the dom/model then syncing will not work.
return userService.getCurrentUser().then(function (userData) {
var startNodes = [];
for (var i = 0; i < userData.startContentIds; i++) {
startNodes.push(userData.startContentIds[i]);
}
}
/** This will deleteAnimations to true after the current digest */
function enableDeleteAnimations() {
//do timeout so that it re-enables them after this digest
$timeout(function () {
//enable delete animations
deleteAnimations = true;
}, 0, false);
}
/*this is the only external interface a tree has */
function setupExternalEvents() {
if (scope.eventhandler) {
scope.eventhandler.clearCache = function (section) {
treeService.clearCache({ section: section });
};
scope.eventhandler.load = function (section) {
scope.section = section;
loadTree();
};
scope.eventhandler.reloadNode = function (node) {
if (!node) {
node = scope.currentNode;
}
if (node) {
scope.loadChildren(node, true);
}
};
/**
Used to do the tree syncing. If the args.tree is not specified we are assuming it has been
specified previously using the _setActiveTreeType
*/
scope.eventhandler.syncTree = function (args) {
if (!args) {
throw "args cannot be null";
}
if (!args.path) {
throw "args.path cannot be null";
}
var deferred = $q.defer();
//this is super complex but seems to be working in other places, here we're listening for our
// own events, once the tree is sycned we'll resolve our promise.
scope.eventhandler.one("treeSynced", function (e, syncArgs) {
deferred.resolve(syncArgs);
});
//this should normally be set unless it is being called from legacy
// code, so set the active tree type before proceeding.
if (args.tree) {
loadActiveTree(args.tree);
}
if (angular.isString(args.path)) {
args.path = args.path.replace('"', '').split(',');
}
//reset current node selection
//scope.currentNode = null;
//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"); });
//Once those are filtered we need to check if the current user has a special start node id,
// if they do, then we're going to trim the start of the array for anything found from that start node
// and previous so that the tree syncs properly. The tree syncs from the top down and if there are parts
// of the tree's path in there that don't actually exist in the dom/model then syncing will not work.
userService.getCurrentUser().then(function (userData) {
var startNodes = [];
for (var i = 0; i < userData.startContentIds; i++) {
startNodes.push(userData.startContentIds[i]);
}
for (var j = 0; j < userData.startMediaIds; j++) {
startNodes.push(userData.startMediaIds[j]);
}
_.each(startNodes, function (i) {
var found = _.find(args.path, function (p) {
return String(p) === String(i);
});
if (found) {
args.path = args.path.splice(_.indexOf(args.path, found));
}
});
loadPath(args.path, args.forceReload, args.activate);
});
return deferred.promise;
};
/**
Internal method that should ONLY be used by the legacy API wrapper, the legacy API used to
have to set an active tree and then sync, the new API does this in one method by using syncTree.
loadChildren is optional but if it is set, it will set the current active tree and load the root
node's children - this is synonymous with the legacy refreshTree method - again should not be used
and should only be used for the legacy code to work.
*/
scope.eventhandler._setActiveTreeType = function (treeAlias, loadChildren) {
loadActiveTree(treeAlias, loadChildren);
};
for (var j = 0; j < userData.startMediaIds; j++) {
startNodes.push(userData.startMediaIds[j]);
}
}
//helper to load a specific path on the active tree as soon as its ready
function loadPath(path, forceReload, activate) {
if (scope.activeTree) {
syncTree(scope.activeTree, path, forceReload, activate);
}
else {
scope.eventhandler.one("activeTreeLoaded", function (e, args) {
syncTree(args.tree, path, forceReload, activate);
_.each(startNodes, function (i) {
var found = _.find(args.path, function (p) {
return String(p) === String(i);
});
}
}
//given a tree alias, this will search the current section tree for the specified tree alias and
//set that to the activeTree
//NOTE: loadChildren is ONLY used for legacy purposes, do not use this when syncing the tree as it will cause problems
// since there will be double request and event handling operations.
function loadActiveTree(treeAlias, loadChildren) {
if (!treeAlias) {
return;
}
scope.activeTree = undefined;
function doLoad(tree) {
var childrenAndSelf = [tree].concat(tree.children);
scope.activeTree = _.find(childrenAndSelf, function (node) {
if (node && node.metaData && node.metaData.treeAlias) {
return node.metaData.treeAlias.toUpperCase() === treeAlias.toUpperCase();
}
return false;
});
if (!scope.activeTree) {
throw "Could not find the tree " + treeAlias + ", activeTree has not been set";
if (found) {
args.path = args.path.splice(_.indexOf(args.path, found));
}
//This is only used for the legacy tree method refreshTree!
if (loadChildren) {
scope.activeTree.expanded = true;
scope.loadChildren(scope.activeTree, false).then(function () {
emitEvent("activeTreeLoaded", { tree: scope.activeTree });
});
}
else {
emitEvent("activeTreeLoaded", { tree: scope.activeTree });
}
}
if (scope.tree) {
doLoad(scope.tree.root);
}
else {
scope.eventhandler.one("treeLoaded", function (e, args) {
doLoad(args.tree.root);
});
}
}
/** 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
deleteAnimations = false;
//default args
var args = { section: scope.section, tree: scope.treealias, cacheKey: scope.cachekey, isDialog: scope.isdialog ? scope.isdialog : false, onlyinitialized: scope.onlyinitialized };
//add the extra query string params if specified
if (scope.customtreeparams) {
args["queryString"] = scope.customtreeparams;
}
treeService.getTree(args)
.then(function (data) {
//set the data once we have it
scope.tree = data;
enableDeleteAnimations();
scope.loading = false;
//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 });
}, function (reason) {
scope.loading = false;
notificationsService.error("Tree Error", reason);
});
}
}
/** syncs the tree, the treeNode can be ANY tree node in the tree that requires syncing */
function syncTree(treeNode, path, forceReload, activate) {
});
deleteAnimations = false;
treeService.syncTree({
return treeService.syncTree({
node: treeNode,
path: path,
forceReload: forceReload
path: args.path,
forceReload: args.forceReload
}).then(function (data) {
if (activate === undefined || activate === true) {
scope.currentNode = data;
if (args.activate === undefined || args.activate === true) {
$scope.currentNode = data;
}
emitEvent("treeSynced", { node: data, activate: activate });
emitEvent("treeSynced", { node: data, activate: args.activate });
enableDeleteAnimations();
enableDeleteAnimations();
return $q.when({ node: data, activate: args.activate });
});
});
}
//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 childrenAndSelf = [$scope.tree.root].concat($scope.tree.root.children);
$scope.activeTree = _.find(childrenAndSelf, function (node) {
if (node && node.metaData && node.metaData.treeAlias) {
return node.metaData.treeAlias.toUpperCase() === treeAlias.toUpperCase();
}
return false;
});
if (!$scope.activeTree) {
throw "Could not find the tree " + treeAlias;
}
/** Returns the css classses assigned to the node (div element) */
scope.getNodeCssClass = function (node) {
if (!node) {
return '';
emitEvent("activeTreeLoaded", { tree: $scope.activeTree });
return $scope.activeTree;
}
/** 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
deleteAnimations = false;
//default args
var args = { section: $scope.section, tree: $scope.treealias, cacheKey: $scope.cachekey, isDialog: $scope.isdialog ? $scope.isdialog : false, onlyinitialized: $scope.onlyinitialized };
//add the extra query string params if specified
if ($scope.customtreeparams) {
args["queryString"] = $scope.customtreeparams;
}
//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.
return treeService.getTree(args)
.then(function (data) {
//set the data once we have it
$scope.tree = data;
var css = [];
if (node.cssClasses) {
_.each(node.cssClasses, function (c) {
css.push(c);
enableDeleteAnimations();
$scope.loading = false;
//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) {
$scope.loading = false;
notificationsService.error("Tree Error", reason);
return $q.reject(reason);
});
}
return css.join(" ");
};
}
else {
return $q.reject();
}
}
scope.selectEnabledNodeClass = function (node) {
return node ?
node.selected ?
'icon umb-tree-icon sprTree icon-check green temporary' :
'' :
'';
};
/** Returns the css classses assigned to the node (div element) */
$scope.getNodeCssClass = function (node) {
if (!node) {
return '';
}
/** 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.
*/
scope.animation = function () {
if (deleteAnimations && scope.tree && scope.tree.root && scope.tree.root.expanded) {
return { leave: 'tree-node-delete-leave' };
}
else {
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.
/* helper to force reloading children of a tree node */
scope.loadChildren = function (node, forceReload) {
var deferred = $q.defer();
var css = [];
if (node.cssClasses) {
_.each(node.cssClasses, function (c) {
css.push(c);
});
}
//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
treeService.loadNodeChildren({ node: node, section: scope.section })
.then(function (data) {
//emit expanded event
emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: data });
enableDeleteAnimations();
deferred.resolve(data);
});
}
else {
emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: node.children });
node.expanded = true;
enableDeleteAnimations();
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
about it.
*/
scope.options = function (n, ev) {
emitEvent("treeOptionsClick", { element: elem, 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: elem, node: n, event: ev });
};
scope.altSelect = function (n, ev) {
emitEvent("treeNodeAltSelect", { element: elem, tree: scope.tree, node: n, event: ev });
};
//watch for section changes and customtreeparams changes
scope.$watchCollection("[section, customtreeparams]", function (newVal, oldVal) {
if (!scope.tree) {
loadTree();
}
if (!newVal) {
//store the last section loaded
lastSection = oldVal;
}
else if (newVal !== oldVal && newVal !== lastSection) {
//only reload the tree data and Dom if the newval is different from the old one
// and if the last section loaded is different from the requested one.
loadTree();
//store the new section to be loaded as the last section
//clear any active trees to reset lookups
lastSection = newVal;
}
});
setupExternalEvents();
loadTree();
return css.join(" ");
};
$scope.selectEnabledNodeClass = function (node) {
return node ?
node.selected ?
'icon umb-tree-icon sprTree icon-check green temporary' :
'' :
'';
};
/** 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.
*/
$scope.animation = function () {
if (deleteAnimations && $scope.tree && $scope.tree.root && $scope.tree.root.expanded) {
return { leave: 'tree-node-delete-leave' };
}
else {
return {};
}
};
/* helper to force reloading children of a tree node */
$scope.loadChildren = function (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 })
.then(function (data) {
//emit expanded event
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: data });
enableDeleteAnimations();
return $q.when(data);
});
}
else {
emitEvent("treeNodeExpanded", { tree: $scope.tree, node: node, children: node.children });
node.expanded = true;
enableDeleteAnimations();
return $q.when(node.children);
}
};
/**
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 });
};
//watch for section changes
$scope.$watch("section", function (newVal, oldVal) {
if (!$scope.tree) {
loadTree();
}
if (!newVal) {
//store the last section loaded
lastSection = oldVal;
}
else if (newVal !== oldVal && newVal !== lastSection) {
//only reload the tree data and Dom if the newval is different from the old one
// and if the last section loaded is different from the requested one.
loadTree();
//store the new section to be loaded as the last section
//clear any active trees to reset lookups
lastSection = newVal;
}
});
//call the callback, this allows for hosting controllers to bind to events and use the exposed API
$scope.onInit();
loadTree();
}
};
}
@@ -22,14 +22,13 @@ angular.module("umbraco.directives")
return {
restrict: 'E',
replace: true,
require: '^umbTree',
scope: {
section: '@',
eventhandler: '=',
currentNode: '=',
enablelistviewexpand: '@',
node: '=',
tree: '='
tree: '=' //TODO: Not sure we need this since we are 'require' on the umbTree
},
//TODO: Remove more of the binding from this template and move the DOM manipulation to be manually done in the link function,
@@ -48,7 +47,7 @@ angular.module("umbraco.directives")
'</div>' +
'</li>',
link: function (scope, element, attrs) {
link: function (scope, element, attrs, umbTreeCtrl) {
localizationService.localize("general_search").then(function (value) {
scope.searchAltText = value;
@@ -57,14 +56,6 @@ angular.module("umbraco.directives")
//flag to enable/disable delete animations, default for an item is true
var deleteAnimations = true;
// Helper function to emit tree events
function emitEvent(eventName, args) {
if (scope.eventhandler) {
$(scope.eventhandler).trigger(eventName, args);
}
}
// updates the node's DOM/styles
function setupNodeDom(node, tree) {
@@ -153,7 +144,7 @@ angular.module("umbraco.directives")
about it.
*/
scope.options = function (n, ev) {
emitEvent("treeOptionsClick", { element: element, tree: scope.tree, node: n, event: ev });
umbTreeCtrl.emitEvent("treeOptionsClick", { element: element, tree: scope.tree, node: n, event: ev });
};
/**
@@ -176,7 +167,7 @@ angular.module("umbraco.directives")
return;
}
emitEvent("treeNodeSelect", { element: element, tree: scope.tree, node: n, event: ev });
umbTreeCtrl.emitEvent("treeNodeSelect", { element: element, tree: scope.tree, node: n, event: ev });
ev.preventDefault();
};
@@ -187,7 +178,7 @@ angular.module("umbraco.directives")
defined on the tree
*/
scope.altSelect = function (n, ev) {
emitEvent("treeNodeAltSelect", { element: element, tree: scope.tree, node: n, event: ev });
umbTreeCtrl.emitEvent("treeNodeAltSelect", { element: element, tree: scope.tree, node: n, event: ev });
};
/** method to set the current animation for the node.
@@ -214,7 +205,7 @@ angular.module("umbraco.directives")
scope.load = function (node) {
if (node.expanded && !node.metaData.isContainer) {
deleteAnimations = false;
emitEvent("treeNodeCollapsing", { tree: scope.tree, node: node, element: element });
umbTreeCtrl.emitEvent("treeNodeCollapsing", { tree: scope.tree, node: node, element: element });
node.expanded = false;
}
else {
@@ -225,19 +216,19 @@ angular.module("umbraco.directives")
/* helper to force reloading children of a tree node */
scope.loadChildren = function (node, forceReload) {
//emit treeNodeExpanding event, if a callback object is set on the tree
emitEvent("treeNodeExpanding", { tree: scope.tree, node: node });
umbTreeCtrl.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 });
umbTreeCtrl.emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: data });
enableDeleteAnimations();
});
}
else {
emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: node.children });
umbTreeCtrl.emitEvent("treeNodeExpanded", { tree: scope.tree, node: node, children: node.children });
node.expanded = true;
enableDeleteAnimations();
}
@@ -253,7 +244,7 @@ angular.module("umbraco.directives")
scope.loadChildren(scope.node);
}
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" enablelistviewexpand="{{enablelistviewexpand}}" eventhandler="eventhandler" tree="tree" current-node="currentNode" node="child" section="{{section}}" ng-animate="animation()"></umb-tree-item></ul>';
var template = '<ul ng-class="{collapsed: !node.expanded}"><umb-tree-item ng-repeat="child in node.children" enablelistviewexpand="{{enablelistviewexpand}}" 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);
@@ -8,7 +8,42 @@
*/
function angularHelper($log, $q) {
return {
/**
* Execute a list of promises sequentially. Unlike $q.all which executes all promises at once, this will execute them in sequence.
* @param {} promises
* @returns {}
*/
executeSequentialPromises: function (promises) {
//this is sequential promise chaining, it's not pretty but we need to do it this way.
//$q.all doesn't execute promises in sequence but that's what we want to do here.
if (!angular.isArray(promises)) {
throw "promises must be an array";
}
//now execute them in sequence... sorry there's no other good way to do it with angular promises
var j = 0;
function pExec(promise) {
j++;
return promise.then(function (data) {
if (j === promises.length) {
return $q.when(data); //exit
}
else {
return pExec(promises[j]); //recurse
}
});
}
if (promises.length > 0) {
return pExec(promises[0]); //start the promise chain
}
else {
return $q.when(true); // just exit, no promises to execute
}
},
/**
* @ngdoc function
* @name safeApply
@@ -9,7 +9,8 @@
app.closeDialogs
app.ysod
app.reInitialize
app.userRefresh
app.userRefresh
app.navigationReady
*/
function eventsService($q, $rootScope) {
@@ -42,4 +43,4 @@ function eventsService($q, $rootScope) {
};
}
angular.module('umbraco.services').factory('eventsService', eventsService);
angular.module('umbraco.services').factory('eventsService', eventsService);
@@ -8,7 +8,7 @@
* @description
* Defines the methods that are called when menu items declare only an action to execute
*/
function umbracoMenuActions($q, treeService, $location, navigationService, appState, localizationService, userResource, umbRequestHelper, notificationsService) {
function umbracoMenuActions(treeService, $location, navigationService, appState, localizationService, usersResource, umbRequestHelper, notificationsService) {
return {
@@ -34,7 +34,7 @@ function umbracoMenuActions($q, treeService, $location, navigationService, appSt
localizationService.localize("defaultdialogs_confirmdisable").then(function (txtConfirmDisable) {
var currentMenuNode = UmbClientMgr.mainTree().getActionNode();
if (confirm(txtConfirmDisable + ' "' + args.entity.name + '"?\n\n')) {
userResource.disableUser(args.entity.id).then(function () {
usersResource.disableUser(args.entity.id).then(function () {
navigationService.syncTree({ tree: args.treeAlias, path: [args.entity.parentId, args.entity.id], forceReload: true });
});
}
@@ -103,4 +103,4 @@ function umbracoMenuActions($q, treeService, $location, navigationService, appSt
};
}
angular.module('umbraco.services').factory('umbracoMenuActions', umbracoMenuActions);
angular.module('umbraco.services').factory('umbracoMenuActions', umbracoMenuActions);
@@ -15,14 +15,18 @@
* Section navigation and search, and maintain their state for the entire application lifetime
*
*/
function navigationService($rootScope, $routeParams, $log, $location, $q, $timeout, $injector, dialogService, umbModelMapper, treeService, notificationsService, historyService, appState, angularHelper) {
function navigationService($rootScope, $routeParams, $log, $location, $q, $timeout, $injector, eventsService, dialogService, umbModelMapper, treeService, notificationsService, historyService, appState, angularHelper) {
//the main tree's API reference, this is acquired when the tree has initialized
var mainTreeApi = null;
eventsService.on("app.navigationReady", function (e, args) {
mainTreeApi = args.treeApi;
});
//used to track the current dialog object
var currentDialog = null;
//the main tree event handler, which gets assigned via the setupTreeEvents method
var mainTreeEventHandler = null;
//tracks the user profile dialog
var userDialog = null;
@@ -165,100 +169,6 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
appState.setGlobalState("showTray", false);
},
/**
Called to assign the main tree event handler - this is called by the navigation controller.
TODO: Potentially another dev could call this which would kind of mung the whole app so potentially there's a better way.
*/
setupTreeEvents: function(treeEventHandler) {
mainTreeEventHandler = treeEventHandler;
//when a tree is loaded into a section, we need to put it into appState
mainTreeEventHandler.bind("treeLoaded", function(ev, args) {
appState.setTreeState("currentRootNode", args.tree);
});
//when a tree node is synced this event will fire, this allows us to set the currentNode
mainTreeEventHandler.bind("treeSynced", function (ev, args) {
if (args.activate === undefined || args.activate === true) {
//set the current selected node
appState.setTreeState("selectedNode", args.node);
//when a node is activated, this is the same as clicking it and we need to set the
//current menu item to be this node as well.
appState.setMenuState("currentNode", args.node);
}
});
//this reacts to the options item in the tree
mainTreeEventHandler.bind("treeOptionsClick", function(ev, args) {
ev.stopPropagation();
ev.preventDefault();
//Set the current action node (this is not the same as the current selected node!)
appState.setMenuState("currentNode", args.node);
if (args.event && args.event.altKey) {
args.skipDefault = true;
}
service.showMenu(ev, args);
});
mainTreeEventHandler.bind("treeNodeAltSelect", function(ev, args) {
ev.stopPropagation();
ev.preventDefault();
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
mainTreeEventHandler.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 });
//put this node into the tree state
appState.setTreeState("selectedNode", args.node);
//when a node is clicked we also need to set the active menu node to this node
appState.setMenuState("currentNode", args.node);
//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
@@ -288,12 +198,9 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
throw "args.tree cannot be null";
}
if (mainTreeEventHandler) {
if (mainTreeEventHandler.syncTree) {
//returns a promise,
return mainTreeEventHandler.syncTree(args);
}
if (mainTreeApi) {
//returns a promise,
return mainTreeApi.syncTree(args);
}
//couldn't sync
@@ -305,33 +212,27 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
have to set an active tree and then sync, the new API does this in one method by using syncTree
*/
_syncPath: function(path, forceReload) {
if (mainTreeEventHandler) {
mainTreeEventHandler.syncTree({ path: path, forceReload: forceReload });
if (mainTreeApi) {
mainTreeApi.syncTree({ path: path, forceReload: forceReload });
}
},
//TODO: This should return a promise
reloadNode: function(node) {
if (mainTreeEventHandler) {
mainTreeEventHandler.reloadNode(node);
if (mainTreeApi) {
return mainTreeApi.reloadNode(node);
}
else {
return $q.reject();
}
},
//TODO: This should return a promise
reloadSection: function(sectionAlias) {
if (mainTreeEventHandler) {
mainTreeEventHandler.clearCache({ section: sectionAlias });
mainTreeEventHandler.load(sectionAlias);
if (mainTreeApi) {
mainTreeApi.clearCache({ section: sectionAlias });
return mainTreeApi.load(sectionAlias);
}
},
/**
Internal method that should ONLY be used by the legacy API wrapper, the legacy API used to
have to set an active tree and then sync, the new API does this in one method by using syncTreePath
*/
_setActiveTreeType: function (treeAlias, loadChildren) {
if (mainTreeEventHandler) {
mainTreeEventHandler._setActiveTreeType(treeAlias, loadChildren);
else {
return $q.reject();
}
},
@@ -364,7 +265,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
*
* @param {Event} event the click event triggering the method, passed from the DOM element
*/
showMenu: function(event, args) {
showMenu: function(args) {
var deferred = $q.defer();
var self = this;
@@ -35,7 +35,42 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
_getTreeCache: function() {
return treeCache;
},
/** Internal method to track expanded paths on a tree */
_trackExpandedPaths: function (node, expandedPaths) {
if (!node.children || !angular.isArray(node.children) || node.children.length == 0) {
return;
}
//take the last child
var childPath = this.getPath(node.children[node.children.length - 1]).join(",");
//check if this already exists, if so exit
if (expandedPaths.indexOf(childPath) !== -1) {
return;
}
if (expandedPaths.length === 0) {
expandedPaths.push(childPath); //track it
return;
}
var clonedPaths = expandedPaths.slice(0); //make a copy to iterate over so we can modify the original in the iteration
_.each(clonedPaths, function (p) {
if (childPath.startsWith(p + ",")) {
//this means that the node's path supercedes this path stored so we can remove the current 'p' and replace it with node.path
expandedPaths.splice(expandedPaths.indexOf(p), 1); //remove it
expandedPaths.push(childPath); //replace it
}
else if (p.startsWith(childPath + ",")) {
//this means we've already tracked a deeper node so we shouldn't track this one
}
else {
expandedPaths.push(childPath); //track it
}
});
},
/** Internal method that ensures there's a routePath, parent and level property on each tree node and adds some icon specific properties so that the nodes display properly */
_formatNodeDataForUseInUI: function (parentNode, treeNodes, section, level) {
//if no level is set, then we make it 1
@@ -263,8 +298,14 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
if (args.node.children && args.node.children.length > 0) {
args.node.expanded = true;
args.node.hasChildren = true;
}
return data;
}
//Since we've removed the children & reloaded them, we need to refresh the UI now because the tree node UI doesn't operate on normal angular $watch since that will be pretty slow
if (angular.isFunction(args.node.updateNodeData)) {
args.node.updateNodeData(args.node);
}
return $q.when(data);
}, function(reason) {
@@ -277,7 +318,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
//tell notications about the error
notificationsService.error(reason);
return reason;
return $q.reject(reason);
});
},
@@ -475,8 +516,6 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
*/
getTree: function (args) {
var deferred = $q.defer();
//set defaults
if (!args) {
args = { section: 'content', cacheKey: null };
@@ -489,12 +528,11 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
//return the cache if it exists
if (cacheKey && treeCache[cacheKey] !== undefined) {
deferred.resolve(treeCache[cacheKey]);
return deferred.promise;
return $q.when(treeCache[cacheKey]);
}
var self = this;
treeResource.loadApplication(args)
return treeResource.loadApplication(args)
.then(function(data) {
//this will be called once the tree app data has loaded
var result = {
@@ -507,16 +545,14 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
//cache this result if a cache key is specified - generally a cache key should ONLY
// be specified for application trees, dialog trees should not be cached.
if (cacheKey) {
if (cacheKey) {
treeCache[cacheKey] = result;
deferred.resolve(treeCache[cacheKey]);
return $q.when(treeCache[cacheKey]);
}
//return un-cached
deferred.resolve(result);
return $q.when(result);
});
return deferred.promise;
},
/**
@@ -579,7 +615,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
.then(function (data) {
//now that we have the data, we need to add the level property to each item and the view
self._formatNodeDataForUseInUI(treeItem, data, section, treeItem.level + 1);
return data;
return $q.when(data);
});
},
@@ -604,12 +640,10 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
throw "cannot reload a single node without an assigned node.section";
}
var deferred = $q.defer();
//set the node to loading
node.loading = true;
this.getChildren({ node: node.parent(), section: node.section }).then(function(data) {
return this.getChildren({ node: node.parent(), section: node.section }).then(function(data) {
//ok, now that we have the children, find the node we're reloading
var found = _.find(data, function(item) {
@@ -632,17 +666,15 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
//set the node loading
node.parent().children[index].loading = false;
//return
deferred.resolve(node.parent().children[index]);
//return
return $q.when(node.parent().children[index]);
}
else {
deferred.reject();
return $q.reject();
}
}, function() {
deferred.reject();
return $q.reject();
});
return deferred.promise;
},
/**
@@ -696,8 +728,6 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
args.path.push("-1");
}
var deferred = $q.defer();
//get the rootNode for the current node, we'll sync based on that
var root = this.getTreeRoot(args.node);
if (!root) {
@@ -711,8 +741,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
if (String(args.path[currPathIndex]).toLowerCase() === String(args.node.id).toLowerCase()) {
if (args.path.length === 1) {
//return the root
deferred.resolve(root);
return deferred.promise;
return $q.when(root);
}
else {
//move to the next path part and continue
@@ -732,16 +761,12 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
if (args.path.length === (currPathIndex + 1)) {
//woot! synced the node
if (!args.forceReload) {
deferred.resolve(child);
return $q.when(child);
}
else {
//even though we've found the node if forceReload is specified
//we want to go update this single node from the server
self.reloadNode(child).then(function (reloaded) {
deferred.resolve(reloaded);
}, function () {
deferred.reject();
});
return self.reloadNode(child);
}
}
else {
@@ -749,46 +774,44 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
currPathIndex++;
node = child;
//recurse
doSync();
return doSync();
}
}
else {
//couldn't find it in the
self.loadNodeChildren({ node: node, section: node.section }).then(function () {
return self.loadNodeChildren({ node: node, section: node.section }).then(function () {
//ok, got the children, let's find it
var found = self.getChildNode(node, args.path[currPathIndex]);
if (found) {
if (args.path.length === (currPathIndex + 1)) {
//woot! synced the node
deferred.resolve(found);
return $q.when(found);
}
else {
//now we need to recurse with the updated node/currPathIndex
currPathIndex++;
node = found;
//recurse
doSync();
return doSync();
}
}
else {
//fail!
deferred.reject();
return $q.reject();
}
}, function () {
//fail!
deferred.reject();
return $q.reject();
});
}
};
//start
doSync();
return deferred.promise;
return doSync();
}
};
}
angular.module('umbraco.services').factory('treeService', treeService);
angular.module('umbraco.services').factory('treeService', treeService);
@@ -247,10 +247,9 @@ angular.module('umbraco.services')
/** Returns the current user object in a promise */
getCurrentUser: function (args) {
var deferred = $q.defer();
if (!currentUser) {
authResource.getCurrentUser()
return authResource.getCurrentUser()
.then(function (data) {
var result = { user: data, authenticated: true, lastUserId: lastUserId, loginType: "implicit" };
@@ -261,19 +260,17 @@ angular.module('umbraco.services')
}
setCurrentUser(data);
deferred.resolve(currentUser);
return $q.when(currentUser);
}, function () {
//it failed, so they are not logged in
deferred.reject();
//it failed, so they are not logged in
return $q.reject(currentUser);
});
}
else {
deferred.resolve(currentUser);
return $q.when(currentUser);
}
return deferred.promise;
},
/** Loads the Moment.js Locale for the current user. */
@@ -295,11 +292,7 @@ angular.module('umbraco.services')
return assetsService.load(localeUrls, $rootScope);
}
else {
//return a noop promise
var deferred = $q.defer();
var promise = deferred.promise;
deferred.resolve(true);
return promise;
$q.when(true);
}
}
@@ -14,6 +14,7 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
$scope.authenticated = null;
$scope.touchDevice = appState.getGlobalState("touchDevice");
$scope.overlay = {};
$scope.navReady = false;
$scope.removeNotification = function (index) {
@@ -60,6 +61,10 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
});
}));
evts.push(eventsService.on('app.navigationReady', function () {
$scope.navReady = true;
}));
//when the app is ready/user is logged in, setup the data
evts.push(eventsService.on("app.ready", function (evt, data) {
@@ -9,18 +9,113 @@
*
* @param {navigationService} navigationService A reference to the navigationService
*/
function NavigationController($scope, $rootScope, $location, $log, $routeParams, $timeout, appState, navigationService, keyboardService, dialogService, historyService, eventsService, sectionResource, angularHelper, languageResource) {
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, treeService, appState, navigationService, keyboardService, dialogService, historyService, eventsService, sectionResource, angularHelper, languageResource) {
//TODO: Need to think about this and an nicer way to acheive what this is doing.
//the tree event handler i used to subscribe to the main tree click events
$scope.treeEventHandler = $({});
navigationService.setupTreeEvents($scope.treeEventHandler);
$scope.treeApi = {};
//Put the navigation service on this scope so we can use it's methods/properties in the view.
//Bind to the main tree events
$scope.onTreeInit = function () {
$scope.treeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
//when a tree is loaded into a section, we need to put it into appState
$scope.treeApi.callbacks.treeLoaded(function (args) {
appState.setTreeState("currentRootNode", args.tree);
});
//when a tree node is synced this event will fire, this allows us to set the currentNode
$scope.treeApi.callbacks.treeSynced(function (args) {
if (args.activate === undefined || args.activate === true) {
//set the current selected node
appState.setTreeState("selectedNode", args.node);
//when a node is activated, this is the same as clicking it and we need to set the
//current menu item to be this node as well.
appState.setMenuState("currentNode", args.node);
}
});
//this reacts to the options item in the tree
$scope.treeApi.callbacks.treeOptionsClick(function (args) {
args.event.stopPropagation();
args.event.preventDefault();
//Set the current action node (this is not the same as the current selected node!)
appState.setMenuState("currentNode", args.node);
if (args.event && args.event.altKey) {
args.skipDefault = true;
}
navigationService.showMenu(args);
});
$scope.treeApi.callbacks.treeNodeAltSelect(function (args) {
args.event.stopPropagation();
args.event.preventDefault();
args.skipDefault = true;
navigationService.showMenu(args);
});
//this reacts to tree items themselves being clicked
//the tree directive should not contain any handling, simply just bubble events
$scope.treeApi.callbacks.treeNodeSelect(function (args) {
var n = args.node;
args.event.stopPropagation();
args.event.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 });
//put this node into the tree state
appState.setTreeState("selectedNode", args.node);
//when a node is clicked we also need to set the active menu node to this node
appState.setMenuState("currentNode", args.node);
//not legacy, lets just set the route value and clear the query string if there is one.
$location.path(n.routePath).search("");
}
else if (n.section) {
$location.path(n.section).search("");
}
navigationService.hideNavigation();
});
//once this is wired up, the nav is ready
eventsService.emit("app.navigationReady", { treeApi: $scope.treeApi});
}
//TODO: Remove this, this is not healthy
// Put the navigation service on this scope so we can use it's methods/properties in the view.
// IMPORTANT: all properties assigned to this scope are generally available on the scope object on dialogs since
// 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;
// TODO: Lets fix this, it is less than ideal to be passing in the navigationController scope to something else to be used as it's scope,
// TODO: Remove this, this is not healthy
// it is less than ideal to be passing in the navigationController scope to something else to be used as it's scope,
// this is going to lead to problems/confusion. I really don't think passing scope's around is very good practice.
$rootScope.nav = navigationService;
@@ -37,7 +132,11 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
$scope.page.languageSelectorIsOpen = false;
$scope.currentSection = appState.getSectionState("currentSection");
$scope.customTreeParams = null;
$scope.treeCacheKey = "_";
$scope.showNavigation = appState.getGlobalState("showNavigation");
// tracks all expanded paths so when the language is switched we can resync it with the already loaded paths
var expandedPaths = [];
//trigger search with a hotkey:
keyboardService.bind("ctrl+shift+s", function () {
@@ -137,32 +236,86 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
languageResource.getAll().then(function(languages) {
$scope.languages = languages;
// select the default language
$scope.languages.forEach(function(language) {
if(language.isDefault) {
$scope.selectLanguage(language);
// make the default language selected
$scope.languages.forEach(function (language) {
if (language.isDefault) {
$scope.selectedLanguage = language;
}
});
});
}));
$scope.selectLanguage = function(language, languages) {
/**
* Updates the tree's query parameters
*/
function initTree() {
//create the custom query string param for this tree
var queryParams = {};
if ($scope.selectedLanguage && $scope.selectedLanguage.id) {
queryParams["languageId"] = $scope.selectedLanguage.id;
}
var queryString = $.param(queryParams); //create the query string from the params object
if (queryString) {
$scope.customTreeParams = queryString;
$scope.treeCacheKey = queryString; // this tree uses caching but we need to change it's cache key per lang
}
else {
$scope.treeCacheKey = "_"; // this tree uses caching, there's no lang selected so use the default
}
}
function nodeExpandedHandler(args) {
//store the reference to the expanded node path
if (args.node) {
treeService._trackExpandedPaths(args.node, expandedPaths);
}
}
$scope.selectLanguage = function(language) {
$scope.selectedLanguage = language;
// close the language selector
$scope.page.languageSelectorIsOpen = false;
initTree(); //this will reset the tree params and the tree directive will pick up the changes in a $watch
//execute after next digest because the internal watch on the customtreeparams needs to be bound now that we've changed it
$timeout(function () {
//reload the tree with it's updated querystring args
$scope.treeApi.load($scope.currentSection).then(function () {
//re-sync to currently edited node
var currNode = appState.getTreeState("selectedNode");
//create the list of promises
var promises = [];
//starting with syncing to the currently selected node if there is one
if (currNode) {
var path = treeService.getPath(currNode);
promises.push($scope.treeApi.syncTree({ path: path, activate: true }));
}
//TODO: If we want to keep all paths expanded ... but we need more testing since we need to deal with unexpanding
//for (var i = 0; i < expandedPaths.length; i++) {
// promises.push($scope.treeApi.syncTree({ path: expandedPaths[i], activate: false, forceReload: true }));
//}
//execute them sequentially
angularHelper.executeSequentialPromises(promises);
});
});
};
//this reacts to the options item in the tree
//todo, migrate to nav service
//TODO: migrate to nav service
//TODO: is this used?
$scope.searchShowMenu = function (ev, args) {
//always skip default
args.skipDefault = true;
navigationService.showMenu(ev, args);
navigationService.showMenu(args);
};
//todo, migrate to nav service
//TODO: migrate to nav service
//TODO: is this used?
$scope.searchHide = function () {
navigationService.hideSearch();
};
+23 -22
View File
@@ -1,31 +1,32 @@
/** Executed when the application starts, binds to events and set global state */
app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService', 'tourService', 'dashboardResource',
function (userService, $log, $rootScope, $location, queryStrings, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService, tourService, dashboardResource) {
app.run(['userService', '$q', '$log', '$rootScope', '$location', 'queryStrings', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService', 'tourService', 'dashboardResource',
function (userService, $q, $log, $rootScope, $location, queryStrings, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService, tourService, dashboardResource) {
//This sets the default jquery ajax headers to include our csrf token, we
// need to user the beforeSend method because our token changes per user/login so
// it cannot be static
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader("X-UMB-XSRF-TOKEN", $cookies["UMB-XSRF-TOKEN"]);
if (queryStrings.getParams().umbDebug === "true" || queryStrings.getParams().umbdebug === "true") {
xhr.setRequestHeader("X-UMB-DEBUG", "true");
}
if (queryStrings.getParams().umbDebug === "true" || queryStrings.getParams().umbdebug === "true") {
xhr.setRequestHeader("X-UMB-DEBUG", "true");
}
}
});
/** Listens for authentication and checks if our required assets are loaded, if/once they are we'll broadcast a ready event */
eventsService.on("app.authenticated", function(evt, data) {
assetsService._loadInitAssets().then(function() {
eventsService.on("app.authenticated", function (evt, data) {
// Loads the user's locale settings for Moment.
userService.loadMomentLocaleForCurrentUser().then(function() {
assetsService._loadInitAssets().then(function() {
$q.all([
userService.loadMomentLocaleForCurrentUser(),
tourService.registerAllTours()
]).then(function () {
//Register all of the tours on the server
tourService.registerAllTours().then(function () {
appReady(data);
// Auto start intro tour
tourService.getTourByAlias("umbIntroIntroduction").then(function (introTour) {
// start intro tour if it hasn't been completed or disabled
@@ -34,7 +35,8 @@ app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navi
}
});
}, function(){
}, function () {
appAuthenticated = true;
appReady(data);
});
});
@@ -50,7 +52,7 @@ app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navi
}
/** execute code on each successful route */
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
var deployConfig = Umbraco.Sys.ServerVariables.deploy;
var deployEnv, deployEnvTitle;
@@ -59,7 +61,7 @@ app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navi
deployEnvTitle = "(" + deployEnv + ") ";
}
if(current.params.section) {
if (current.params.section) {
//Uppercase the current section, content, media, settings, developer, forms
var currentSection = current.params.section.charAt(0).toUpperCase() + current.params.section.slice(1);
@@ -67,18 +69,18 @@ app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navi
var baseTitle = currentSection + " - " + $location.$$host;
//Check deploy for Global Umbraco.Sys obj workspace
if(deployEnv){
if (deployEnv) {
$rootScope.locationTitle = deployEnvTitle + baseTitle;
}
else {
$rootScope.locationTitle = baseTitle;
}
}
else {
if(deployEnv) {
$rootScope.locationTitle = deployEnvTitle + "Umbraco - " + $location.$$host;
if (deployEnv) {
$rootScope.locationTitle = deployEnvTitle + "Umbraco - " + $location.$$host;
}
$rootScope.locationTitle = "Umbraco - " + $location.$$host;
@@ -95,7 +97,7 @@ app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navi
/** When the route change is rejected - based on checkAuth - we'll prevent the rejected route from executing including
wiring up it's controller, etc... and then redirect to the rejected URL. */
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
$rootScope.$on('$routeChangeError', function (event, current, previous, rejection) {
event.preventDefault();
var returnPath = null;
@@ -111,13 +113,12 @@ app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navi
});
/* this will initialize the navigation service once the application has started */
navigationService.init();
//check for touch device, add to global appState
//var touchDevice = ("ontouchstart" in window || window.touch || window.navigator.msMaxTouchPoints === 5 || window.DocumentTouch && document instanceof DocumentTouch);
var touchDevice = /android|webos|iphone|ipad|ipod|blackberry|iemobile|touch/i.test(navigator.userAgent.toLowerCase());
var touchDevice = /android|webos|iphone|ipad|ipod|blackberry|iemobile|touch/i.test(navigator.userAgent.toLowerCase());
appState.setGlobalState("touchDevice", touchDevice);
}]);
+27 -27
View File
@@ -1,54 +1,56 @@
app.config(function ($routeProvider) {
/** This checks if the user is authenticated for a route and what the isRequired is set to.
Depending on whether isRequired = true, it first check if the user is authenticated and will resolve successfully
/**
* This determines if the route can continue depending on authentication and initialization requirements
* @param {boolean} authRequired If true, it first checks if the user is authenticated and will resolve successfully
otherwise the route will fail and the $routeChangeError event will execute, in that handler we will redirect to the rejected
path that is resolved from this method and prevent default (prevent the route from executing) */
var canRoute = function(isRequired) {
path that is resolved from this method and prevent default (prevent the route from executing)
* @param {boolean} navRequired if true, the route can only continue once the main navigation is ready
* @returns {promise}
*/
var canRoute = function(authRequired) {
return {
/** Checks that the user is authenticated, then ensures that are requires assets are loaded */
isAuthenticatedAndReady: function ($q, userService, $route, assetsService, appState) {
var deferred = $q.defer();
//don't need to check if we've redirected to login and we've already checked auth
if (!$route.current.params.section
&& ($route.current.params.check === false || $route.current.params.check === "false")) {
deferred.resolve(true);
return deferred.promise;
return $q.when(true);
}
userService.isAuthenticated()
return userService.isAuthenticated()
.then(function () {
assetsService._loadInitAssets().then(function() {
return assetsService._loadInitAssets().then(function () {
//This could be the first time has loaded after the user has logged in, in this case
// we need to broadcast the authenticated event - this will be handled by the startup (init)
// handler to set/broadcast the ready state
var broadcast = appState.getGlobalState("isReady") !== true;
userService.getCurrentUser({ broadcastEvent: broadcast }).then(function (user) {
return userService.getCurrentUser({ broadcastEvent: broadcast }).then(function (user) {
//is auth, check if we allow or reject
if (isRequired) {
if (authRequired) {
//This checks the current section and will force a redirect to 'content' as the default
if ($route.current.params.section.toLowerCase() === "default" || $route.current.params.section.toLowerCase() === "umbraco" || $route.current.params.section === "") {
$route.current.params.section = "content";
}
}
// U4-5430, Benjamin Howarth
// We need to change the current route params if the user only has access to a single section
// To do this we need to grab the current user's allowed sections, then reject the promise with the correct path.
if (user.allowedSections.indexOf($route.current.params.section) > -1) {
//this will resolve successfully so the route will continue
deferred.resolve(true);
return $q.when(true);
} else {
deferred.reject({ path: "/" + user.allowedSections[0] });
return $q.reject({ path: "/" + user.allowedSections[0] });
}
}
else {
deferred.reject({ path: "/" });
return $q.reject({ path: "/" });
}
});
@@ -56,17 +58,17 @@ app.config(function ($routeProvider) {
}, function () {
//not auth, check if we allow or reject
if (isRequired) {
if (authRequired) {
//the check=false is checked above so that we don't have to make another http call to check
//if they are logged in since we already know they are not.
deferred.reject({ path: "/login/false" });
return $q.reject({ path: "/login/false" });
}
else {
//this will resolve successfully so the route will continue
deferred.resolve(true);
return $q.when(true);
}
});
return deferred.promise;
}
};
};
@@ -75,15 +77,13 @@ app.config(function ($routeProvider) {
var doLogout = function() {
return {
isLoggedOut: function ($q, userService) {
var deferred = $q.defer();
userService.logout().then(function () {
return userService.logout().then(function () {
//success so continue
deferred.resolve(true);
return $q.when(true);
}, function() {
//logout failed somehow ? we'll reject with the login page i suppose
deferred.reject({ path: "/login/false" });
return $q.reject({ path: "/login/false" });
});
return deferred.promise;
}
}
}
@@ -8,7 +8,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
searchText = value + "...";
});
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
$scope.target = {};
$scope.searchInfo = {
searchFromId: null,
@@ -30,7 +30,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
entityResource.getPath(id, "Document").then(function (path) {
$scope.target.path = path;
//now sync the tree to this path
$scope.dialogTreeEventHandler.syncTree({ path: $scope.target.path, tree: "content" });
$scope.dialogTreeApi.syncTree({ path: $scope.target.path, tree: "content" });
});
}
@@ -40,7 +40,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
}
}
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -80,7 +80,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
}
}
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
if (angular.isArray(args.children)) {
//iterate children
@@ -138,12 +138,10 @@ angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
$scope.searchInfo.results = results;
$scope.searchInfo.showSearch = true;
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
});
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
});
@@ -46,7 +46,8 @@
<umb-tree section="content"
hideheader="true"
hideoptions="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
isdialog="true"
enablecheckboxes="true">
</umb-tree>
@@ -2,7 +2,7 @@
angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerController",
function($scope, eventsService, entityResource, searchService, $log) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
$scope.multiPicker = dialogOptions.multiPicker;
/** Method used for selecting a node */
@@ -16,7 +16,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerControlle
}
}
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -29,10 +29,9 @@ angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerControlle
//toggle checked state
args.node.selected = args.node.selected === true ? false : true;
}
function onTreeInit() {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
});
});
@@ -7,8 +7,9 @@
treealias="memberGroups"
hideheader="true"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
isdialog="true"
on-init="onTreeInit()"
api="dialogTreeApi"
enablecheckboxes="{{multiPicker}}">
</umb-tree>
</div>
@@ -31,4 +32,4 @@
</div>
</div>
</div>
</div>
</div>
@@ -4,7 +4,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
var tree = null;
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
$scope.section = dialogOptions.section;
$scope.treeAlias = dialogOptions.treeAlias;
$scope.multiPicker = dialogOptions.multiPicker;
@@ -138,7 +138,7 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
}
//gets the tree object when it loads
function treeLoadedHandler(ev, args) {
function treeLoadedHandler(args) {
tree = args.tree;
}
@@ -418,14 +418,11 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
$scope.searchInfo.showSearch = true;
};
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeLoaded(treeLoadedHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
$scope.dialogTreeEventHandler.bind("treeLoaded", treeLoadedHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeLoaded", treeLoadedHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
});
});
@@ -29,7 +29,8 @@
hideoptions="true"
isdialog="true"
customtreeparams="{{customTreeParams}}"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewsearch="true"
enablecheckboxes="{{multiPicker}}">
</umb-tree>
@@ -22,7 +22,7 @@
});
$scope.model.relateToOriginal = true;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
vm.searchInfo = {
searchFromId: null,
@@ -35,7 +35,7 @@
// get entity type based on the section
$scope.entityType = entityHelper.getEntityTypeFromSection(dialogOptions.section);
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
if(args && args.event) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -52,7 +52,7 @@
$scope.model.target.selected = true;
}
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
@@ -78,13 +78,11 @@
vm.searchInfo.showSearch = true;
}
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
});
// Mini list view
$scope.selectListViewNode = function (node) {
@@ -26,7 +26,8 @@
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
@@ -12,7 +12,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
$scope.model.title = localizationService.localize("defaultdialogs_selectLink");
}
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
$scope.model.target = {};
$scope.searchInfo = {
searchFromId: null,
@@ -38,7 +38,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
entityResource.getPath(id, "Document").then(function (path) {
$scope.model.target.path = path;
//now sync the tree to this path
$scope.dialogTreeEventHandler.syncTree({ path: $scope.model.target.path, tree: "content" });
$scope.dialogTreeApi.syncTree({ path: $scope.model.target.path, tree: "content" });
});
}
@@ -48,7 +48,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
}
}
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
if(args && args.event) {
args.event.preventDefault();
@@ -82,7 +82,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
}
}
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
@@ -131,14 +131,11 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
$scope.searchInfo.showSearch = true;
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
// Mini list view
$scope.selectListViewNode = function (node) {
node.selected = node.selected === true ? false : true;
@@ -52,7 +52,8 @@
section="content"
hideheader="true"
hideoptions="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
isdialog="true"
enablecheckboxes="true">
@@ -6,7 +6,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.MemberGroupPickerControll
$scope.model.title = localizationService.localize("defaultdialogs_selectMemberGroup");
}
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
$scope.multiPicker = $scope.model.multiPicker;
function activate() {
@@ -39,7 +39,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.MemberGroupPickerControll
}
}
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -52,13 +52,11 @@ angular.module("umbraco").controller("Umbraco.Overlays.MemberGroupPickerControll
//toggle checked state
args.node.selected = args.node.selected === true ? false : true;
}
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
};
activate();
});
@@ -5,7 +5,8 @@
hideheader="true"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablecheckboxes="{{model.multiPicker}}">
</umb-tree>
@@ -22,7 +22,7 @@
}
$scope.model.relateToOriginal = true;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
vm.searchInfo = {
searchFromId: null,
@@ -35,7 +35,7 @@
// get entity type based on the section
$scope.entityType = entityHelper.getEntityTypeFromSection(dialogOptions.section);
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
if(args && args.event) {
args.event.preventDefault();
@@ -54,7 +54,7 @@
}
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
@@ -80,13 +80,10 @@
vm.searchInfo.showSearch = true;
}
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
// Mini list view
$scope.selectListViewNode = function (node) {
@@ -25,7 +25,8 @@
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
@@ -23,10 +23,13 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
// Search and listviews is only working for content, media and member section
var searchableSections = ["content", "media", "member"];
// tracks all expanded paths so when the language is switched we can resync it with the already loaded paths
var expandedPaths = [];
var vm = this;
vm.treeReady = false;
vm.dialogTreeEventHandler = $({});
vm.treeReady = false;
vm.dialogTreeApi = {};
vm.initDialogTree = initDialogTree;
vm.section = $scope.model.section;
vm.treeAlias = $scope.model.treeAlias;
vm.multiPicker = $scope.model.multiPicker;
@@ -61,11 +64,18 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
vm.closeMiniListView = closeMiniListView;
vm.selectListViewNode = selectListViewNode;
function initDialogTree() {
vm.dialogTreeApi.callbacks.treeLoaded(treeLoadedHandler);
//TODO: Also deal with unexpanding!!
vm.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
vm.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
/**
* Performs the initialization of this component
*/
function onInit () {
function onInit () {
// load languages
languageResource.getAll().then(function (languages) {
vm.languages = languages;
@@ -97,14 +107,8 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
$scope.model.title = localizationService.localize("defaultdialogs_selectMedia");
}
}
//var searchText = "Search...";
//localizationService.localize("general_search").then(function (value) {
// searchText = value + "...";
//});
//min / max values
//TODO: Where are these used?
//TODO: Seems odd this logic is here, i don't think it needs to be and should just exist on the property editor using this
if ($scope.model.minNumber) {
$scope.model.minNumber = parseInt($scope.model.minNumber, 10);
}
@@ -188,14 +192,35 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
vm.selectedLanguage = language;
// close the language selector
vm.languageSelectorIsOpen = false;
initTree();
initTree(); //this will reset the tree params and the tree directive will pick up the changes in a $watch
//execute after next digest because the internal watch on the customtreeparams needs to be bound now that we've changed it
$timeout(function () {
//reload the tree with it's updated querystring args
vm.dialogTreeApi.load(vm.section).then(function () {
//create the list of promises
var promises = [];
for (var i = 0; i < expandedPaths.length; i++) {
promises.push(vm.dialogTreeApi.syncTree({ path: expandedPaths[i], activate: false }));
}
//execute them sequentially
angularHelper.executeSequentialPromises(promises);
});
});
};
function toggleLanguageSelector() {
vm.languageSelectorIsOpen = !vm.languageSelectorIsOpen;
};
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
//store the reference to the expanded node path
if (args.node) {
treeService._trackExpandedPaths(args.node, expandedPaths);
}
// open mini list view for list views
if (args.node.metaData.isContainer) {
@@ -225,7 +250,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
}
//gets the tree object when it loads
function treeLoadedHandler(ev, args) {
function treeLoadedHandler(args) {
//args.tree contains children (args.tree.root.children)
vm.hasItems = args.tree.root.children.length > 0;
@@ -233,7 +258,7 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
}
//wires up selection
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -578,17 +603,6 @@ angular.module("umbraco").controller("Umbraco.Overlays.TreePickerController",
function closeMiniListView() {
vm.miniListView = undefined;
}
vm.dialogTreeEventHandler.bind("treeLoaded", treeLoadedHandler);
vm.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
vm.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy',
function () {
vm.dialogTreeEventHandler.unbind("treeLoaded", treeLoadedHandler);
vm.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
vm.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
//initialize
onInit();
@@ -39,10 +39,11 @@
isdialog="true"
onlyinitialized="{{vm.onlyInitialized}}"
customtreeparams="{{vm.customTreeParams}}"
eventhandler="vm.dialogTreeEventHandler"
enablelistviewsearch="true"
enablelistviewexpand="true"
enablecheckboxes="{{vm.multiPicker}}">
enablecheckboxes="{{vm.multiPicker}}"
on-init="vm.initDialogTree()"
api="vm.dialogTreeApi">
</umb-tree>
</div>
@@ -16,11 +16,13 @@
</div>
<!-- the tree -->
<div id="tree" ng-if="authenticated">
<div id="tree" ng-show="authenticated">
<umb-tree
cachekey="_"
eventhandler="treeEventHandler"
section="{{currentSection}}">
cachekey="{{treeCacheKey}}"
api="treeApi"
on-init="onTreeInit()"
section="{{currentSection}}"
customtreeparams="{{customTreeParams}}">
</umb-tree>
</div>
</div>
@@ -49,4 +51,4 @@
</div>
</div>
</div>
</div>
@@ -9,7 +9,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
$scope.relateToOriginal = true;
$scope.recursive = true;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
$scope.busy = false;
$scope.searchInfo = {
searchFromId: null,
@@ -27,7 +27,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
var node = dialogOptions.currentNode;
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
if(args && args.event) {
args.event.preventDefault();
@@ -46,7 +46,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
}
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
@@ -110,13 +110,10 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
// Mini list view
$scope.selectListViewNode = function (node) {
@@ -7,7 +7,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
searchText = value + "...";
});
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
$scope.busy = false;
$scope.searchInfo = {
searchFromId: null,
@@ -25,7 +25,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
var node = dialogOptions.currentNode;
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
if(args && args.event) {
args.event.preventDefault();
@@ -44,7 +44,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
}
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
@@ -111,14 +111,11 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
// Mini list view
$scope.selectListViewNode = function (node) {
node.selected = node.selected === true ? false : true;
@@ -133,4 +130,4 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
$scope.miniListView = node;
}
});
});
@@ -51,7 +51,8 @@
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
@@ -90,4 +91,4 @@
<localize key="actions_copy">Copy</localize>
</button>
</div>
</div>
</div>
@@ -52,7 +52,8 @@
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
@@ -80,4 +81,4 @@
<localize key="actions_move">Move</localize>
</button>
</div>
</div>
</div>
@@ -2,9 +2,9 @@ angular.module("umbraco")
.controller("Umbraco.Editors.DataType.MoveController",
function ($scope, dataTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -60,9 +60,8 @@ angular.module("umbraco")
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
});
@@ -30,7 +30,8 @@
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablecheckboxes="true">
</umb-tree>
</div>
@@ -2,9 +2,9 @@ angular.module("umbraco")
.controller("Umbraco.Editors.DocumentTypes.CopyController",
function ($scope, contentTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -55,9 +55,9 @@ angular.module("umbraco")
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
});
@@ -31,7 +31,8 @@
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablecheckboxes="true">
</umb-tree>
</div>
@@ -2,9 +2,9 @@ angular.module("umbraco")
.controller("Umbraco.Editors.DocumentTypes.MoveController",
function ($scope, contentTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -60,9 +60,9 @@ angular.module("umbraco")
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
});
@@ -31,7 +31,8 @@
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablecheckboxes="true">
</umb-tree>
</div>
@@ -3,7 +3,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
function ($scope, userService, eventsService, mediaResource, appState, treeService, navigationService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
var node = dialogOptions.currentNode;
$scope.treeModel = {
@@ -13,7 +13,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
$scope.treeModel.hideHeader = userData.startMediaIds.length > 0 && userData.startMediaIds.indexOf(-1) == -1;
});
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
if(args && args.event) {
args.event.preventDefault();
@@ -31,15 +31,17 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
$scope.target.selected = true;
}
function nodeExpandedHandler(ev, args) {
function nodeExpandedHandler(args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
openMiniListView(args.node);
}
}
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
$scope.dialogTreeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
}
$scope.move = function () {
mediaResource.move({ parentId: $scope.target.id, id: node.id })
@@ -69,12 +71,7 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
$scope.error = err;
});
};
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
$scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
});
// Mini list view
$scope.selectListViewNode = function (node) {
node.selected = node.selected === true ? false : true;
@@ -89,4 +86,4 @@ angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
$scope.miniListView = node;
}
});
});
@@ -30,7 +30,8 @@
hideheader="{{treeModel.hideHeader}}"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
enablecheckboxes="true">
</umb-tree>
@@ -2,9 +2,9 @@ angular.module("umbraco")
.controller("Umbraco.Editors.MediaTypes.CopyController",
function ($scope, mediaTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -55,9 +55,8 @@ angular.module("umbraco")
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
});
@@ -31,7 +31,8 @@
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablecheckboxes="true">
</umb-tree>
</div>
@@ -3,9 +3,9 @@ angular.module("umbraco")
function ($scope, mediaTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.dialogTreeApi = {};
function nodeSelectHandler(ev, args) {
function nodeSelectHandler(args) {
args.event.preventDefault();
args.event.stopPropagation();
@@ -61,9 +61,9 @@ angular.module("umbraco")
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
$scope.onTreeInit = function () {
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
}
});
@@ -30,7 +30,8 @@
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
api="dialogTreeApi"
on-init="onTreeInit()"
enablecheckboxes="true">
</umb-tree>
</div>
-23
View File
@@ -216,13 +216,6 @@
<DependentUpon>sort.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Umbraco\Dialogs\Publish.aspx.cs">
<DependentUpon>publish.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Umbraco\Dialogs\Publish.aspx.designer.cs">
<DependentUpon>publish.aspx</DependentUpon>
</Compile>
<Compile Include="Umbraco\Masterpages\Default.Master.cs">
<DependentUpon>default.Master</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
@@ -406,17 +399,7 @@
<Content Include="Umbraco_client\Dialogs\SortDialog.js" />
<Content Include="Umbraco_Client\Dialogs\AssignDomain2.js" />
<Content Include="Umbraco_Client\Dialogs\AssignDomain2.css" />
<Content Include="Umbraco_Client\Dialogs\PublishDialog.css" />
<Content Include="Umbraco_Client\Dialogs\PublishDialog.js" />
<Content Include="Umbraco_Client\Dialogs\UmbracoField.js" />
<Content Include="Umbraco_Client\Editors\EditXslt.css" />
<Content Include="Umbraco_Client\Editors\EditXslt.js" />
<Content Include="Umbraco_Client\Editors\DirectoryBrowser.css" />
<Content Include="Umbraco_Client\Editors\EditMacro.css" />
<Content Include="Umbraco_Client\Editors\EditStyleSheet.js" />
<Content Include="Umbraco_Client\Editors\EditTemplate.js" />
<Content Include="Umbraco_Client\Editors\EditView.js" />
<Content Include="Umbraco_Client\PunyCode\punycode.min.js" />
<Content Include="Umbraco_Client\Splitbutton\InsertMacroSplitButton.js" />
<Content Include="Umbraco_Client\Tablesorting\img\asc.gif" />
<Content Include="Umbraco_Client\Tablesorting\img\desc.gif" />
@@ -454,10 +437,6 @@
<Content Include="Umbraco\Controls\Tree\TreeControl.ascx" />
<Content Include="Umbraco_Client\CodeArea\UmbracoEditor.js" />
<Content Include="default.aspx" />
<Content Include="Umbraco\Actions\delete.aspx" />
<Content Include="Umbraco\Actions\editContent.aspx" />
<Content Include="Umbraco\Actions\preview.aspx" />
<Content Include="Umbraco\Actions\publish.aspx" />
<Content Include="Umbraco\Config\Lang\da.xml" />
<Content Include="Umbraco\Config\Lang\de.xml" />
<Content Include="Umbraco\Config\Lang\es.xml" />
@@ -490,7 +469,6 @@
<Content Include="Umbraco\Dialogs\notifications.aspx" />
<Content Include="Umbraco\Developer\Packages\installer.aspx" />
<Content Include="Umbraco\Dialogs\protectPage.aspx" />
<Content Include="Umbraco\Dialogs\publish.aspx" />
<Content Include="Umbraco\Dialogs\rollBack.aspx" />
<Content Include="Umbraco\Dialogs\sendToTranslation.aspx" />
<Content Include="Umbraco\Dialogs\treePicker.aspx" />
@@ -613,7 +591,6 @@
<SubType>Form</SubType>
</Content>
<Content Include="Umbraco\Settings\EditDictionaryItem.aspx" />
<Content Include="Umbraco\Settings\editLanguage.aspx" />
<Content Include="Umbraco\Settings\Modals\ShowUmbracoTags.aspx" />
<Content Include="Umbraco\Settings\Stylesheet\editstylesheet.aspx" />
<Content Include="Umbraco\Settings\Stylesheet\Property\EditStyleSheetProperty.aspx" />
@@ -11,6 +11,7 @@
@using Umbraco.Web
@using Umbraco.Web.Editors
@using umbraco
@using Umbraco.Core.Configuration
@inherits System.Web.Mvc.WebViewPage<Umbraco.Web.Editors.BackOfficeModel>
@{
Layout = null;
@@ -25,7 +26,7 @@
<html lang="en">
<head>
<base href="@Model.Path.EnsureEndsWith('/')" />
<base href="@Model.GlobalSettings.Path.EnsureEndsWith('/')" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -59,7 +60,7 @@
redirectUrl = Url.Action("AuthorizeUpgrade", "BackOffice")
});
}
@Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features)
@Html.BareMinimumServerVariablesScript(Url, externalLoginUrl, Model.Features, Model.GlobalSettings)
<script type="text/javascript">
document.angularReady = function (app) {
@@ -37,7 +37,7 @@
<html lang="en">
<head>
<base href="@Model.Path.EnsureEndsWith('/')" />
<base href="@Model.GlobalSettings.Path.EnsureEndsWith('/')" />
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
@@ -64,7 +64,7 @@
<umb-navigation></umb-navigation>
<section id="contentwrapper">
<section id="contentwrapper" ng-if="navReady">
<div id="contentcolumn" ng-view></div>
</section>
@@ -1,30 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="../masterpages/umbracoPage.Master" CodeBehind="delete.aspx.cs" Inherits="umbraco.presentation.actions.delete" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<style type="text/css">
body{background-image: none !Important;}
</style>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="body" runat="server">
<cc1:UmbracoPanel ID="Panel2" runat="server" AutoResize="false" Width="500px" Height="200px" Text="Delete">
<asp:Panel ID="confirm" runat="server">
<cc1:Pane ID="pane_delete" runat="server">
<p><asp:Literal ID="warning" runat="server"></asp:Literal></p>
</cc1:Pane>
<p>
<asp:Button ID="deleteButton" runat="server" OnClick="deleteButton_Click" />
</p>
</asp:Panel>
<cc1:Pane ID="deleteMessage" runat="server" Visible="false">
<p><asp:Literal ID="deleted" runat="server"></asp:Literal></p>
</cc1:Pane>
</cc1:UmbracoPanel>
</asp:Content>
@@ -1,16 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="editContent.aspx.cs" Inherits="umbraco.presentation.actions.editContent" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
@@ -1,16 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="preview.aspx.cs" Inherits="umbraco.presentation.actions.preview" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Preview page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
@@ -1,30 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="../masterpages/umbracoPage.Master" CodeBehind="publish.aspx.cs" Inherits="umbraco.presentation.actions.publish" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %>
<asp:Content ContentPlaceHolderID="head" runat="server">
<style type="text/css">
body{background-image: none !Important;}
</style>
</asp:Content>
<asp:Content ContentPlaceHolderID="body" runat="server">
<cc1:UmbracoPanel ID="Panel2" Text="Publish" AutoResize="false" Width="500px" Height="200px" runat="server">
<asp:Panel ID="confirm" runat="server">
<cc1:Pane ID="pane_publish" runat="server">
<p>
<asp:Literal ID="warning" runat="server"></asp:Literal>
</p>
</cc1:Pane>
<br />
<p>
<asp:Button ID="deleteButton" runat="server" OnClick="deleteButton_Click" />
</p>
</asp:Panel>
<cc1:Pane ID="deleteMessage" runat="server" Visible="false">
<p><asp:Literal ID="deleted" runat="server"></asp:Literal></p>
</cc1:Pane>
</cc1:UmbracoPanel>
</asp:Content>
@@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web.UI.Umbraco.Dialogs
{
public partial class Publish : UmbracoEnsuredPage
{
protected string PageName { get; private set; }
protected int DocumentId { get; private set; }
protected string DocumentPath { get; private set; }
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
int id;
if (!int.TryParse(Request.GetItemAsString("id"), out id))
{
throw new InvalidOperationException("The id value must be an integer");
}
var doc = Services.ContentService.GetById(id);
if (doc == null)
{
throw new InvalidOperationException("No document found with id " + id);
}
DocumentId = doc.Id;
PageName = Server.HtmlEncode(doc.Name);
DocumentPath = doc.Path;
}
}
}
@@ -1,51 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Web.UI.Umbraco.Dialogs {
public partial class Publish {
/// <summary>
/// JsInclude1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::ClientDependency.Core.Controls.JsInclude JsInclude1;
/// <summary>
/// JsInclude2 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::ClientDependency.Core.Controls.JsInclude JsInclude2;
/// <summary>
/// CssInclude1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::ClientDependency.Core.Controls.CssInclude CssInclude1;
/// <summary>
/// ProgBar1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.ProgressBar ProgBar1;
}
}
@@ -1,98 +0,0 @@
<%@ Page Language="c#" MasterPageFile="../masterpages/umbracoDialog.Master" CodeBehind="Publish.aspx.cs" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.Dialogs.Publish" %>
<%@ Import Namespace="Umbraco.Core" %>
<%@ Import Namespace="Umbraco.Web" %>
<%@ Import Namespace="Umbraco.Web.Mvc" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="js/umbracoCheckKeys.js" PathNameAlias="UmbracoRoot" />
<umb:JsInclude ID="JsInclude2" runat="server" FilePath="Dialogs/PublishDialog.js" PathNameAlias="UmbracoClient" />
<umb:CssInclude ID="CssInclude1" runat="server" FilePath="Dialogs/PublishDialog.css" PathNameAlias="UmbracoClient" />
<script type="text/javascript">
//NOTE: These variables are required for the legacy UmbracoCheckKeys.js
var functionsFrame = this;
var tabFrame = this;
var isDialog = true;
var submitOnEnter = true;
(function ($) {
$(document).ready(function () {
Umbraco.Dialogs.PublishDialog.getInstance().init({
restServiceLocation: "<%= Url.GetBulkPublishServicePath() %>",
documentId: <%= DocumentId %>,
documentPath: '<%= DocumentPath %>'
});
});
})(jQuery);
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="body" runat="server">
<div id="container" >
<div class="propertyDiv" data-bind="visible: processStatus() == 'init'">
<p>
<%= Services.TextService.Localize("publish/publishHelp", new[] { PageName}) %>
</p>
<div>
<input type="checkbox" id="publishAllCheckBox" data-bind="checked: publishAll" />
<label for="publishAllCheckBox">
<%=Services.TextService.Localize("publish/publishAll", new[] { PageName}) %>
</label>
</div>
<div id="includeUnpublished">
<input type="checkbox" id="includeUnpublishedCheckBox" data-bind="checked: includeUnpublished, attr: { disabled: !publishAll() }" />
<label for="includeUnpublishedCheckBox" data-bind="css: { disabled: !publishAll() }">
<%=Services.TextService.Localize("publish/includeUnpublished") %>
</label>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" data-bind="visible: processStatus() == 'init'">
<a href="#" class="btn btn-link" data-bind="click: closeDialog">
<%=Services.TextService.Localize("general/cancel")%>
</a>
<button id="ok" class="btn btn-primary" data-bind="click: startPublish">
<%=Services.TextService.Localize("content/publish")%>
</button>
</div>
<div id="animDiv" class="propertyDiv" data-bind="visible: processStatus() == 'publishing'">
<div>
<p>
<%=Services.TextService.Localize("publish/inProgress")%>
</p>
<cc1:ProgressBar runat="server" ID="ProgBar1" />
<br />
</div>
</div>
<div id="feedbackMsg" data-bind="visible: processStatus() == 'complete'">
<div data-bind="css: { success: isSuccessful(), error: !isSuccessful() }">
<span data-bind="text: resultMessage, visible: resultMessages().length == 0"></span>
<ul data-bind="foreach: resultMessages, visible: resultMessages().length > 1">
<li data-bind="text: message"></li>
</ul>
</div>
<p>
<a href='#' class="btn" data-bind="click: closeDialog"><%=Services.TextService.Localize("closeThisWindow") %></a>
</p>
</div>
</div>
</asp:Content>
@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Umbraco.Web.UI.Umbraco.Settings
{
public partial class EditTemplate : global::umbraco.cms.presentation.settings.editTemplate
{
}
}
@@ -1,24 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Web.UI.Umbraco.Settings {
public partial class EditTemplate {
/// <summary>
/// JsInclude1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::ClientDependency.Core.Controls.JsInclude JsInclude1;
}
}
@@ -1,19 +0,0 @@
<%@ Page Language="c#" CodeBehind="editLanguage.aspx.cs" AutoEventWireup="True" MasterPageFile="../masterpages/umbracoPage.Master"
Inherits="umbraco.settings.editLanguage" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %>
<asp:Content ContentPlaceHolderID="body" runat="server">
<cc1:UmbracoPanel ID="Panel1" runat="server" Width="608px" Height="336px" hasMenu="true">
<cc1:Pane ID="Pane7" runat="server">
<cc1:PropertyPanel runat="server" ID="pp_language">
<asp:DropDownList ID="Cultures" runat="server">
</asp:DropDownList>
</cc1:PropertyPanel>
</cc1:Pane>
</cc1:UmbracoPanel>
<script type="text/javascript">
jQuery(document).ready(function () {
UmbClientMgr.appActions().bindSaveShortCut();
});
</script>
</asp:Content>
@@ -1,167 +0,0 @@
<%@ Page MasterPageFile="../masterpages/umbracoPage.Master" Language="c#" CodeBehind="EditTemplate.aspx.cs"
ValidateRequest="false" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.Settings.EditTemplate" %>
<%@ OutputCache Location="None" %>
<%@ Import Namespace="Umbraco.Core" %>
<%@ Import Namespace="Umbraco.Core.Configuration" %>
<%@ Import Namespace="Umbraco.Core.IO" %>
<%@ Import Namespace="Umbraco.Web.Mvc" %>
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
<asp:Content ID="DocTypeContent" ContentPlaceHolderID="DocType" runat="server">
<!DOCTYPE html>
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<umb:CssInclude ID="CssInclude1" runat="server" FilePath="splitbutton/splitbutton.css" PathNameAlias="UmbracoClient" />
<umb:JsInclude ID="JsInclude" runat="server" FilePath="splitbutton/jquery.splitbutton.js" PathNameAlias="UmbracoClient" />
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="Editors/EditTemplate.js" PathNameAlias="UmbracoClient" />
<script type="text/javascript">
jQuery(document).ready(function() {
//create the editor
var editor = new Umbraco.Editors.EditTemplate({
templateAliasClientId: '<%= AliasTxt.ClientID %>',
templateNameClientId: '<%= NameTxt.ClientID %>',
saveButton: $("#<%= ((Control)SaveButton).ClientID %>"),
restServiceLocation: "<%= Url.GetSaveFileServicePath() %>",
umbracoPath: '<%= IOHelper.ResolveUrl(SystemDirectories.Umbraco) %>',
editorClientId: '<%= editorSource.ClientID %>',
useMasterPages: <%=UmbracoConfig.For.UmbracoSettings().Templates.UseAspNetMasterPages.ToString().ToLower()%>,
templateId: <%= Request.QueryString["templateID"] %>,
masterTemplateId: jQuery('#<%= MasterTemplate.ClientID %>').val(),
masterPageDropDown: $("#<%= MasterTemplate.ClientID %>"),
treeSyncPath: '<%=TemplateTreeSyncPath%>',
text: {
templateErrorHeader: "<%= HttpUtility.JavaScriptStringEncode(Services.TextService.Localize("speechBubbles/templateErrorHeader")) %>",
templateSavedHeader: "<%= HttpUtility.JavaScriptStringEncode(Services.TextService.Localize("speechBubbles/templateSavedHeader")) %>",
templateErrorText: "<%= HttpUtility.JavaScriptStringEncode(Services.TextService.Localize("speechBubbles/templateErrorText")) %>",
templateSavedText: "<%= HttpUtility.JavaScriptStringEncode(Services.TextService.Localize("speechBubbles/templateSavedText")) %>"
}
});
editor.init();
});
//TODO: the below should be refactored into being part of the EditTemplate.js class but have left it here for now since i don't have time.
function umbracoTemplateInsertMasterPageContentContainer() {
var master = document.getElementById('<%= MasterTemplate.ClientID %>')[document.getElementById('<%= MasterTemplate.ClientID %>').selectedIndex].value;
if (master == "") master = 0;
umbraco.presentation.webservices.legacyAjaxCalls.TemplateMasterPageContentContainer(<%=Request["templateID"] %>, master, umbracoTemplateInsertMasterPageContentContainerDo);
}
function umbracoTemplateInsertMasterPageContentContainerDo(result) {
UmbEditor.Insert(result + '\n', '\n</asp\:Content>\n', '<%= editorSource.ClientID%>');
}
function changeMasterPageFile() {
var editor = document.getElementById("<%= editorSource.ClientID %>");
var templateDropDown = document.getElementById("<%= MasterTemplate.ClientID %>");
var templateCode = UmbEditor.GetCode();
var selectedTemplate = templateDropDown.options[templateDropDown.selectedIndex].id;
var masterTemplate = "<%= Umbraco.Core.IO.SystemDirectories.Masterpages%>/" + selectedTemplate + ".master";
if (selectedTemplate == "")
masterTemplate = "<%= Umbraco.Core.IO.SystemDirectories.Umbraco%>/masterpages/default.master";
var regex = /MasterPageFile=[~a-z0-9/._"-]+/im;
if (templateCode.match(regex)) {
templateCode = templateCode.replace(regex, 'MasterPageFile="' + masterTemplate + '"');
UmbEditor.SetCode(templateCode);
}
else {
//todo, spot if a directive is there, and if not suggest that the user inserts it..
alert("Master directive not found...");
return false;
}
}
function insertContentElement(id) {
//nasty hack to avoid asp.net freaking out because of the markup...
var cp = 'asp:Content ContentPlaceHolderId="' + id + '"';
cp += ' runat="server"';
cp += '>\n\t<!-- Insert "' + id + '" markup here -->';
UmbEditor.Insert('\n<' + cp, '\n</asp:Content' + '>\n', '<%= editorSource.ClientID %>');
}
function insertPlaceHolderElement(id) {
var cp = 'asp:ContentPlaceHolder Id="' + id + '"';
cp += ' runat="server"';
cp += '>\n\t<!-- Insert default "' + id + '" markup here -->';
UmbEditor.Insert('\n<' + cp, '\n</asp:ContentPlaceHolder' + '>\n', '<%= editorSource.ClientID %>');
}
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="body" runat="server">
<cc1:TabView ID="Panel1" runat="server" hasMenu="true">
<cc1:Pane ID="Pane7" runat="server">
<cc1:PropertyPanel ID="pp_name" runat="server">
<asp:TextBox ID="NameTxt" runat="server"></asp:TextBox>
</cc1:PropertyPanel>
<cc1:PropertyPanel ID="pp_alias" runat="server">
<asp:TextBox ID="AliasTxt" runat="server"></asp:TextBox>
</cc1:PropertyPanel>
<cc1:PropertyPanel ID="pp_masterTemplate" runat="server">
<asp:DropDownList ID="MasterTemplate" runat="server" />
</cc1:PropertyPanel>
</cc1:Pane>
<cc1:Pane ID="Pane8" runat="server">
<cc1:PropertyPanel ID="pp_source" runat="server">
<cc1:CodeArea ID="editorSource" runat="server" CodeBase="HtmlMixed" EditorMimeType="text/html" ClientSaveMethod="doSubmit"
AutoResize="false" />
</cc1:PropertyPanel>
</cc1:Pane>
</cc1:TabView>
<div id="splitButton" style="display: inline; height: 23px; vertical-align: top;">
<a href="#" id="sb" class="sbLink">
<img alt="Insert Inline Razor Macro" src="../images/editor/insRazorMacro.png" title="Insert Inline Razor Macro"
style="vertical-align: top;">
</a>
</div>
<div id="codeTemplateMenu" style="width: 285px;">
<asp:Repeater ID="rpt_codeTemplates" runat="server">
<ItemTemplate>
<div class="codeTemplate" rel="<%# DataBinder.Eval(Container, "DataItem.Key") %>">
<%# DataBinder.Eval(Container, "DataItem.Value") %>
</div>
</ItemTemplate>
</asp:Repeater>
</div>
<div id="splitButtonMacro" style="display: inline; height: 23px; vertical-align: top;">
<a href="#" id="sbMacro" class="sbLink">
<img alt="Insert Macro" src="../images/editor/insMacroSB.png" title="Insert Macro"
style="vertical-align: top;">
</a>
</div>
<div id="macroMenu" style="width: 285px">
<asp:Repeater ID="rpt_macros" runat="server">
<ItemTemplate>
<div class="macro" rel="<%# Eval("macroAlias") %>"
params="<%# DoesMacroHaveSettings(Eval("id").ToString()) %>">
<%# Eval("macroName")%>
</div>
</ItemTemplate>
</asp:Repeater>
</div>
<script type="text/javascript">
jQuery(document).ready(function () {
UmbClientMgr.appActions().bindSaveShortCut();
});
</script>
</asp:Content>
@@ -1,27 +0,0 @@
#includeUnpublished {
margin-left: 16px;
margin-bottom: 20px;
margin-top: 5px;
}
#animDiv > div {
margin-left:auto;
margin-right:auto;
}
#container label{
display: inline;
}
.disabled {
color: #999;
}
#feedbackMsg > div {
padding: 5px;
}
#feedbackMsg ul {
margin: 0;
padding-left: 15px;
}
@@ -1,98 +0,0 @@
Umbraco.Sys.registerNamespace("Umbraco.Dialogs");
(function ($) {
Umbraco.Dialogs.PublishDialog = base2.Base.extend({
//private methods/variables
_opts: null,
_koViewModel: null,
// Constructor
constructor: function () {
},
//public methods
init: function (opts) {
/// <summary>Initializes the class and any UI bindings</summary>
// Merge options with default
this._opts = $.extend({
}, opts);
var self = this;
//The knockout js view model for the selected item
self._koViewModel = {
publishAll: ko.observable(false),
includeUnpublished: ko.observable(false),
processStatus: ko.observable("init"),
isSuccessful: ko.observable(false),
resultMessages: ko.observableArray(),
resultMessage: ko.observable(""), //if there's only one result message
closeDialog: function () {
UmbClientMgr.closeModalWindow();
},
startPublish: function() {
this.processStatus("publishing");
$.post(self._opts.restServiceLocation + "PublishDocument",
JSON.stringify({
documentId: self._opts.documentId,
publishDescendants: self._koViewModel.publishAll(),
includeUnpublished: self._koViewModel.includeUnpublished()
}),
function (e) {
self._koViewModel.processStatus("complete");
self._koViewModel.isSuccessful(e.success);
var msgs = e.message.trim().split("\r\n");
if (msgs.length > 1) {
for (var m in msgs) {
self._koViewModel.resultMessages.push({ message: msgs[m] });
}
}
else {
self._koViewModel.resultMessage(msgs[0]);
}
//sync the tree
UmbClientMgr.mainTree().setActiveTreeType('content');
UmbClientMgr.mainTree().syncTree(self._opts.documentPath, true);
});
}
};
//ensure includeUnpublished is always false if publishAll is ever false
self._koViewModel.publishAll.subscribe(function (newValue) {
if (newValue === false) {
self._koViewModel.includeUnpublished(false);
}
});
ko.applyBindings(self._koViewModel);
}
}, {
//Static members
//private methods/variables
_instance: null,
// Singleton accessor
getInstance: function () {
if (this._instance == null)
this._instance = new Umbraco.Dialogs.PublishDialog();
return this._instance;
}
});
//Set defaults for jQuery ajax calls.
$.ajaxSetup({
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8'
});
})(jQuery);
@@ -1,28 +0,0 @@
a
{
color: #3C6B96;
}
.tdDir a
{
color: #3C6B96;
padding: 3px;
padding-left: 25px;
background: url(../../umbraco/images/foldericon.png) no-repeat 2px 2px;
}
.tdFile a
{
color: #3C6B96;
padding: 3px;
padding-left: 25px;
background: url(../../umbraco/images/file.png) no-repeat 2px 2px;
}
small a
{
color: #999;
padding-left: 3px !Important;
background-image: none !Important;
text-decoration: none;
}
@@ -1,36 +0,0 @@
table.macro-props {
width: 98%;
border: 0;
}
table.macro-props td {
padding: 4px;
}
table.macro-props td.propertyHeader {
width: 200px;
vertical-align: middle;
}
table.macro-props td.propertyContent {
vertical-align: middle;
}
table.macro-props td.propertyContent .guiInputText {
width: 300px;
}
table.macro-props td.propertyContent .guiInputText.small
{
width: 60px;
display: inline-block;
}
table.macro-props.params td.propertyHeader
{
width: 25%;
}
table.macro-props.params td.propertyContent input,
table.macro-props.params td.propertyContent select
{
width: 90%;
}
table.macro-props.params td.propertyContent input[type=submit] {
width: 100px;
}
@@ -1,109 +0,0 @@
Umbraco.Sys.registerNamespace("Umbraco.Editors");
(function ($) {
Umbraco.Editors.EditStyleSheet = base2.Base.extend({
//private methods/variables
_opts: null,
// Constructor
constructor: function(opts) {
// Merge options with default
this._opts = $.extend({
// Default options go here
}, opts);
},
init: function() {
//setup UI elements
var self = this;
//bind to the save event
this._opts.saveButton.click(function (event) {
event.preventDefault();
self.doSubmit();
});
},
doSubmit: function() {
var self = this;
var filename = this._opts.nameTxtBox.val();
var codeval = this._opts.editorSourceElement.val();
//if CodeMirror is not defined, then the code editor is disabled.
if (typeof(CodeMirror) != "undefined") {
codeval = UmbEditor.GetCode();
}
this.save(
filename,
self._opts.originalFileName,
codeval);
},
save: function (filename, oldName, contents) {
var self = this;
$.post(self._opts.restServiceLocation + "SaveStylesheet",
JSON.stringify({
filename: filename,
oldName: oldName,
contents: contents
}),
function (e) {
if (e.success) {
self.submitSuccess(e);
} else {
self.submitFailure(e.message, e.header);
}
});
},
submitSuccess: function (args) {
var msg = args.message;
var header = args.header;
var path = this._opts.treeSyncPath;
var pathChanged = false;
if (args.path) {
if (path != args.path) {
pathChanged = true;
}
path = args.path;
}
if (args.contents) {
UmbEditor.SetCode(args.contents);
}
UmbClientMgr.mainTree().setActiveTreeType("stylesheets");
if (pathChanged) {
// file is used in url so we need to redirect
var qs = window.location.search;
if (qs.startsWith("?")) qs = qs.substring("?".length);
var qp1 = qs.split("&");
var qp2 = [];
for (var i = 0; i < qp1.length; i++)
if (!qp1[i].startsWith("id="))
qp2.push(qp1[i]);
var location = window.location.pathname + "?" + qp2.join("&") + "&id=" + args.name;
UmbClientMgr.contentFrame(location);
// need to do it after we navigate otherwise the navigation waits until the message timeout is done
top.UmbSpeechBubble.ShowMessage("save", header, msg);
}
else {
top.UmbSpeechBubble.ShowMessage("save", header, msg);
this._opts.lttPathElement.prop("href", args.url).html(args.url);
this._opts.originalFileName = args.name;
this._opts.treeSyncPath = args.path;
UmbClientMgr.mainTree().syncTree(path, true);
}
},
submitFailure: function(err, header) {
top.UmbSpeechBubble.ShowMessage('error', header, err);
}
});
})(jQuery);
@@ -1,181 +0,0 @@
Umbraco.Sys.registerNamespace("Umbraco.Editors");
(function ($) {
Umbraco.Editors.EditTemplate = base2.Base.extend({
//private methods/variables
_opts: null,
_openMacroModal: function(alias) {
var self = this;
UmbClientMgr.openAngularModalWindow({
template: "views/common/dialogs/insertmacro.html",
dialogData: {
renderingEngine: "WebForms",
macroData: { macroAlias: alias }
},
callback: function(data) {
UmbEditor.Insert(data.syntax, '', self._opts.editorClientId);
}
});
},
_insertMacro: function(alias) {
var macroElement = "umbraco:Macro";
if (!this._opts.useMasterPages) {
macroElement = "?UMBRACO_MACRO";
}
var cp = macroElement + ' Alias="' + alias + '" runat="server"';
UmbEditor.Insert('<' + cp + ' />', '', this._opts.editorClientId);
},
_insertCodeBlockFromTemplate: function(templateId) {
var self = this;
$.ajax({
type: "POST",
url: this._opts.umbracoPath + "/webservices/templates.asmx/GetCodeSnippet",
data: "{templateId: '" + templateId + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
var cp = 'umbraco:Macro runat="server" language="cshtml"';
UmbEditor.Insert('\n<' + cp + '>\n' + msg.d, '\n</umbraco:Macro' + '>\n', self._opts.editorClientId);
}
});
},
_insertCodeBlock: function() {
var snip = this._umbracoInsertSnippet();
UmbEditor.Insert(snip.BeginTag, snip.EndTag, this._opts.editorClientId);
},
_umbracoInsertSnippet: function() {
var snip = new UmbracoCodeSnippet();
var cp = 'umbraco:Macro runat="server" language="cshtml"';
snip.BeginTag = '\n<' + cp + '>\n';
snip.EndTag = '\n<' + '/umbraco:Macro' + '>\n';
snip.TargetId = this._opts.editorClientId;
return snip;
},
// Constructor
constructor: function(opts) {
// Merge options with default
this._opts = $.extend({
// Default options go here
}, opts);
},
init: function() {
//<summary>Sets up the UI and binds events</summary>
var self = this;
//bind to the save event
this._opts.saveButton.click(function (event) {
event.preventDefault();
self.doSubmit();
});
$("#sb").click(function() {
self._insertCodeBlock();
});
$("#sbMacro").click(function() {
self._openMacroModal();
});
//macro split button
$('#sbMacro').splitbutton({ menu: '#macroMenu' });
$("#splitButtonMacro").appendTo("#splitButtonMacroPlaceHolder");
////razor macro split button
$('#sb').splitbutton({ menu: '#codeTemplateMenu' });
$("#splitButton").appendTo("#splitButtonPlaceHolder");
$(".macro").click(function() {
var alias = $(this).attr("rel");
if ($(this).attr("params") == "1") {
self._openMacroModal(alias);
}
else {
self._insertMacro(alias);
}
});
$(".codeTemplate").click(function() {
self._insertCodeBlockFromTemplate($(this).attr("rel"));
});
},
doSubmit: function() {
this.save(jQuery('#' + this._opts.templateNameClientId).val(), jQuery('#' + this._opts.templateAliasClientId).val(), UmbEditor.GetCode());
},
save: function(templateName, templateAlias, codeVal) {
var self = this;
$.post(self._opts.restServiceLocation + "SaveTemplate",
JSON.stringify({
templateName: templateName,
templateAlias: templateAlias,
templateContents: codeVal,
templateId: self._opts.templateId,
masterTemplateId: this._opts.masterPageDropDown.val()
}),
function (e) {
if (e.success) {
self.submitSuccess(e);
} else {
self.submitFailure(e.message, e.header);
}
});
},
submitSuccess: function (args) {
var msg = args.message;
var header = args.header;
var path = this._opts.treeSyncPath;
var pathChanged = false;
if (args.path) {
if (path != args.path) {
pathChanged = true;
}
path = args.path;
}
if (args.contents) {
UmbEditor.SetCode(args.contents);
}
var alias = args.alias;
this._opts.aliasTxtBox.val(alias);
top.UmbSpeechBubble.ShowMessage('save', header, msg);
UmbClientMgr.mainTree().setActiveTreeType('templates');
if (pathChanged) {
UmbClientMgr.mainTree().moveNode(this._opts.templateId, path);
}
else {
UmbClientMgr.mainTree().syncTree(path, true);
}
},
submitFailure: function (err, header) {
top.UmbSpeechBubble.ShowMessage('error', header, err);
}
});
//Set defaults for jQuery ajax calls.
$.ajaxSetup({
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8'
});
})(jQuery);
@@ -1,288 +0,0 @@
Umbraco.Sys.registerNamespace("Umbraco.Editors");
(function ($) {
Umbraco.Editors.EditView = base2.Base.extend({
/// <summary>Defines the EditView class to controll the persisting of the view file and UI interaction</summary>
//private methods/variables
_opts: null,
// Constructor
constructor: function (opts) {
// Merge options with default
this._opts = $.extend({
// Default options go here
}, opts);
},
//public methods/variables
init: function () {
var self = this;
//bind to the change of the master template drop down
this._opts.masterPageDropDown.change(function () {
self.changeMasterPageFile();
});
//bind to the save event
this._opts.saveButton.click(function (event) {
event.preventDefault();
self.doSubmit();
});
},
insertMacroMarkup: function(alias) {
/// <summary>callback used to insert the markup for a macro with no parameters</summary>
UmbEditor.Insert("@Umbraco.RenderMacro(\"" + alias + "\")", "", this._opts.codeEditorElementId);
},
insertRenderBody: function() {
UmbEditor.Insert("@RenderBody()", "", this._opts.codeEditorElementId);
},
openMacroModal: function (alias) {
/// <summary>callback used to display the modal dialog to insert a macro with parameters</summary>
var self = this;
UmbClientMgr.openAngularModalWindow({
template: "views/common/dialogs/insertmacro.html",
dialogData: {
renderingEngine: "Mvc",
macroData: {macroAlias: alias}
},
callback: function (data) {
UmbEditor.Insert(data.syntax, '', self._opts.codeEditorElementId);
}
});
},
openSnippetModal: function (type) {
/// <summary>callback used to display the modal dialog to insert a macro with parameters</summary>
var self = this;
UmbClientMgr.openAngularModalWindow({
template: "views/common/dialogs/template/snippet.html",
callback: function (data) {
var code = "";
if (type === 'section') {
code = "\n@section " + data.name + "{\n";
code += "<!-- Content here -->\n" +
"}\n";
}
if (type === 'rendersection') {
if (data.required) {
code = "\n@RenderSection(\"" + data.name + "\", true)\n";
} else {
code = "\n@RenderSection(\"" + data.name + "\", false)\n";
}
}
UmbEditor.Insert(code, '', self._opts.codeEditorElementId);
},
type: type
});
},
openQueryModal: function () {
/// <summary>callback used to display the modal dialog to insert a macro with parameters</summary>
var self = this;
UmbClientMgr.openAngularModalWindow({
template: "views/common/dialogs/template/queryBuilder.html",
callback: function (data) {
//var dataFormatted = data.replace(new RegExp('[' + "." + ']', 'g'), "\n\t\t\t\t\t.");
var code = "\n@{\n" + "\tvar selection = " + data + ";\n}\n";
code += "<ul>\n" +
"\t@foreach(var item in selection){\n" +
"\t\t<li>\n" +
"\t\t\t<a href=\"@item.Url\">@item.Name</a>\n" +
"\t\t</li>\n" +
"\t}\n" +
"</ul>\n\n";
UmbEditor.Insert(code, '', self._opts.codeEditorElementId);
}
});
},
doSubmit: function () {
/// <summary>Submits the data to the server for saving</summary>
var codeVal = UmbClientMgr.contentFrame().UmbEditor.GetCode();
var self = this;
if (this._opts.editorType == "Template") {
//saving a template view
$.post(self._opts.restServiceLocation + "SaveTemplate",
JSON.stringify({
templateName: this._opts.nameTxtBox.val(),
templateAlias: this._opts.aliasTxtBox.val(),
templateContents: codeVal,
templateId: this._opts.templateId,
masterTemplateId: this._opts.masterPageDropDown.val()
}),
function(e) {
if (e.success) {
self.submitSuccess(e);
} else {
self.submitFailure(e.message, e.header);
}
});
}
else {
//saving a partial view
var actionName = this._opts.editorType === "PartialViewMacro" ? "SavePartialViewMacro" : "SavePartialView";
$.post(self._opts.restServiceLocation + actionName,
JSON.stringify({
filename: this._opts.nameTxtBox.val(),
oldName: this._opts.originalFileName,
contents: codeVal
}),
function(e) {
if (e.success) {
self.submitSuccess(e);
} else {
self.submitFailure(e.message, e.header);
}
});
}
},
submitSuccess: function (args) {
var msg = args.message;
var header = args.header;
var path = this._opts.treeSyncPath;
var pathChanged = false;
if (args.path) {
if (path != args.path) {
pathChanged = true;
}
path = args.path;
}
if (args.contents) {
UmbEditor.SetCode(args.contents);
} else if (!this.IsSimpleEditor) {
// Restore focuse to text region. SetCode also does this.
UmbEditor._editor.focus();
}
UmbClientMgr.mainTree().setActiveTreeType(this._opts.currentTreeType);
if (this._opts.editorType == "Template") {
var alias = args.alias;
this._opts.aliasTxtBox.val(alias);
top.UmbSpeechBubble.ShowMessage('save', header, msg);
//templates are different because they are ID based, whereas view files are file based without a static id
if (pathChanged) {
UmbClientMgr.mainTree().moveNode(this._opts.templateId, path);
this._opts.treeSyncPath = path;
}
else {
UmbClientMgr.mainTree().syncTree(path, true);
}
}
else {
var newFilePath = this._opts.nameTxtBox.val();
function trimStart(str, trim) {
if (str.startsWith(trim)) {
return str.substring(trim.length);
}
return str;
}
//if the filename changes, we need to redirect since the file name is used in the url
if (this._opts.originalFileName != newFilePath) {
var queryParts = trimStart(window.location.search, "?").split('&');
var notFileParts = [];
for (var i = 0; i < queryParts.length; i++) {
if (queryParts[i].substr(0, "file=".length) != "file=") {
notFileParts.push(queryParts[i]);
}
}
var newLocation = window.location.pathname + "?" + notFileParts.join("&") + "&file=" + newFilePath;
UmbClientMgr.contentFrame(newLocation);
//we need to do this after we navigate otherwise the navigation will wait unti lthe message timeout is done!
top.UmbSpeechBubble.ShowMessage('save', header, msg);
}
else {
top.UmbSpeechBubble.ShowMessage('save', header, msg);
if (args && args.name) {
this._opts.originalFileName = args.name;
}
if (args && args.path) {
this._opts.treeSyncPath = args.path;
}
UmbClientMgr.mainTree().syncTree(path, true, null, newFilePath.split("/")[1]);
}
}
},
submitFailure: function (err, header) {
top.UmbSpeechBubble.ShowMessage('error', header, err);
},
changeMasterPageFile: function ( ) {
//var editor = document.getElementById(this._opts.sourceEditorId);
var templateDropDown = this._opts.masterPageDropDown.get(0);
var templateCode = UmbClientMgr.contentFrame().UmbEditor.GetCode();
var newValue = templateDropDown.options[templateDropDown.selectedIndex].id;
var layoutDefRegex = new RegExp("(@{[\\s\\S]*?Layout\\s*?=\\s*?)(\"[^\"]*?\"|null)(;[\\s\\S]*?})", "gi");
if (newValue != undefined && newValue != "") {
if (layoutDefRegex.test(templateCode)) {
// Declaration exists, so just update it
templateCode = templateCode.replace(layoutDefRegex, "$1\"" + newValue + "\"$3");
} else {
// Declaration doesn't exist, so prepend to start of doc
//TODO: Maybe insert at the cursor position, rather than just at the top of the doc?
templateCode = "@{\n\tLayout = \"" + newValue + "\";\n}\n" + templateCode;
}
} else {
if (layoutDefRegex.test(templateCode)) {
// Declaration exists, so just update it
templateCode = templateCode.replace(layoutDefRegex, "$1null$3");
}
}
UmbClientMgr.contentFrame().UmbEditor.SetCode(templateCode);
return false;
}
});
//Set defaults for jQuery ajax calls.
$.ajaxSetup({
dataType: 'json',
cache: false,
contentType: 'application/json; charset=utf-8'
});
})(jQuery);
@@ -1,14 +0,0 @@
#errorDiv
{
margin-bottom: 10px;
}
#errorDiv a
{
float: right;
}
.propertyItemheader
{
width: 200px !important;
}
@@ -1,80 +0,0 @@
Umbraco.Sys.registerNamespace("Umbraco.Editors");
(function ($) {
Umbraco.Editors.EditXslt = base2.Base.extend({
//private methods/variables
_opts: null,
// Constructor
constructor: function(opts) {
// Merge options with default
this._opts = $.extend({
// Default options go here
}, opts);
},
init: function () {
//setup UI elements
var self = this;
//bind to the save event
this._opts.saveButton.click(function (event) {
event.preventDefault();
self.doSubmit();
});
},
doSubmit: function () {
var self = this;
var fileName = this._opts.nameTxtBox.val();
var codeVal = this._opts.editorSourceElement.val();
//if CodeMirror is not defined, then the code editor is disabled.
if (typeof (CodeMirror) != "undefined") {
codeVal = UmbEditor.GetCode();
}
umbraco.presentation.webservices.codeEditorSave.SaveXslt(
fileName, self._opts.originalFileName, codeVal, true,
function (t) { self.submitSucces(t); },
function (t) { self.submitFailure(t); });
},
submitSucces: function (t) {
if (t != 'true') {
top.UmbSpeechBubble.ShowMessage('error', 'Saving XSLT file failed',"<pre>" + t + "</pre>");
}
var newFilePath = this._opts.nameTxtBox.val();
//if the filename changes, we need to redirect since the file name is used in the url
if (this._opts.originalFileName != newFilePath) {
var newLocation = window.location.pathname + "?" + "&file=" + newFilePath;
UmbClientMgr.contentFrame(newLocation);
//we need to do this after we navigate otherwise the navigation will wait unti lthe message timeout is done!
top.UmbSpeechBubble.ShowMessage('save', 'XSLT file saved', '');
}
else {
top.UmbSpeechBubble.ShowMessage('save', 'XSLT file saved', '');
UmbClientMgr.mainTree().setActiveTreeType('xslt');
//we need to pass in the newId parameter so it knows which node to resync after retreival from the server
UmbClientMgr.mainTree().syncTree("-1,init," + this._opts.originalFileName, true, null, newFilePath);
//set the original file path to the new one
this._opts.originalFileName = newFilePath;
}
},
submitFailure: function (t) {
alert(t);
top.UmbSpeechBubble.ShowMessage('warning', 'XSLT file could not be saved', '');
}
});
})(jQuery);
@@ -1,2 +0,0 @@
/*! https://mths.be/punycode v1.3.2 by @mathias */
!function (a) { function b(a) { throw RangeError(E[a]) } function c(a, b) { for (var c = a.length, d = []; c--;) d[c] = b(a[c]); return d } function d(a, b) { var d = a.split("@"), e = ""; d.length > 1 && (e = d[0] + "@", a = d[1]), a = a.replace(D, "."); var f = a.split("."), g = c(f, b).join("."); return e + g } function e(a) { for (var b, c, d = [], e = 0, f = a.length; f > e;) b = a.charCodeAt(e++), b >= 55296 && 56319 >= b && f > e ? (c = a.charCodeAt(e++), 56320 == (64512 & c) ? d.push(((1023 & b) << 10) + (1023 & c) + 65536) : (d.push(b), e--)) : d.push(b); return d } function f(a) { return c(a, function (a) { var b = ""; return a > 65535 && (a -= 65536, b += H(a >>> 10 & 1023 | 55296), a = 56320 | 1023 & a), b += H(a) }).join("") } function g(a) { return 10 > a - 48 ? a - 22 : 26 > a - 65 ? a - 65 : 26 > a - 97 ? a - 97 : t } function h(a, b) { return a + 22 + 75 * (26 > a) - ((0 != b) << 5) } function i(a, b, c) { var d = 0; for (a = c ? G(a / x) : a >> 1, a += G(a / b) ; a > F * v >> 1; d += t) a = G(a / F); return G(d + (F + 1) * a / (a + w)) } function j(a) { var c, d, e, h, j, k, l, m, n, o, p = [], q = a.length, r = 0, w = z, x = y; for (d = a.lastIndexOf(A), 0 > d && (d = 0), e = 0; d > e; ++e) a.charCodeAt(e) >= 128 && b("not-basic"), p.push(a.charCodeAt(e)); for (h = d > 0 ? d + 1 : 0; q > h;) { for (j = r, k = 1, l = t; h >= q && b("invalid-input"), m = g(a.charCodeAt(h++)), (m >= t || m > G((s - r) / k)) && b("overflow"), r += m * k, n = x >= l ? u : l >= x + v ? v : l - x, !(n > m) ; l += t) o = t - n, k > G(s / o) && b("overflow"), k *= o; c = p.length + 1, x = i(r - j, c, 0 == j), G(r / c) > s - w && b("overflow"), w += G(r / c), r %= c, p.splice(r++, 0, w) } return f(p) } function k(a) { var c, d, f, g, j, k, l, m, n, o, p, q, r, w, x, B = []; for (a = e(a), q = a.length, c = z, d = 0, j = y, k = 0; q > k; ++k) p = a[k], 128 > p && B.push(H(p)); for (f = g = B.length, g && B.push(A) ; q > f;) { for (l = s, k = 0; q > k; ++k) p = a[k], p >= c && l > p && (l = p); for (r = f + 1, l - c > G((s - d) / r) && b("overflow"), d += (l - c) * r, c = l, k = 0; q > k; ++k) if (p = a[k], c > p && ++d > s && b("overflow"), p == c) { for (m = d, n = t; o = j >= n ? u : n >= j + v ? v : n - j, !(o > m) ; n += t) x = m - o, w = t - o, B.push(H(h(o + x % w, 0))), m = G(x / w); B.push(H(h(m, 0))), j = i(d, r, f == g), d = 0, ++f } ++d, ++c } return B.join("") } function l(a) { return d(a, function (a) { return B.test(a) ? j(a.slice(4).toLowerCase()) : a }) } function m(a) { return d(a, function (a) { return C.test(a) ? "xn--" + k(a) : a }) } var n = "object" == typeof exports && exports && !exports.nodeType && exports, o = "object" == typeof module && module && !module.nodeType && module, p = "object" == typeof global && global; (p.global === p || p.window === p || p.self === p) && (a = p); var q, r, s = 2147483647, t = 36, u = 1, v = 26, w = 38, x = 700, y = 72, z = 128, A = "-", B = /^xn--/, C = /[^\x20-\x7E]/, D = /[\x2E\u3002\uFF0E\uFF61]/g, E = { overflow: "Overflow: input needs wider integers to process", "not-basic": "Illegal input >= 0x80 (not a basic code point)", "invalid-input": "Invalid input" }, F = t - u, G = Math.floor, H = String.fromCharCode; if (q = { version: "1.3.2", ucs2: { decode: e, encode: f }, decode: j, encode: k, toASCII: m, toUnicode: l }, "function" == typeof define && "object" == typeof define.amd && define.amd) define("punycode", function () { return q }); else if (n && o) if (module.exports == n) o.exports = q; else for (r in q) q.hasOwnProperty(r) && (n[r] = q[r]); else a.punycode = q }(this);
@@ -38,17 +38,6 @@ using JArray = Newtonsoft.Json.Linq.JArray;
namespace Umbraco.Web.Editors
{
public class BackOfficeModel
{
public BackOfficeModel(string path, UmbracoFeatures features)
{
Path = path;
Features = features;
}
public string Path { get; }
public UmbracoFeatures Features { get; }
}
/// <summary>
/// Represents a controller user to render out the default back office view and JS results.
@@ -85,8 +74,8 @@ namespace Umbraco.Web.Editors
public async Task<ActionResult> Default()
{
return await RenderDefaultOrProcessExternalLoginAsync(
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(GlobalSettings.Path, _features)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(GlobalSettings.Path, _features)));
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)));
}
[HttpGet]
@@ -159,7 +148,7 @@ namespace Umbraco.Web.Editors
{
return await RenderDefaultOrProcessExternalLoginAsync(
//The default view to render when there is no external login info or errors
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(GlobalSettings.Path, _features)),
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings)),
//The ActionResult to perform if external login is successful
() => Redirect("/"));
}
@@ -0,0 +1,17 @@
using Umbraco.Core.Configuration;
using Umbraco.Web.Features;
namespace Umbraco.Web.Editors
{
public class BackOfficeModel
{
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings)
{
Features = features;
GlobalSettings = globalSettings;
}
public UmbracoFeatures Features { get; }
public IGlobalSettings GlobalSettings { get; }
}
}
@@ -47,10 +47,11 @@ namespace Umbraco.Web.Trees
/// <inheritdoc />
protected override TreeNode GetSingleTreeNode(IEntitySlim entity, string parentId, FormDataCollection queryStrings)
{
var langId = queryStrings["languageId"].TryConvertTo<int?>();
var allowedUserOptions = GetAllowedUserMenuItemsForNode(entity);
if (CanUserAccessNode(entity, allowedUserOptions))
if (CanUserAccessNode(entity, allowedUserOptions, langId.Success ? langId.Result : null))
{
//Special check to see if it ia a container, if so then we'll hide children.
var isContainer = entity.IsContainer; // && (queryStrings.Get("isDialog") != "true");
@@ -211,7 +212,6 @@ namespace Umbraco.Web.Trees
AddActionNode<ActionRollback>(item, menu, convert: true);
AddActionNode<ActionAudit>(item, menu, convert: true);
AddActionNode<ActionPublish>(item, menu, true, true);
AddActionNode<ActionToPublish>(item, menu, convert: true);
AddActionNode<ActionAssignDomain>(item, menu, convert: true);
AddActionNode<ActionRights>(item, menu, convert: true);
@@ -14,7 +14,7 @@ using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using System.Globalization;
using Umbraco.Core.Models.Entities;
using Umbraco.Web._Legacy.Actions;
using Umbraco.Web._Legacy.Actions;
namespace Umbraco.Web.Trees
{
@@ -148,8 +148,9 @@ namespace Umbraco.Web.Trees
}
// get child entities - if id is root, but user's start nodes do not contain the
// root node, this returns the start nodes instead of root's children
var entities = GetChildEntities(id).ToList();
// root node, this returns the start nodes instead of root's children
var langId = queryStrings["languageId"].TryConvertTo<int?>();
var entities = GetChildEntities(id, langId.Success ? langId.Result : null).ToList();
nodes.AddRange(entities.Select(x => GetSingleTreeNodeWithAccessCheck(x, id, queryStrings)).Where(x => x != null));
// if the user does not have access to the root node, what we have is the start nodes,
@@ -181,7 +182,7 @@ namespace Umbraco.Web.Trees
protected abstract UmbracoObjectTypes UmbracoObjectType { get; }
protected IEnumerable<IEntitySlim> GetChildEntities(string id)
protected IEnumerable<IEntitySlim> GetChildEntities(string id, int? langId)
{
// try to parse id as an integer else use GetEntityFromId
// which will grok Guids, Udis, etc and let use obtain the id
@@ -193,17 +194,42 @@ namespace Umbraco.Web.Trees
entityId = entity.Id;
}
IEntitySlim[] result;
// if a request is made for the root node but user has no access to
// root node, return start nodes instead
if (entityId == Constants.System.Root && UserStartNodes.Contains(Constants.System.Root) == false)
{
return UserStartNodes.Length > 0
? Services.EntityService.GetAll(UmbracoObjectType, UserStartNodes)
: Enumerable.Empty<IEntitySlim>();
}
return Services.EntityService.GetChildren(entityId, UmbracoObjectType).ToArray();
result = UserStartNodes.Length > 0
? Services.EntityService.GetAll(UmbracoObjectType, UserStartNodes).ToArray()
: Array.Empty<IEntitySlim>();
}
else
{
result = Services.EntityService.GetChildren(entityId, UmbracoObjectType).ToArray();
}
if (langId.HasValue)
{
//need to update all node names
//TODO: This is not currently stored, we need to wait until U4-11128 is complete for this to work, in the meantime
// we'll mock using this and it will just be some mock data
foreach(var e in result)
{
if (e.AdditionalData.TryGetValue("VariantNames", out var variantNames))
{
var casted = (IDictionary<int, string>)variantNames;
e.Name = casted[langId.Value];
}
else
{
e.Name = e.Name + " (lang: " + langId.Value + ")";
}
}
}
return result;
}
/// <summary>
@@ -362,8 +388,9 @@ namespace Umbraco.Web.Trees
/// <param name="allowedUserOptions">A list of MenuItems that the user has permissions to execute on the current document</param>
/// <remarks>By default the user must have Browse permissions to see the node in the Content tree</remarks>
/// <returns></returns>
internal bool CanUserAccessNode(IUmbracoEntity doc, IEnumerable<MenuItem> allowedUserOptions)
{
internal bool CanUserAccessNode(IUmbracoEntity doc, IEnumerable<MenuItem> allowedUserOptions, int? langId)
{
//TODO: At some stage when we implement permissions on languages we'll need to take care of langId
return allowedUserOptions.Select(x => x.Action).OfType<ActionBrowse>().Any();
}
-20
View File
@@ -54,7 +54,6 @@ namespace Umbraco.Web.UI.Pages
public static string CopyNode { get { return GetMainTree + ".copyNode('{0}', '{1}');"; } }
public static string MoveNode { get { return GetMainTree + ".moveNode('{0}', '{1}');"; } }
public static string ReloadActionNode { get { return GetMainTree + ".reloadActionNode({0}, {1}, null);"; } }
public static string SetActiveTreeType { get { return GetMainTree + ".setActiveTreeType('{0}');"; } }
public static string RefreshTree { get { return GetMainTree + ".refreshTree();"; } }
public static string RefreshTreeType { get { return GetMainTree + ".refreshTree('{0}');"; } }
public static string CloseModalWindow()
@@ -283,25 +282,6 @@ namespace Umbraco.Web.UI.Pages
return this;
}
/// <summary>
/// When the application searches for a node, it searches for nodes in specific tree types.
/// If SyncTree is used, it will sync the tree nodes with the active tree type, therefore if
/// a developer wants to sync a specific tree, they can call this method to set the type to sync.
/// </summary>
/// <remarks>
/// Each branch of a particular tree should theoretically be the same type, however, developers can
/// override the type of each branch in their BaseTree's but this is not standard practice. If there
/// are multiple types of branches in one tree, then only those branches that have the Active tree type
/// will be searched for syncing.
/// </remarks>
/// <param name="treeType"></param>
/// <returns></returns>
public ClientTools SetActiveTreeType(string treeType)
{
RegisterClientScript(string.Format(Scripts.SetActiveTreeType, treeType));
return this;
}
/// <summary>
/// Closes the Umbraco dialog window if it is open
/// </summary>
+1 -41
View File
@@ -123,6 +123,7 @@
<Compile Include="CompositionExtensions.cs" />
<Compile Include="Composing\Current.cs" />
<Compile Include="Editors\BackOfficeAssetsController.cs" />
<Compile Include="Editors\BackOfficeModel.cs" />
<Compile Include="Editors\BackOfficeServerVariables.cs" />
<Compile Include="Editors\CodeFileController.cs" />
<Compile Include="Editors\DashboardHelper.cs" />
@@ -1253,33 +1254,6 @@
<Compile Include="umbraco.presentation\umbracoPageHolder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\delete.aspx.cs">
<DependentUpon>delete.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\delete.aspx.designer.cs">
<DependentUpon>delete.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\editContent.aspx.cs">
<DependentUpon>editContent.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\editContent.aspx.designer.cs">
<DependentUpon>editContent.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\preview.aspx.cs">
<DependentUpon>preview.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\preview.aspx.designer.cs">
<DependentUpon>preview.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\publish.aspx.cs">
<DependentUpon>publish.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\actions\publish.aspx.designer.cs">
<DependentUpon>publish.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\controls\ContentControl.cs" />
<Compile Include="umbraco.presentation\umbraco\controls\ContentPicker.cs" />
<Compile Include="umbraco.presentation\umbraco\controls\ContentTypeControl.cs" />
@@ -1471,13 +1445,6 @@
<Compile Include="umbraco.presentation\umbraco\settings\EditDictionaryItem.aspx.designer.cs">
<DependentUpon>EditDictionaryItem.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\settings\editLanguage.aspx.cs">
<DependentUpon>editLanguage.aspx</DependentUpon>
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="umbraco.presentation\umbraco\settings\editLanguage.aspx.designer.cs">
<DependentUpon>editLanguage.aspx</DependentUpon>
</Compile>
<Compile Include="umbraco.presentation\umbraco\Trees\ITreeService.cs">
<SubType>Code</SubType>
</Compile>
@@ -1624,7 +1591,6 @@
<Content Include="umbraco.presentation\umbraco\settings\EditDictionaryItem.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\settings\editLanguage.aspx" />
<!--<Content Include="umbraco.presentation\umbraco\users\PermissionEditor.aspx" />-->
<Content Include="umbraco.presentation\umbraco\webservices\CacheRefresher.asmx">
<SubType>Form</SubType>
@@ -1649,12 +1615,6 @@
<Content Include="umbraco.presentation\umbraco\controls\ProgressBar.ascx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\actions\delete.aspx" />
<Content Include="umbraco.presentation\umbraco\actions\editContent.aspx" />
<Content Include="umbraco.presentation\umbraco\actions\preview.aspx" />
<Content Include="umbraco.presentation\umbraco\actions\publish.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>
<Content Include="umbraco.presentation\umbraco\developer\Xslt\xsltVisualize.aspx" />
<Content Include="umbraco.presentation\umbraco\dialogs\empty.htm" />
<Content Include="umbraco.presentation\umbraco\dialogs\insertMasterpageContent.aspx">
@@ -43,7 +43,7 @@ namespace Umbraco.Web._Legacy.Actions
{
get
{
return string.Format("{0}.actionPublish()", ClientTools.Scripts.GetAppActions);
return string.Empty;
}
}
@@ -67,7 +67,7 @@ namespace Umbraco.Web._Legacy.Actions
{
get
{
return "globe";
return string.Empty;
}
}
@@ -1,30 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="../masterpages/umbracoPage.Master" CodeBehind="delete.aspx.cs" Inherits="umbraco.presentation.actions.delete" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<style type="text/css">
body{background-image: none !Important;}
</style>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="body" runat="server">
<cc1:UmbracoPanel ID="Panel2" runat="server" AutoResize="false" Width="500px" Height="200px" Text="Delete">
<asp:Panel ID="confirm" runat="server">
<cc1:Pane ID="pane_delete" runat="server">
<p><asp:Literal ID="warning" runat="server"></asp:Literal></p>
</cc1:Pane>
<p>
<asp:Button ID="deleteButton" runat="server" OnClick="deleteButton_Click" />
</p>
</asp:Panel>
<cc1:Pane ID="deleteMessage" runat="server" Visible="false">
<p><asp:Literal ID="deleted" runat="server"></asp:Literal></p>
</cc1:Pane>
</cc1:UmbracoPanel>
</asp:Content>
@@ -1,39 +0,0 @@
using System;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.Composing;
using Umbraco.Web.UI.Pages;
namespace umbraco.presentation.actions
{
public partial class delete : UmbracoEnsuredPage
{
private IContent c;
protected void Page_Load(object sender, EventArgs e)
{
c = Current.Services.ContentService.GetById(int.Parse(Request.GetItemAsString("id")));
if (Security.ValidateUserApp(Constants.Applications.Content) == false)
throw new ArgumentException("The current user doesn't have access to this application. Please contact the system administrator.");
CheckPathAndPermissions(c.Id, UmbracoObjectTypes.Document, Umbraco.Web._Legacy.Actions.ActionDelete.Instance);
pane_delete.Text = Services.TextService.Localize("delete") + " '" + c.Name + "'";
Panel2.Text = Services.TextService.Localize("delete");
warning.Text = Services.TextService.Localize("confirmdelete") + " '" + c.Name + "'";
deleteButton.Text = Services.TextService.Localize("delete");
}
protected void deleteButton_Click(object sender, EventArgs e)
{
deleteMessage.Text = Services.TextService.Localize("deleted");
deleted.Text = "'" + c.Name + "' " + Services.TextService.Localize("deleted");
deleteMessage.Visible = true;
confirm.Visible = false;
Current.Services.ContentService.Delete(c);
}
}
}
@@ -1,78 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace umbraco.presentation.actions {
public partial class delete {
/// <summary>
/// Panel2 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.UmbracoPanel Panel2;
/// <summary>
/// confirm control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Panel confirm;
/// <summary>
/// pane_delete control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.Pane pane_delete;
/// <summary>
/// warning control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal warning;
/// <summary>
/// deleteButton control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button deleteButton;
/// <summary>
/// deleteMessage control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.Pane deleteMessage;
/// <summary>
/// deleted control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal deleted;
}
}
@@ -1,16 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="editContent.aspx.cs" Inherits="umbraco.presentation.actions.editContent" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
@@ -1,27 +0,0 @@
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Umbraco.Web;
using Umbraco.Web.UI.Pages;
namespace umbraco.presentation.actions
{
/// <summary>
/// This page is used only to deeplink to the edit content page with the tree
/// </summary>
public partial class editContent : UmbracoEnsuredPage
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Redirect("../umbraco.aspx?app=content&rightAction=editContent&id=" + Request.GetItemAsString("id") + "#content", true);
}
}
}
@@ -1,31 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.312
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace umbraco.presentation.actions {
/// <summary>
/// editContent class.
/// </summary>
/// <remarks>
/// Auto-generated class.
/// </remarks>
public partial class editContent {
/// <summary>
/// form1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
}
}
@@ -1,16 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="preview.aspx.cs" Inherits="umbraco.presentation.actions.preview" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Preview page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
@@ -1,27 +0,0 @@
using System;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Web;
using Umbraco.Web.UI.Pages;
namespace umbraco.presentation.actions
{
public partial class preview : UmbracoEnsuredPage
{
public preview()
{
CurrentApp = Constants.Applications.Content;
}
/// <summary>
/// Handles the Load event of the Page control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Page_Load(object sender, EventArgs e)
{
Response.Redirect(IOHelper.ResolveUrl(string.Format("{0}/dialogs/preview.aspx?id= {1}", SystemDirectories.Umbraco, int.Parse(Request.GetItemAsString("id")))));
}
}
}
@@ -1,31 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.832
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace umbraco.presentation.actions {
/// <summary>
/// preview class.
/// </summary>
/// <remarks>
/// Auto-generated class.
/// </remarks>
public partial class preview {
/// <summary>
/// form1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
}
}
@@ -1,30 +0,0 @@
<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="../masterpages/umbracoPage.Master" CodeBehind="publish.aspx.cs" Inherits="umbraco.presentation.actions.publish" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" %>
<asp:Content ContentPlaceHolderID="head" runat="server">
<style type="text/css">
body{background-image: none !Important;}
</style>
</asp:Content>
<asp:Content ContentPlaceHolderID="body" runat="server">
<cc1:UmbracoPanel ID="Panel2" Text="Publish" AutoResize="false" Width="500px" Height="200px" runat="server">
<asp:Panel ID="confirm" runat="server">
<cc1:Pane ID="pane_publish" runat="server">
<p>
<asp:Literal ID="warning" runat="server"></asp:Literal>
</p>
</cc1:Pane>
<br />
<p>
<asp:Button ID="deleteButton" runat="server" OnClick="deleteButton_Click" />
</p>
</asp:Panel>
<cc1:Pane ID="deleteMessage" runat="server" Visible="false">
<p><asp:Literal ID="deleted" runat="server"></asp:Literal></p>
</cc1:Pane>
</cc1:UmbracoPanel>
</asp:Content>
@@ -1,88 +0,0 @@
//TODO: REbuild this in angular and new apis then remove this
//using System;
//using System.Data;
//using System.Configuration;
//using System.Collections;
//using System.Linq;
//using System.Web;
//using System.Web.Security;
//using System.Web.UI;
//using System.Web.UI.WebControls;
//using System.Web.UI.WebControls.WebParts;
//using System.Web.UI.HtmlControls;
//using Umbraco.Core.Publishing;
//using umbraco.cms.businesslogic.web;
//using Umbraco.Core;
//namespace umbraco.presentation.actions
//{
// public partial class publish : Umbraco.Web.UI.Pages.UmbracoEnsuredPage
// {
// private Document d;
// protected void Page_Load(object sender, EventArgs e)
// {
// d = new Document(int.Parse(helper.Request("id")));
// if (!base.ValidateUserApp(Constants.Applications.Content))
// throw new ArgumentException("The current user doesn't have access to this application. Please contact the system administrator.");
// if (!base.ValidateUserNodeTreePermissions(d.Path, "U"))
// throw new ArgumentException("The current user doesn't have permissions to publish this document. Please contact the system administrator.");
// pane_publish.Text = Services.TextService.Localize("publish") + " '" + d.Text + "'";
// Panel2.Text = Services.TextService.Localize("publish");
// warning.Text = Services.TextService.Localize("publish") + " '" + d.Text + "'. " + Services.TextService.Localize("areyousure");
// deleteButton.Text = Services.TextService.Localize("publish");
// }
// protected void deleteButton_Click(object sender, EventArgs e)
// {
// deleteMessage.Visible = true;
// deleteMessage.Text = Services.TextService.Localize("editContentPublishedHeader");
// confirm.Visible = false;
// var result = d.SaveAndPublishWithResult(UmbracoUser);
// if (result.Success)
// {
// deleted.Text = Services.TextService.Localize("editContentPublishedHeader") + " ('" + d.Text + "') " + Services.TextService.Localize("editContentPublishedText") + "</p><p><a href=\"" + library.NiceUrl(d.Id) + "\"> " + Services.TextService.Localize("view") + " " + d.Text + "</a>";
// }
// else
// {
// deleted.Text = "<div class='error' style='padding:10px'>" + GetMessageForStatus(result.Result) + "</div>";
// }
// }
// private string GetMessageForStatus(PublishStatus status)
// {
// switch (status.StatusType)
// {
// case PublishStatusType.Success:
// case PublishStatusType.SuccessAlreadyPublished:
// return Services.TextService.Localize("speechBubbles/editContentPublishedText");
// case PublishStatusType.FailedPathNotPublished:
// return ui.Text("publish", "contentPublishedFailedByParent",
// string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id),
// UmbracoUser).Trim();
// case PublishStatusType.FailedCancelledByEvent:
// return Services.TextService.Localize("speechBubbles/contentPublishedFailedByEvent");
// case PublishStatusType.FailedHasExpired:
// case PublishStatusType.FailedAwaitingRelease:
// case PublishStatusType.FailedIsTrashed:
// return "Cannot publish document with a status of " + status.StatusType;
// case PublishStatusType.FailedContentInvalid:
// return ui.Text("publish", "contentPublishedFailedInvalid",
// new[]
// {
// string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id),
// string.Join(",", status.InvalidProperties.Select(x => x.Alias))
// }, UmbracoUser);
// default:
// throw new IndexOutOfRangeException();
// }
// }
// }
//}
@@ -1,78 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace umbraco.presentation.actions {
public partial class publish {
/// <summary>
/// Panel2 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.UmbracoPanel Panel2;
/// <summary>
/// confirm control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Panel confirm;
/// <summary>
/// pane_publish control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.Pane pane_publish;
/// <summary>
/// warning control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal warning;
/// <summary>
/// deleteButton control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Button deleteButton;
/// <summary>
/// deleteMessage control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.Pane deleteMessage;
/// <summary>
/// deleted control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Literal deleted;
}
}
@@ -45,7 +45,6 @@ namespace umbraco.cms.presentation.developer
if (IsPostBack == false)
{
ClientTools
.SetActiveTreeType(Constants.Trees.Macros)
.SyncTree("-1," + _macro.Id, false);
string tempMacroAssembly = _macro.ControlAssembly ?? "";
@@ -290,7 +289,6 @@ namespace umbraco.cms.presentation.developer
Page.Validate();
ClientTools
.SetActiveTreeType(Constants.Trees.Macros)
.SyncTree("-1," + _macro.Id.ToInvariantString(), true); //true forces the reload
var tempMacroAssembly = macroAssembly.Text;
@@ -58,7 +58,6 @@ namespace umbraco.presentation.developer.packages
if (Page.IsPostBack == false)
{
ClientTools
.SetActiveTreeType(Constants.Trees.Packages)
.SyncTree("-1,created," + createdPackage.Data.Id, false);
packageAuthorName.Text = pack.Author;
@@ -194,7 +193,6 @@ namespace umbraco.presentation.developer.packages
else
{
ClientTools
.SetActiveTreeType(Constants.Trees.Packages)
.SyncTree("-1,created," + createdPackage.Data.Id, true);
}
}
@@ -30,7 +30,6 @@ namespace umbraco.cms.presentation.developer
string file = Request.QueryString["file"];
string path = BaseTree.GetTreePathFromFilePath(file, false, true);
ClientTools
.SetActiveTreeType(Constants.Trees.Xslt)
.SyncTree(path, false);
}
}
@@ -92,7 +92,6 @@ namespace umbraco.settings
{
var path = BuildPath(currentItem);
ClientTools
.SetActiveTreeType(Constants.Trees.Dictionary)
.SyncTree(path, false);
}
@@ -1,19 +0,0 @@
<%@ Page Language="c#" CodeBehind="editLanguage.aspx.cs" AutoEventWireup="True" MasterPageFile="../masterpages/umbracoPage.Master"
Inherits="umbraco.settings.editLanguage" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" %>
<asp:Content ContentPlaceHolderID="body" runat="server">
<cc1:UmbracoPanel ID="Panel1" runat="server" Width="608px" Height="336px" hasMenu="true">
<cc1:Pane ID="Pane7" runat="server">
<cc1:PropertyPanel runat="server" ID="pp_language">
<asp:DropDownList ID="Cultures" runat="server">
</asp:DropDownList>
</cc1:PropertyPanel>
</cc1:Pane>
</cc1:UmbracoPanel>
<script type="text/javascript">
jQuery(document).ready(function () {
UmbClientMgr.appActions().bindSaveShortCut();
});
</script>
</asp:Content>
@@ -1,107 +0,0 @@
using System;
using System.Collections;
using System.Globalization;
using System.Web.UI.WebControls;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.Composing;
using Umbraco.Web.UI;
namespace umbraco.settings
{
/// <summary>
/// Summary description for editLanguage.
/// </summary>
[WebformsPageTreeAuthorize(Constants.Trees.Languages)]
public partial class editLanguage : Umbraco.Web.UI.Pages.UmbracoEnsuredPage
{
public editLanguage()
{
CurrentApp = Constants.Applications.Settings.ToString();
}
protected System.Web.UI.WebControls.TextBox NameTxt;
protected System.Web.UI.WebControls.Literal DisplayName;
//cms.businesslogic.language.Language currentLanguage;
private ILanguage lang;
protected void Page_Load(object sender, System.EventArgs e)
{
//currentLanguage = new cms.businesslogic.language.Language(int.Parse(Request.GetItemAsString("id")));
lang = Current.Services.LocalizationService.GetLanguageById(int.Parse(Request.GetItemAsString("id")));
// Put user code to initialize the page here
Panel1.Text = Services.TextService.Localize("editlanguage");
pp_language.Text = Services.TextService.Localize("language/displayName");
if (!IsPostBack)
{
updateCultureList();
ClientTools
.SetActiveTreeType(Constants.Trees.Languages)
.SyncTree(Request.GetItemAsString("id"), false);
}
}
private void updateCultureList()
{
SortedList sortedCultures = new SortedList();
Cultures.Items.Clear();
Cultures.Items.Add(new ListItem(Services.TextService.Localize("choose") + "...", ""));
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures))
sortedCultures.Add(ci.DisplayName + "|||" + Guid.NewGuid().ToString(), ci.Name);
IDictionaryEnumerator ide = sortedCultures.GetEnumerator();
while (ide.MoveNext())
{
ListItem li = new ListItem(ide.Key.ToString().Substring(0, ide.Key.ToString().IndexOf("|||")), ide.Value.ToString());
if (ide.Value.ToString() == lang.IsoCode)
li.Selected = true;
Cultures.Items.Add(li);
}
}
private void save_click(object sender, EventArgs e)
{
//currentLanguage.CultureAlias = Cultures.SelectedValue;
//currentLanguage.Save();
lang.IsoCode = Cultures.SelectedValue;
Current.Services.LocalizationService.Save(lang);
updateCultureList();
ClientTools.ShowSpeechBubble(SpeechBubbleIcon.Save, Services.TextService.Localize("speechBubbles/languageSaved"), "");
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
Panel1.hasMenu = true;
var save = Panel1.Menu.NewButton();
save.Click += save_click;
save.ToolTip = Services.TextService.Localize("save");
save.Text = Services.TextService.Localize("save");
save.ID = "save";
save.ButtonType = Umbraco.Web._Legacy.Controls.MenuButtonType.Primary;
Panel1.Text = Services.TextService.Localize("language/editLanguage");
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
#endregion
}
}
@@ -1,51 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace umbraco.settings {
public partial class editLanguage {
/// <summary>
/// Panel1 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.UmbracoPanel Panel1;
/// <summary>
/// Pane7 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.Pane Pane7;
/// <summary>
/// pp_language control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::Umbraco.Web._Legacy.Controls.PropertyPanel pp_language;
/// <summary>
/// Cultures control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.DropDownList Cultures;
}
}
@@ -63,7 +63,6 @@ namespace umbraco.cms.presentation.settings.stylesheet
if (IsPostBack == false)
{
ClientTools
.SetActiveTreeType(Constants.Trees.Stylesheets)
.SyncTree(TreeSyncPath, false);
}
}
@@ -64,9 +64,7 @@ namespace umbraco.cms.presentation.settings.stylesheet
var nodePath = string.Format(BaseTree.GetTreePathFromFilePath(path) +
",{0}_{1}", path, HttpUtility.UrlEncode(_stylesheetproperty.Name));
ClientTools
.SetActiveTreeType(Constants.Trees.Stylesheets)
.SyncTree(nodePath, IsPostBack);
ClientTools.SyncTree(nodePath, IsPostBack);
prStyles.Attributes["style"] = _stylesheetproperty.Value;