Merge remote-tracking branch 'origin/temp8' into temp8-4037
This commit is contained in:
@@ -7,27 +7,32 @@ namespace Umbraco.Core.Scoping
|
||||
internal class ScopeContext : IScopeContext, IInstanceIdentifiable
|
||||
{
|
||||
private Dictionary<string, IEnlistedObject> _enlisted;
|
||||
private bool _exiting;
|
||||
|
||||
public void ScopeExit(bool completed)
|
||||
{
|
||||
if (_enlisted == null)
|
||||
return;
|
||||
|
||||
_exiting = true;
|
||||
// fixme - can we create infinite loops?
|
||||
// fixme - what about nested events? will they just be plainly ignored = really bad?
|
||||
|
||||
List<Exception> exceptions = null;
|
||||
foreach (var enlisted in _enlisted.Values.OrderBy(x => x.Priority))
|
||||
List<IEnlistedObject> orderedEnlisted;
|
||||
while ((orderedEnlisted = _enlisted.Values.OrderBy(x => x.Priority).ToList()).Count > 0)
|
||||
{
|
||||
try
|
||||
_enlisted.Clear();
|
||||
foreach (var enlisted in orderedEnlisted)
|
||||
{
|
||||
enlisted.Execute(completed);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (exceptions == null)
|
||||
exceptions = new List<Exception>();
|
||||
exceptions.Add(e);
|
||||
try
|
||||
{
|
||||
enlisted.Execute(completed);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (exceptions == null)
|
||||
exceptions = new List<Exception>();
|
||||
exceptions.Add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,9 +79,6 @@ namespace Umbraco.Core.Scoping
|
||||
|
||||
public T Enlist<T>(string key, Func<T> creator, Action<bool, T> action = null, int priority = 100)
|
||||
{
|
||||
if (_exiting)
|
||||
throw new InvalidOperationException("Cannot enlist now, context is exiting.");
|
||||
|
||||
var enlistedObjects = _enlisted ?? (_enlisted = new Dictionary<string, IEnlistedObject>());
|
||||
|
||||
if (enlistedObjects.TryGetValue(key, out var enlisted))
|
||||
|
||||
@@ -540,7 +540,7 @@ namespace Umbraco.Tests.Scoping
|
||||
var scopeProvider = ScopeProvider;
|
||||
|
||||
bool? completed = null;
|
||||
Exception exception = null;
|
||||
bool? completed2 = null;
|
||||
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
using (var scope = scopeProvider.CreateScope())
|
||||
@@ -551,15 +551,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
// at that point the scope is gone, but the context is still there
|
||||
var ambientContext = scopeProvider.AmbientContext;
|
||||
|
||||
try
|
||||
{
|
||||
ambientContext.Enlist("another", c2 => { });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = e;
|
||||
}
|
||||
ambientContext.Enlist("another", c2 => { completed2 = c2; });
|
||||
});
|
||||
if (complete)
|
||||
scope.Complete();
|
||||
@@ -567,8 +559,8 @@ namespace Umbraco.Tests.Scoping
|
||||
Assert.IsNull(scopeProvider.AmbientScope);
|
||||
Assert.IsNull(scopeProvider.AmbientContext);
|
||||
Assert.IsNotNull(completed);
|
||||
Assert.IsNotNull(exception);
|
||||
Assert.IsInstanceOf<InvalidOperationException>(exception);
|
||||
Assert.AreEqual(complete,completed.Value);
|
||||
Assert.AreEqual(complete, completed2.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -29,5 +29,30 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"});
|
||||
Assert.AreEqual("<div style=\"color:red;\" onclick=\"void();\">hello world</div>", output.ToHtmlString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetRelatedLinkHtml_Simple()
|
||||
{
|
||||
var relatedLink = new Umbraco.Web.Models.RelatedLink {
|
||||
Caption = "Link Caption",
|
||||
NewWindow = true,
|
||||
Link = "https://www.google.com/"
|
||||
};
|
||||
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink);
|
||||
Assert.AreEqual("<a href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetRelatedLinkHtml_HtmlAttributes()
|
||||
{
|
||||
var relatedLink = new Umbraco.Web.Models.RelatedLink
|
||||
{
|
||||
Caption = "Link Caption",
|
||||
NewWindow = true,
|
||||
Link = "https://www.google.com/"
|
||||
};
|
||||
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink, new { @class = "test-class"});
|
||||
Assert.AreEqual("<a class=\"test-class\" href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -97,9 +97,9 @@
|
||||
}
|
||||
|
||||
//load in the audit trail if we are currently looking at the INFO tab
|
||||
if (umbVariantContentCtrl) {
|
||||
if (umbVariantContentCtrl && umbVariantContentCtrl.editor) {
|
||||
var activeApp = _.find(umbVariantContentCtrl.editor.content.apps, a => a.active);
|
||||
if (activeApp.alias === "umbInfo") {
|
||||
if (activeApp && activeApp.alias === "umbInfo") {
|
||||
isInfoTab = true;
|
||||
loadAuditTrail();
|
||||
loadRedirectUrls();
|
||||
|
||||
+17
-17
@@ -86,20 +86,21 @@ angular.module("umbraco.directives")
|
||||
function generateAlias(value) {
|
||||
|
||||
if (generateAliasTimeout) {
|
||||
$timeout.cancel(generateAliasTimeout);
|
||||
$timeout.cancel(generateAliasTimeout);
|
||||
}
|
||||
|
||||
if( value !== undefined && value !== "" && value !== null) {
|
||||
if (value !== undefined && value !== "" && value !== null) {
|
||||
|
||||
scope.alias = "";
|
||||
scope.alias = "";
|
||||
scope.placeholderText = scope.labels.busy;
|
||||
|
||||
generateAliasTimeout = $timeout(function () {
|
||||
updateAlias = true;
|
||||
entityResource.getSafeAlias(value, true).then(function (safeAlias) {
|
||||
if (updateAlias) {
|
||||
scope.alias = safeAlias.alias;
|
||||
}
|
||||
scope.alias = safeAlias.alias;
|
||||
}
|
||||
scope.placeholderText = scope.labels.idle;
|
||||
});
|
||||
}, 500);
|
||||
|
||||
@@ -108,7 +109,6 @@ angular.module("umbraco.directives")
|
||||
scope.alias = "";
|
||||
scope.placeholderText = scope.labels.idle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if alias gets unlocked - stop watching alias
|
||||
@@ -119,17 +119,17 @@ angular.module("umbraco.directives")
|
||||
}));
|
||||
|
||||
// validate custom entered alias
|
||||
eventBindings.push(scope.$watch('alias', function(newValue, oldValue){
|
||||
|
||||
if(scope.alias === "" && bindWatcher === true || scope.alias === null && bindWatcher === true) {
|
||||
// add watcher
|
||||
eventBindings.push(scope.$watch('aliasFrom', function(newValue, oldValue) {
|
||||
if(bindWatcher) {
|
||||
generateAlias(newValue);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
eventBindings.push(scope.$watch('alias', function (newValue, oldValue) {
|
||||
if (scope.alias === "" || scope.alias === null || scope.alias === undefined) {
|
||||
if (bindWatcher === true) {
|
||||
// add watcher
|
||||
eventBindings.push(scope.$watch('aliasFrom', function (newValue, oldValue) {
|
||||
if (bindWatcher) {
|
||||
generateAlias(newValue);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
// clean up
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @name umbraco.resources.codefileResource
|
||||
* @description Loads in data for files that contain code such as js scripts, partial views and partial view macros
|
||||
**/
|
||||
function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
function codefileResource($q, $http, umbDataFormatter, umbRequestHelper, localizationService) {
|
||||
|
||||
return {
|
||||
|
||||
@@ -106,13 +106,16 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
deleteByPath: function (type, virtualpath) {
|
||||
|
||||
var promise = localizationService.localize("codefile_deleteItemFailed", [virtualpath]);
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"Delete",
|
||||
[{ type: type }, { virtualPath: virtualpath}])),
|
||||
"Failed to delete item: " + virtualpath);
|
||||
promise);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -236,13 +239,19 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
|
||||
createContainer: function(type, parentId, name) {
|
||||
createContainer: function (type, parentId, name) {
|
||||
|
||||
// Is the parent ID numeric?
|
||||
var key = "codefile_createFolderFailedBy" + (isNaN(parseInt(parentId)) ? "Name" : "Id");
|
||||
|
||||
var promise = localizationService.localize(key, [parentId]);
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"PostCreateContainer",
|
||||
{ type: type, parentId: parentId, name: encodeURIComponent(name) })),
|
||||
'Failed to create a folder under parent id ' + parentId);
|
||||
promise);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @name umbraco.resources.templateResource
|
||||
* @description Loads in data for templates
|
||||
**/
|
||||
function templateResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
function templateResource($q, $http, umbDataFormatter, umbRequestHelper, localizationService) {
|
||||
|
||||
return {
|
||||
|
||||
@@ -152,13 +152,16 @@ function templateResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
*/
|
||||
deleteById: function(id) {
|
||||
|
||||
var promise = localizationService.localize("template_deleteByIdFailed", [id]);
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"DeleteById",
|
||||
[{ id: id }])),
|
||||
"Failed to delete item " + id);
|
||||
promise);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* @param {navigationService} navigationService A reference to the navigationService
|
||||
*/
|
||||
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource) {
|
||||
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource) {
|
||||
|
||||
//this is used to trigger the tree to start loading once everything is ready
|
||||
var treeInitPromise = $q.defer();
|
||||
@@ -344,9 +344,6 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
$scope.languages = languages;
|
||||
|
||||
if ($scope.languages.length > 1) {
|
||||
var defaultLang = _.find($scope.languages, function (l) {
|
||||
return l.isDefault;
|
||||
});
|
||||
//if there's already one set, check if it exists
|
||||
var currCulture = null;
|
||||
var mainCulture = $location.search().mculture;
|
||||
@@ -356,7 +353,20 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
});
|
||||
}
|
||||
if (!currCulture) {
|
||||
$location.search("mculture", defaultLang ? defaultLang.culture : null);
|
||||
// no culture in the request, let's look for one in the cookie that's set when changing language
|
||||
var defaultCulture = $cookies.get("UMB_MCULTURE");
|
||||
if (!defaultCulture || !_.find($scope.languages, function (l) {
|
||||
return l.culture.toLowerCase() === defaultCulture.toLowerCase();
|
||||
})) {
|
||||
// no luck either, look for the default language
|
||||
var defaultLang = _.find($scope.languages, function (l) {
|
||||
return l.isDefault;
|
||||
});
|
||||
if (defaultLang) {
|
||||
defaultCulture = defaultLang.culture;
|
||||
}
|
||||
}
|
||||
$location.search("mculture", defaultCulture ? defaultCulture : null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,6 +401,10 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
$scope.selectLanguage = function (language) {
|
||||
|
||||
$location.search("mculture", language.culture);
|
||||
// add the selected culture to a cookie so the user will log back into the same culture later on (cookie lifetime = one year)
|
||||
var expireDate = new Date();
|
||||
expireDate.setDate(expireDate.getDate() + 365);
|
||||
$cookies.put("UMB_MCULTURE", language.culture, {path: "/", expires: expireDate});
|
||||
|
||||
// close the language selector
|
||||
$scope.page.languageSelectorIsOpen = false;
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
@import "components/umb-file-dropzone.less";
|
||||
@import "components/umb-node-preview.less";
|
||||
@import "components/umb-mini-editor.less";
|
||||
@import "components/umb-property-file-upload.less";
|
||||
|
||||
@import "components/users/umb-user-cards.less";
|
||||
@import "components/users/umb-user-details.less";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
.umb-file-dropzone-directive{
|
||||
.umb-file-dropzone {
|
||||
|
||||
// drop zone
|
||||
// tall and small version - animate height
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-nested-content-property-container {
|
||||
position: relative;
|
||||
&:not(:last-child){
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-nested-content--not-supported {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
.umb-property-file-upload {
|
||||
|
||||
.umb-upload-button-big {
|
||||
display: block;
|
||||
padding: 20px;
|
||||
opacity: 1;
|
||||
border: 1px dashed @gray-8;
|
||||
background: none;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
|
||||
&, &:hover {
|
||||
color: @gray-8;
|
||||
}
|
||||
|
||||
i.icon {
|
||||
font-size: 55px;
|
||||
line-height: 70px
|
||||
}
|
||||
|
||||
input {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
@checkered-background: url(../img/checkered-background.png);
|
||||
|
||||
//
|
||||
// Container styles
|
||||
// --------------------------------------------------
|
||||
@@ -353,7 +355,7 @@
|
||||
max-height:100%;
|
||||
margin:auto;
|
||||
display:block;
|
||||
background-image: url(../img/checkered-background.png);
|
||||
background-image: @checkered-background;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails li .trashed {
|
||||
@@ -576,12 +578,18 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.gravity-container .viewport {
|
||||
max-width: 600px;
|
||||
}
|
||||
.gravity-container {
|
||||
border: 1px solid @gray-8;
|
||||
line-height: 0;
|
||||
|
||||
.gravity-container .viewport:hover {
|
||||
cursor: pointer;
|
||||
.viewport {
|
||||
max-width: 600px;
|
||||
background: @checkered-background;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.imagecropper {
|
||||
@@ -594,6 +602,10 @@
|
||||
float: left;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.viewport img {
|
||||
background: @checkered-background;
|
||||
}
|
||||
}
|
||||
|
||||
.imagecropper .umb-cropper__container {
|
||||
@@ -687,7 +699,7 @@
|
||||
//
|
||||
// folder-browser
|
||||
// --------------------------------------------------
|
||||
.umb-folderbrowser .add-link{
|
||||
.umb-folderbrowser .add-link {
|
||||
display: inline-block;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
@@ -696,17 +708,6 @@
|
||||
line-height: 120px
|
||||
}
|
||||
|
||||
.umb-upload-button-big:hover{color: @gray-8;}
|
||||
|
||||
.umb-upload-button-big {display: block}
|
||||
.umb-upload-button-big input {
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// File upload
|
||||
// --------------------------------------------------
|
||||
@@ -724,6 +725,10 @@
|
||||
list-style: none;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 0;
|
||||
|
||||
img {
|
||||
background: @checkered-background;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-fileupload label {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<!-- Icon for files -->
|
||||
<span class="umb-media-grid__item-file-icon" ng-if="!item.thumbnail && item.extension != 'svg'">
|
||||
<i class="umb-media-grid__item-icon {{item.icon}}"></i>
|
||||
<span>.{{item.extension}}</span>
|
||||
<span ng-if="item.extension">.{{item.extension}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div data-element="dropzone" class="umb-file-dropzone-directive">
|
||||
<div data-element="dropzone" class="umb-file-dropzone">
|
||||
|
||||
<ng-form name="uploadForm" umb-isolate-form>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<div>
|
||||
<div class="umb-property-file-upload">
|
||||
|
||||
<ng-form name="vm.fileUploadForm">
|
||||
|
||||
<div class="fileinput-button umb-upload-button-big"
|
||||
|
||||
@@ -1,26 +1,91 @@
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController",
|
||||
function ($scope, relationResource, contentResource, entityResource, navigationService, appState, treeService, localizationService) {
|
||||
function ($scope, relationResource, contentResource, entityResource, navigationService, appState, treeService, userService) {
|
||||
|
||||
$scope.source = _.clone($scope.currentNode);
|
||||
|
||||
$scope.error = null;
|
||||
$scope.success = false;
|
||||
$scope.error = null;
|
||||
$scope.loading = true;
|
||||
$scope.moving = false;
|
||||
$scope.success = false;
|
||||
|
||||
$scope.dialogTreeApi = {};
|
||||
$scope.searchInfo = {
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
}
|
||||
$scope.treeModel = {
|
||||
hideHeader: false
|
||||
}
|
||||
userService.getCurrentUser().then(function (userData) {
|
||||
$scope.treeModel.hideHeader = userData.startContentIds.length > 0 && userData.startContentIds.indexOf(-1) == -1;
|
||||
});
|
||||
|
||||
function nodeSelectHandler(args) {
|
||||
|
||||
if (args && args.event) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
}
|
||||
|
||||
if ($scope.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.target.selected = false;
|
||||
}
|
||||
|
||||
$scope.target = args.node;
|
||||
$scope.target.selected = true;
|
||||
|
||||
}
|
||||
|
||||
function nodeExpandedHandler(args) {
|
||||
// open mini list view for list views
|
||||
if (args.node.metaData.isContainer) {
|
||||
openMiniListView(args.node);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.hideSearch = function () {
|
||||
$scope.searchInfo.showSearch = false;
|
||||
$scope.searchInfo.results = [];
|
||||
}
|
||||
|
||||
// method to select a search result
|
||||
$scope.selectResult = function (evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler(evt, { event: evt, node: result });
|
||||
};
|
||||
|
||||
//callback when there are search results
|
||||
$scope.onSearchResults = function (results) {
|
||||
$scope.searchInfo.results = results;
|
||||
$scope.searchInfo.showSearch = true;
|
||||
};
|
||||
|
||||
$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;
|
||||
nodeSelectHandler({}, { node: node });
|
||||
};
|
||||
|
||||
$scope.closeMiniListView = function () {
|
||||
$scope.miniListView = undefined;
|
||||
};
|
||||
|
||||
function openMiniListView(node) {
|
||||
$scope.miniListView = node;
|
||||
}
|
||||
|
||||
relationResource.getByChildId($scope.source.id, "relateParentDocumentOnDelete").then(function (data) {
|
||||
$scope.loading = false;
|
||||
|
||||
if (!data.length) {
|
||||
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_noRestoreRelation"])
|
||||
.then(function(values) {
|
||||
$scope.success = false;
|
||||
$scope.error = {
|
||||
errorMsg: values[0],
|
||||
data: {
|
||||
Message: values[1]
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.moving = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -30,40 +95,32 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
|
||||
$scope.target = { id: -1, name: "Root" };
|
||||
|
||||
} else {
|
||||
$scope.loading = true;
|
||||
$scope.loading = true;
|
||||
|
||||
entityResource.getById($scope.relation.parentId, "Document").then(function (data) {
|
||||
$scope.loading = false;
|
||||
$scope.target = data;
|
||||
// make sure the target item isn't in the recycle bin
|
||||
if($scope.target.path.indexOf("-20") !== -1) {
|
||||
localizationService.localizeMany(["recycleBin_itemCannotBeRestored", "recycleBin_restoreUnderRecycled"])
|
||||
.then(function (values) {
|
||||
$scope.success = false;
|
||||
$scope.error = {
|
||||
errorMsg: values[0],
|
||||
data: {
|
||||
Message: values[1].replace('%0%', $scope.target.name)
|
||||
}
|
||||
}
|
||||
});
|
||||
$scope.success = false;
|
||||
}
|
||||
$scope.target = data;
|
||||
|
||||
// make sure the target item isn't in the recycle bin
|
||||
if ($scope.target.path.indexOf("-20") !== -1) {
|
||||
$scope.moving = true;
|
||||
$scope.target = null;
|
||||
}
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
}
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
|
||||
$scope.restore = function () {
|
||||
$scope.loading = true;
|
||||
// this code was copied from `content.move.controller.js`
|
||||
|
||||
// this code was copied from `content.move.controller.js`
|
||||
contentResource.move({ parentId: $scope.target.id, id: $scope.source.id })
|
||||
.then(function (path) {
|
||||
|
||||
@@ -88,9 +145,8 @@ angular.module("umbraco").controller("Umbraco.Editors.Content.RestoreController"
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
$scope.success = false;
|
||||
$scope.error = err;
|
||||
$scope.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,34 +1,93 @@
|
||||
<div ng-controller="Umbraco.Editors.Content.RestoreController">
|
||||
<div class="umb-dialog-body">
|
||||
<umb-pane>
|
||||
<div class="umb-dialog-body" ng-cloak>
|
||||
<umb-pane>
|
||||
<umb-load-indicator
|
||||
ng-show="loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<umb-load-indicator
|
||||
ng-show="loading">
|
||||
</umb-load-indicator>
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.Message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="abstract" ng-hide="loading || error != null || success">
|
||||
<localize key="actions_restore">Restore</localize> <strong>{{source.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
|
||||
</p>
|
||||
<div ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{source.name}}</strong>
|
||||
<span ng-hide="moving"><localize key="recycleBin_wasRestored">was restored under</localize></span>
|
||||
<span ng-show="moving"><localize key="editdatatype_wasMoved">was moved underneath</localize></span>
|
||||
<strong>{{target.name}}</strong>
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="close()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.Message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-hide="moving || loading || success">
|
||||
|
||||
<div ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{source.name}}</strong> <localize key="editdatatype_wasMoved">was moved underneath</localize> <strong>{{target.name}}</strong>
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="close()"><localize key="general_ok">Ok</localize></button>
|
||||
</div>
|
||||
<p class="abstract" ng-hide="error || success">
|
||||
<localize key="actions_restore">Restore</localize> <strong>{{source.name}}</strong> <localize key="general_under">under</localize> <strong>{{target.name}}</strong>?
|
||||
</p>
|
||||
|
||||
</umb-pane>
|
||||
</div>
|
||||
|
||||
<div ng-hide="!moving || loading || success">
|
||||
<div>
|
||||
<div class="alert alert-info">
|
||||
<div><strong><localize key="recycleBin_itemCannotBeRestored">Cannot automatically restore this item</localize></strong></div>
|
||||
<div><localize key="recycleBin_itemCannotBeRestoredHelpText">There is no location where this item can be automatically restored. You can move the item manually using the tree below.</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-hide="miniListView">
|
||||
<umb-tree-search-box
|
||||
hide-search-callback="hideSearch"
|
||||
search-callback="onSearchResults"
|
||||
show-search="{{searchInfo.showSearch}}"
|
||||
section="content">
|
||||
</umb-tree-search-box>
|
||||
|
||||
<br />
|
||||
|
||||
<umb-tree-search-results
|
||||
ng-if="searchInfo.showSearch"
|
||||
results="searchInfo.results"
|
||||
select-result-callback="selectResult">
|
||||
</umb-tree-search-results>
|
||||
|
||||
<div ng-hide="searchInfo.showSearch">
|
||||
<umb-tree
|
||||
section="content"
|
||||
hideheader="{{treeModel.hideHeader}}"
|
||||
hideoptions="true"
|
||||
isdialog="true"
|
||||
api="dialogTreeApi"
|
||||
on-init="onTreeInit()"
|
||||
enablelistviewexpand="true"
|
||||
enablecheckboxes="true">
|
||||
</umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-mini-list-view
|
||||
ng-if="miniListView"
|
||||
node="miniListView"
|
||||
entity-type="Document"
|
||||
on-select="selectListViewNode(node)"
|
||||
on-close="closeMiniListView()">
|
||||
</umb-mini-list-view>
|
||||
|
||||
</div>
|
||||
|
||||
</umb-pane>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || success">
|
||||
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
|
||||
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null"><localize key="actions_restore">Restore</localize></button>
|
||||
</div>
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || moving || success">
|
||||
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
|
||||
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null"><localize key="actions_restore">Restore</localize></button>
|
||||
</div>
|
||||
|
||||
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="loading || !moving || success">
|
||||
<a class="btn btn-link" ng-click="close()"><localize key="general_cancel">Cancel</localize></a>
|
||||
<button class="btn btn-primary" ng-click="restore()" ng-show="error == null" ng-disabled="!target"><localize key="actions_move">Move</localize></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-control-group label="Enter a folder name" hide-label="false">
|
||||
<umb-control-group label="@create_enterFolderName" localize="label" hide-label="false">
|
||||
<input type="text" name="folderName" ng-model="vm.folderName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
|
||||
</umb-control-group>
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ function PartialViewsDeleteController($scope, codefileResource, treeService, nav
|
||||
|
||||
//mark it for deletion (used in the UI)
|
||||
$scope.currentNode.loading = true;
|
||||
|
||||
// Reset the error message
|
||||
$scope.error = null;
|
||||
|
||||
codefileResource.deleteByPath('partialViews', $scope.currentNode.id)
|
||||
.then(function() {
|
||||
@@ -21,6 +24,9 @@ function PartialViewsDeleteController($scope, codefileResource, treeService, nav
|
||||
//TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
}, function (err) {
|
||||
$scope.currentNode.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.PartialViews.DeleteController">
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="umb-abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
|
||||
</p>
|
||||
|
||||
+6
-20
@@ -81,25 +81,6 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
: undefined;
|
||||
});
|
||||
|
||||
$scope.editIconTitle = '';
|
||||
$scope.moveIconTitle = '';
|
||||
$scope.deleteIconTitle = '';
|
||||
|
||||
// localize the edit icon title
|
||||
localizationService.localize('general_edit').then(function (value) {
|
||||
$scope.editIconTitle = value;
|
||||
});
|
||||
|
||||
// localize the delete icon title
|
||||
localizationService.localize('general_delete').then(function (value) {
|
||||
$scope.deleteIconTitle = value;
|
||||
});
|
||||
|
||||
// localize the move icon title
|
||||
localizationService.localize('actions_move').then(function (value) {
|
||||
$scope.moveIconTitle = value;
|
||||
});
|
||||
|
||||
$scope.nodes = [];
|
||||
$scope.currentNode = undefined;
|
||||
$scope.realCurrentNode = undefined;
|
||||
@@ -116,6 +97,11 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
$scope.showIcons = $scope.model.config.showIcons || true;
|
||||
$scope.wideMode = $scope.model.config.hideLabel == "1";
|
||||
|
||||
$scope.labels = {};
|
||||
localizationService.localizeMany(["grid_insertControl"]).then(function(data) {
|
||||
$scope.labels.docTypePickerTitle = data[0];
|
||||
});
|
||||
|
||||
// helper to force the current form into the dirty state
|
||||
$scope.setDirty = function () {
|
||||
if ($scope.propertyForm) {
|
||||
@@ -138,7 +124,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
}
|
||||
|
||||
$scope.overlayMenu = {
|
||||
title: localizationService.localize('grid_insertControl'),
|
||||
title: $scope.labels.docTypePickerTitle,
|
||||
show: false,
|
||||
style: {},
|
||||
filter: $scope.scaffolds.length > 15 ? true : false,
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<div class="umb-pane">
|
||||
<div ng-repeat="property in tab.properties" style="position: relative;">
|
||||
<div ng-repeat="property in tab.properties" class="umb-nested-content-property-container">
|
||||
|
||||
<umb-property property="property" ng-class="{'umb-nested-content--not-supported': property.notSupported}">
|
||||
<umb-property-editor model="property"></umb-property-editor>
|
||||
|
||||
+3
-3
@@ -12,13 +12,13 @@
|
||||
<div class="umb-nested-content__heading" ng-class="{'-with-icon': showIcons}"><i ng-if="showIcons" class="icon" ng-class="$parent.getIcon($index)"></i><span class="umb-nested-content__item-name" ng-bind="$parent.getName($index)"></span></div>
|
||||
|
||||
<div class="umb-nested-content__icons">
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--edit" title="{{editIconTitle}}" ng-class="{ 'umb-nested-content__icon--active' : $parent.realCurrentNode.id == node.id }" ng-click="$parent.editNode($index); $event.stopPropagation();" ng-show="$parent.maxItems > 1" prevent-default>
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--edit" localize="title" title="general_edit" ng-class="{ 'umb-nested-content__icon--active' : $parent.realCurrentNode.id == node.id }" ng-click="$parent.editNode($index); $event.stopPropagation();" ng-show="$parent.maxItems > 1" prevent-default>
|
||||
<i class="icon icon-edit"></i>
|
||||
</a>
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--move" title="{{moveIconTitle}}" ng-click="$event.stopPropagation();" ng-show="$parent.nodes.length > 1" prevent-default>
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--move" localize="title" title="actions_move" ng-click="$event.stopPropagation();" ng-show="$parent.nodes.length > 1" prevent-default>
|
||||
<i class="icon icon-navigation"></i>
|
||||
</a>
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--delete" title="{{deleteIconTitle}}" ng-class="{ 'umb-nested-content__icon--disabled': $parent.nodes.length <= $parent.minItems }" ng-click="$parent.deleteNode($index); $event.stopPropagation();" prevent-default>
|
||||
<a class="umb-nested-content__icon umb-nested-content__icon--delete" localize="title" title="general_delete" ng-class="{ 'umb-nested-content__icon--disabled': $parent.nodes.length <= $parent.minItems }" ng-click="$parent.deleteNode($index); $event.stopPropagation();" prevent-default>
|
||||
<i class="icon icon-trash"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.TagsController",
|
||||
function ($scope) {
|
||||
function ($scope, angularHelper) {
|
||||
|
||||
$scope.valueChanged = function(value) {
|
||||
$scope.model.value = value;
|
||||
// the model value seems to be a reference to the same array, so we need
|
||||
// to set the form as dirty explicitly when the content of the array changes
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,6 +12,10 @@ function TemplatesDeleteController($scope, templateResource , treeService, navig
|
||||
|
||||
//mark it for deletion (used in the UI)
|
||||
$scope.currentNode.loading = true;
|
||||
|
||||
// Reset the error message
|
||||
$scope.error = null;
|
||||
|
||||
templateResource.deleteById($scope.currentNode.id).then(function () {
|
||||
$scope.currentNode.loading = false;
|
||||
|
||||
@@ -21,6 +25,9 @@ function TemplatesDeleteController($scope, templateResource , treeService, navig
|
||||
//TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
}, function (err) {
|
||||
$scope.currentNode.loading = false;
|
||||
$scope.error = err;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.Templates.DeleteController">
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
<div><strong>{{error.errorMsg}}</strong></div>
|
||||
<div>{{error.data.message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="umb-abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -180,6 +180,11 @@
|
||||
<key alias="validationErrorPropertyWithMoreThanOneMapping">Overførsel af egenskaber kunne ikke fuldføres, da en eller flere egenskaber er indstillet til at blive overført mere end én gang.</key>
|
||||
<key alias="validDocTypesNote">Kun andre dokumenttyper, der er gyldige på denne placering, vises.</key>
|
||||
</area>
|
||||
<area alias="codefile">
|
||||
<key alias="createFolderFailedById">Oprettelse af mappen under parent med ID %0% fejlede</key>
|
||||
<key alias="createFolderFailedByName">Oprettelse af mappen under parent med navnet %0% fejlede</key>
|
||||
<key alias="deleteItemFailed">Sletning af filen/mappen fejlede: %0%</key>
|
||||
</area>
|
||||
<area alias="content">
|
||||
<key alias="isPublished" version="7.2">Udgivet</key>
|
||||
<key alias="about">Om siden</key>
|
||||
@@ -276,6 +281,7 @@
|
||||
<key alias="chooseNode">Hvor ønsker du at oprette den nye %0%</key>
|
||||
<key alias="createUnder">Opret under</key>
|
||||
<key alias="createContentBlueprint">Vælg den dokumenttype, du vil oprette en indholdsskabelon til</key>
|
||||
<key alias="enterFolderName">Angiv et navn for mappen</key>
|
||||
<key alias="updateData">Vælg en type og skriv en titel</key>
|
||||
<key alias="noDocumentTypes" version="7.0"><![CDATA[Der kunne ikke findes nogen tilladte dokument typer. Du skal tillade disse i indstillinger under <strong>"dokument typer"</strong>.]]></key>
|
||||
<key alias="noMediaTypes" version="7.0"><![CDATA[Der kunne ikke findes nogen tilladte media typer. Du skal tillade disse i indstillinger under <strong>"media typer"</strong>.]]></key>
|
||||
@@ -1062,6 +1068,7 @@ Mange hilsner fra Umbraco robotten
|
||||
<key alias="tabRules">Editor</key>
|
||||
</area>
|
||||
<area alias="template">
|
||||
<key alias="deleteByIdFailed">Sletning af skabelonen med ID %0% fejlede</key>
|
||||
<key alias="edittemplate">Rediger skabelon</key>
|
||||
<key alias="insertSections">Sektioner</key>
|
||||
<key alias="insertContentArea">Indsæt indholdsområde</key>
|
||||
|
||||
@@ -189,6 +189,11 @@
|
||||
<key alias="validationErrorPropertyWithMoreThanOneMapping">Could not complete property mapping as one or more properties have more than one mapping defined.</key>
|
||||
<key alias="validDocTypesNote">Only alternate types valid for the current location are displayed.</key>
|
||||
</area>
|
||||
<area alias="codefile">
|
||||
<key alias="createFolderFailedById">Failed to create a folder under parent with ID %0%</key>
|
||||
<key alias="createFolderFailedByName">Failed to create a folder under parent with name %0%</key>
|
||||
<key alias="deleteItemFailed">Failed to delete item: %0%</key>
|
||||
</area>
|
||||
<area alias="content">
|
||||
<key alias="isPublished" version="7.2">Is Published</key>
|
||||
<key alias="about">About this page</key>
|
||||
@@ -291,6 +296,7 @@
|
||||
<key alias="chooseNode">Where do you want to create the new %0%</key>
|
||||
<key alias="createUnder">Create an item under</key>
|
||||
<key alias="createContentBlueprint">Select the document type you want to make a content template for</key>
|
||||
<key alias="enterFolderName">Enter a folder name</key>
|
||||
<key alias="updateData">Choose a type and a title</key>
|
||||
<key alias="noDocumentTypes" version="7.0"><![CDATA[There are no allowed document types available. You must enable these in the settings section under <strong>"document types"</strong>.]]></key>
|
||||
<key alias="noMediaTypes" version="7.0"><![CDATA[There are no allowed media types available. You must enable these in the settings section under <strong>"media types"</strong>.]]></key>
|
||||
@@ -1248,6 +1254,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="contentTypeUses">This Content Type uses</key>
|
||||
<key alias="asAContentMasterType">as a Master Content Type. Tabs from Master Content Types are not shown and can only be edited on the Master Content Type itself</key>
|
||||
<key alias="noPropertiesDefinedOnTab">No properties defined on this tab. Click on the "add a new property" link at the top to create a new property.</key>
|
||||
<key alias="createMatchingTemplate">Create matching template</key>
|
||||
<key alias="addIcon">Add icon</key>
|
||||
</area>
|
||||
<area alias="sort">
|
||||
@@ -1347,6 +1354,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="tabRules">Editor</key>
|
||||
</area>
|
||||
<area alias="template">
|
||||
<key alias="deleteByIdFailed">Failed to delete template with ID %0%</key>
|
||||
<key alias="edittemplate">Edit template</key>
|
||||
<key alias="insertSections">Sections</key>
|
||||
<key alias="insertContentArea">Insert content area</key>
|
||||
@@ -1968,8 +1976,8 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="contentTrashed">Trashed content with Id: {0} related to original parent content with Id: {1}</key>
|
||||
<key alias="mediaTrashed">Trashed media with Id: {0} related to original parent media item with Id: {1}</key>
|
||||
<key alias="itemCannotBeRestored">Cannot automatically restore this item</key>
|
||||
<key alias="noRestoreRelation">There is no 'restore' relation found for this node. Use the Move menu item to move it manually.</key>
|
||||
<key alias="restoreUnderRecycled">The item you want to restore it under ('%0%') is in the recycle bin. Use the Move menu item to move the item manually.</key>
|
||||
<key alias="itemCannotBeRestoredHelpText">There is no location where this item can be automatically restored. You can move the item manually using the tree below.</key>
|
||||
<key alias="wasRestored">was restored under</key>
|
||||
</area>
|
||||
<area alias="relationType">
|
||||
<key alias="direction">Direction</key>
|
||||
|
||||
@@ -196,6 +196,11 @@
|
||||
<key alias="validationErrorPropertyWithMoreThanOneMapping">Could not complete property mapping as one or more properties have more than one mapping defined.</key>
|
||||
<key alias="validDocTypesNote">Only alternate types valid for the current location are displayed.</key>
|
||||
</area>
|
||||
<area alias="codefile">
|
||||
<key alias="createFolderFailedById">Failed to create a folder under parent with ID %0%</key>
|
||||
<key alias="createFolderFailedByName">Failed to create a folder under parent with name %0%</key>
|
||||
<key alias="deleteItemFailed">Failed to delete item: %0%</key>
|
||||
</area>
|
||||
<area alias="content">
|
||||
<key alias="isPublished" version="7.2">Is Published</key>
|
||||
<key alias="about">About this page</key>
|
||||
@@ -316,6 +321,7 @@
|
||||
<key alias="chooseNode">Where do you want to create the new %0%</key>
|
||||
<key alias="createUnder">Create an item under</key>
|
||||
<key alias="createContentBlueprint">Select the document type you want to make a content template for</key>
|
||||
<key alias="enterFolderName">Enter a folder name</key>
|
||||
<key alias="updateData">Choose a type and a title</key>
|
||||
<key alias="noDocumentTypes" version="7.0"><![CDATA[There are no allowed document types available. You must enable these in the settings section under <strong>"document types"</strong>.]]></key>
|
||||
<key alias="noMediaTypes" version="7.0"><![CDATA[There are no allowed media types available. You must enable these in the settings section under <strong>"media types"</strong>.]]></key>
|
||||
@@ -1272,6 +1278,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="contentTypeUses">This Content Type uses</key>
|
||||
<key alias="asAContentMasterType">as a Master Content Type. Tabs from Master Content Types are not shown and can only be edited on the Master Content Type itself</key>
|
||||
<key alias="noPropertiesDefinedOnTab">No properties defined on this tab. Click on the "add a new property" link at the top to create a new property.</key>
|
||||
<key alias="createMatchingTemplate">Create matching template</key>
|
||||
<key alias="addIcon">Add icon</key>
|
||||
</area>
|
||||
<area alias="sort">
|
||||
@@ -1387,6 +1394,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="previewHelp">How the text will look like in the rich text editor.</key>
|
||||
</area>
|
||||
<area alias="template">
|
||||
<key alias="deleteByIdFailed">Failed to delete template with ID %0%</key>
|
||||
<key alias="edittemplate">Edit template</key>
|
||||
<key alias="insertSections">Sections</key>
|
||||
<key alias="insertContentArea">Insert content area</key>
|
||||
@@ -2024,8 +2032,8 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="contentTrashed">Trashed content with Id: {0} related to original parent content with Id: {1}</key>
|
||||
<key alias="mediaTrashed">Trashed media with Id: {0} related to original parent media item with Id: {1}</key>
|
||||
<key alias="itemCannotBeRestored">Cannot automatically restore this item</key>
|
||||
<key alias="noRestoreRelation">There is no 'restore' relation found for this node. Use the Move menu item to move it manually.</key>
|
||||
<key alias="restoreUnderRecycled">The item you want to restore it under ('%0%') is in the recycle bin. Use the Move menu item to move the item manually.</key>
|
||||
<key alias="itemCannotBeRestoredHelpText">There is no location where this item can be automatically restored. You can move the item manually using the tree below.</key>
|
||||
<key alias="wasRestored">was restored under</key>
|
||||
</area>
|
||||
<area alias="relationType">
|
||||
<key alias="direction">Direction</key>
|
||||
|
||||
@@ -142,8 +142,8 @@ namespace Umbraco.Web.Cache
|
||||
() => ContentService.Saved -= ContentService_Saved);
|
||||
Bind(() => ContentService.Copied += ContentService_Copied, // needed for permissions
|
||||
() => ContentService.Copied -= ContentService_Copied);
|
||||
Bind(() => ContentService.TreeChanged += ContentService_Changed,// handles all content changes
|
||||
() => ContentService.TreeChanged -= ContentService_Changed);
|
||||
Bind(() => ContentService.TreeChanged += ContentService_TreeChanged,// handles all content changes
|
||||
() => ContentService.TreeChanged -= ContentService_TreeChanged);
|
||||
|
||||
// TreeChanged should also deal with this
|
||||
//Bind(() => ContentService.SavedBlueprint += ContentService_SavedBlueprint,
|
||||
@@ -206,7 +206,7 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
}
|
||||
|
||||
private void ContentService_Changed(IContentService sender, TreeChange<IContent>.EventArgs args)
|
||||
private void ContentService_TreeChanged(IContentService sender, TreeChange<IContent>.EventArgs args)
|
||||
{
|
||||
_distributedCache.RefreshContentCache(args.Changes.ToArray());
|
||||
}
|
||||
|
||||
@@ -53,6 +53,16 @@ namespace Umbraco.Web.Editors.Filters
|
||||
if (currentUser.IsAdmin())
|
||||
return Attempt<string>.Succeed();
|
||||
|
||||
var existingGroups = _userService.GetUserGroupsByAlias(groupAliases);
|
||||
|
||||
if(!existingGroups.Any())
|
||||
{
|
||||
// We're dealing with new groups,
|
||||
// so authorization should be given to any user with access to Users section
|
||||
if (currentUser.AllowedSections.Contains(Constants.Applications.Users))
|
||||
return Attempt<string>.Succeed();
|
||||
}
|
||||
|
||||
var userGroups = currentUser.Groups.Select(x => x.Alias).ToArray();
|
||||
var missingAccess = groupAliases.Except(userGroups).ToArray();
|
||||
return missingAccess.Length == 0
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Umbraco.Web.Editors
|
||||
//authorize that the user has access to save this user group
|
||||
var authHelper = new UserGroupEditorAuthorizationHelper(
|
||||
Services.UserService, Services.ContentService, Services.MediaService, Services.EntityService);
|
||||
|
||||
var isAuthorized = authHelper.AuthorizeGroupAccess(Security.CurrentUser, userGroupSave.Alias);
|
||||
if (isAuthorized == false)
|
||||
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, isAuthorized.Result));
|
||||
@@ -51,6 +52,14 @@ namespace Umbraco.Web.Editors
|
||||
if (isAuthorized == false)
|
||||
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, isAuthorized.Result));
|
||||
|
||||
//current user needs to be added to a new group if not an admin (possibly only if no other users are added?) to avoid a 401
|
||||
if(!Security.CurrentUser.IsAdmin() && (userGroupSave.Id == null || Convert.ToInt32(userGroupSave.Id) >= 0)/* && !userGroupSave.Users.Any() */)
|
||||
{
|
||||
var userIds = userGroupSave.Users.ToList();
|
||||
userIds.Add(Security.CurrentUser.Id);
|
||||
userGroupSave.Users = userIds;
|
||||
}
|
||||
|
||||
//save the group
|
||||
Services.UserService.Save(userGroupSave.PersistedUserGroup, userGroupSave.Users.ToArray());
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Security;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
@@ -831,5 +832,37 @@ namespace Umbraco.Web
|
||||
#endregion
|
||||
|
||||
|
||||
#region RelatedLink
|
||||
|
||||
/// <summary>
|
||||
/// Renders an anchor element for a RelatedLink instance.
|
||||
/// Format: <a href="relatedLink.Link" target="_blank/_self">relatedLink.Caption</a>
|
||||
/// </summary>
|
||||
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
|
||||
/// <param name="relatedLink">The RelatedLink instance</param>
|
||||
/// <returns>An anchor element </returns>
|
||||
public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink)
|
||||
{
|
||||
return htmlHelper.GetRelatedLinkHtml(relatedLink, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders an anchor element for a RelatedLink instance, accepting htmlAttributes.
|
||||
/// Format: <a href="relatedLink.Link" target="_blank/_self" htmlAttributes>relatedLink.Caption</a>
|
||||
/// </summary>
|
||||
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
|
||||
/// <param name="relatedLink">The RelatedLink instance</param>
|
||||
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
|
||||
/// <returns></returns>
|
||||
public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink, object htmlAttributes)
|
||||
{
|
||||
var tagBuilder = new TagBuilder("a");
|
||||
tagBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
|
||||
tagBuilder.MergeAttribute("href", relatedLink.Link);
|
||||
tagBuilder.MergeAttribute("target", relatedLink.NewWindow ? "_blank" : "_self");
|
||||
tagBuilder.InnerHtml = HttpUtility.HtmlEncode(relatedLink.Caption);
|
||||
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Web.Hosting;
|
||||
using CSharpTest.Net.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
@@ -15,7 +14,6 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
@@ -26,7 +24,6 @@ using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Web.Cache;
|
||||
using Umbraco.Web.Install;
|
||||
using Umbraco.Web.PublishedCache.NuCache.DataSource;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
Reference in New Issue
Block a user