From 066927742e47cd29776e796077347370269d423b Mon Sep 17 00:00:00 2001 From: AussieInSeattle Date: Thu, 19 Feb 2015 15:47:11 -0800 Subject: [PATCH 001/605] Update UI for settings for a custom grid editor --- .../src/views/propertyeditors/grid/grid.html | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html index 6f092c8ea8..687130c952 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html @@ -162,6 +162,15 @@ + + +
+ + + +
@@ -251,4 +260,4 @@ - \ No newline at end of file + From b2947264e1e25e5284fab03990d7e833cba06a75 Mon Sep 17 00:00:00 2001 From: AussieInSeattle Date: Thu, 19 Feb 2015 15:49:03 -0800 Subject: [PATCH 002/605] edit function for settings on a custom grid editor --- .../propertyeditors/grid/grid.controller.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js index e4cb4e380d..86bfce3f32 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js @@ -273,6 +273,36 @@ angular.module("umbraco") }); }; + + + // ********************************************* + // Control management functions + // ********************************************* + + $scope.editControlSettings = function (control) { + + var obj = $scope.model.config; + obj.items.config = control.editor.config.settings; + + dialogService.open( + { + template: "views/propertyeditors/grid/dialogs/config.html", + gridItem: { "config": (control.value ? control.value.settings : null) }, + itemType: null, + config: obj, + callback: function (data) { + if (angular.isObject(control.value)) + control.value.settings = data.config; + else { + control.value = { + "settings": data.config + }; + } + //console.log(control.value); + //console.log(control.value.settings); + } + }); + }; // ********************************************* // Area management functions From 05a0846e89cf97ae14459b25b3d928de77a2ce6a Mon Sep 17 00:00:00 2001 From: AussieInSeattle Date: Mon, 9 Mar 2015 11:22:16 -0700 Subject: [PATCH 003/605] Update grid.controller.js --- .../src/views/propertyeditors/grid/grid.controller.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js index 86bfce3f32..4bdf4088ca 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js @@ -291,15 +291,7 @@ angular.module("umbraco") itemType: null, config: obj, callback: function (data) { - if (angular.isObject(control.value)) - control.value.settings = data.config; - else { - control.value = { - "settings": data.config - }; - } - //console.log(control.value); - //console.log(control.value.settings); + control.settings = data.config; } }); }; From 2276584c90d0d2237c7a5bc0bf9c0246335cbcf5 Mon Sep 17 00:00:00 2001 From: AussieInSeattle Date: Wed, 11 Mar 2015 11:52:57 -0700 Subject: [PATCH 004/605] Update for when first control has settings Adding style for when first control has settings - it was previously overlapping the "cog" icon above it --- .../src/views/propertyeditors/grid/grid.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html index 687130c952..fa8515fcc7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.html @@ -164,7 +164,7 @@ -
+
From 7eeb0c496652c33115cf1fcd4434810c63ebb66f Mon Sep 17 00:00:00 2001 From: TimGeyssens Date: Wed, 14 Oct 2015 11:29:34 +0200 Subject: [PATCH 005/605] Fixes U4-7249 Insert Macro split button, when selecting a macro that has parameters the dialog should immediately show those --- src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js | 4 ++-- src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js index d9b1a28505..b8c1a203d6 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditTemplate.js @@ -9,12 +9,12 @@ _openMacroModal: function(alias) { var self = this; - + UmbClientMgr.openAngularModalWindow({ template: "views/common/dialogs/insertmacro.html", dialogData: { renderingEngine: "WebForms", - selectedAlias: alias + macroData: { macroAlias: alias } }, callback: function(data) { UmbEditor.Insert(data.syntax, '', self._opts.editorClientId); diff --git a/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js b/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js index 28398d081a..16a0635b70 100644 --- a/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js +++ b/src/Umbraco.Web.UI/umbraco_client/Editors/EditView.js @@ -41,12 +41,12 @@ /// callback used to display the modal dialog to insert a macro with parameters var self = this; - + UmbClientMgr.openAngularModalWindow({ template: "views/common/dialogs/insertmacro.html", dialogData: { renderingEngine: "Mvc", - selectedAlias: alias + macroData: {macroAlias: alias} }, callback: function (data) { UmbEditor.Insert(data.syntax, '', self._opts.codeEditorElementId); From d04b7ae9c7a2814cdd9e0366b3abe71d8ac59c49 Mon Sep 17 00:00:00 2001 From: Per Ploug Date: Tue, 20 Oct 2015 10:44:44 +0200 Subject: [PATCH 006/605] Revert "doctype editcontroller for modelsbuilder" This reverts commit 8cf27c810dcf966ff3ee0df6e3df85b85c9a5e1c. --- .../views/documenttypes/edit.controller.js | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js index 64157d3183..5c5654bb88 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js @@ -9,7 +9,7 @@ (function() { "use strict"; - function DocumentTypesEditController($scope, $routeParams, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter) { + function DocumentTypesEditController($scope, $routeParams, modelsResource, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter) { var vm = this; @@ -17,6 +17,7 @@ vm.currentNode = null; vm.contentType = {}; + vm.page = {}; vm.page.loading = false; vm.page.saveButtonState = "init"; @@ -44,6 +45,51 @@ } ]; + + + //disable by default, turn on if detected correctly. + vm.page.modelsBuilder = false; + modelsResource.getModelsOutOfDateStatus().then(function () { + vm.page.modelsBuilder = true; + }); + + //Models builder mode: + + vm.page.defaultButton = { + hotKey: "ctrl+s", + labelKey: "buttons_save", + letter: "S", + type: "submit", + handler: function () { vm.save(); } + }; + vm.page.subButtons = [{ + hotKey: "ctrl+g", + labelKey: "buttons_generateModels", + letter: "G", + handler: function(){ + + vm.page.saveButtonState = "busy"; + notificationsService.info("Building models", "this can take abit of time, don't worry"); + + modelsResource.buildModels().then(function(){ + vm.page.saveButtonState = "init"; + + //clear and add success + notificationsService.success("Models Generated"); + + //just calling this to get the servar back to life + modelsResource.getModelsOutOfDateStatus(); + + }, function(){ + notificationsService.error("Models could not be generated"); + vm.page.saveButtonState = "error"; + }); + + } + }]; + + + vm.page.keyboardShortcutsOverview = [ { "name": "Sections", From 2a747857554d8eddbcfdbd99ec8b0ccb61b56f42 Mon Sep 17 00:00:00 2001 From: Per Ploug Date: Tue, 20 Oct 2015 14:17:45 +0200 Subject: [PATCH 007/605] Adds ModelsBuilder Nuget --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 30 ++++++++++++++++++++++++ src/Umbraco.Web.UI/packages.config | 7 ++++++ src/Umbraco.Web.UI/web.Template.config | 4 ++++ 3 files changed, 41 insertions(+) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index c4c4e3d34f..c752e78d03 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -159,6 +159,14 @@ False ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll + + ..\packages\Microsoft.CodeAnalysis.Common.1.0.0\lib\net45\Microsoft.CodeAnalysis.dll + True + + + ..\packages\Microsoft.CodeAnalysis.CSharp.1.0.0\lib\net45\Microsoft.CodeAnalysis.CSharp.dll + True + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll @@ -203,6 +211,10 @@ System + + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + True + @@ -235,6 +247,10 @@ False False + + ..\packages\System.Reflection.Metadata.1.0.21\lib\portable-net45+win8\System.Reflection.Metadata.dll + True + @@ -336,6 +352,14 @@ ..\packages\UrlRewritingNet.UrlRewriter.2.0.60829.1\lib\UrlRewritingNet.UrlRewriter.dll + + ..\packages\Zbu.ModelsBuilder.2.1.5\lib\Zbu.ModelsBuilder.dll + True + + + ..\packages\Zbu.ModelsBuilder.AspNet.2.1.5\lib\Zbu.ModelsBuilder.AspNet.dll + True + @@ -1952,6 +1976,8 @@ + + Designer @@ -2390,6 +2416,10 @@ + + + + 11.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0 diff --git a/src/Umbraco.Web.UI/packages.config b/src/Umbraco.Web.UI/packages.config index 289aed138d..6df29cc1bf 100644 --- a/src/Umbraco.Web.UI/packages.config +++ b/src/Umbraco.Web.UI/packages.config @@ -20,6 +20,9 @@ + + + @@ -32,5 +35,9 @@ + + + + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 49174edf01..a98d9f6231 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -52,6 +52,10 @@ + + + + From 2c0d79d786734c711793ab530adae043a8c4f393 Mon Sep 17 00:00:00 2001 From: Per Ploug Date: Fri, 23 Oct 2015 08:29:26 +0200 Subject: [PATCH 008/605] Ensuring the doctype UI changes are pushed, git seems unsure... --- .../src/views/documenttypes/edit.controller.js | 1 - src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.html | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js index 5c5654bb88..3dc38c4cac 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js @@ -84,7 +84,6 @@ notificationsService.error("Models could not be generated"); vm.page.saveButtonState = "error"; }); - } }]; diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.html b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.html index c1dd63910b..30ef902a02 100644 --- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.html @@ -45,6 +45,7 @@ label-key="buttons_save"> + Date: Sat, 24 Oct 2015 22:10:17 +0200 Subject: [PATCH 009/605] poc of templates with models --- src/Umbraco.Web/Editors/ContentTypeController.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 8e52819b2d..d002733d75 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -184,6 +184,15 @@ namespace Umbraco.Web.Editors if (template == null) { template = new Template(contentType.Name, contentType.Alias); + + //POC: temporary models template support, this should really not be handled here but by + //the models builder + var design = @"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = null; +}"; + + template.Content = design.Replace("IPublishedContent", contentType.Name.ToSafeAlias(false)); Services.FileService.SaveTemplate(template); } From a6b56db2f542a3a9e971f5798cc9fe879d31e211 Mon Sep 17 00:00:00 2001 From: Jordan Lane Date: Thu, 29 Oct 2015 15:16:44 +0000 Subject: [PATCH 010/605] Fixes an issue with the contentService.RePublishAll() where it wouldn't publish an old published version if the newest version of the content wasn't published i.e had a scheduled date set because this would create a new version with status not published --- .../Repositories/ContentRepository.cs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 60d7d8e7ef..2eab12a6a0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -234,7 +234,7 @@ namespace Umbraco.Core.Persistence.Repositories var processed = 0; do { - var descendants = GetPagedResultsByQuery(query, pageIndex, pageSize, out total, "Path", Direction.Ascending); + var descendants = GetPagedResultsByQueryNoFilter(query, pageIndex, pageSize, out total, "Path", Direction.Ascending); var xmlItems = (from descendant in descendants let xml = serializer(descendant) @@ -728,7 +728,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// public void AddOrUpdateContentXml(IContent content, Func xml) - { + { _contentXmlRepository.AddOrUpdate(new ContentXmlEntity(content, xml)); } @@ -787,6 +787,26 @@ namespace Umbraco.Core.Persistence.Repositories } + /// + /// Gets paged content results + /// + /// Query to excute + /// Page number + /// Page size + /// Total records query would return without paging + /// Field to order by + /// Direction to order by + /// An Enumerable list of objects + public IEnumerable GetPagedResultsByQueryNoFilter(IQuery query, long pageIndex, int pageSize, out long totalRecords, + string orderBy, Direction orderDirection) + { + + return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, + new Tuple("cmsDocument", "nodeId"), + ProcessQuery, orderBy, orderDirection); + + } + #endregion #region IRecycleBinRepository members @@ -826,11 +846,11 @@ namespace Umbraco.Core.Persistence.Repositories var contentTypes = _contentTypeRepository.GetAll(dtos.Select(x => x.ContentVersionDto.ContentDto.ContentTypeId).ToArray()) .ToArray(); - + var ids = dtos .Where(dto => dto.TemplateId.HasValue && dto.TemplateId.Value > 0) .Select(x => x.TemplateId.Value).ToArray(); - + //NOTE: This should be ok for an SQL 'IN' statement, there shouldn't be an insane amount of content types var templates = ids.Length == 0 ? Enumerable.Empty() : _templateRepository.GetAll(ids).ToArray(); @@ -972,4 +992,4 @@ namespace Umbraco.Core.Persistence.Repositories _contentXmlRepository.Dispose(); } } -} +} \ No newline at end of file From 1e4c9c2505c155e72b8c74215487db1e3a6684c7 Mon Sep 17 00:00:00 2001 From: Jordan Lane Date: Thu, 29 Oct 2015 15:20:35 +0000 Subject: [PATCH 011/605] Set the publish status of new content version to saved if validation of publication fails e.g. a release date of the future or past unpublish date --- src/Umbraco.Core/Services/ContentService.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index da25bd0938..6819ce2859 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1966,6 +1966,10 @@ namespace Umbraco.Core.Services var uow = UowProvider.GetUnitOfWork(); using (var repository = RepositoryFactory.CreateContentRepository(uow)) { + if (published == false) + { + content.ChangePublishedState(PublishedState.Saved); + } //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed if (content.HasIdentity == false) { From c5cf1fa6b2d3930bc4ee818124feaac217936c71 Mon Sep 17 00:00:00 2001 From: Jordan Lane Date: Thu, 29 Oct 2015 15:21:15 +0000 Subject: [PATCH 012/605] Checks if content has expired or is awaiting release before publishing --- src/Umbraco.Core/Services/ContentService.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 6819ce2859..68038fe9c0 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -2112,6 +2112,22 @@ namespace Umbraco.Core.Services content.Name, content.Id)); return PublishStatusType.FailedPathNotPublished; } + else if (content.ExpireDate.HasValue && content.ExpireDate.Value > DateTime.MinValue && DateTime.Now > content.ExpireDate.Value) + { + Logger.Info( + string.Format( + "Content '{0}' with Id '{1}' has expired and could not be published.", + content.Name, content.Id)); + return PublishStatusType.FailedHasExpired; + } + else if (content.ReleaseDate.HasValue && content.ReleaseDate.Value > DateTime.MinValue && content.ReleaseDate.Value > DateTime.Now) + { + Logger.Info( + string.Format( + "Content '{0}' with Id '{1}' is awaiting release and could not be published.", + content.Name, content.Id)); + return PublishStatusType.FailedAwaitingRelease; + } return PublishStatusType.Success; } From 8e6bac534a9042828c0331cd49b6419a5f521fe4 Mon Sep 17 00:00:00 2001 From: Jordan Lane Date: Thu, 29 Oct 2015 15:23:40 +0000 Subject: [PATCH 013/605] Fix a bug where PublishStatusType would fallback to FailedContentInvalid (and break) if it was expired or trashed and add error message for FailedHasExpired TODO: Add error message to other languages --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 3 +++ src/Umbraco.Web/Editors/ContentController.cs | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 8f493d2582..90c9e0c605 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -689,6 +689,9 @@ To manage your website, simply open the Umbraco back office and start adding con %0% could not be published because the item is scheduled for release. ]]> + diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 1b6fbfa3cb..9e63a45353 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -659,9 +659,17 @@ namespace Umbraco.Web.Editors new[] {string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id)}).Trim()); break; case PublishStatusType.FailedHasExpired: - //TODO: We should add proper error messaging for this! + display.AddWarningNotification( + Services.TextService.Localize("publish"), + Services.TextService.Localize("publish/contentPublishedFailedExpired", + new[] + { + string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), + }).Trim()); + break; case PublishStatusType.FailedIsTrashed: //TODO: We should add proper error messaging for this! + break; case PublishStatusType.FailedContentInvalid: display.AddWarningNotification( Services.TextService.Localize("publish"), From 1cd00cb6f61b7e06ec6bb1527e081d52725bff5f Mon Sep 17 00:00:00 2001 From: Darren Ferguson Date: Fri, 20 Nov 2015 18:11:13 +0000 Subject: [PATCH 014/605] change the text "Reload nodes" to just "Reload" my editors don't know what a node is! --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 582bb077ef..0a8411b04e 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -25,7 +25,7 @@ Public access Publish Unpublish - Reload nodes + Reload Republish entire site Restore Permissions diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index c9dcd1554a..df72aa8e0b 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -25,7 +25,7 @@ Public access Publish Unpublish - Reload nodes + Reload Republish entire site Restore Permissions From dbece874dd7d1ffbe124c4f6f8e18a11a290fe32 Mon Sep 17 00:00:00 2001 From: kiasyn Date: Wed, 25 Nov 2015 10:25:00 +1300 Subject: [PATCH 015/605] U4-7400 - Datepicker is not updating scope model value in time for 3rd party plugins Force set scope model value when the datetime changes, rather than just on formsubmit. This means that 3rd party plugins (such as grids) can use this editor. --- .../views/propertyeditors/datepicker/datepicker.controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index fe413e0159..1c29184273 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -44,6 +44,7 @@ function dateTimePickerController($scope, notificationsService, assetsService, a $scope.datePickerForm.datepicker.$setValidity("pickerError", true); $scope.hasDatetimePickerValue = true; $scope.datetimePickerValue = e.date.format($scope.model.config.format); + $scope.model.value = $scope.datetimePickerValue; } else { $scope.hasDatetimePickerValue = false; From 5d9bde807e125843e02702a94b146d1099543074 Mon Sep 17 00:00:00 2001 From: Wincent Date: Sat, 31 Oct 2015 16:29:02 +0100 Subject: [PATCH 016/605] Changes GetBigThumbnail to image processor in mediahelper.service.js and fileupload.controller.js Changed ImageController.GetBigThumbnail to redirect Changed thumbnail paths to include rnd equal to UpdateDate --- .../fileupload/fileupload.controller.js | 47 ++- src/Umbraco.Web/Editors/ImagesController.cs | 293 +++++++----------- 2 files changed, 141 insertions(+), 199 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js index 37dea64c21..d62d76c982 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/fileupload/fileupload.controller.js @@ -144,31 +144,28 @@ function fileUploadController($scope, $element, $compile, imageHelper, fileManag }; angular.module("umbraco") .controller('Umbraco.PropertyEditors.FileUploadController', fileUploadController) - .run(function(mediaHelper, umbRequestHelper){ + .run(function(mediaHelper, umbRequestHelper, assetsService){ if (mediaHelper && mediaHelper.registerFileResolver) { - - //NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource - // they contain different data structures so if we need to query against it we need to be aware of this. - mediaHelper.registerFileResolver("Umbraco.UploadField", function(property, entity, thumbnail){ - if (thumbnail) { - - if (mediaHelper.detectIfImageByExtension(property.value)) { - - var thumbnailUrl = umbRequestHelper.getApiUrl( - "imagesApiBaseUrl", - "GetBigThumbnail", - [{ originalImagePath: property.value }]); - - return thumbnailUrl; - } - else { - return null; - } - + assetsService.load(["lib/moment/moment-with-locales.js"]).then( + function () { + //NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource + // they contain different data structures so if we need to query against it we need to be aware of this. + mediaHelper.registerFileResolver("Umbraco.UploadField", function(property, entity, thumbnail){ + if (thumbnail) { + if (mediaHelper.detectIfImageByExtension(property.value)) { + //get default big thumbnail from image processor + var thumbnailUrl = property.value + "?rnd=" + moment(entity.updateDate).format("YYYYMMDDHHmmss") + "&width=500"; + return thumbnailUrl; + } + else { + return null; + } + } + else { + return property.value; + } + }); } - else { - return property.value; - } - }); + ); } - }); \ No newline at end of file + }); diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index 39960317b1..d437b08ecc 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -1,175 +1,120 @@ -using System; -using System.Drawing; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Media; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; - -namespace Umbraco.Web.Editors -{ - /// - /// A controller used to return images for media - /// - [PluginController("UmbracoApi")] - public class ImagesController : UmbracoAuthorizedApiController - { - /// - /// Gets the big thumbnail image for the media id - /// - /// - /// - /// - /// If there is no media, image property or image file is found then this will return not found. - /// - public HttpResponseMessage GetBigThumbnail(int mediaId) - { - var media = Services.MediaService.GetById(mediaId); - if (media == null) - { - return Request.CreateResponse(HttpStatusCode.NotFound); - } - var imageProp = media.Properties[Constants.Conventions.Media.File]; - if (imageProp == null) - { - return Request.CreateResponse(HttpStatusCode.NotFound); - } - - var imagePath = imageProp.Value.ToString(); - - return GetBigThumbnail(imagePath); - } - - /// - /// Gets the big thumbnail image for the original image path - /// - /// - /// - /// - /// If there is no original image is found then this will return not found. - /// - public HttpResponseMessage GetBigThumbnail(string originalImagePath) - { - if (string.IsNullOrWhiteSpace(originalImagePath)) - return Request.CreateResponse(HttpStatusCode.OK); - - return GetResized(originalImagePath, 500, "big-thumb"); - } - - /// - /// Gets a resized image for the media id - /// - /// - /// - /// - /// - /// If there is no media, image property or image file is found then this will return not found. - /// - public HttpResponseMessage GetResized(int mediaId, int width) - { - var media = Services.MediaService.GetById(mediaId); - if (media == null) - { - return new HttpResponseMessage(HttpStatusCode.NotFound); - } - var imageProp = media.Properties[Constants.Conventions.Media.File]; - if (imageProp == null) - { - return new HttpResponseMessage(HttpStatusCode.NotFound); - } - - var imagePath = imageProp.Value.ToString(); - - return GetResized(imagePath, width); - } - - /// - /// Gets a resized image for the image at the given path - /// - /// - /// - /// - /// - /// If there is no media, image property or image file is found then this will return not found. - /// - public HttpResponseMessage GetResized(string imagePath, int width) - { - return GetResized(imagePath, width, Convert.ToString(width)); - } - - //TODO: We should delegate this to ImageProcessing - - /// - /// Gets a resized image - if the requested max width is greater than the original image, only the original image will be returned. - /// - /// - /// - /// - /// - private HttpResponseMessage GetResized(string imagePath, int width, string suffix) - { - var mediaFileSystem = FileSystemProviderManager.Current.GetFileSystemProvider(); - var ext = Path.GetExtension(imagePath); - - //we need to check if it is an image by extension - if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.InvariantContains(ext.TrimStart('.')) == false) - { - return Request.CreateResponse(HttpStatusCode.NotFound); - } - - var thumbFilePath = imagePath.TrimEnd(ext) + "_" + suffix + ".jpg"; - var fullOrgPath = mediaFileSystem.GetFullPath(mediaFileSystem.GetRelativePath(imagePath)); - var fullNewPath = mediaFileSystem.GetFullPath(mediaFileSystem.GetRelativePath(thumbFilePath)); - var thumbIsNew = mediaFileSystem.FileExists(fullNewPath) == false; - if (thumbIsNew) - { - //we need to generate it - if (mediaFileSystem.FileExists(fullOrgPath) == false) - { - return Request.CreateResponse(HttpStatusCode.NotFound); - } - - using (var fileStream = mediaFileSystem.OpenFile(fullOrgPath)) - { - if (fileStream.CanSeek) fileStream.Seek(0, 0); - using (var originalImage = Image.FromStream(fileStream)) - { - //If it is bigger, then do the resize - if (originalImage.Width >= width && originalImage.Height >= width) - { - ImageHelper.GenerateThumbnail( - originalImage, - width, - fullNewPath, - "jpg", - mediaFileSystem); - } - else - { - //just return the original image - fullNewPath = fullOrgPath; - } - - } - } - } - - var result = Request.CreateResponse(HttpStatusCode.OK); - //NOTE: That we are not closing this stream as the framework will do that for us, if we try it will - // fail. See http://stackoverflow.com/questions/9541351/returning-binary-file-from-controller-in-asp-net-web-api - var stream = mediaFileSystem.OpenFile(fullNewPath); - if (stream.CanSeek) stream.Seek(0, 0); - result.Content = new StreamContent(stream); - result.Headers.Date = mediaFileSystem.GetLastModified(imagePath); - result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg"); - return result; - } - } +using System; +using System.Drawing; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Core.Media; +using Umbraco.Core.Models; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Editors +{ + /// + /// A controller used to return images for media + /// + [PluginController("UmbracoApi")] + public class ImagesController : UmbracoAuthorizedApiController + { + /// + /// Gets the big thumbnail image for the media id + /// + /// + /// + /// + /// If there is no media, image property or image file is found then this will return not found. + /// + public HttpResponseMessage GetBigThumbnail(int mediaId) + { + var media = Services.MediaService.GetById(mediaId); + if (media == null) + { + return Request.CreateResponse(HttpStatusCode.NotFound); + } + + return GetResized(media, 500); + } + + /// + /// Gets the big thumbnail image for the original image path + /// + /// + /// + /// + /// If there is no original image is found then this will return not found. + /// + public HttpResponseMessage GetBigThumbnail(string originalImagePath) + { + if (string.IsNullOrWhiteSpace(originalImagePath)) + return Request.CreateResponse(HttpStatusCode.OK); + + return GetResized(originalImagePath, 500); + } + + /// + /// Gets a resized image for the media id + /// + /// + /// + /// + /// + /// If there is no media, image property or image file is found then this will return not found. + /// + public HttpResponseMessage GetResized(int mediaId, int width) + { + var media = Services.MediaService.GetById(mediaId); + if (media == null) + { + return new HttpResponseMessage(HttpStatusCode.NotFound); + } + + return GetResized( media, 500 ); + } + + /// + /// Gets a resized image for the image at the given path + /// + /// + /// + /// + /// + /// If there is no media, image property or image file is found then this will return not found. + /// + public HttpResponseMessage GetResized(string imagePath, int width) + { + var media = Services.MediaService.GetMediaByPath( imagePath ); + if (media == null) + { + return new HttpResponseMessage( HttpStatusCode.NotFound ); + } + + return GetResized( media, 500 ); + } + + /// + /// Gets a resized image by redirecting to ImageProcessor + /// + /// + /// + /// + private HttpResponseMessage GetResized(IMedia media, int width) + { + var imageProp = media.Properties[Constants.Conventions.Media.File]; + if (imageProp == null) + { + return Request.CreateResponse( HttpStatusCode.NotFound ); + } + + var imagePath = imageProp.Value.ToString(); + var response = Request.CreateResponse( HttpStatusCode.Found ); + response.Headers.Location = new Uri( string.Format( "{0}?rnd={1}&width={2}", imagePath, string.Format( "{0:yyyyMMddHHmmss}", media.UpdateDate ), width ), UriKind.Relative ); + return response; + } + } } \ No newline at end of file From 2664a75c84d11711ccb3efaf11638b771c65289c Mon Sep 17 00:00:00 2001 From: Wincent Date: Tue, 10 Nov 2015 21:09:34 +0100 Subject: [PATCH 017/605] Removed generation of old thumbnails --- .../FileUploadPropertyValueEditor.cs | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs index e4ff4da1d6..775cf67c77 100644 --- a/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -128,29 +128,6 @@ namespace Umbraco.Web.PropertyEditors { var umbracoFile = UmbracoMediaFile.Save(fileStream, fileName); - if (umbracoFile.SupportsResizing) - { - var additionalSizes = new List(); - //get the pre-vals value - var thumbs = editorValue.PreValues.FormatAsDictionary(); - if (thumbs.Any()) - { - var thumbnailSizes = thumbs.First().Value.Value; - // additional thumbnails configured as prevalues on the DataType - foreach (var thumb in thumbnailSizes.Split(new[] { ";", "," }, StringSplitOptions.RemoveEmptyEntries)) - { - int thumbSize; - if (thumb == "" || int.TryParse(thumb, out thumbSize) == false) continue; - additionalSizes.Add(thumbSize); - } - } - - using (var image = Image.FromStream(fileStream)) - { - ImageHelper.GenerateMediaThumbnails(fs, fileName, umbracoFile.Extension, image, additionalSizes); - } - - } newValue.Add(umbracoFile.Url); //add to the saved paths savedFilePaths.Add(umbracoFile.Url); From e0ee786271e334116fafc58b25127caf6cc1320f Mon Sep 17 00:00:00 2001 From: Wincent Date: Fri, 4 Dec 2015 09:31:39 +0100 Subject: [PATCH 018/605] Re-enables support for non media thumbnails --- src/Umbraco.Web/Editors/ImagesController.cs | 250 ++++++++++---------- 1 file changed, 131 insertions(+), 119 deletions(-) diff --git a/src/Umbraco.Web/Editors/ImagesController.cs b/src/Umbraco.Web/Editors/ImagesController.cs index d437b08ecc..73389c0185 100644 --- a/src/Umbraco.Web/Editors/ImagesController.cs +++ b/src/Umbraco.Web/Editors/ImagesController.cs @@ -1,120 +1,132 @@ -using System; -using System.Drawing; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.IO; -using Umbraco.Core.Media; -using Umbraco.Core.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using Umbraco.Web.WebApi.Filters; -using Constants = Umbraco.Core.Constants; - -namespace Umbraco.Web.Editors -{ - /// - /// A controller used to return images for media - /// - [PluginController("UmbracoApi")] - public class ImagesController : UmbracoAuthorizedApiController - { - /// - /// Gets the big thumbnail image for the media id - /// - /// - /// - /// - /// If there is no media, image property or image file is found then this will return not found. - /// - public HttpResponseMessage GetBigThumbnail(int mediaId) - { - var media = Services.MediaService.GetById(mediaId); - if (media == null) - { - return Request.CreateResponse(HttpStatusCode.NotFound); - } - - return GetResized(media, 500); - } - - /// - /// Gets the big thumbnail image for the original image path - /// - /// - /// - /// - /// If there is no original image is found then this will return not found. - /// - public HttpResponseMessage GetBigThumbnail(string originalImagePath) - { - if (string.IsNullOrWhiteSpace(originalImagePath)) - return Request.CreateResponse(HttpStatusCode.OK); - - return GetResized(originalImagePath, 500); - } - - /// - /// Gets a resized image for the media id - /// - /// - /// - /// - /// - /// If there is no media, image property or image file is found then this will return not found. - /// - public HttpResponseMessage GetResized(int mediaId, int width) - { - var media = Services.MediaService.GetById(mediaId); - if (media == null) - { - return new HttpResponseMessage(HttpStatusCode.NotFound); - } - - return GetResized( media, 500 ); - } - - /// - /// Gets a resized image for the image at the given path - /// - /// - /// - /// - /// - /// If there is no media, image property or image file is found then this will return not found. - /// - public HttpResponseMessage GetResized(string imagePath, int width) - { - var media = Services.MediaService.GetMediaByPath( imagePath ); - if (media == null) - { - return new HttpResponseMessage( HttpStatusCode.NotFound ); - } - - return GetResized( media, 500 ); - } - - /// - /// Gets a resized image by redirecting to ImageProcessor - /// - /// - /// - /// - private HttpResponseMessage GetResized(IMedia media, int width) - { - var imageProp = media.Properties[Constants.Conventions.Media.File]; - if (imageProp == null) - { - return Request.CreateResponse( HttpStatusCode.NotFound ); - } - - var imagePath = imageProp.Value.ToString(); - var response = Request.CreateResponse( HttpStatusCode.Found ); - response.Headers.Location = new Uri( string.Format( "{0}?rnd={1}&width={2}", imagePath, string.Format( "{0:yyyyMMddHHmmss}", media.UpdateDate ), width ), UriKind.Relative ); - return response; - } - } +using System; +using System.Drawing; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.IO; +using Umbraco.Core.Media; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Editors +{ + /// + /// A controller used to return images for media + /// + [PluginController("UmbracoApi")] + public class ImagesController : UmbracoAuthorizedApiController + { + /// + /// Gets the big thumbnail image for the media id + /// + /// + /// + /// + /// If there is no media, image property or image file is found then this will return not found. + /// + public HttpResponseMessage GetBigThumbnail(int mediaId) + { + var media = Services.MediaService.GetById(mediaId); + if (media == null) + { + return Request.CreateResponse(HttpStatusCode.NotFound); + } + var imageProp = media.Properties[Constants.Conventions.Media.File]; + if (imageProp == null) + { + return Request.CreateResponse(HttpStatusCode.NotFound); + } + + var imagePath = imageProp.Value.ToString(); + + return GetBigThumbnail(imagePath); + } + + /// + /// Gets the big thumbnail image for the original image path + /// + /// + /// + /// + /// If there is no original image is found then this will return not found. + /// + public HttpResponseMessage GetBigThumbnail(string originalImagePath) + { + if (string.IsNullOrWhiteSpace(originalImagePath)) + return Request.CreateResponse(HttpStatusCode.OK); + + return GetResized(originalImagePath, 500, "big-thumb"); + } + + /// + /// Gets a resized image for the media id + /// + /// + /// + /// + /// + /// If there is no media, image property or image file is found then this will return not found. + /// + public HttpResponseMessage GetResized(int mediaId, int width) + { + var media = Services.MediaService.GetById(mediaId); + if (media == null) + { + return new HttpResponseMessage(HttpStatusCode.NotFound); + } + var imageProp = media.Properties[Constants.Conventions.Media.File]; + if (imageProp == null) + { + return new HttpResponseMessage(HttpStatusCode.NotFound); + } + + var imagePath = imageProp.Value.ToString(); + + return GetResized(imagePath, width); + } + + /// + /// Gets a resized image for the image at the given path + /// + /// + /// + /// + /// + /// If there is no media, image property or image file is found then this will return not found. + /// + public HttpResponseMessage GetResized(string imagePath, int width) + { + return GetResized(imagePath, width, Convert.ToString(width)); + } + + /// + /// Gets a resized image - if the requested max width is greater than the original image, only the original image will be returned. + /// + /// + /// + /// + /// + private HttpResponseMessage GetResized(string imagePath, int width, string suffix) + { + var mediaFileSystem = FileSystemProviderManager.Current.GetFileSystemProvider(); + var ext = Path.GetExtension(imagePath); + + //we need to check if it is an image by extension + if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.InvariantContains(ext.TrimStart('.')) == false) + { + return Request.CreateResponse(HttpStatusCode.NotFound); + } + + //redirect to ImageProcessor thumbnail with rnd generated from last write time of original media file + var fullOrgPath = mediaFileSystem.GetFullPath(mediaFileSystem.GetRelativePath(imagePath)); + var response = Request.CreateResponse( HttpStatusCode.Found ); + response.Headers.Location = new Uri( string.Format( "{0}?rnd={1}&width={2}", imagePath, string.Format( "{0:yyyyMMddHHmmss}", System.IO.File.GetLastWriteTime( fullOrgPath ) ), width ), UriKind.Relative ); + return response; + } + } } \ No newline at end of file From 632bccb9dd015f07e0ccb206129ed8ac30c4e63c Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Mon, 21 Dec 2015 12:22:14 +0100 Subject: [PATCH 019/605] Added new mediapicker ui for consistency through the backoffice, removing text-decoration problem --- .../src/less/property-editors.less | 20 +++---------------- .../views/prevalueeditors/imagepicker.html | 7 +++---- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 082e8d079d..3bcf5db1b6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -122,7 +122,7 @@ ul.color-picker li a { // // Media picker // -------------------------------------------------- -.umb-mediapicker .add-link{ +.umb-mediapicker .add-link { display: inline-block; height: 120px; width: 120px; @@ -133,7 +133,7 @@ ul.color-picker li a { text-decoration: none; } -.umb-mediapicker .picked-image{ +.umb-mediapicker .picked-image { position: absolute; bottom: 10px; right: 10px; @@ -178,12 +178,8 @@ ul.color-picker li a { } -.umb-sortable-thumbnails li{ +.umb-sortable-thumbnails li { display: inline-block; - border: 1px solid @grayLighter; - padding: 2px; - background: white; - margin: 5px; position: relative; text-align: center; vertical-align: top; @@ -207,16 +203,6 @@ ul.color-picker li a { max-height: none !important; } -.umb-sortable-thumbnails .icon-holder .icon{ - font-size: 60px; - line-height: 70px; -} -.umb-sortable-thumbnails .icon-holder * -{ - color: @grayLight; - display: block -} - // // Cropper diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html index d73f221764..c07e1f16aa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/imagepicker.html @@ -1,10 +1,9 @@
    -
  • +
  • - - - Choose... + + From 3a640c7a785e607288db3f491d4ddfc8d6425ca7 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Mon, 21 Dec 2015 12:32:15 +0100 Subject: [PATCH 020/605] Added hover state --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 3bcf5db1b6..282a9cae7b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -128,9 +128,16 @@ ul.color-picker li a { width: 120px; text-align: center; color: @grayLight; - border: 2px @grayLight dashed !important; + border: 2px @grayLight dashed; line-height: 120px; text-decoration: none; + + transition: all 150ms ease-in-out; + + &:hover { + color: @gray; + border-color: @gray; + } } .umb-mediapicker .picked-image { From 4a660433dea78ce8c5589cee00d0fee6968382f0 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Mon, 21 Dec 2015 12:37:21 +0100 Subject: [PATCH 021/605] Removed hover state --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 282a9cae7b..a19bb6ad23 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -131,13 +131,6 @@ ul.color-picker li a { border: 2px @grayLight dashed; line-height: 120px; text-decoration: none; - - transition: all 150ms ease-in-out; - - &:hover { - color: @gray; - border-color: @gray; - } } .umb-mediapicker .picked-image { From 8e3b6ffd59490bb79c44364f85e8b01fb379df9a Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Mon, 21 Dec 2015 12:38:22 +0100 Subject: [PATCH 022/605] added blue hover state --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index a19bb6ad23..80de85069d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -131,6 +131,13 @@ ul.color-picker li a { border: 2px @grayLight dashed; line-height: 120px; text-decoration: none; + + transition: all 150ms ease-in-out; + + &:hover { + color: @blue; + border-color: @blue; + } } .umb-mediapicker .picked-image { From 6a9f6bc91b5d95562bdc1a3bddf48f661b1fafc7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 21 Dec 2015 14:48:46 +0100 Subject: [PATCH 023/605] make it possible to select folders in media picker, fix issue with deselecting image in some cases + a bit code clean up. --- .../components/umbmediagrid.directive.js | 8 ++++ .../src/less/components/umb-media-grid.less | 13 ++++++ .../mediaPicker/mediapicker.controller.js | 37 +++++++--------- .../overlays/mediaPicker/mediapicker.html | 3 +- .../src/views/components/umb-media-grid.html | 5 ++- .../mediapicker/mediapicker.controller.js | 42 +++++++++---------- 6 files changed, 60 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js index 2626fc7f33..b6edcf228c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js @@ -128,6 +128,13 @@ } }; + scope.clickFolderSelect = function(item, $event, $index) { + if(scope.onFolderSelect) { + scope.onFolderSelect(item, $event, $index); + $event.stopPropagation(); + } + }; + var unbindItemsWatcher = scope.$watch('items', function(newValue, oldValue){ if(angular.isArray(newValue)) { activate(); @@ -149,6 +156,7 @@ onDetailsHover: "=", onSelect: '=', onClick: '=', + onFolderSelect: "=", filterBy: "=" }, link: link diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less index 01c1cf5206..b63dcaf23d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less @@ -13,6 +13,7 @@ position: relative; background: @grayLighter; overflow: hidden; + cursor: pointer; } .umb-media-grid__item:hover { @@ -73,6 +74,18 @@ box-sizing: border-box; } +.umb-media-grid__item-folder-select { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 30px; + background: @grayLight; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; +} .umb-media-grid__item-icon { color: @gray; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js index 48ac33125c..d48c67dc42 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js @@ -142,39 +142,32 @@ angular.module("umbraco") }; + $scope.selectFolder = function(folder, event, index) { + eventsService.emit("dialogs.mediaPicker.select", folder); + selectImage(folder); + }; + function selectImage(image) { - if ($scope.model.selectedImages.length > 0) { + if(image.selected) { - var selectImage = false; + for(var i = 0; $scope.model.selectedImages.length > i; i++) { - for (var i = 0; i < $scope.model.selectedImages.length; i++) { - - var selectedImage = $scope.model.selectedImages[i]; - - if (image.key === selectedImage.key) { + var imageInSelection = $scope.model.selectedImages[i]; + if(image.key === imageInSelection.key) { image.selected = false; $scope.model.selectedImages.splice(i, 1); - selectImage = false; - } else { - selectImage = true; } - - } - - if (selectImage) { - - if(!$scope.multiPicker) { - deselectAllImages($scope.model.selectedImages); - } - - image.selected = true; - $scope.model.selectedImages.push(image); } } else { - $scope.model.selectedImages.push(image); + + if(!$scope.multiPicker) { + deselectAllImages($scope.model.selectedImages); + } + image.selected = true; + $scope.model.selectedImages.push(image); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.html index 68752df784..370d1f96fe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.html @@ -70,7 +70,8 @@ + on-click="clickHandler" + on-folder-select="selectFolder">
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html index bdcf0da482..7166050372 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html @@ -1,6 +1,6 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js index 0859e70cdd..b77ad15a23 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js @@ -59,35 +59,31 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl $scope.add = function() { - $scope.mediaPickerOverlay = {}; - $scope.mediaPickerOverlay.startNodeId = $scope.model.config.startNodeId; - $scope.mediaPickerOverlay.multiPicker = multiPicker; - $scope.mediaPickerOverlay.view = "mediaPicker"; - $scope.mediaPickerOverlay.title = "Select media"; - $scope.mediaPickerOverlay.show = true; + $scope.mediaPickerOverlay = { + view: "mediapicker", + title: "Select media", + startNodeId: $scope.model.config.startNodeId, + multiPicker: multiPicker, + show: true, + submit: function(model) { - $scope.mediaPickerOverlay.submit = function(model) { + _.each(model.selectedImages, function(media, i) { - _.each(model.selectedImages, function(media, i) { + if (!media.thumbnail) { + media.thumbnail = mediaHelper.resolveFileFromEntity(media, true); + } - if (!media.thumbnail) { - media.thumbnail = mediaHelper.resolveFileFromEntity(media, true); - } + $scope.images.push(media); + $scope.ids.push(media.id); + }); - $scope.images.push(media); - $scope.ids.push(media.id); - }); + $scope.sync(); - $scope.sync(); + $scope.mediaPickerOverlay.show = false; + $scope.mediaPickerOverlay = null; - $scope.mediaPickerOverlay.show = false; - $scope.mediaPickerOverlay = null; - }; - - $scope.mediaPickerOverlay.close = function(oldModel) { - $scope.mediaPickerOverlay.show = false; - $scope.mediaPickerOverlay = null; - }; + } + }; }; From 89e2bb1d0aca7b56b34921d838283dc62b2d8344 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 22 Dec 2015 14:07:12 +0100 Subject: [PATCH 024/605] Fixes: U4-7569 Listview should not loose focus after filtering and U4-7582 When searching in media with no results, show a no results message + make empty state directive --- .../components/umbemptystate.directive.js | 22 +++++++ src/Umbraco.Web.UI.Client/src/less/belle.less | 1 + .../src/less/components/umb-empty-state.less | 23 +++++++ src/Umbraco.Web.UI.Client/src/less/main.less | 24 ------- .../compositions/compositions.html | 8 ++- .../overlays/macropicker/macropicker.html | 6 +- .../views/components/umb-content-grid.html | 5 +- .../src/views/components/umb-empty-state.html | 9 +++ .../src/views/components/umb-table.html | 6 +- .../listview/layouts/grid/grid.html | 17 ++++- .../listview/layouts/list/list.html | 12 +++- .../listview/listview.controller.js | 65 ++++++++++--------- .../propertyeditors/listview/listview.html | 15 ++++- 13 files changed, 144 insertions(+), 69 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/components/umbemptystate.directive.js create mode 100644 src/Umbraco.Web.UI.Client/src/less/components/umb-empty-state.less create mode 100644 src/Umbraco.Web.UI.Client/src/views/components/umb-empty-state.html diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbemptystate.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbemptystate.directive.js new file mode 100644 index 0000000000..6f5cbd2166 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbemptystate.directive.js @@ -0,0 +1,22 @@ +(function() { + 'use strict'; + + function EmptyStateDirective() { + + var directive = { + restrict: 'E', + replace: true, + transclude: true, + templateUrl: 'views/components/umb-empty-state.html', + scope: { + size: '@', + position: '@' + } + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbEmptyState', EmptyStateDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index 191d75dd4f..133d13c019 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -106,6 +106,7 @@ @import "components/tooltip/umb-tooltip-list.less"; @import "components/overlays/umb-overlay-backdrop.less"; @import "components/umb-grid.less"; +@import "components/umb-empty-state.less"; @import "components/buttons/umb-button.less"; @import "components/buttons/umb-button-group.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-empty-state.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-empty-state.less new file mode 100644 index 0000000000..9ed61bcb39 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-empty-state.less @@ -0,0 +1,23 @@ +.umb-empty-state { + font-size: @fontSizeMedium; + line-height: 1.8em; + color: @grayMed; + text-align: center; +} + +.umb-empty-state.-small { + font-size: @fontSizeSmall; +} + +.umb-empty-state.-large { + font-size: @fontSizeLarge; +} + +.umb-empty-state.-center { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + width: 80%; + max-width: 400px; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 16dd3b91fd..d9d60e90b0 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -574,27 +574,3 @@ input[type=checkbox]:checked + .input-label--small { font-weight: bold; line-height: 20px; } - -.umb-empty-state-text { - font-size: @fontSizeMedium; - line-height: 1.8em; - color: @grayMed; - text-align: center; -} - -.umb-empty-state-text.-small { - font-size: @fontSizeSmall; -} - -.umb-empty-state-text.-large { - font-size: @fontSizeLarge; -} - -.umb-empty-state-text.-center { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%,-50%); - width: 80%; - max-width: 400px; -} diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/compositions/compositions.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/compositions/compositions.html index 1e06166970..3467b8568e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/compositions/compositions.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/compositions/compositions.html @@ -14,9 +14,11 @@ Inherit tabs and properties from an existing document type. New tabs will be added to the current document type or merged if a tab with an identical name exists.
-
- This content type is used in a composition, and therefore cannot be composed itself. -
+ + This content type is used in a composition, and therefore cannot be composed itself. +
  • diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/macropicker/macropicker.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/macropicker/macropicker.html index ecd8943a63..37bc70bd77 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/macropicker/macropicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/macropicker/macropicker.html @@ -30,7 +30,11 @@
-
There are no parameters for this macro
+ + There are no parameters for this macro +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html index 52d7f3542b..6c61558ae3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-content-grid.html @@ -27,6 +27,9 @@ -
There are no items to show
+ + There are no items to show + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-empty-state.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-empty-state.html new file mode 100644 index 0000000000..e98227753e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-empty-state.html @@ -0,0 +1,9 @@ +
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html index 06dd1c16b2..b39ccf1da5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-table.html @@ -68,8 +68,10 @@ -
+ There are no items show in the list. -
+ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html index ccf18b0236..5a4975ac18 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/grid/grid.html @@ -4,12 +4,19 @@ ng-if="entityType !== 'media'"> + + Sorry, we can not find what you are looking for + +
@@ -53,6 +60,12 @@ -
+ + Sorry, we can not find what you are looking for + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.html index 6f52b14af1..5a234ea69d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/layouts/list/list.html @@ -13,12 +13,13 @@ files-uploaded="vm.onUploadComplete" accept="{{vm.acceptedFileTypes}}" max-file-size="{{vm.maxFileSize}}" - hide-dropzone="{{!vm.activeDrag && items.length > 0 }}" + hide-dropzone="{{!vm.activeDrag && items.length > 0 || !items && options.filter }}" compact="{{ items.length > 0 }}" files-queued="vm.onFilesQueue"> - + + Sorry, we can not find what you are looking for + + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 63db542ee7..0d42428334 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -155,22 +155,13 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie /*Pagination is done by an array of objects, due angularJS's funky way of monitoring state with simple values */ - $scope.reloadView = function (id) { + $scope.reloadView = function(id) { - $scope.viewLoaded = false; + $scope.viewLoaded = false; - listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection); + listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection); - if($scope.entityType === 'media') { - - mediaResource.getChildFolders($scope.contentId) - .then(function(folders) { - $scope.folders = folders; - }); - - } - - getListResultsCallback(id, $scope.options).then(function (data) { + getListResultsCallback(id, $scope.options).then(function(data) { $scope.actionInProgress = false; @@ -178,11 +169,23 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie //update all values for display if ($scope.listViewResultSet.items) { - _.each($scope.listViewResultSet.items, function (e, index) { + _.each($scope.listViewResultSet.items, function(e, index) { setPropertyValues(e); }); } + if ($scope.entityType === 'media') { + + mediaResource.getChildFolders($scope.contentId) + .then(function(folders) { + $scope.folders = folders; + $scope.viewLoaded = true; + }); + + } else { + $scope.viewLoaded = true; + } + //NOTE: This might occur if we are requesting a higher page number than what is actually available, for example // if you have more than one page and you delete all items on the last page. In this case, we need to reset to the last // available page and then re-load again @@ -193,39 +196,37 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.reloadView(id); } - $scope.viewLoaded = true; - }); }; - $scope.$watch(function() { - return $scope.options.filter; - }, _.debounce(function(newVal, oldVal) { + var searchListView = _.debounce(function(){ $scope.$apply(function() { - if (newVal !== null && newVal !== undefined && newVal !== oldVal) { - $scope.options.pageNumber = 1; - $scope.actionInProgress = true; - $scope.reloadView($scope.contentId); - } + makeSearch(); }); - }, 1000)); + }, 500); - $scope.filterResults = function (ev) { + $scope.forceSearch = function (ev) { //13: enter - switch (ev.keyCode) { case 13: - $scope.options.pageNumber = 1; - $scope.actionInProgress = true; - $scope.reloadView($scope.contentId); + makeSearch(); break; } }; - $scope.enterSearch = function ($event) { - $($event.target).next().focus(); + $scope.enterSearch = function() { + $scope.viewLoaded = false; + searchListView(); }; + function makeSearch() { + if ($scope.options.filter !== null && $scope.options.filter !== undefined) { + $scope.options.pageNumber = 1; + //$scope.actionInProgress = true; + $scope.reloadView($scope.contentId); + } + } + $scope.isAnythingSelected = function() { if ($scope.selection.length === 0) { return false; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 879471e6bc..ad9083d084 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -61,11 +61,20 @@ - + @@ -144,6 +153,8 @@ on-get-content="reloadView"> + + Date: Tue, 22 Dec 2015 14:08:31 +0100 Subject: [PATCH 025/605] remove fadeOut class from load indicator directive to make in animate more than once --- .../src/views/components/umb-load-indicator.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-load-indicator.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-load-indicator.html index 6573dcbfde..4d545e21e2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-load-indicator.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-load-indicator.html @@ -1,4 +1,4 @@ -
    +
    • From 552cbada887dbed0e7027b94b753b13824fd427e Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Tue, 22 Dec 2015 15:07:57 +0100 Subject: [PATCH 026/605] Fix for http://issues.umbraco.org/issue/U4-7573 --- .../components/editor/umbeditorview.directive.js | 5 ++++- src/Umbraco.Web.UI.Client/src/less/components/editor.less | 8 ++++++-- .../src/less/components/overlays.less | 6 ++++-- src/Umbraco.Web.UI.Client/src/views/common/dashboard.html | 4 +++- .../src/views/components/editor/umb-editor-view.html | 6 +++++- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorview.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorview.directive.js index aad87178cc..8a79b64649 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorview.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorview.directive.js @@ -7,7 +7,10 @@ transclude: true, restrict: 'E', replace: true, - templateUrl: 'views/components/editor/umb-editor-view.html' + templateUrl: 'views/components/editor/umb-editor-view.html', + scope: { + footer: "@" + } }; return directive; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor.less b/src/Umbraco.Web.UI.Client/src/less/components/editor.less index b90271b5e5..6d43286f2d 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor.less @@ -20,16 +20,20 @@ } -.umb-editor-container{ +.umb-editor-container { top: 101px; left: 0px; right: 0px; - bottom: 60px; + bottom: 52px; position: absolute; clear: both; overflow: auto; } +.umb-editor-wrapper.-no-footer .umb-editor-container { + bottom: 0; +} + .umb-editor-container.-stop-scrolling { overflow: hidden; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less index 49153ea6a8..eff17fb20a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less @@ -46,7 +46,9 @@ height: 31px; padding: 10px; margin: 0; - background: #ffffff; + + background: @grayLighter; + border-top: 1px solid @grayLight; } .umb-overlay .umb-overlay-drawer .umb-overlay-drawer-content { @@ -114,7 +116,7 @@ top: 100px; left: 0; right: 0; - bottom: 51px; + bottom: 52px; padding: 20px; } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html index 0c9f319e17..3136bc28e7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html @@ -7,7 +7,9 @@ class="umb-dashboard" val-form-manager> - + +
      From 0d7363af23d93f8561d54d1ad115923ef4ef52f6 Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Tue, 22 Dec 2015 10:47:04 -0500 Subject: [PATCH 027/605] Fix for MarkdownEditor no seeing changes from button clicks. --- .../markdowneditor.controller.js | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js index 8893ebd523..2fe3fbf5e3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js @@ -1,5 +1,5 @@ //inject umbracos assetsServce and dialog service -function MarkdownEditorController($scope, assetsService, dialogService, $timeout) { +function MarkdownEditorController($scope, assetsService, dialogService, angularHelper, $timeout) { //tell the assets service to load the markdown.editor libs from the markdown editors //plugin folder @@ -17,29 +17,31 @@ function MarkdownEditorController($scope, assetsService, dialogService, $timeout .then(function () { // we need a short delay to wait for the textbox to appear. - setTimeout(function () { - //this function will execute when all dependencies have loaded - // but in the case that they've been previously loaded, we can only - // init the md editor after this digest because the DOM needs to be ready first - // so run the init on a timeout - $timeout(function () { - var converter2 = new Markdown.Converter(); - var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias); - editor2.run(); + //this function will execute when all dependencies have loaded + // but in the case that they've been previously loaded, we can only + // init the md editor after this digest because the DOM needs to be ready first + // so run the init on a timeout + $timeout(function () { + var converter2 = new Markdown.Converter(); + var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias); + editor2.run(); - //subscribe to the image dialog clicks - editor2.hooks.set("insertImageDialog", function (callback) { + //subscribe to the image dialog clicks + editor2.hooks.set("insertImageDialog", function (callback) { - dialogService.mediaPicker({ - callback: function (data) { - callback(data.image); - } - }); - - return true; // tell the editor that we'll take care of getting the image url + dialogService.mediaPicker({ + callback: function (data) { + callback(data.image); + } }); - }, 200); - }); + + return true; // tell the editor that we'll take care of getting the image url + }); + + editor2.hooks.set("onPreviewRefresh", function () { + angularHelper.getCurrentForm($scope).$setDirty(); + }); + }, 200); //load the seperat css for the editor to avoid it blocking our js loading TEMP HACK assetsService.loadCss("lib/markdown/markdown.css"); From 9649e6d9bf3604dc91d135ea01893b096e6f7a95 Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Tue, 22 Dec 2015 11:17:53 -0500 Subject: [PATCH 028/605] Add code to manually update the model. --- .../markdowneditor/markdowneditor.controller.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js index 2fe3fbf5e3..bcf73469af 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js @@ -1,5 +1,5 @@ //inject umbracos assetsServce and dialog service -function MarkdownEditorController($scope, assetsService, dialogService, angularHelper, $timeout) { +function MarkdownEditorController($scope, $element, assetsService, dialogService, angularHelper, $timeout) { //tell the assets service to load the markdown.editor libs from the markdown editors //plugin folder @@ -40,6 +40,10 @@ function MarkdownEditorController($scope, assetsService, dialogService, angularH editor2.hooks.set("onPreviewRefresh", function () { angularHelper.getCurrentForm($scope).$setDirty(); + // We must manually update the model as there is no way to hook into the markdown editor events without editing that code. + $scope.$apply(function () { + $scope.model.value = $("textarea", $element).val(); + }); }); }, 200); From 9dbdae3b90b2c0f25e2b7c4ac3ec4cf8e179407b Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Tue, 22 Dec 2015 11:49:13 -0500 Subject: [PATCH 029/605] Added Markdown package and code to MarkdownEditorValueConverter to automatically convert the markdown text to Html when rendered in the front end. --- .../ValueConverters/MarkdownEditorValueConverter.cs | 8 ++++++-- src/Umbraco.Web/Umbraco.Web.csproj | 4 ++++ src/Umbraco.Web/packages.config | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs index af66278815..681aa2ee72 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs @@ -1,4 +1,5 @@ -using System; +using MarkdownSharp; +using System; using System.Web; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; @@ -31,8 +32,11 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview) { + // Convert markup to html for frontend rendering. + Markdown mark = new Markdown(); + // source should come from ConvertSource and be a string (or null) already - return new HtmlString(source == null ? string.Empty : (string)source); + return new HtmlString(source == null ? string.Empty : mark.Transform((string)source)); } public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview) diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f84a2872ac..279f46a58a 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -132,6 +132,10 @@ False ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + + ..\packages\Markdown.1.14.4\lib\net45\MarkdownSharp.dll + True + False ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index d255e152ba..41f4bc1ea7 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -6,6 +6,7 @@ + From 7a112c43d8d36c7e347eed2303b388beb5f7e43f Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Tue, 22 Dec 2015 20:05:29 +0100 Subject: [PATCH 030/605] Fix for http://issues.umbraco.org/issue/U4-6854 Grid editor - insert control: Make blue area clickable --- .../src/less/components/card.less | 5 +++-- .../editorpicker/editorpicker.html | 14 ++++++++++---- .../common/overlays/itempicker/itempicker.html | 7 +++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/card.less b/src/Umbraco.Web.UI.Client/src/less/components/card.less index 9a06c0d2dc..6e1603b3d8 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/card.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/card.less @@ -111,12 +111,13 @@ flex: 0 0 33.33%; } -.umb-card-grid li:hover, .umb-card-grid li:hover *{ +.umb-card-grid li:hover, .umb-card-grid li:hover * { background: @blue; color: white; + cursor: pointer; } -.umb-card-grid a{ +.umb-card-grid a { color: #222; text-decoration: none; } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.html index 9d1735f174..0ddf13b0ea 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.html @@ -28,8 +28,11 @@
      {{key}}
        -
      • - +
      • + {{ systemDataType.name }} @@ -49,8 +52,11 @@
        {{key}}
        - +
        -
        - - \ No newline at end of file + + diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index ad9083d084..a9a05a8163 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -66,7 +66,7 @@
        Date: Tue, 5 Jan 2016 15:35:42 +0100 Subject: [PATCH 064/605] Fixes: U4-7636 Change re-use back to Reuse --- .../contenttypeeditor/editorpicker/editorpicker.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.controller.js index 5b2dbbb26d..d8a15f841b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/contenttypeeditor/editorpicker/editorpicker.controller.js @@ -28,7 +28,7 @@ { active: false, id: 2, - label: "Re-use", + label: "Reuse", alias: "Reuse", userConfigured: [] } From 726416fe0c4a0bc3e7f196e0b11f37dc76a5c8c6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 5 Jan 2016 15:47:42 +0100 Subject: [PATCH 065/605] Fixes: U4-7624 Datepicker Sql server error Since we are not saving the formatted value, don't try parsing the date with formatting config. Added in explicit parsing format compatible with the one used when saving the value, just to ensure parsing is done the same way. --- .../propertyeditors/datepicker/datepicker.controller.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index 1c29184273..693bd49ec6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -97,11 +97,11 @@ function dateTimePickerController($scope, notificationsService, assetsService, a }); if ($scope.hasDatetimePickerValue) { - //assign value to plugin/picker - var dateVal = $scope.model.value ? moment($scope.model.value, $scope.model.config.format) : moment(); + var dateVal = $scope.model.value ? moment($scope.model.value, "YYYY-MM-DD HH:mm:ss") : moment(); + element.datetimepicker("setValue", dateVal); - $scope.datetimePickerValue = moment($scope.model.value).format($scope.model.config.format); + $scope.datetimePickerValue = dateVal.format($scope.model.config.format); } element.find("input").bind("blur", function() { From db538d95ba3278fe4534b457a4bd40278a270dfa Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 16:11:59 +0100 Subject: [PATCH 066/605] Bumps version --- build/UmbracoVersion.txt | 2 +- src/SolutionInfo.cs | 6 +++--- src/Umbraco.Core/Configuration/UmbracoVersion.cs | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/UmbracoVersion.txt b/build/UmbracoVersion.txt index 71c6f2956c..e847b7606c 100644 --- a/build/UmbracoVersion.txt +++ b/build/UmbracoVersion.txt @@ -1,2 +1,2 @@ # Usage: on line 2 put the release version, on line 3 put the version comment (example: beta) -7.3.4 \ No newline at end of file +7.3.5 \ No newline at end of file diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs index a8ea69e06e..f2c18b921b 100644 --- a/src/SolutionInfo.cs +++ b/src/SolutionInfo.cs @@ -2,7 +2,7 @@ using System.Resources; [assembly: AssemblyCompany("Umbraco")] -[assembly: AssemblyCopyright("Copyright © Umbraco 2015")] +[assembly: AssemblyCopyright("Copyright © Umbraco 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -11,5 +11,5 @@ using System.Resources; [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyFileVersion("7.3.4")] -[assembly: AssemblyInformationalVersion("7.3.4")] \ No newline at end of file +[assembly: AssemblyFileVersion("7.3.5")] +[assembly: AssemblyInformationalVersion("7.3.5")] \ No newline at end of file diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index c2cafcfe2e..8b9fbf05fd 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("7.3.4"); + private static readonly Version Version = new Version("7.3.5"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 4532f568e6..49d29097cb 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2413,9 +2413,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" True True - 7340 + 7350 / - http://localhost:7340 + http://localhost:7350 False False From 4ef7b7735ea714d1f23eb71191591d8574c8e23a Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 17:04:11 +0100 Subject: [PATCH 067/605] Fixes U4-6510 again as merging PR apparently went wrong --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- .../no.xml => Umbraco/config/lang/nb.xml} | 1922 ++++++++--------- 2 files changed, 962 insertions(+), 962 deletions(-) rename src/Umbraco.Web.UI/{umbraco/config/lang/no.xml => Umbraco/config/lang/nb.xml} (98%) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 49d29097cb..21277593ab 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -1696,7 +1696,7 @@ - + diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/no.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml similarity index 98% rename from src/Umbraco.Web.UI/umbraco/config/lang/no.xml rename to src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml index d877cdc3c5..3710acb0a8 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/no.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml @@ -1,962 +1,962 @@ - - - - The Umbraco community - http://our.umbraco.org/documentation/Extending-Umbraco/Language-Files - - - Angi domene - Revisjoner - Bla gjennom - Skift dokumenttype - Kopier - Opprett - Opprett pakke - Slett - Deaktiver - Tøm papirkurv - Eksporter dokumenttype - Importer dokumenttype - Importer pakke - Rediger i Canvas - Logg av - Flytt - Varslinger - Offentlig tilgang - Publiser - Avpubliser - Oppdater noder - Republiser hele siten - Gjenopprett - Rettigheter - Reverser - Send til publisering - Send til oversetting - Sorter - Send til publisering - Oversett - Oppdater - Standard verdi - - - Ingen tilgang. - Legg til domene - Fjern - Ugyldig node. - Ugyldig domeneformat. - Domene er allerede tilknyttet. - Språk - Domene - Domene '%0%' er nå opprettet og tilknyttet siden - Domenet '%0%' er nå slettet - Domenet '%0%' er allerede tilknyttet - Domenet '%0%' er nå oppdatert - eller rediger eksisterende domener -
        Stier med ett nivå støttes, f.eks. "eksempel.com/no". Imidlertid bør det unngås. Bruk heller språkinnstillingen over.]]>
        - Arv - Språk - Vil også gjelde denne noden, med mindre et underordnet domene også gjelder.]]> - Domener - - - Viser for - - - Velg - Velg gjeldende mappe - Gjør noe annet - Fet - Reduser innrykk - Sett inn skjemafelt - Sett inn grafisk overskrift - Rediger HTML - Øk innrykk - Kursiv - Midtstill - Juster tekst venstre - Juster tekst høyre - Sett inn lenke - Sett inn lokal lenke (anker) - Punktmerking - Nummerering - Sett inn makro - Sett inn bilde - Rediger relasjoner - Tilbake til listen - Lagre - Lagre og publiser - Lagre og send til publisering - Forhåndsvis - Forhåndsvisning er deaktivert siden det ikke er angitt noen mal - Velg formattering - Vis stiler - Sett inn tabell - - - For å endre det valge innholdets dokumenttype, velger du først en ny dokumenttype som er gyldig på gjeldende plassering. - Kontroller deretter at alle egenskaper blir overført riktig til den nye dokumenttypen og klikk på Lagre. - Innholdet har blitt republisert. - Nåværende egenskap - Nåværende type - Du kan ikke endre dokumenttype, ettersom det ikke er andre gyldige dokumenttyper på denne plasseringen. - Dokumenttype endret - Overfør egenskaper - Overfør til egenskap - Ny mal - Ny type - ingen - Innhold - Velg ny dokumenttype - Dokumenttypen på det valgte innhold ble endret til [new type], og følgende egenskaper ble overført: - til - Overføringen av egenskaper kunne ikke fullføres da en eller flere egenskaper er satt til å bli overført mer enn en gang. - Kun andre dokumenttyper som er gyldige for denne plasseringen vises. - - - Publisert - Om siden - Alias - (hvordan du ville beskrevet bildet over telefon) - Alternative lenker - Klikk for å redigere denne noden - Opprettet av - Opprinnelig forfatter - Oppdatert av - Opprettet den - Tidspunkt for opprettelse - Dokumenttype - Redigerer - Utløpsdato - Denne noden er endret siden siste publisering - Denne noden er enda ikke publisert - Sist publisert - Det er ingen elementer å vise i listen. - Mediatype - Link til media - Medlemsgruppe - Rolle - Medlemstype - Ingen dato valgt - Sidetittel - Egenskaper - Dette dokumentet er publisert, men ikke synlig ettersom den overliggende siden '%0%' ikke er publisert - Intern feil: dokumentet er publisert men finnes ikke i hurtigbuffer - Publisert - Publiseringsstatus - Publiseringsdato - Dato for avpublisering - Fjern dato - Sorteringsrekkefølgen er oppdatert - Trekk og slipp nodene eller klikk på kolonneoverskriftene for å sortere. Du kan velge flere noder ved å holde shift eller control tastene mens du velger. - Statistikk - Tittel (valgfri) - Alternativ tekst (valgfri) - Type - Avpubliser - Sist endret - Tidspunkt for siste endring - Fjern fil - Lenke til dokument - Medlem av gruppe(ne) - Ikke medlem av gruppe(ne) - Undersider - Åpne i vindu - - - Klikk for å laste opp - Slipp filene her... - - - Opprett et nytt medlem - Alle medlemmer - - - Hvor ønsker du å oprette den nye %0% - Opprett under - Velg en type og skriv en tittel - "dokumenttyper".]]> - "mediatyper".]]> - - - Til ditt nettsted - - Skjul - Hvis Umbraco ikke starter, kan det skyldes at pop-up vinduer ikke er tillatt - er åpnet i nytt vindu - Omstart - Besøk - Velkommen - - - Navn på lokal link - Rediger domener - Lukk dette vinduet - Er du sikker på at du vil slette - Er du sikker på at du vil deaktivere - Vennligst kryss av i denne boksen for å bekrefte sletting av %0% element(er) - Er du sikker på at du vil forlate Umbraco? - Er du sikker? - Klipp ut - Rediger ordboksnøkkel - Rediger språk - Sett inn lokal link - Sett inn spesialtegn - Sett inn grafisk overskrift - Sett inn bilde - Sett inn lenke - Sett inn makro - Sett inn tabell - Sist redigert - Lenke - Intern link: - Ved lokal link, sett inn "#" foran link - Åpne i nytt vindu? - Makroinnstillinger - Denne makroen har ingen egenskaper du kan endre - Lim inn - Endre rettigheter for - Innholdet i papirkurven blir nå slettet. Vennligst ikke lukk dette vinduet mens denne operasjonen foregår - Papirkurven er nå tom - Når elementer blir slettet fra papirkurven vil de være slettet for alltid - regexlib.com
        tjenesten opplever for tiden problemer som vi ikke har kontroll over. Vi beklager denne ubeleiligheten.]]> - Søk etter et regulært uttrykk for å legge inn validering til et felt. Eksempel: 'email, 'zip-code' 'url' - Fjern makro - Obligatorisk - Nettstedet er indeksert - Hurtigbufferen er blitt oppdatert. Alt publisert innhold er nå à jour. Alt upublisert innhold er fortsatt ikke publisert. - Hurtigbufferen for siden vil bli oppdatert. Alt publisert innhold vil bli oppdatert, mens upublisert innhold vil forbli upublisert. - Antall kolonner - Antall rader - Sett en plassholder-ID
        Ved å sette en ID på plassholderen kan du legge inn innhold i denne malen fra underliggende maler, ved å referere denne ID'en ved hjelp av et <asp:content /> element.]]>
        - Velg en plassholder ID fra listen under. Du kan bare velge ID'er fra den gjeldende malens overordnede mal.]]> - Klikk på bildet for å se det i full størrelse - Velg punkt - Se buffret node - - - %0%' under.
        Du kan legge til flere språk under 'språk' i menyen til venstre.]]>
        - Språk - - - Skriv inn ditt brukernavn - Skriv inn ditt passord - Navngi %0%... - Skriv inn navn... - Søk... - Filtrer... - Skriv inn nøkkelord (trykk på Enter etter hvert nøkkelord)... - - - Tillat på rotnivå - Kun dokumenttyper med denne innstillingen aktivert kan opprettes på rotnivå under Innhold og Mediearkiv - Tillatte underordnede noder - Sammensetting av dokumenttyper - Opprett - Slett arkfane - Beskrivelse - Ny arkfane - Arkfane - Miniatyrbilde - Aktiver listevisning - Viser undersider i en søkbar liste, undersider vises ikke i innholdstreet - Gjeldende listevisning - Den aktive listevisningsdatatypen - Opprett brukerdefinert listevisning - Fjern brukerdefinert listevisning - - - Legg til forhåndsverdi - Database datatype - Kontrollelement GUID - Kontrollelement - Knapper - Aktiver avanserte instillinger for - Aktiver kontektsmeny - Maksimum standard størrelse på innsatte bilder - Beslektede stilark - Vis etikett - Bredde og høyde - - - Dine data har blitt lagret, men før du kan publisere denne siden må du rette noen feil: - Den gjeldende Membership Provider støtter ikke endring av passord. (EnablePasswordRetrieval må være satt til sann) - %0% finnes allerede - Det var feil i dokumentet: - Det var feil i skjemaet: - Passordet bør være minst %0% tegn og inneholde minst %1% numeriske tegn - %0% må være et heltall - %0% under %1% er obligatorisk - %0% er obligatorisk - %0% under %1% er ikke i et korrekt format - %0% er ikke i et korrekt format - - - Filtypen er deaktivert av administrator - NB! Selv om CodeMirror er aktivert i konfigurasjon er det deaktivert i Internet Explorer pga. ustabilitet. - Fyll ut både alias og navn på den nye egenskapstypen! - Det er et problem med lese/skrive rettighetene til en fil eller mappe - Tittel mangler - Type mangler - Du er i ferd med å gjøre bildet større enn originalen. Det vil forringe kvaliteten på bildet, ønsker du å fortsette? - Feil i python-skriptet - Python-skriptet ble ikke lagret fordi det inneholder en eller flere feil - Startnode er slettet. Kontakt din administrator - Du må markere innhold før du kan endre stil - Det er ingen aktive stiler eller formateringer på denne siden - Sett markøren til venstre i de 2 cellene du ønsker å slå sammen - Du kan ikke dele en celle som allerede er delt. - Feil i XSLT kode - XSLT ble ikke lagret på grunn av feil i koden - Det er et problem dem datatypen som brukes til denne egenskapen. Kontroller innstillingene og prøv igjen. - - - Om - Handling - Muligheter - Legg til - Alias - Er du sikker? - Ramme - av - Avbryt - Cellemargin - Velg - Lukk - Lukk vindu - Kommentar - Bekreft - Behold proposjoner - Fortsett - Kopier - Opprett - Database - Dato - Standard - Slett - Slettet - Sletter... - Design - Dimensjoner - Ned - Last ned - Rediger - Endret - Elementer - E-post - Feil - Finn - Høyde - Hjelp - Ikon - Importer - Indre margin - Sett inn - Installer - Justering - Språk - Layout - Laster - Låst - Logg inn - Logg ut - Logg ut - Makro - Flytt - Mer - Navn - Ny - Neste - Nei - av - OK - Åpne - eller - Passord - Sti - Plassholder ID - Ett øyeblikk... - Forrige - Egenskaper - E-post som innholdet i skjemaet skal sendes til - Papirkurv - Gjenværende - Gi nytt navn - Forny - Påkrevd - Prøv igjen - Rettigheter - Søk - Server - Vis - Hvilken side skal vises etter at skjemaet er sendt - Størrelse - Sorter - Type - Søk... - Opp - Oppdater - Oppgrader - Last opp - Url - Bruker - Brukernavn - Verdi - Visning - Velkommen... - Bredde - Ja - Mappe - Søkeresultater - - - Bakgrunnsfarge - Fet - Tekstfarge - Skrifttype - Tekst - - - Side - - - Installasjonsprogrammet kan ikke koble til databasen - Kunne ikke lagre Web.Config-filen. Vennligst endre databasens tilkoblingsstreng manuelt. - Din database er funnet og identifisert som - Databasekonfigurasjon - installer-knappen for å installere Umbraco %0% databasen]]> - Neste for å fortsette.]]> - Databasen ble ikke funnet! Vennligst sjekk at informasjonen i "connection string" i "web.config"-filen er korrekt.

        For å fortsette, vennligst rediger "web.config"-filen (bruk Visual Studio eller din favoritteditor), rull ned til bunnen, og legg til tilkoblingsstrengen for din database i nøkkelen "umbracoDbDSN" og lagre filen.

        Klikk prøv på nytt når du er ferdig.
        Mer informasjon om redigering av web.config her.

        ]]>
        - Vennligst kontakt din ISP om nødvendig. Hvis du installerer på en lokal maskin eller server, må du kanskje skaffe informasjonen fra din systemadministrator.]]> - Trykk på knappen oppgrader for å oppgradere databasen din til Umbraco %0%

        Ikke vær urolig - intet innhold vil bli slettet og alt vil fortsette å virke etterpå!

        ]]>
        - Trykk Neste for å fortsette.]]> - neste for å fortsette konfigurasjonsveiviseren]]> - Passordet til standardbrukeren må endres!]]> - Standardbrukeren har blitt deaktivert eller har ingen tilgang til Umbraco!

        Ingen videre handling er nødvendig. Klikk neste for å fortsette.]]> - Passordet til standardbrukeren har blitt forandret etter installasjonen!

        Ingen videre handling er nødvendig. Klikk Neste for å fortsette.]]> - Passordet er blitt endret! - Umbraco skaper en standard bruker med login ( "admin") og passord ( "default") . Det er viktig at passordet er endret til noe unikt.

        Dette trinnet vil sjekke standard brukerens passord og foreslår hvis det må skiftes ]]> - Få en god start med våre introduksjonsvideoer - Ved å klikke på Neste-knappen (eller endre UmbracoConfigurationStatus i Web.config), godtar du lisensen for denne programvaren som angitt i boksen nedenfor. Legg merke til at denne Umbraco distribusjon består av to ulike lisenser, åpen kilde MIT lisens for rammen og Umbraco frivareverktøy lisens som dekker brukergrensesnittet. - Ikke installert. - Berørte filer og mapper - Mer informasjon om å sette opp rettigheter for Umbraco her - Du må gi ASP.NET brukeren rettigheter til å endre de følgende filer og mapper - Rettighetene er nesten perfekt satt opp!

        Du kan kjøre Umbraco uten problemer, men du vil ikke være i stand til å installere de anbefalte pakkene for å utnytte Umbraco fullt ut.]]> - Hvordan løse problemet - Klikk her for å lese tekstversjonen - innføringsvideo
        om å sette opp rettigheter for Umbraco eller les tekstversjonen.]]> - Rettighetsinnstillingene kan være et problem!


        Du kan kjøre Umbraco uten problemer, men du vil ikke være i stand til å installere de anbefalte pakkene for å utnytte Umbraco fullt ut.]]> - Rettighetsinstillingene er ikke klargjort for Umbraco!

        For å kunne kjøre Umbraco, må du oppdatere rettighetsinnstillingene dine.]]>
        - Rettighetsinnstillingene er perfekt!

        Du er klar for å kjøre Umbraco og installere pakker!]]>
        - Løser mappeproblem - Følg denne linken for mer informasjon om problemer med ASP.NET og oppretting av mapper - Konfigurerer mappetillatelser - - Jeg ønsker å starte fra bunnen. - lær hvordan) Du kan fortsatt velge å installere Runway senere. Vennligst gå til Utvikler-seksjonen og velg Pakker.]]> - Du har akkurat satt opp en ren Umbraco plattform. Hva vil du gjøre nå? - Runway er installert - Dette er vår liste av anbefalte moduler- Kryss av de du ønsker å installere, eller se denfulle listen av moduler ]]> - Bare anbefalt for erfarne brukere - Jeg vil starte med en enkel webside - "Runway" er en enkel webside som utstyrer deg med noen grunnleggende dokumenttyper og maler. Veiviseren kan sette opp Runway for deg automatisk, men du kan enkelt endre, utvide eller slette den. Runway er ikke nødvendig, og du kan enkelt bruke Umbraco uten den. Imidlertidig tilbyr Runway et enkelt fundament basert på de beste metodene for å hjelpe deg i gang fortere enn noensinne. Hvis du velger å installere Runway, kan du også velge blant grunnleggende byggeklosser kalt Runway Moduler for å forøke dine Runway-sider.

        Sider inkludert i Runway: Hjemmeside, Komme-i-gang, Installere moduler.
        Valgfrie Moduler: Toppnavigasjon, Sidekart, Kontakt, Galleri.
        ]]>
        - Hva er Runway - Steg 1/5 Godta lisens - Steg 2/5 Database konfigurasjon - Steg 3/5: Valider filrettigheter - Steg 4/5: Skjekk Umbraco sikkerheten - Steg 5/5: Umbraco er klar for deg til å starte! - Tusen takk for at du valgte Umbraco! - Se ditt nye nettsted Du har installert Runway, hvorfor ikke se hvordan ditt nettsted ser ut.]]> - Mer hjelp og info Få hjelp fra vårt prisbelønte samfunn, bla gjennom dokumentasjonen eller se noen gratis videoer på hvordan man bygger et enkelt nettsted, hvordan bruke pakker og en rask guide til Umbraco terminologi]]> - Umbraco %0% er installert og klar til bruk - web.config filen, og oppdatere AppSetting-nøkkelen UmbracoConfigurationStatus til verdien '%0%']]> - starte øyeblikkelig ved å klikke på "Start Umbraco" knappen nedenfor.
        Hvis du er ny på Umbraco, kan du finne mange ressurser på våre komme-i-gang sider.]]>
        - Start Umbraco For å administrere din webside, åpne Umbraco og begynn å legge til innhold, oppdatere maler og stilark eller utvide funksjonaliteten]]> - Tilkobling til databasen mislyktes. - Umbraco Versjon 3 - Umbraco Versjon 4 - Se - Umbraco %0% for en ny installasjon eller oppgradering fra versjon 3.0.

        Trykk "neste" for å starte veiviseren.]]>
        - - - Språkkode - Språk - - - Du har vært inaktiv og vil logges ut automatisk om - Forny innlogging for å lagre - - - Da er det søndag! - Smil, det er mandag! - Hurra, det er tirsdag! - For en herlig onsdag! - Gledelig torsdag! - Endelig fredag! - Gledelig lørdag - Logg på nedenfor - Din sesjon er utløpt - © 2001 - %0%
        umbraco.com

        ]]>
        - - - Skrivebord - Seksjoner - Innhold - - - Velg side over... - %0% er nå kopiert til %1% - Kopier til - %0% er nå flyttet til %1% - Flytt til - har blitt valgt som rot til ditt nye innhold, klikk 'ok' nedenfor. - Ingen node er valgt, vennligst velg en node i listen over før du klikker 'fortsett' - Gjeldende nodes type tillates ikke under valgt node - Gjeldende node kan ikke legges under en underordnet node - Denne noden kan ikke ligge på rotnivå - Handlingen tillates ikke. Du mangler tilgang til en eller flere underordnede noder. - Relater kopierte elementer til original(e) - - - Rediger dine varsler for %0% - - Hei %0%

        - -

        Dette er en automatisk mail for å informere om at handlingen '%1%' - er blitt utført på siden '%2%' - av brukeren '%3%' -

        - -

        -

        Rettelser:

        - - %6% -
        -

        - - - -

        Ha en fin dag!

        - Vennlig hilsen Umbraco roboten -

        ]]>
        - [%0%] Varsling om %1% utført på %2% - Varslinger - - - Umbraco-pakker har vanligvis endelsen ".umb" eller ".zip".]]> - Utvikler - Demonstrasjon - Dokumentasjon - Metadata - Pakkenavn - Pakken inneholder ingen elementer -
        Du kan trygt fjerne pakken fra systemet ved å klikke "avinstaller pakke" nedenfor.]]>
        - Ingen oppdateringer tilgjengelig - Alternativer for pakke - Lesmeg for pakke - Pakkebrønn - Bekreft avinstallering - Pakken ble avinstallert - Pakken ble vellykket avinstallert - Avinstaller pakke - Advarsel: alle dokumenter, media, etc. som som er avhengig av elementene du sletter, vil slutte å virke, noe som kan føre til ustabilitet, så avinstaller med forsiktighet. Hvis du er i tvil, kontakt pakkeutvikleren.]]> - Last ned oppdatering fra pakkeregisteret - Oppgrader pakke - Oppgraderingsinstrukser - Det er en oppdatering tilgjengelig for denne pakken. Du kan laste den ned direkte fra pakkebrønnen. - Pakkeversjon - Pakkeversjonshistorie - Se pakkens nettsted - - - Lim inn med full formattering (Anbefales ikke) - Teksten du er i ferd med å lime inn, inneholder spesialtegn eller formattering. Dette kan skyldes at du kopierer fra f.eks. Microsoft Word. Umbraco kan fjerne denne spesialformatteringen automatisk slik at innholdet er mer velegnet for visning på en webside. - Lim inn som ren tekst, dvs. fjern al formattering - Lim inn og fjern uegnet formatering (anbefalt) - - - Avansert: Beskytt ved å velge hvilke brukergrupper som har tilgang til siden - ved å bruke Umbraco's medlems-grupper]]> - rollebasert autentikasjon.]]> - Feilside - Brukt når personer logger på, men ikke har tilgang - Hvordan vil du beskytte siden din? - %0% er nå beskyttet - Beskyttelse fjernet fra %0% - Innloggingsside - Velg siden som har loginformularet - Fjern beskyttelse - Velg sidene som inneholder login-skjema og feilmelding ved feil innolgging. - Velg rollene som har tilgang til denne siden - Sett brukernavn og passord for denne siden - Enkelt: Beskytt ved hjelp av brukernavn og passord - Om du ønsker å bruke enkel autentisering via ett enkelt brukernavn og passord - - - %0% kunne ikke publiseres fordi den har planlagt utgivelsesdato. - %0% ble ikke publisert. Ett eller flere felter ble ikke godkjent av validering. - %0% kunne ikke publiseres fordi et tredjepartstillegg avbrøt handlingen. - %0% kan ikke publiseres fordi en overordnet side ikke er publisert. - Inkluder upubliserte undersider - Publiserer - vennligst vent... - %0% av %1% sider har blitt publisert... - %0% er nå publisert - %0% og alle undersider er nå publisert - Publiser alle undersider - ok for å publisere %0% og dermed gjøre innholdet synlig for alle.

        Du kan publisere denne siden og alle dens undersider ved å krysse av Publiser alle undersider nedenfor.]]>
        - - - Du har ikke konfigurert noen godkjente farger - - - skriv inn ekstern lenke - velg en intern side - Tittel - Lenke - Åpne i nytt vindu - Skriv inn en tekst - Skriv inn en lenke - - - Nullstill - - - Gjeldende versjon - Rød tekst vil ikke bli vist i den valgte versjonen. , grønn betyr lagt til]]> - Dokumentet er tilbakeført til en tidligere versjon - Dette viser den valgte versjonen som HTML, bruk avviksvisningen hvis du ønsker å se forksjellene mellom to versjoner samtidig. - Tilbakefør til - Velg versjon - Vis - - - Rediger scriptfilen - - - Concierge - Innhold - Courier - Utvikler - Umbraco konfigurasjonsveiviser - Mediaarkiv - Medlemmer - Nyhetsbrev - Innstillinger - Statistikk - Oversettelse - Brukere - Hjelp - Skjemaer - Analytics - - - gå til - Hjelpeemner for - Videokapitler for - De beste Umbraco opplæringsvideoer - - - Standardmal - Ordboksnøkkel - For å importere en dokumenttype, finn ".udt" filen på datamaskinen din ved å klikke "Utforsk" knappen og klikk "Importer" (du vil bli spurt om bekreftelse i det neste skjermbildet) - Ny tittel på arkfane - Nodetype - Type - Stilark - Script - Stilark-egenskap - Arkfane - Tittel på arkfane - Arkfaner - Hovedinnholdstype aktivert - Denne dokumenttypen bruker - som hoveddokumenttype. Arkfaner fra hoveddokumenttyper vises ikke og kan kun endres på hoveddokumenttypen selv. - Ingen egenskaper definert i denne arkfanen. Klikk på "legg til ny egenskap" lenken i toppen for å opprette en ny egenskap. - Hovedinnholdstype - Opprett tilhørende mal - - - Sortering ferdig. - Dra elementene opp eller ned for å arrangere dem. Du kan også klikke kolonneoverskriftene for å sortere alt på en gang. -
        Ikke lukk dette vinduet under sortering]]>
        - - - En feil oppsto - Utilstrekkelige brukertillatelser, kunne ikke fullføre operasjonen - Avbrutt - Handlingen ble avbrutt av et tredjepartstillegg - Publisering ble avbrutt av et tredjepartstillegg - Egenskaptypen finnes allerede - Egenskapstype opprettet - DataType: %1%]]> - Egenskapstype slettet - Innholdstype lagret - Du har opprettet en arkfane - Arkfane slettet - Arkfane med id: %0% slettet - Stilarket ble ikke lagret - Stilarket ble lagret - Stilark lagret uten feil - Datatype lagret - Ordbokelement lagret - Publiseringen feilet fordi den overliggende siden ikke er publisert - Innhold publisert - og er nå synlig for besøkende - Innhold lagret - Husk å publisere for å gjøre endringene synlig for besøkende - Sendt for godkjenning - Endringer har blitt sendt til godkjenning - Media lagret - Media lagret uten feil - Medlem lagret - Stilarksegenskap lagret - Stilark lagret - Mal lagret - Feil ved lagring av bruker (sjekk loggen) - Bruker lagret - Brukertypen lagret - Filen ble ikke lagret - Filen kunne ikke lagres. Vennligst sjekk filrettigheter - Filen ble lagret - Filen ble lagret uten feil - Språk lagret - Python-skriptet ble ikke lagret - Python-skriptet kunne ikke lagres fordi det inneholder en eller flere feil - Python-skriptet er lagret! - Ingen feil i python-skriptet! - Malen ble ikke lagret - Vennligst forviss deg om at du ikke har to maler med samme alias - Malen ble lagret - Malen ble lagret uten feil! - XSLT-koden ble ikke lagret - XSLT-koden inneholdt en feil - XSLT-koden ble ikke lagret, sjekk filrettigheter - XSLT lagret - Ingen feil i XSLT! - Innhold avpublisert - Delmal lagret - Delmal lagret uten feil - Delmal ble ikke lagret! - En feil oppsto ved lagring av delmal - Script visning lagret - Script visning lagret uten feil! - Script visning ikke lagret - En feil oppsto under lagring av filen. - En feil oppsto under lagring av filen. - - - Bruk CSS syntaks f.eks: h1, .redHeader, .blueText - Rediger stilark - Rediger egenskap for stilark - Navn for å identifisere stilarksegenskapen i rik-tekst editoren - Forhåndsvis - Stiler - - - Rediger mal - Sett inn innholdsområde - Sett inn plassholder for innholdsområde - Sett inn ordbokselement - Sett inn makro - Sett inn Umbraco sidefelt - Hovedmal - Hurtigguide til Umbraco sine maltagger - Mal - - - Sett inn element - Velg ett oppsett for denne seksjonen - nedenfor og legg til det første elementet]]> - Klikk for å bygge inn - Klikk for å sette inn et bilde - Bildetekst... - Skriv her... - Rutenettoppsett - Et oppsett er det overordnede arbeidsområdet til ditt rutenett - du vil typisk kun behøve ét eller to - Legg til rutenettoppsett - Juster oppsettet ved at justere kolonnebredder og legg til ytterligere seksjoner - Radkonfigurasjoner - Rader er forhåndsdefinerte celler arrangert vannrett - Legg til radkonfigurasjon - Juster raden ved å sette celle bredder og legge til flere celler - Kolonner - Totale antallet kolonner i rutenettet - Innstillinger - Konfigurer hvilke innstillinger brukeren kan endre - Stiler - Konfigurer hvilke stiler redaktørene kan endre - Innstillingene lagres kun når json-konfigurasjonen er gyldig - Tillatt alle editorer - Tillat alle radkonfigurasjoner - - - Alternativt felt - Alternativ tekst - Store/små bokstaver - Encoding - Felt som skal settes inn - Konverter linjeskift - Erstatter et linjeskift med htmltaggen <br> - Egendefinerte felt - Ja, kun dato - Formatter som dato - HTML koding - Formater spesialtegn med tilsvarende HTML-tegn. - Denne teksten vil settes inn etter verdien av feltet - Denne teksten vil settes inn før verdien av feltet - Små bokstaver - Ingen - Sett inn etter felt - Sett inn før felt - Rekursivt - Fjern paragraftagger - Fjerner eventuelle <P> rundt teksten - Standardfelter - Store bokstaver - URL koding - Dersom innholdet av feltene skal sendes til en URL skal spesialtegn formatteres - Denne teksten vil benyttes dersom feltene over er tomme - Dette feltet vil benyttes dersom feltet over er tomt - Ja, med klokkeslett. Dato/tid separator: - - - Oppgaver satt til deg - som du er tildelt. For å se en detaljert visning inkludert kommentarer, klikk på "Detaljer" eller navnet på siden. Du kan også laste ned siden som XML direkte ved å klikke på linken "Last ned XML".
        For å lukke en oversettelsesoppgave, vennligst gå til detaljvisningen og klikk på "Lukk" knappen.]]>
        - Lukk oppgave - Oversettelses detaljer - Last ned all oversettelsesoppgaver som XML - Last ned XML - Last ned XML DTD - Felt - Inkluder undersider - - [%0%] Oversettingsoppgave for %1% - Ingen oversettelses-bruker funnet. Vennligst opprett en oversettelses-bruker før du begynner å sende innhold til oversetting - Oppgaver opprettet av deg - opprettet av deg. For å se en detaljert visning inkludert kommentarer, klikk på "Detaljer" eller navnet på siden. Du kan også laste ned siden som XML direkte ved å klikke på linken "Last ned XML". For å lukke en oversettelsesoppgave, vennligst gå til detaljvisningen og klikk på "Lukk" knappen.]]> - Siden '%0%' har blitt sendt til oversetting - Send til oversetting - Tildelt av - Oppgave åpnet - Antall ord - Oversett til - Oversetting fullført. - Du kan forhåndsvise sidene du nettopp har oversatt ved å klikke nedenfor. Hvis den originale siden finnes, vil du få en sammenligning av sidene. - Oversetting mislykkes, XML filen kan være korrupt - Alternativer for oversetting - Oversetter - Last opp XML med oversettelse - - - Hurtigbufferleser - Papirkurv - Opprettede pakker - Datatyper - Ordbok - Installerte pakker - Installer utseende - Installer startpakke - Språk - Installer lokal pakke - Makroer - Mediatyper - Medlemmer - Medlemsgrupper - Roller - Medlemstyper - Dokumenttyper - Pakker - Pakker - Python Filer - Installer fra pakkeregister - Installer Runway - Runway moduler - Skriptfiler - Skript - Stiler - Maler - XSLT Filer - Analytics - - - Ny oppdatering er klar - %0% er klar, klikk her for å laste ned - Ingen forbindelse til server - Kunne ikke sjekke etter ny oppdatering. Se trace for mere info. - - - Administrator - Kategorifelt - Bytt passord - Nytt passord - Bekreft nytt passord - Du kan endre passordet til Umbraco ved å fylle ut skjemaet under og klikke "Bytt passord" knappen. - Innholdskanal - Beskrivelsesfelt - Deaktiver bruker - Dokumenttype - Redaktør - Utdragsfelt - Språk - Brukernavn - Øverste nivå i Media - Moduler - Deaktiver tilgang til Umbraco - Passord - Nullstill passord - Passordet er endret - Bekreft nytt passord - Nytt passord - Nytt passord kan ikke være blankt - Gjeldende passord - Feil passord - Nytt og bekreftet passord må være like - Nytt og bekreftet passord må være like - Overskriv tillatelser på undernoder - Du redigerer for øyeblikket tillatelser for sidene: - Velg sider for å redigere deres tillatelser - Søk i alle undersider - Startnode - Navn - Brukertillatelser - Brukertype - Brukertyper - Forfatter - Oversetter - Endre - Din profil - Din historikk - Sesjonen utløper om - + + + + The Umbraco community + http://our.umbraco.org/documentation/Extending-Umbraco/Language-Files + + + Angi domene + Revisjoner + Bla gjennom + Skift dokumenttype + Kopier + Opprett + Opprett pakke + Slett + Deaktiver + Tøm papirkurv + Eksporter dokumenttype + Importer dokumenttype + Importer pakke + Rediger i Canvas + Logg av + Flytt + Varslinger + Offentlig tilgang + Publiser + Avpubliser + Oppdater noder + Republiser hele siten + Gjenopprett + Rettigheter + Reverser + Send til publisering + Send til oversetting + Sorter + Send til publisering + Oversett + Oppdater + Standard verdi + + + Ingen tilgang. + Legg til domene + Fjern + Ugyldig node. + Ugyldig domeneformat. + Domene er allerede tilknyttet. + Språk + Domene + Domene '%0%' er nå opprettet og tilknyttet siden + Domenet '%0%' er nå slettet + Domenet '%0%' er allerede tilknyttet + Domenet '%0%' er nå oppdatert + eller rediger eksisterende domener +
        Stier med ett nivå støttes, f.eks. "eksempel.com/no". Imidlertid bør det unngås. Bruk heller språkinnstillingen over.]]>
        + Arv + Språk + Vil også gjelde denne noden, med mindre et underordnet domene også gjelder.]]> + Domener + + + Viser for + + + Velg + Velg gjeldende mappe + Gjør noe annet + Fet + Reduser innrykk + Sett inn skjemafelt + Sett inn grafisk overskrift + Rediger HTML + Øk innrykk + Kursiv + Midtstill + Juster tekst venstre + Juster tekst høyre + Sett inn lenke + Sett inn lokal lenke (anker) + Punktmerking + Nummerering + Sett inn makro + Sett inn bilde + Rediger relasjoner + Tilbake til listen + Lagre + Lagre og publiser + Lagre og send til publisering + Forhåndsvis + Forhåndsvisning er deaktivert siden det ikke er angitt noen mal + Velg formattering + Vis stiler + Sett inn tabell + + + For å endre det valge innholdets dokumenttype, velger du først en ny dokumenttype som er gyldig på gjeldende plassering. + Kontroller deretter at alle egenskaper blir overført riktig til den nye dokumenttypen og klikk på Lagre. + Innholdet har blitt republisert. + Nåværende egenskap + Nåværende type + Du kan ikke endre dokumenttype, ettersom det ikke er andre gyldige dokumenttyper på denne plasseringen. + Dokumenttype endret + Overfør egenskaper + Overfør til egenskap + Ny mal + Ny type + ingen + Innhold + Velg ny dokumenttype + Dokumenttypen på det valgte innhold ble endret til [new type], og følgende egenskaper ble overført: + til + Overføringen av egenskaper kunne ikke fullføres da en eller flere egenskaper er satt til å bli overført mer enn en gang. + Kun andre dokumenttyper som er gyldige for denne plasseringen vises. + + + Publisert + Om siden + Alias + (hvordan du ville beskrevet bildet over telefon) + Alternative lenker + Klikk for å redigere denne noden + Opprettet av + Opprinnelig forfatter + Oppdatert av + Opprettet den + Tidspunkt for opprettelse + Dokumenttype + Redigerer + Utløpsdato + Denne noden er endret siden siste publisering + Denne noden er enda ikke publisert + Sist publisert + Det er ingen elementer å vise i listen. + Mediatype + Link til media + Medlemsgruppe + Rolle + Medlemstype + Ingen dato valgt + Sidetittel + Egenskaper + Dette dokumentet er publisert, men ikke synlig ettersom den overliggende siden '%0%' ikke er publisert + Intern feil: dokumentet er publisert men finnes ikke i hurtigbuffer + Publisert + Publiseringsstatus + Publiseringsdato + Dato for avpublisering + Fjern dato + Sorteringsrekkefølgen er oppdatert + Trekk og slipp nodene eller klikk på kolonneoverskriftene for å sortere. Du kan velge flere noder ved å holde shift eller control tastene mens du velger. + Statistikk + Tittel (valgfri) + Alternativ tekst (valgfri) + Type + Avpubliser + Sist endret + Tidspunkt for siste endring + Fjern fil + Lenke til dokument + Medlem av gruppe(ne) + Ikke medlem av gruppe(ne) + Undersider + Åpne i vindu + + + Klikk for å laste opp + Slipp filene her... + + + Opprett et nytt medlem + Alle medlemmer + + + Hvor ønsker du å oprette den nye %0% + Opprett under + Velg en type og skriv en tittel + "dokumenttyper".]]> + "mediatyper".]]> + + + Til ditt nettsted + - Skjul + Hvis Umbraco ikke starter, kan det skyldes at pop-up vinduer ikke er tillatt + er åpnet i nytt vindu + Omstart + Besøk + Velkommen + + + Navn på lokal link + Rediger domener + Lukk dette vinduet + Er du sikker på at du vil slette + Er du sikker på at du vil deaktivere + Vennligst kryss av i denne boksen for å bekrefte sletting av %0% element(er) + Er du sikker på at du vil forlate Umbraco? + Er du sikker? + Klipp ut + Rediger ordboksnøkkel + Rediger språk + Sett inn lokal link + Sett inn spesialtegn + Sett inn grafisk overskrift + Sett inn bilde + Sett inn lenke + Sett inn makro + Sett inn tabell + Sist redigert + Lenke + Intern link: + Ved lokal link, sett inn "#" foran link + Åpne i nytt vindu? + Makroinnstillinger + Denne makroen har ingen egenskaper du kan endre + Lim inn + Endre rettigheter for + Innholdet i papirkurven blir nå slettet. Vennligst ikke lukk dette vinduet mens denne operasjonen foregår + Papirkurven er nå tom + Når elementer blir slettet fra papirkurven vil de være slettet for alltid + regexlib.com tjenesten opplever for tiden problemer som vi ikke har kontroll over. Vi beklager denne ubeleiligheten.]]> + Søk etter et regulært uttrykk for å legge inn validering til et felt. Eksempel: 'email, 'zip-code' 'url' + Fjern makro + Obligatorisk + Nettstedet er indeksert + Hurtigbufferen er blitt oppdatert. Alt publisert innhold er nå à jour. Alt upublisert innhold er fortsatt ikke publisert. + Hurtigbufferen for siden vil bli oppdatert. Alt publisert innhold vil bli oppdatert, mens upublisert innhold vil forbli upublisert. + Antall kolonner + Antall rader + Sett en plassholder-ID
        Ved å sette en ID på plassholderen kan du legge inn innhold i denne malen fra underliggende maler, ved å referere denne ID'en ved hjelp av et <asp:content /> element.]]>
        + Velg en plassholder ID fra listen under. Du kan bare velge ID'er fra den gjeldende malens overordnede mal.]]> + Klikk på bildet for å se det i full størrelse + Velg punkt + Se buffret node + + + %0%' under.
        Du kan legge til flere språk under 'språk' i menyen til venstre.]]>
        + Språk + + + Skriv inn ditt brukernavn + Skriv inn ditt passord + Navngi %0%... + Skriv inn navn... + Søk... + Filtrer... + Skriv inn nøkkelord (trykk på Enter etter hvert nøkkelord)... + + + Tillat på rotnivå + Kun dokumenttyper med denne innstillingen aktivert kan opprettes på rotnivå under Innhold og Mediearkiv + Tillatte underordnede noder + Sammensetting av dokumenttyper + Opprett + Slett arkfane + Beskrivelse + Ny arkfane + Arkfane + Miniatyrbilde + Aktiver listevisning + Viser undersider i en søkbar liste, undersider vises ikke i innholdstreet + Gjeldende listevisning + Den aktive listevisningsdatatypen + Opprett brukerdefinert listevisning + Fjern brukerdefinert listevisning + + + Legg til forhåndsverdi + Database datatype + Kontrollelement GUID + Kontrollelement + Knapper + Aktiver avanserte instillinger for + Aktiver kontektsmeny + Maksimum standard størrelse på innsatte bilder + Beslektede stilark + Vis etikett + Bredde og høyde + + + Dine data har blitt lagret, men før du kan publisere denne siden må du rette noen feil: + Den gjeldende Membership Provider støtter ikke endring av passord. (EnablePasswordRetrieval må være satt til sann) + %0% finnes allerede + Det var feil i dokumentet: + Det var feil i skjemaet: + Passordet bør være minst %0% tegn og inneholde minst %1% numeriske tegn + %0% må være et heltall + %0% under %1% er obligatorisk + %0% er obligatorisk + %0% under %1% er ikke i et korrekt format + %0% er ikke i et korrekt format + + + Filtypen er deaktivert av administrator + NB! Selv om CodeMirror er aktivert i konfigurasjon er det deaktivert i Internet Explorer pga. ustabilitet. + Fyll ut både alias og navn på den nye egenskapstypen! + Det er et problem med lese/skrive rettighetene til en fil eller mappe + Tittel mangler + Type mangler + Du er i ferd med å gjøre bildet større enn originalen. Det vil forringe kvaliteten på bildet, ønsker du å fortsette? + Feil i python-skriptet + Python-skriptet ble ikke lagret fordi det inneholder en eller flere feil + Startnode er slettet. Kontakt din administrator + Du må markere innhold før du kan endre stil + Det er ingen aktive stiler eller formateringer på denne siden + Sett markøren til venstre i de 2 cellene du ønsker å slå sammen + Du kan ikke dele en celle som allerede er delt. + Feil i XSLT kode + XSLT ble ikke lagret på grunn av feil i koden + Det er et problem dem datatypen som brukes til denne egenskapen. Kontroller innstillingene og prøv igjen. + + + Om + Handling + Muligheter + Legg til + Alias + Er du sikker? + Ramme + av + Avbryt + Cellemargin + Velg + Lukk + Lukk vindu + Kommentar + Bekreft + Behold proposjoner + Fortsett + Kopier + Opprett + Database + Dato + Standard + Slett + Slettet + Sletter... + Design + Dimensjoner + Ned + Last ned + Rediger + Endret + Elementer + E-post + Feil + Finn + Høyde + Hjelp + Ikon + Importer + Indre margin + Sett inn + Installer + Justering + Språk + Layout + Laster + Låst + Logg inn + Logg ut + Logg ut + Makro + Flytt + Mer + Navn + Ny + Neste + Nei + av + OK + Åpne + eller + Passord + Sti + Plassholder ID + Ett øyeblikk... + Forrige + Egenskaper + E-post som innholdet i skjemaet skal sendes til + Papirkurv + Gjenværende + Gi nytt navn + Forny + Påkrevd + Prøv igjen + Rettigheter + Søk + Server + Vis + Hvilken side skal vises etter at skjemaet er sendt + Størrelse + Sorter + Type + Søk... + Opp + Oppdater + Oppgrader + Last opp + Url + Bruker + Brukernavn + Verdi + Visning + Velkommen... + Bredde + Ja + Mappe + Søkeresultater + + + Bakgrunnsfarge + Fet + Tekstfarge + Skrifttype + Tekst + + + Side + + + Installasjonsprogrammet kan ikke koble til databasen + Kunne ikke lagre Web.Config-filen. Vennligst endre databasens tilkoblingsstreng manuelt. + Din database er funnet og identifisert som + Databasekonfigurasjon + installer-knappen for å installere Umbraco %0% databasen]]> + Neste for å fortsette.]]> + Databasen ble ikke funnet! Vennligst sjekk at informasjonen i "connection string" i "web.config"-filen er korrekt.

        For å fortsette, vennligst rediger "web.config"-filen (bruk Visual Studio eller din favoritteditor), rull ned til bunnen, og legg til tilkoblingsstrengen for din database i nøkkelen "umbracoDbDSN" og lagre filen.

        Klikk prøv på nytt når du er ferdig.
        Mer informasjon om redigering av web.config her.

        ]]>
        + Vennligst kontakt din ISP om nødvendig. Hvis du installerer på en lokal maskin eller server, må du kanskje skaffe informasjonen fra din systemadministrator.]]> + Trykk på knappen oppgrader for å oppgradere databasen din til Umbraco %0%

        Ikke vær urolig - intet innhold vil bli slettet og alt vil fortsette å virke etterpå!

        ]]>
        + Trykk Neste for å fortsette.]]> + neste for å fortsette konfigurasjonsveiviseren]]> + Passordet til standardbrukeren må endres!]]> + Standardbrukeren har blitt deaktivert eller har ingen tilgang til Umbraco!

        Ingen videre handling er nødvendig. Klikk neste for å fortsette.]]> + Passordet til standardbrukeren har blitt forandret etter installasjonen!

        Ingen videre handling er nødvendig. Klikk Neste for å fortsette.]]> + Passordet er blitt endret! + Umbraco skaper en standard bruker med login ( "admin") og passord ( "default") . Det er viktig at passordet er endret til noe unikt.

        Dette trinnet vil sjekke standard brukerens passord og foreslår hvis det må skiftes ]]> + Få en god start med våre introduksjonsvideoer + Ved å klikke på Neste-knappen (eller endre UmbracoConfigurationStatus i Web.config), godtar du lisensen for denne programvaren som angitt i boksen nedenfor. Legg merke til at denne Umbraco distribusjon består av to ulike lisenser, åpen kilde MIT lisens for rammen og Umbraco frivareverktøy lisens som dekker brukergrensesnittet. + Ikke installert. + Berørte filer og mapper + Mer informasjon om å sette opp rettigheter for Umbraco her + Du må gi ASP.NET brukeren rettigheter til å endre de følgende filer og mapper + Rettighetene er nesten perfekt satt opp!

        Du kan kjøre Umbraco uten problemer, men du vil ikke være i stand til å installere de anbefalte pakkene for å utnytte Umbraco fullt ut.]]> + Hvordan løse problemet + Klikk her for å lese tekstversjonen + innføringsvideo
        om å sette opp rettigheter for Umbraco eller les tekstversjonen.]]> + Rettighetsinnstillingene kan være et problem!


        Du kan kjøre Umbraco uten problemer, men du vil ikke være i stand til å installere de anbefalte pakkene for å utnytte Umbraco fullt ut.]]> + Rettighetsinstillingene er ikke klargjort for Umbraco!

        For å kunne kjøre Umbraco, må du oppdatere rettighetsinnstillingene dine.]]>
        + Rettighetsinnstillingene er perfekt!

        Du er klar for å kjøre Umbraco og installere pakker!]]>
        + Løser mappeproblem + Følg denne linken for mer informasjon om problemer med ASP.NET og oppretting av mapper + Konfigurerer mappetillatelser + + Jeg ønsker å starte fra bunnen. + lær hvordan) Du kan fortsatt velge å installere Runway senere. Vennligst gå til Utvikler-seksjonen og velg Pakker.]]> + Du har akkurat satt opp en ren Umbraco plattform. Hva vil du gjøre nå? + Runway er installert + Dette er vår liste av anbefalte moduler- Kryss av de du ønsker å installere, eller se denfulle listen av moduler ]]> + Bare anbefalt for erfarne brukere + Jeg vil starte med en enkel webside + "Runway" er en enkel webside som utstyrer deg med noen grunnleggende dokumenttyper og maler. Veiviseren kan sette opp Runway for deg automatisk, men du kan enkelt endre, utvide eller slette den. Runway er ikke nødvendig, og du kan enkelt bruke Umbraco uten den. Imidlertidig tilbyr Runway et enkelt fundament basert på de beste metodene for å hjelpe deg i gang fortere enn noensinne. Hvis du velger å installere Runway, kan du også velge blant grunnleggende byggeklosser kalt Runway Moduler for å forøke dine Runway-sider.

        Sider inkludert i Runway: Hjemmeside, Komme-i-gang, Installere moduler.
        Valgfrie Moduler: Toppnavigasjon, Sidekart, Kontakt, Galleri.
        ]]>
        + Hva er Runway + Steg 1/5 Godta lisens + Steg 2/5 Database konfigurasjon + Steg 3/5: Valider filrettigheter + Steg 4/5: Skjekk Umbraco sikkerheten + Steg 5/5: Umbraco er klar for deg til å starte! + Tusen takk for at du valgte Umbraco! + Se ditt nye nettsted Du har installert Runway, hvorfor ikke se hvordan ditt nettsted ser ut.]]> + Mer hjelp og info Få hjelp fra vårt prisbelønte samfunn, bla gjennom dokumentasjonen eller se noen gratis videoer på hvordan man bygger et enkelt nettsted, hvordan bruke pakker og en rask guide til Umbraco terminologi]]> + Umbraco %0% er installert og klar til bruk + web.config filen, og oppdatere AppSetting-nøkkelen UmbracoConfigurationStatus til verdien '%0%']]> + starte øyeblikkelig ved å klikke på "Start Umbraco" knappen nedenfor.
        Hvis du er ny på Umbraco, kan du finne mange ressurser på våre komme-i-gang sider.]]>
        + Start Umbraco For å administrere din webside, åpne Umbraco og begynn å legge til innhold, oppdatere maler og stilark eller utvide funksjonaliteten]]> + Tilkobling til databasen mislyktes. + Umbraco Versjon 3 + Umbraco Versjon 4 + Se + Umbraco %0% for en ny installasjon eller oppgradering fra versjon 3.0.

        Trykk "neste" for å starte veiviseren.]]>
        + + + Språkkode + Språk + + + Du har vært inaktiv og vil logges ut automatisk om + Forny innlogging for å lagre + + + Da er det søndag! + Smil, det er mandag! + Hurra, det er tirsdag! + For en herlig onsdag! + Gledelig torsdag! + Endelig fredag! + Gledelig lørdag + Logg på nedenfor + Din sesjon er utløpt + © 2001 - %0%
        umbraco.com

        ]]>
        + + + Skrivebord + Seksjoner + Innhold + + + Velg side over... + %0% er nå kopiert til %1% + Kopier til + %0% er nå flyttet til %1% + Flytt til + har blitt valgt som rot til ditt nye innhold, klikk 'ok' nedenfor. + Ingen node er valgt, vennligst velg en node i listen over før du klikker 'fortsett' + Gjeldende nodes type tillates ikke under valgt node + Gjeldende node kan ikke legges under en underordnet node + Denne noden kan ikke ligge på rotnivå + Handlingen tillates ikke. Du mangler tilgang til en eller flere underordnede noder. + Relater kopierte elementer til original(e) + + + Rediger dine varsler for %0% + + Hei %0%

        + +

        Dette er en automatisk mail for å informere om at handlingen '%1%' + er blitt utført på siden '%2%' + av brukeren '%3%' +

        + +

        +

        Rettelser:

        + + %6% +
        +

        + + + +

        Ha en fin dag!

        + Vennlig hilsen Umbraco roboten +

        ]]>
        + [%0%] Varsling om %1% utført på %2% + Varslinger + + + Umbraco-pakker har vanligvis endelsen ".umb" eller ".zip".]]> + Utvikler + Demonstrasjon + Dokumentasjon + Metadata + Pakkenavn + Pakken inneholder ingen elementer +
        Du kan trygt fjerne pakken fra systemet ved å klikke "avinstaller pakke" nedenfor.]]>
        + Ingen oppdateringer tilgjengelig + Alternativer for pakke + Lesmeg for pakke + Pakkebrønn + Bekreft avinstallering + Pakken ble avinstallert + Pakken ble vellykket avinstallert + Avinstaller pakke + Advarsel: alle dokumenter, media, etc. som som er avhengig av elementene du sletter, vil slutte å virke, noe som kan føre til ustabilitet, så avinstaller med forsiktighet. Hvis du er i tvil, kontakt pakkeutvikleren.]]> + Last ned oppdatering fra pakkeregisteret + Oppgrader pakke + Oppgraderingsinstrukser + Det er en oppdatering tilgjengelig for denne pakken. Du kan laste den ned direkte fra pakkebrønnen. + Pakkeversjon + Pakkeversjonshistorie + Se pakkens nettsted + + + Lim inn med full formattering (Anbefales ikke) + Teksten du er i ferd med å lime inn, inneholder spesialtegn eller formattering. Dette kan skyldes at du kopierer fra f.eks. Microsoft Word. Umbraco kan fjerne denne spesialformatteringen automatisk slik at innholdet er mer velegnet for visning på en webside. + Lim inn som ren tekst, dvs. fjern al formattering + Lim inn og fjern uegnet formatering (anbefalt) + + + Avansert: Beskytt ved å velge hvilke brukergrupper som har tilgang til siden + ved å bruke Umbraco's medlems-grupper]]> + rollebasert autentikasjon.]]> + Feilside + Brukt når personer logger på, men ikke har tilgang + Hvordan vil du beskytte siden din? + %0% er nå beskyttet + Beskyttelse fjernet fra %0% + Innloggingsside + Velg siden som har loginformularet + Fjern beskyttelse + Velg sidene som inneholder login-skjema og feilmelding ved feil innolgging. + Velg rollene som har tilgang til denne siden + Sett brukernavn og passord for denne siden + Enkelt: Beskytt ved hjelp av brukernavn og passord + Om du ønsker å bruke enkel autentisering via ett enkelt brukernavn og passord + + + %0% kunne ikke publiseres fordi den har planlagt utgivelsesdato. + %0% ble ikke publisert. Ett eller flere felter ble ikke godkjent av validering. + %0% kunne ikke publiseres fordi et tredjepartstillegg avbrøt handlingen. + %0% kan ikke publiseres fordi en overordnet side ikke er publisert. + Inkluder upubliserte undersider + Publiserer - vennligst vent... + %0% av %1% sider har blitt publisert... + %0% er nå publisert + %0% og alle undersider er nå publisert + Publiser alle undersider + ok for å publisere %0% og dermed gjøre innholdet synlig for alle.

        Du kan publisere denne siden og alle dens undersider ved å krysse av Publiser alle undersider nedenfor.]]>
        + + + Du har ikke konfigurert noen godkjente farger + + + skriv inn ekstern lenke + velg en intern side + Tittel + Lenke + Åpne i nytt vindu + Skriv inn en tekst + Skriv inn en lenke + + + Nullstill + + + Gjeldende versjon + Rød tekst vil ikke bli vist i den valgte versjonen. , grønn betyr lagt til]]> + Dokumentet er tilbakeført til en tidligere versjon + Dette viser den valgte versjonen som HTML, bruk avviksvisningen hvis du ønsker å se forksjellene mellom to versjoner samtidig. + Tilbakefør til + Velg versjon + Vis + + + Rediger scriptfilen + + + Concierge + Innhold + Courier + Utvikler + Umbraco konfigurasjonsveiviser + Mediaarkiv + Medlemmer + Nyhetsbrev + Innstillinger + Statistikk + Oversettelse + Brukere + Hjelp + Skjemaer + Analytics + + + gå til + Hjelpeemner for + Videokapitler for + De beste Umbraco opplæringsvideoer + + + Standardmal + Ordboksnøkkel + For å importere en dokumenttype, finn ".udt" filen på datamaskinen din ved å klikke "Utforsk" knappen og klikk "Importer" (du vil bli spurt om bekreftelse i det neste skjermbildet) + Ny tittel på arkfane + Nodetype + Type + Stilark + Script + Stilark-egenskap + Arkfane + Tittel på arkfane + Arkfaner + Hovedinnholdstype aktivert + Denne dokumenttypen bruker + som hoveddokumenttype. Arkfaner fra hoveddokumenttyper vises ikke og kan kun endres på hoveddokumenttypen selv. + Ingen egenskaper definert i denne arkfanen. Klikk på "legg til ny egenskap" lenken i toppen for å opprette en ny egenskap. + Hovedinnholdstype + Opprett tilhørende mal + + + Sortering ferdig. + Dra elementene opp eller ned for å arrangere dem. Du kan også klikke kolonneoverskriftene for å sortere alt på en gang. +
        Ikke lukk dette vinduet under sortering]]>
        + + + En feil oppsto + Utilstrekkelige brukertillatelser, kunne ikke fullføre operasjonen + Avbrutt + Handlingen ble avbrutt av et tredjepartstillegg + Publisering ble avbrutt av et tredjepartstillegg + Egenskaptypen finnes allerede + Egenskapstype opprettet + DataType: %1%]]> + Egenskapstype slettet + Innholdstype lagret + Du har opprettet en arkfane + Arkfane slettet + Arkfane med id: %0% slettet + Stilarket ble ikke lagret + Stilarket ble lagret + Stilark lagret uten feil + Datatype lagret + Ordbokelement lagret + Publiseringen feilet fordi den overliggende siden ikke er publisert + Innhold publisert + og er nå synlig for besøkende + Innhold lagret + Husk å publisere for å gjøre endringene synlig for besøkende + Sendt for godkjenning + Endringer har blitt sendt til godkjenning + Media lagret + Media lagret uten feil + Medlem lagret + Stilarksegenskap lagret + Stilark lagret + Mal lagret + Feil ved lagring av bruker (sjekk loggen) + Bruker lagret + Brukertypen lagret + Filen ble ikke lagret + Filen kunne ikke lagres. Vennligst sjekk filrettigheter + Filen ble lagret + Filen ble lagret uten feil + Språk lagret + Python-skriptet ble ikke lagret + Python-skriptet kunne ikke lagres fordi det inneholder en eller flere feil + Python-skriptet er lagret! + Ingen feil i python-skriptet! + Malen ble ikke lagret + Vennligst forviss deg om at du ikke har to maler med samme alias + Malen ble lagret + Malen ble lagret uten feil! + XSLT-koden ble ikke lagret + XSLT-koden inneholdt en feil + XSLT-koden ble ikke lagret, sjekk filrettigheter + XSLT lagret + Ingen feil i XSLT! + Innhold avpublisert + Delmal lagret + Delmal lagret uten feil + Delmal ble ikke lagret! + En feil oppsto ved lagring av delmal + Script visning lagret + Script visning lagret uten feil! + Script visning ikke lagret + En feil oppsto under lagring av filen. + En feil oppsto under lagring av filen. + + + Bruk CSS syntaks f.eks: h1, .redHeader, .blueText + Rediger stilark + Rediger egenskap for stilark + Navn for å identifisere stilarksegenskapen i rik-tekst editoren + Forhåndsvis + Stiler + + + Rediger mal + Sett inn innholdsområde + Sett inn plassholder for innholdsområde + Sett inn ordbokselement + Sett inn makro + Sett inn Umbraco sidefelt + Hovedmal + Hurtigguide til Umbraco sine maltagger + Mal + + + Sett inn element + Velg ett oppsett for denne seksjonen + nedenfor og legg til det første elementet]]> + Klikk for å bygge inn + Klikk for å sette inn et bilde + Bildetekst... + Skriv her... + Rutenettoppsett + Et oppsett er det overordnede arbeidsområdet til ditt rutenett - du vil typisk kun behøve ét eller to + Legg til rutenettoppsett + Juster oppsettet ved at justere kolonnebredder og legg til ytterligere seksjoner + Radkonfigurasjoner + Rader er forhåndsdefinerte celler arrangert vannrett + Legg til radkonfigurasjon + Juster raden ved å sette celle bredder og legge til flere celler + Kolonner + Totale antallet kolonner i rutenettet + Innstillinger + Konfigurer hvilke innstillinger brukeren kan endre + Stiler + Konfigurer hvilke stiler redaktørene kan endre + Innstillingene lagres kun når json-konfigurasjonen er gyldig + Tillatt alle editorer + Tillat alle radkonfigurasjoner + + + Alternativt felt + Alternativ tekst + Store/små bokstaver + Encoding + Felt som skal settes inn + Konverter linjeskift + Erstatter et linjeskift med htmltaggen <br> + Egendefinerte felt + Ja, kun dato + Formatter som dato + HTML koding + Formater spesialtegn med tilsvarende HTML-tegn. + Denne teksten vil settes inn etter verdien av feltet + Denne teksten vil settes inn før verdien av feltet + Små bokstaver + Ingen + Sett inn etter felt + Sett inn før felt + Rekursivt + Fjern paragraftagger + Fjerner eventuelle <P> rundt teksten + Standardfelter + Store bokstaver + URL koding + Dersom innholdet av feltene skal sendes til en URL skal spesialtegn formatteres + Denne teksten vil benyttes dersom feltene over er tomme + Dette feltet vil benyttes dersom feltet over er tomt + Ja, med klokkeslett. Dato/tid separator: + + + Oppgaver satt til deg + som du er tildelt. For å se en detaljert visning inkludert kommentarer, klikk på "Detaljer" eller navnet på siden. Du kan også laste ned siden som XML direkte ved å klikke på linken "Last ned XML".
        For å lukke en oversettelsesoppgave, vennligst gå til detaljvisningen og klikk på "Lukk" knappen.]]>
        + Lukk oppgave + Oversettelses detaljer + Last ned all oversettelsesoppgaver som XML + Last ned XML + Last ned XML DTD + Felt + Inkluder undersider + + [%0%] Oversettingsoppgave for %1% + Ingen oversettelses-bruker funnet. Vennligst opprett en oversettelses-bruker før du begynner å sende innhold til oversetting + Oppgaver opprettet av deg + opprettet av deg. For å se en detaljert visning inkludert kommentarer, klikk på "Detaljer" eller navnet på siden. Du kan også laste ned siden som XML direkte ved å klikke på linken "Last ned XML". For å lukke en oversettelsesoppgave, vennligst gå til detaljvisningen og klikk på "Lukk" knappen.]]> + Siden '%0%' har blitt sendt til oversetting + Send til oversetting + Tildelt av + Oppgave åpnet + Antall ord + Oversett til + Oversetting fullført. + Du kan forhåndsvise sidene du nettopp har oversatt ved å klikke nedenfor. Hvis den originale siden finnes, vil du få en sammenligning av sidene. + Oversetting mislykkes, XML filen kan være korrupt + Alternativer for oversetting + Oversetter + Last opp XML med oversettelse + + + Hurtigbufferleser + Papirkurv + Opprettede pakker + Datatyper + Ordbok + Installerte pakker + Installer utseende + Installer startpakke + Språk + Installer lokal pakke + Makroer + Mediatyper + Medlemmer + Medlemsgrupper + Roller + Medlemstyper + Dokumenttyper + Pakker + Pakker + Python Filer + Installer fra pakkeregister + Installer Runway + Runway moduler + Skriptfiler + Skript + Stiler + Maler + XSLT Filer + Analytics + + + Ny oppdatering er klar + %0% er klar, klikk her for å laste ned + Ingen forbindelse til server + Kunne ikke sjekke etter ny oppdatering. Se trace for mere info. + + + Administrator + Kategorifelt + Bytt passord + Nytt passord + Bekreft nytt passord + Du kan endre passordet til Umbraco ved å fylle ut skjemaet under og klikke "Bytt passord" knappen. + Innholdskanal + Beskrivelsesfelt + Deaktiver bruker + Dokumenttype + Redaktør + Utdragsfelt + Språk + Brukernavn + Øverste nivå i Media + Moduler + Deaktiver tilgang til Umbraco + Passord + Nullstill passord + Passordet er endret + Bekreft nytt passord + Nytt passord + Nytt passord kan ikke være blankt + Gjeldende passord + Feil passord + Nytt og bekreftet passord må være like + Nytt og bekreftet passord må være like + Overskriv tillatelser på undernoder + Du redigerer for øyeblikket tillatelser for sidene: + Velg sider for å redigere deres tillatelser + Søk i alle undersider + Startnode + Navn + Brukertillatelser + Brukertype + Brukertyper + Forfatter + Oversetter + Endre + Din profil + Din historikk + Sesjonen utløper om +
        \ No newline at end of file From f4e29d90e04bba51be7bb9112e02c179d806908a Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 23:12:09 +0100 Subject: [PATCH 068/605] Code sample No.1 --- src/Umbraco.Web/Models/ImageCropDataSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Models/ImageCropDataSet.cs b/src/Umbraco.Web/Models/ImageCropDataSet.cs index b3b584682a..22ff136c6b 100644 --- a/src/Umbraco.Web/Models/ImageCropDataSet.cs +++ b/src/Umbraco.Web/Models/ImageCropDataSet.cs @@ -55,7 +55,7 @@ namespace Umbraco.Web.Models public bool HasFocalPoint() { - return FocalPoint != null && FocalPoint.Top != 0.5m && FocalPoint.Top != 0.5m; + return FocalPoint != null && FocalPoint.Left != 0.5m && FocalPoint.Top != 0.5m; } public bool HasCrop(string alias) From f68b2de9e340297c3782ed8a47497919c01e049c Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 23:13:37 +0100 Subject: [PATCH 069/605] Code sample No.2 --- src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs index 5abe5dee1c..49d8c7214d 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/BaseTree.cs @@ -500,7 +500,7 @@ namespace umbraco.cms.presentation.Trees /// The instance containing the event data. protected virtual void OnBeforeNodeRender(ref XmlTree sender, ref XmlTreeNode node, EventArgs e) { - if (node != null && node != null) + if (sender != null && node != null) { if (BeforeNodeRender != null) BeforeNodeRender(ref sender, ref node, e); From 8afc4f5ad13e9d20f9412c808834bf26f460bc04 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 23:15:25 +0100 Subject: [PATCH 070/605] Code sample No.3 --- src/Umbraco.Core/Media/Exif/ExifPropertyCollection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Media/Exif/ExifPropertyCollection.cs b/src/Umbraco.Core/Media/Exif/ExifPropertyCollection.cs index 452c05adb8..1be504ea45 100644 --- a/src/Umbraco.Core/Media/Exif/ExifPropertyCollection.cs +++ b/src/Umbraco.Core/Media/Exif/ExifPropertyCollection.cs @@ -75,7 +75,7 @@ namespace Umbraco.Core.Media.Exif { if (items.ContainsKey (key)) items.Remove (key); - if (key == ExifTag.WindowsTitle || key == ExifTag.WindowsTitle || key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor || key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject) { + if (key == ExifTag.WindowsTitle || key == ExifTag.WindowsComment || key == ExifTag.WindowsAuthor || key == ExifTag.WindowsKeywords || key == ExifTag.WindowsSubject) { items.Add (key, new WindowsByteString (key, value)); } else { items.Add (key, new ExifAscii (key, value, parent.Encoding)); From b94c396d4e796f776da7a10dbf2bf7e0ffd90481 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 23:20:47 +0100 Subject: [PATCH 071/605] Code sample No.5 --- src/umbraco.editorControls/tinyMCE3/TinyMCE.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/umbraco.editorControls/tinyMCE3/TinyMCE.cs b/src/umbraco.editorControls/tinyMCE3/TinyMCE.cs index f8de39e536..fcae44b113 100644 --- a/src/umbraco.editorControls/tinyMCE3/TinyMCE.cs +++ b/src/umbraco.editorControls/tinyMCE3/TinyMCE.cs @@ -164,13 +164,8 @@ namespace umbraco.editorControls.tinyMCE3 foreach (StylesheetProperty p in s.Properties) { if (styles != string.Empty) - { styles += ";"; - } - if (p.Alias.StartsWith(".")) - styles += p.Text + "=" + p.Alias; - else - styles += p.Text + "=" + p.Alias; + styles += p.Text + "=" + p.Alias; } cssFiles += ","; From a15b005d95c52b33871425ceda791098bba797db Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 23:22:16 +0100 Subject: [PATCH 072/605] Code sample No.6, No.7 --- src/Umbraco.Core/Services/MemberService.cs | 2 +- src/Umbraco.Core/Services/UserService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index fdfe401ca9..4f0647dbf7 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -111,7 +111,7 @@ namespace Umbraco.Core.Services member.RawPasswordValue = result.RawPasswordValue; member.LastPasswordChangeDate = result.LastPasswordChangeDate; - member.UpdateDate = member.UpdateDate; + member.UpdateDate = result.UpdateDate; } /// diff --git a/src/Umbraco.Core/Services/UserService.cs b/src/Umbraco.Core/Services/UserService.cs index 55d7dd9742..c7a63a884b 100644 --- a/src/Umbraco.Core/Services/UserService.cs +++ b/src/Umbraco.Core/Services/UserService.cs @@ -266,7 +266,7 @@ namespace Umbraco.Core.Services //should never be null but it could have been deleted by another thread. user.RawPasswordValue = result.RawPasswordValue; user.LastPasswordChangeDate = result.LastPasswordChangeDate; - user.UpdateDate = user.UpdateDate; + user.UpdateDate = result.UpdateDate; } } From 59fe690a884a2c97785402a9ec1a38c5f652b5bf Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 5 Jan 2016 23:34:30 +0100 Subject: [PATCH 073/605] Code sample No.10 --- src/Umbraco.Tests/UriExtensionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/UriExtensionsTests.cs b/src/Umbraco.Tests/UriExtensionsTests.cs index 4ea8e8875a..91f727f5f9 100644 --- a/src/Umbraco.Tests/UriExtensionsTests.cs +++ b/src/Umbraco.Tests/UriExtensionsTests.cs @@ -141,7 +141,7 @@ namespace Umbraco.Tests public void GetAbsolutePathDecoded(string input, string expected) { var source = new Uri(input, UriKind.RelativeOrAbsolute); - var output = source.GetSafeAbsolutePathDecoded(); + var output = source.GetAbsolutePathDecoded(); Assert.AreEqual(expected, output); } From 2bdea2ef309fc97e7022e6bfd2a4f658cd2a29d1 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 09:23:55 +0100 Subject: [PATCH 074/605] Fixes: U4-7556 Export/import document types isn't available in 7.4 Added in export to context menu on document types using the legacy dialog. --- src/Umbraco.Web/Trees/ContentTypeTreeController.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs index 43cf60a178..31ad9f10bb 100644 --- a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs @@ -94,8 +94,15 @@ namespace Umbraco.Web.Trees } else { - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias)), hasSeparator: true); + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias))); + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionExport.Instance.Alias)), hasSeparator: true).ConvertLegacyMenuItem(new UmbracoEntity + { + Id = int.Parse(id), + Level = 1, + ParentId = -1, + Name = "" + }, "documenttypes", "settings"); ; + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), hasSeparator: true); } return menu; From 83963003f9f311e21874974183ae943a9dfa8907 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 09:25:15 +0100 Subject: [PATCH 075/605] Ensures XML serializer doesn't fail when trying to serialize null properties. Some properties can now be nulls instead of string.Empty when using the new content type editor. --- src/Umbraco.Core/Services/EntityXmlSerializer.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index 712f98aeb2..fca29ddd6e 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -374,14 +374,15 @@ namespace Umbraco.Core.Services : contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value); var genericProperty = new XElement("GenericProperty", - new XElement("Name", propertyType.Name), - new XElement("Alias", propertyType.Alias), - new XElement("Type", propertyType.PropertyEditorAlias), + propertyType.Name != null ? new XElement("Name", propertyType.Name) : null, + propertyType.Alias != null ? new XElement("Alias", propertyType.Alias) : null, + propertyType.PropertyEditorAlias != null ? new XElement("Type", propertyType.PropertyEditorAlias) : null, new XElement("Definition", definition.Key), new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("Mandatory", propertyType.Mandatory.ToString()), - new XElement("Validation", propertyType.ValidationRegExp), - new XElement("Description", new XCData(propertyType.Description))); + propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, + propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null); + genericProperties.Add(genericProperty); } From e489cffa3dd237b8dc3a5129ef32c5f215d21f00 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 09:26:58 +0100 Subject: [PATCH 076/605] Removed unused namespaces and cleanup. --- src/Umbraco.Web/Trees/ContentTypeTreeController.cs | 6 +----- .../umbraco.presentation/umbraco/Trees/loadNodeTypes.cs | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs index 31ad9f10bb..6cb38c6480 100644 --- a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs @@ -1,14 +1,10 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Net.Http.Formatting; -using System.Text; -using System.Threading.Tasks; using umbraco; using umbraco.BusinessLogic.Actions; using Umbraco.Core; using Umbraco.Core.Models; -using Umbraco.Core.Models.EntityBase; using Umbraco.Web.Models.Trees; using Umbraco.Web.WebApi.Filters; using Umbraco.Core.Services; @@ -101,7 +97,7 @@ namespace Umbraco.Web.Trees Level = 1, ParentId = -1, Name = "" - }, "documenttypes", "settings"); ; + }, "documenttypes", "settings"); menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), hasSeparator: true); } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadNodeTypes.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadNodeTypes.cs index c2940a8a5d..af3da401e8 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadNodeTypes.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadNodeTypes.cs @@ -1,14 +1,11 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Text; using Umbraco.Core.Services; -using umbraco.businesslogic; using umbraco.interfaces; using umbraco.BusinessLogic.Actions; using umbraco.cms.presentation.Trees; -using Umbraco.Core; using Umbraco.Web.umbraco.presentation.umbraco.Trees; From e49033a602bc5f5be6fe66d3cb9de0a2d8a680e7 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 09:44:12 +0100 Subject: [PATCH 077/605] Added import document type option to context menu on root node. --- .../Trees/ContentTypeTreeController.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs index 6cb38c6480..c9b0551217 100644 --- a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs @@ -69,7 +69,14 @@ namespace Umbraco.Web.Trees // root actions menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias))); + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionImport.Instance.Alias)), true).ConvertLegacyMenuItem(new UmbracoEntity + { + Id = int.Parse(id), + Level = 1, + ParentId = -1, + Name = "" + }, "documenttypes", "settings"); + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); return menu; } @@ -86,19 +93,19 @@ namespace Umbraco.Web.Trees //can delete doc type menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); } - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), hasSeparator: true); + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); } else { menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionMove.Instance.Alias))); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionExport.Instance.Alias)), hasSeparator: true).ConvertLegacyMenuItem(new UmbracoEntity + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionExport.Instance.Alias)), true).ConvertLegacyMenuItem(new UmbracoEntity { Id = int.Parse(id), Level = 1, ParentId = -1, Name = "" }, "documenttypes", "settings"); - menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), hasSeparator: true); + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true); } return menu; From 2dcb9c93f7b0760da6b70200ff42f5eaf327029b Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 10:26:09 +0100 Subject: [PATCH 078/605] Dropped these null checks to avoid serializing invalid objects. --- src/Umbraco.Core/Services/EntityXmlSerializer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index fca29ddd6e..16f33a1ce9 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -374,15 +374,15 @@ namespace Umbraco.Core.Services : contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value); var genericProperty = new XElement("GenericProperty", - propertyType.Name != null ? new XElement("Name", propertyType.Name) : null, - propertyType.Alias != null ? new XElement("Alias", propertyType.Alias) : null, - propertyType.PropertyEditorAlias != null ? new XElement("Type", propertyType.PropertyEditorAlias) : null, + new XElement("Name", propertyType.Name), + new XElement("Alias", propertyType.Alias), + new XElement("Type", propertyType.PropertyEditorAlias), new XElement("Definition", definition.Key), new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("Mandatory", propertyType.Mandatory.ToString()), propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null); - + genericProperties.Add(genericProperty); } From bfa9c80ed603b283aa1e1742ea28340772209145 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 10:27:39 +0100 Subject: [PATCH 079/605] Added null checks for elements on import. --- src/Umbraco.Core/Services/PackagingService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 8ca9d3e3da..0d1d8388b6 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -655,9 +655,9 @@ namespace Umbraco.Core.Services var propertyType = new PropertyType(dataTypeDefinition, property.Element("Alias").Value) { Name = property.Element("Name").Value, - Description = property.Element("Description").Value, - Mandatory = property.Element("Mandatory").Value.ToLowerInvariant().Equals("true"), - ValidationRegExp = property.Element("Validation").Value, + Description = property.Element("Description") != null ? property.Element("Description").Value : null, + Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false, + ValidationRegExp = property.Element("Validation") != null ? property.Element("Validation").Value : null, }; var tab = property.Element("Tab").Value; From f1cc32771ec77f242c726ba84c3ce60dbb9cddaa Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 10:31:21 +0100 Subject: [PATCH 080/605] Using constants instead of -1. --- src/Umbraco.Web/Trees/ContentTypeTreeController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs index c9b0551217..e29f9d6be9 100644 --- a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs @@ -73,7 +73,7 @@ namespace Umbraco.Web.Trees { Id = int.Parse(id), Level = 1, - ParentId = -1, + ParentId = Constants.System.Root, Name = "" }, "documenttypes", "settings"); menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); @@ -102,7 +102,7 @@ namespace Umbraco.Web.Trees { Id = int.Parse(id), Level = 1, - ParentId = -1, + ParentId = Constants.System.Root, Name = "" }, "documenttypes", "settings"); menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)), true); From dca6f2b42a3570cbbd770ed4f3a980e077d4924a Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 10:47:58 +0100 Subject: [PATCH 081/605] fixes build --- .../UmbracoBackOfficeCookieAuthOptions.cs | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs index afc00a27ed..5e6f9c85b8 100644 --- a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs +++ b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs @@ -89,38 +89,6 @@ namespace Umbraco.Web.Security.Identity return cookieOptions; } - - /// - /// Creates the cookie options for saving the auth cookie - /// - /// - /// - /// - public CookieOptions CreateRequestCookieOptions(IOwinContext ctx, AuthenticationTicket ticket) - { - if (ctx == null) throw new ArgumentNullException("ctx"); - if (ticket == null) throw new ArgumentNullException("ticket"); - - var issuedUtc = ticket.Properties.IssuedUtc ?? SystemClock.UtcNow; - var expiresUtc = ticket.Properties.ExpiresUtc ?? issuedUtc.Add(ExpireTimeSpan); - - var cookieOptions = new CookieOptions - { - Path = "/", - Domain = this.CookieDomain ?? null, - HttpOnly = true, - Secure = this.CookieSecure == CookieSecureOption.Always - || (this.CookieSecure == CookieSecureOption.SameAsRequest && ctx.Request.IsSecure), - }; - - if (ticket.Properties.IsPersistent) - { - cookieOptions.Expires = expiresUtc.ToUniversalTime().DateTime; - } - - return cookieOptions; - } - } } \ No newline at end of file From 403af78ba962a41d682985cc3ff0f41059c53016 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 6 Jan 2016 11:22:15 +0100 Subject: [PATCH 082/605] U4-5168 Media Items label says "Document Type" instead of "Media Type" --- .../LocalizedTextServiceExtensions.cs | 31 ++++++- .../Editors/ContentTypeController.cs | 43 ++-------- src/Umbraco.Web/Editors/MemberController.cs | 5 +- .../Models/Mapping/ContentModelMapper.cs | 19 +++-- .../Models/Mapping/MediaModelMapper.cs | 22 +++-- .../Models/Mapping/MemberModelMapper.cs | 50 ++++++++--- .../Mapping/TabsAndPropertiesResolver.cs | 84 +++++-------------- 7 files changed, 129 insertions(+), 125 deletions(-) diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs index 292f8c585e..7885443ec8 100644 --- a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs +++ b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs @@ -2,10 +2,10 @@ using System.Globalization; using System.Linq; using System.Threading; +using Umbraco.Core.Dictionary; namespace Umbraco.Core.Services { - /// /// Extension methods for ILocalizedTextService /// @@ -61,5 +61,34 @@ namespace Umbraco.Core.Services return variables.Select((s, i) => new { index = i.ToString(CultureInfo.InvariantCulture), value = s }) .ToDictionary(keyvals => keyvals.index, keyvals => keyvals.value); } + + private static ICultureDictionary _cultureDictionary; + + internal static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text) + { + var cultureDictionary = CultureDictionary; + return UmbracoDictionaryTranslate(text, cultureDictionary); + } + + private static string UmbracoDictionaryTranslate(string text, ICultureDictionary cultureDictionary) + { + if (text == null) + return null; + + if (text.StartsWith("#") == false) + return text; + + text = text.Substring(1); + return cultureDictionary[text].IfNullOrWhiteSpace(text); + } + + private static ICultureDictionary CultureDictionary + { + get + { + return _cultureDictionary + ?? (_cultureDictionary = CultureDictionaryFactoryResolver.Current.Factory.CreateDictionary()); + } + } } } diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index 4c2ea733b6..89d6f49d6d 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -1,18 +1,14 @@ using System.Collections.Generic; +using System.Linq; using System.Net; using System.Web.Http; using AutoMapper; -using Umbraco.Core; -using Umbraco.Core.Dictionary; using Umbraco.Core.Models; +using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Models.Mapping; using Umbraco.Web.Mvc; -using Umbraco.Web.WebApi; -using System.Linq; -using Umbraco.Web.WebApi.Filters; using Constants = Umbraco.Core.Constants; -using Newtonsoft.Json; +using Umbraco.Core.Services; namespace Umbraco.Web.Editors { @@ -27,8 +23,6 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class ContentTypeController : ContentTypeControllerBase { - private ICultureDictionary _cultureDictionary; - /// /// Constructor /// @@ -91,38 +85,13 @@ namespace Umbraco.Web.Editors var basics = types.Select(Mapper.Map).ToList(); + var localizedTextService = Services.TextService; foreach (var basic in basics) { - basic.Name = TranslateItem(basic.Name); - basic.Description = TranslateItem(basic.Description); + basic.Name = localizedTextService.UmbracoDictionaryTranslate(basic.Name); + basic.Description = localizedTextService.UmbracoDictionaryTranslate(basic.Description); } - return basics; } - - // TODO: This should really be centralized and used anywhere globalization applies. - internal string TranslateItem(string text) - { - if (text == null) - { - return null; - } - - if (text.StartsWith("#") == false) - return text; - - text = text.Substring(1); - return CultureDictionary[text].IfNullOrWhiteSpace(text); - } - - private ICultureDictionary CultureDictionary - { - get - { - return - _cultureDictionary ?? - (_cultureDictionary = CultureDictionaryFactoryResolver.Current.Factory.CreateDictionary()); - } - } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs index 4405f257c4..0788ba43eb 100644 --- a/src/Umbraco.Web/Editors/MemberController.cs +++ b/src/Umbraco.Web/Editors/MemberController.cs @@ -135,7 +135,7 @@ namespace Umbraco.Web.Editors ParentId = -1 }; - TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService); + TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService, Services.TextService); return display; } @@ -343,12 +343,13 @@ namespace Umbraco.Web.Editors //lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403 HandleInvalidModelState(display); + var localizedTextService = Services.TextService; //put the correct msgs in switch (contentItem.Action) { case ContentSaveAction.Save: case ContentSaveAction.SaveNew: - display.AddSuccessNotification(ui.Text("speechBubbles", "editMemberSaved"), ui.Text("speechBubbles", "editMemberSaved")); + display.AddSuccessNotification(localizedTextService.Localize("speechBubbles/editMemberSaved"), localizedTextService.Localize("speechBubbles/editMemberSaved")); break; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index b9a0cabdae..b152c3bbee 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -6,6 +6,7 @@ using System.Web; using System.Web.Mvc; using System.Web.Routing; using AutoMapper; +using umbraco; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; @@ -14,6 +15,7 @@ using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Trees; using Umbraco.Web.Routing; using umbraco.BusinessLogic.Actions; +using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.Models.Mapping { @@ -65,7 +67,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Notifications, expression => expression.Ignore()) .ForMember(display => display.Errors, expression => expression.Ignore()) .ForMember(display => display.Alias, expression => expression.Ignore()) - .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) + .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService))) .ForMember(display => display.AllowedActions, expression => expression.ResolveUsing( new ActionButtonsResolver(new Lazy(() => applicationContext.Services.UserService)))) .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, @@ -159,11 +161,18 @@ namespace Umbraco.Web.Models.Mapping if (content.ContentType.IsContainer) { - TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService); + TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText); } - + var properties = new List { + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = localizedText.Localize("content/documentType"), + Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), + View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + }, new ContentPropertyDisplay { Alias = string.Format("{0}releasedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), @@ -181,7 +190,7 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}template", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = "Template", //TODO: localize this? + Label = localizedText.Localize("template/template"), Value = display.TemplateAlias, View = "dropdown", //TODO: Hard coding until we make a real dropdown property editor to lookup Config = new Dictionary @@ -198,7 +207,7 @@ namespace Umbraco.Web.Models.Mapping } }; - TabsAndPropertiesResolver.MapGenericProperties(content, display, properties.ToArray(), + TabsAndPropertiesResolver.MapGenericProperties(content, display, localizedText, properties.ToArray(), genericProperties => { //TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs index 3c27d0f183..9a71686c28 100644 --- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs @@ -7,6 +7,7 @@ using System.Web; using System.Web.Mvc; using System.Web.Routing; using AutoMapper; +using umbraco; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Mapping; @@ -50,8 +51,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Updater, expression => expression.Ignore()) .ForMember(display => display.Alias, expression => expression.Ignore()) .ForMember(display => display.IsContainer, expression => expression.Ignore()) - .ForMember(display => display.Tabs, expression => expression.ResolveUsing()) - .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService)); + .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService))) + .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService)); //FROM IMedia TO ContentItemBasic config.CreateMap>() @@ -82,7 +83,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.Alias, expression => expression.Ignore()); } - private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService) + private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText) { // Adapted from ContentModelMapper //map the IsChildOfListView (this is actually if it is a descendant of a list view!) @@ -121,10 +122,21 @@ namespace Umbraco.Web.Models.Mapping if (media.ContentType.IsContainer) { - TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService); + TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, localizedText); } + + var genericProperties = new List + { + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = localizedText.Localize("content/mediatype"), + Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), + View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + } + }; - TabsAndPropertiesResolver.MapGenericProperties(media, display); + TabsAndPropertiesResolver.MapGenericProperties(media, display, localizedText, genericProperties); } } diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs index 6b033f4a01..52fadd7a6a 100644 --- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs @@ -13,6 +13,7 @@ using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; using umbraco; using System.Linq; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.Security; using Umbraco.Web.Trees; @@ -75,7 +76,7 @@ namespace Umbraco.Web.Models.Mapping expression => expression.MapFrom(content => content.ContentType.Name)) .ForMember(display => display.Properties, expression => expression.Ignore()) .ForMember(display => display.Tabs, - expression => expression.ResolveUsing()) + expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService))) .ForMember(display => display.MemberProviderFieldMapping, expression => expression.ResolveUsing()) .ForMember(display => display.MembershipScenario, @@ -89,7 +90,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(display => display.Trashed, expression => expression.Ignore()) .ForMember(display => display.IsContainer, expression => expression.Ignore()) .ForMember(display => display.TreeNodeUrl, expression => expression.Ignore()) - .AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, member, display)); + .AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, member, display, applicationContext.Services.TextService)); //FROM IMember TO MemberBasic config.CreateMap() @@ -163,10 +164,11 @@ namespace Umbraco.Web.Models.Mapping /// /// /// + /// /// /// If this is a new entity and there is an approved field then we'll set it to true by default. /// - private static void MapGenericCustomProperties(IMemberService memberService, IMember member, MemberDisplay display) + private static void MapGenericCustomProperties(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText) { var membersProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); @@ -177,14 +179,21 @@ namespace Umbraco.Web.Models.Mapping var url = urlHelper.GetUmbracoApiService(controller => controller.GetTreeNode(display.Key.ToString("N"), null)); display.TreeNodeUrl = url; } - + var genericProperties = new List { - GetLoginProperty(memberService, member, display), + new ContentPropertyDisplay + { + Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), + Label = localizedText.Localize("content/membertype"), + Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName), + View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + }, + GetLoginProperty(memberService, member, display, localizedText), new ContentPropertyDisplay { Alias = string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("general", "email"), + Label = localizedText.Localize("general/email"), Value = display.Email, View = "email", Validation = {Mandatory = true} @@ -192,7 +201,7 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("password"), + Label = localizedText.Localize("password"), //NOTE: The value here is a json value - but the only property we care about is the generatedPassword one if it exists, the newPassword exists // only when creating a new member and we want to have a generated password pre-filled. Value = new Dictionary @@ -212,15 +221,16 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}membergroup", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "membergroup"), + Label = localizedText.Localize("content/membergroup"), Value = GetMemberGroupValue(display.Username), View = "membergroups", Config = new Dictionary {{"IsRequired", true}} } }; - TabsAndPropertiesResolver.MapGenericProperties(member, display, genericProperties); + TabsAndPropertiesResolver.MapGenericProperties(member, display, localizedText, genericProperties); + //check if there's an approval field var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider; if (member.HasIdentity == false && provider != null) @@ -247,12 +257,12 @@ namespace Umbraco.Web.Models.Mapping /// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively /// allow that. /// - internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display) + internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText) { var prop = new ContentPropertyDisplay { Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("login"), + Label = localizedText.Localize("login"), Value = display.Username }; @@ -321,6 +331,20 @@ namespace Umbraco.Web.Models.Mapping /// internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver { + private readonly ILocalizedTextService _localizedTextService; + + public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService) + : base(localizedTextService) + { + _localizedTextService = localizedTextService; + } + + public MemberTabsAndPropertiesResolver(ILocalizedTextService localizedTextService, + IEnumerable ignoreProperties) : base(localizedTextService, ignoreProperties) + { + _localizedTextService = localizedTextService; + } + protected override IEnumerable> ResolveCore(IContentBase content) { var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider(); @@ -339,7 +363,7 @@ namespace Umbraco.Web.Models.Mapping if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; - isLockedOutProperty.Value = ui.Text("general", "no"); + isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } return result; @@ -355,7 +379,7 @@ namespace Umbraco.Web.Models.Mapping if (isLockedOutProperty != null && isLockedOutProperty.Value.ToString() != "1") { isLockedOutProperty.View = "readonlyvalue"; - isLockedOutProperty.Value = ui.Text("general", "no"); + isLockedOutProperty.Value = _localizedTextService.Localize("general/no"); } return result; diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index ecf5e2da42..fc053e6cda 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -1,11 +1,8 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; -using System.Web; using AutoMapper; using Umbraco.Core; -using Umbraco.Core.Dictionary; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -18,16 +15,19 @@ namespace Umbraco.Web.Models.Mapping /// Creates the tabs collection with properties assigned for display models /// internal class TabsAndPropertiesResolver : ValueResolver>> - { - private ICultureDictionary _cultureDictionary; + { + private readonly ILocalizedTextService _localizedTextService; protected IEnumerable IgnoreProperties { get; set; } - public TabsAndPropertiesResolver() + public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService) { + if (localizedTextService == null) throw new ArgumentNullException("localizedTextService"); + _localizedTextService = localizedTextService; IgnoreProperties = new List(); } - public TabsAndPropertiesResolver(IEnumerable ignoreProperties) + public TabsAndPropertiesResolver(ILocalizedTextService localizedTextService, IEnumerable ignoreProperties) + : this(localizedTextService) { if (ignoreProperties == null) throw new ArgumentNullException("ignoreProperties"); IgnoreProperties = ignoreProperties; @@ -38,6 +38,7 @@ namespace Umbraco.Web.Models.Mapping ///
        /// /// + /// /// /// Any additional custom properties to assign to the generic properties tab. /// @@ -49,6 +50,7 @@ namespace Umbraco.Web.Models.Mapping public static void MapGenericProperties( TPersisted content, ContentItemDisplayBase display, + ILocalizedTextService localizedTextService, IEnumerable customProperties = null, Action> onGenericPropertiesMapped = null) where TPersisted : IContentBase @@ -72,33 +74,26 @@ namespace Umbraco.Web.Models.Mapping new ContentPropertyDisplay { Alias = string.Format("{0}creator", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "createBy"), - Description = ui.Text("content", "createByDesc"), //TODO: Localize this + Label = localizedTextService.Localize("content/createBy"), + Description = localizedTextService.Localize("content/createByDesc"), Value = display.Owner.Name, View = labelEditor }, new ContentPropertyDisplay { Alias = string.Format("{0}createdate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "createDate"), - Description = ui.Text("content", "createDateDesc"), + Label = localizedTextService.Localize("content/createDate"), + Description = localizedTextService.Localize("content/createDateDesc"), Value = display.CreateDate.ToIsoString(), View = labelEditor }, new ContentPropertyDisplay { Alias = string.Format("{0}updatedate", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "updateDate"), - Description = ui.Text("content", "updateDateDesc"), + Label = localizedTextService.Localize("content/updateDate"), + Description = localizedTextService.Localize("content/updateDateDesc"), Value = display.UpdateDate.ToIsoString(), View = labelEditor - }, - new ContentPropertyDisplay - { - Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix), - Label = ui.Text("content", "documentType"), - Value = TranslateItem(display.ContentTypeName, CreateDictionary()), - View = labelEditor } }; @@ -131,7 +126,7 @@ namespace Umbraco.Web.Models.Mapping /// /// This must be either 'content' or 'media' /// - internal static void AddListView(TabbedContentItem display, string entityType, IDataTypeService dataTypeService) + internal static void AddListView(TabbedContentItem display, string entityType, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService) where TPersisted : IContentBase { int dtdId; @@ -171,7 +166,7 @@ namespace Umbraco.Web.Models.Mapping var listViewTab = new Tab(); listViewTab.Alias = Constants.Conventions.PropertyGroups.ListViewGroupName; - listViewTab.Label = ui.Text("content", "childItems"); + listViewTab.Label = localizedTextService.Localize("content/childItems"); listViewTab.Id = 25; listViewTab.IsActive = true; @@ -227,11 +222,12 @@ namespace Umbraco.Web.Models.Mapping //then we'll just use the root group's data to make the composite tab var rootGroup = propertyGroups.First(x => x.ParentId == null); + aggregateTabs.Add(new Tab { Id = rootGroup.Id, Alias = rootGroup.Name, - Label = TranslateItem(rootGroup.Name), + Label = _localizedTextService.UmbracoDictionaryTranslate(rootGroup.Name), Properties = aggregateProperties, IsActive = false }); @@ -248,7 +244,7 @@ namespace Umbraco.Web.Models.Mapping aggregateTabs.Add(new Tab { Id = 0, - Label = ui.Text("general", "properties"), + Label = _localizedTextService.Localize("general/properties"), Alias = "Generic properties", Properties = genericproperties }); @@ -264,45 +260,9 @@ namespace Umbraco.Web.Models.Mapping // Not sure whether it's a good idea to add this to the ContentPropertyDisplay mapper foreach (var prop in properties) { - prop.Label = TranslateItem(prop.Label); - prop.Description = TranslateItem(prop.Description); + prop.Label = _localizedTextService.UmbracoDictionaryTranslate(prop.Label); + prop.Description = _localizedTextService.UmbracoDictionaryTranslate(prop.Description); } } - - // TODO: This should really be centralized and used anywhere globalization applies. - internal string TranslateItem(string text) - { - var cultureDictionary = CultureDictionary; - return TranslateItem(text, cultureDictionary); - } - - private static string TranslateItem(string text, ICultureDictionary cultureDictionary) - { - if (text == null) - { - return null; - } - - if (text.StartsWith("#") == false) - return text; - - text = text.Substring(1); - return cultureDictionary[text].IfNullOrWhiteSpace(text); - } - - private ICultureDictionary CultureDictionary - { - get - { - return - _cultureDictionary ?? - (_cultureDictionary = CreateDictionary()); - } - } - - private static ICultureDictionary CreateDictionary() - { - return CultureDictionaryFactoryResolver.Current.Factory.CreateDictionary(); - } } } From a2b0f6f7f9fd132b3ab8a7ba5bf6265b077b8821 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 11:59:09 +0100 Subject: [PATCH 083/605] removes erroneous reverse call --- src/umbraco.cms/helpers/DeepLink.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/umbraco.cms/helpers/DeepLink.cs b/src/umbraco.cms/helpers/DeepLink.cs index 595647c612..9c401ea87a 100644 --- a/src/umbraco.cms/helpers/DeepLink.cs +++ b/src/umbraco.cms/helpers/DeepLink.cs @@ -16,7 +16,7 @@ namespace umbraco.cms.helpers treePath.Add("-1"); treePath.Add("init"); string[] pathPaths = filePath.Split('/'); - pathPaths.Reverse(); + for (int p = 0; p < pathPaths.Length; p++) { treePath.Add(string.Join("/", pathPaths.Take(p + 1).ToArray())); From 58c30cd7a6a96519c8c2277a34cb63641cd714e9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 12:00:50 +0100 Subject: [PATCH 084/605] removes erroneous reverse call --- src/umbraco.cms/helpers/DeepLink.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/umbraco.cms/helpers/DeepLink.cs b/src/umbraco.cms/helpers/DeepLink.cs index 595647c612..9c401ea87a 100644 --- a/src/umbraco.cms/helpers/DeepLink.cs +++ b/src/umbraco.cms/helpers/DeepLink.cs @@ -16,7 +16,7 @@ namespace umbraco.cms.helpers treePath.Add("-1"); treePath.Add("init"); string[] pathPaths = filePath.Split('/'); - pathPaths.Reverse(); + for (int p = 0; p < pathPaths.Length; p++) { treePath.Add(string.Join("/", pathPaths.Take(p + 1).ToArray())); From b5fb82e9349b68b2f5223355710e4c48f4f38f46 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 12:01:01 +0100 Subject: [PATCH 085/605] Fixes: U4-7655 PropertyValueEditor tests failing Passing in CurrentUICulture to TryParse method, since it is also used for the normalization part. NumberStyles.Number is the default parameter used by the other TryParse overload so should be good to use here too. --- src/Umbraco.Core/ObjectExtensions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 90d173b49a..37f0fc0ac3 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; @@ -322,8 +323,9 @@ namespace Umbraco.Core else if (destinationType == typeof(Decimal)) { Decimal value; + var currentUiCulture = System.Threading.Thread.CurrentThread.CurrentUICulture; var input2 = NormalizeNumberDecimalSeparator(input); - return Decimal.TryParse(input2, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + return Decimal.TryParse(input2, NumberStyles.Number, currentUiCulture, out value) ? Attempt.Succeed(value) : Attempt.Fail(); } else if (destinationType == typeof(Version)) { From b4ca4917cc53dfebd52a205f6df8b06fa9cc3bb9 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 12:12:29 +0100 Subject: [PATCH 086/605] Updating Double and Single conversion (where NormalizeNumberDecimalSeparator is also used) to include CurrentUICulture. --- src/Umbraco.Core/ObjectExtensions.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 37f0fc0ac3..99918f7416 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -247,14 +247,16 @@ namespace Umbraco.Core else if (destinationType == typeof(Double)) { Double value; - var input2 = NormalizeNumberDecimalSeparator(input); - return Double.TryParse(input2, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + var currentUiCulture = System.Threading.Thread.CurrentThread.CurrentUICulture; + var input2 = NormalizeNumberDecimalSeparator(input); + return Double.TryParse(input2, NumberStyles.Float | NumberStyles.AllowThousands, currentUiCulture, out value) ? Attempt.Succeed(value) : Attempt.Fail(); } else if (destinationType == typeof(Single)) { Single value; + var currentUiCulture = System.Threading.Thread.CurrentThread.CurrentUICulture; var input2 = NormalizeNumberDecimalSeparator(input); - return Single.TryParse(input2, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + return Single.TryParse(input2, NumberStyles.Float | NumberStyles.AllowThousands, currentUiCulture, out value) ? Attempt.Succeed(value) : Attempt.Fail(); } else if (destinationType == typeof(Char)) { From b1b7598e3ca507ec0411ba73815575cc90cf9f2b Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 12:17:30 +0100 Subject: [PATCH 087/605] code cleanup. --- src/Umbraco.Core/ObjectExtensions.cs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 99918f7416..505af5f7f3 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -1,16 +1,11 @@ using System; using System.Collections; -using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; -using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Security; using System.Xml; namespace Umbraco.Core @@ -52,7 +47,7 @@ namespace Umbraco.Core public static Attempt TryConvertTo(this object input) { var result = TryConvertTo(input, typeof(T)); - if (!result.Success) + if (result.Success == false) { //just try a straight up conversion try @@ -65,7 +60,7 @@ namespace Umbraco.Core return Attempt.Fail(e); } } - return !result.Success ? Attempt.Fail() : Attempt.Succeed((T)result.Result); + return result.Success == false ? Attempt.Fail() : Attempt.Succeed((T)result.Result); } /// @@ -118,7 +113,7 @@ namespace Umbraco.Core } // we've already dealed with nullables, so any other generic types need to fall through - if (!destinationType.IsGenericType) + if (destinationType.IsGenericType == false) { if (input is string) { @@ -339,7 +334,7 @@ namespace Umbraco.Core return null; // we can't decide... } - private readonly static char[] NumberDecimalSeparatorsToNormalize = new[] {'.', ','}; + private static readonly char[] NumberDecimalSeparatorsToNormalize = new[] {'.', ','}; private static string NormalizeNumberDecimalSeparator(string s) { @@ -446,7 +441,7 @@ namespace Umbraco.Core { var props = TypeDescriptor.GetProperties(o); var d = new Dictionary(); - foreach (var prop in props.Cast().Where(x => !ignoreProperties.Contains(x.Name))) + foreach (var prop in props.Cast().Where(x => ignoreProperties.Contains(x.Name) == false)) { var val = prop.GetValue(o); if (val != null) @@ -482,13 +477,13 @@ namespace Umbraco.Core var items = (from object enumItem in enumerable let value = GetEnumPropertyDebugString(enumItem, levels) where value != null select value).Take(10).ToList(); - return items.Count() > 0 + return items.Any() ? "{{ {0} }}".InvariantFormat(String.Join(", ", items)) : null; } var props = obj.GetType().GetProperties(); - if ((props.Count() == 2) && props[0].Name == "Key" && props[1].Name == "Value" && levels > -2) + if ((props.Length == 2) && props[0].Name == "Key" && props[1].Name == "Value" && levels > -2) { try { @@ -504,12 +499,12 @@ namespace Umbraco.Core if (levels > -1) { var items = - from propertyInfo in props + (from propertyInfo in props let value = GetPropertyDebugString(propertyInfo, obj, levels) where value != null - select "{0}={1}".InvariantFormat(propertyInfo.Name, value); + select "{0}={1}".InvariantFormat(propertyInfo.Name, value)).ToArray(); - return items.Count() > 0 + return items.Any() ? "[{0}]:{{ {1} }}".InvariantFormat(obj.GetType().Name, String.Join(", ", items)) : null; } From 43e983e27aa0e87d085ed568174dbf6cf5b9a0dd Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 6 Jan 2016 12:17:48 +0100 Subject: [PATCH 088/605] Corrects spelling of localStorateDir to localStorageDir --- .../LocalStorage/LocalTempStorageIndexer.cs | 8 ++++---- src/UmbracoExamine/UmbracoExamineSearcher.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs b/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs index 2075a0f786..f4642eb0cd 100644 --- a/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs +++ b/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs @@ -44,7 +44,7 @@ namespace UmbracoExamine.LocalStorage public void Initialize(NameValueCollection config, string configuredPath, FSDirectory baseLuceneDirectory, Analyzer analyzer, LocalStorageType localStorageType) { //this is the default - ILocalStorageDirectory localStorateDir = new CodeGenLocalStorageDirectory(); + ILocalStorageDirectory localStorageDir = new CodeGenLocalStorageDirectory(); if (config["tempStorageDirectory"] != null) { //try to get the type @@ -53,7 +53,7 @@ namespace UmbracoExamine.LocalStorage { try { - localStorateDir = (ILocalStorageDirectory)Activator.CreateInstance(dirType); + localStorageDir = (ILocalStorageDirectory)Activator.CreateInstance(dirType); } catch (Exception ex) { @@ -64,8 +64,8 @@ namespace UmbracoExamine.LocalStorage } } - var tempPath = localStorateDir.GetLocalStorageDirectory(config, configuredPath); - if (tempPath == null) throw new InvalidOperationException("Could not resolve a temp location from the " + localStorateDir.GetType() + " specified"); + var tempPath = localStorageDir.GetLocalStorageDirectory(config, configuredPath); + if (tempPath == null) throw new InvalidOperationException("Could not resolve a temp location from the " + localStorageDir.GetType() + " specified"); TempPath = tempPath.FullName; switch (localStorageType) diff --git a/src/UmbracoExamine/UmbracoExamineSearcher.cs b/src/UmbracoExamine/UmbracoExamineSearcher.cs index 60eeb6a02f..acbfefb180 100644 --- a/src/UmbracoExamine/UmbracoExamineSearcher.cs +++ b/src/UmbracoExamine/UmbracoExamineSearcher.cs @@ -81,7 +81,7 @@ namespace UmbracoExamine if (attemptUseTempStorage) { //this is the default - ILocalStorageDirectory localStorateDir = new CodeGenLocalStorageDirectory(); + ILocalStorageDirectory localStorageDir = new CodeGenLocalStorageDirectory(); if (config["tempStorageDirectory"] != null) { //try to get the type @@ -90,7 +90,7 @@ namespace UmbracoExamine { try { - localStorateDir = (ILocalStorageDirectory)Activator.CreateInstance(dirType); + localStorageDir = (ILocalStorageDirectory)Activator.CreateInstance(dirType); } catch (Exception ex) { @@ -102,8 +102,8 @@ namespace UmbracoExamine } var indexSet = IndexSets.Instance.Sets[IndexSetName]; var configuredPath = indexSet.IndexPath; - var tempPath = localStorateDir.GetLocalStorageDirectory(config, configuredPath); - if (tempPath == null) throw new InvalidOperationException("Could not resolve a temp location from the " + localStorateDir.GetType() + " specified"); + var tempPath = localStorageDir.GetLocalStorageDirectory(config, configuredPath); + if (tempPath == null) throw new InvalidOperationException("Could not resolve a temp location from the " + localStorageDir.GetType() + " specified"); _localTempPath = tempPath.FullName; _localStorageType = attemptUseTempStorage.Result; } From e8a0fae55769f5ce4b8be0c8412785ea81f1c797 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 12:24:09 +0100 Subject: [PATCH 089/605] adds notes --- .../Services/LocalizedTextServiceExtensions.cs | 9 +++++++++ src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs index 7885443ec8..6d8215492b 100644 --- a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs +++ b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs @@ -64,6 +64,15 @@ namespace Umbraco.Core.Services private static ICultureDictionary _cultureDictionary; + /// + /// TODO: We need to refactor how we work with ICultureDictionary - this is supposed to be the 'fast' way to + /// do readonly access to the Dictionary without using the ILocalizationService. See TODO Notes in `DefaultCultureDictionary` + /// Also NOTE that the ICultureDictionary is based on the ILocalizationService not the ILocalizedTextService (which is used + /// only for the localization files - not the dictionary) + /// + /// + /// + /// internal static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text) { var cultureDictionary = CultureDictionary; diff --git a/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs b/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs index 29954701ea..4087d26bea 100644 --- a/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs +++ b/src/Umbraco.Web/Dictionary/UmbracoCultureDictionary.cs @@ -18,6 +18,11 @@ namespace Umbraco.Web.Dictionary /// /// A culture dictionary that uses the Umbraco ILocalizationService /// + /// + /// TODO: The ICultureDictionary needs to represent the 'fast' way to do dictionary item retrieval - for front-end and back office. + /// The ILocalizationService is the service used for interacting with this data from the database which isn't all that fast + /// (even though there is caching involved, if there's lots of dictionary items the caching is not great) + /// public class DefaultCultureDictionary : Umbraco.Core.Dictionary.ICultureDictionary { private readonly ILocalizationService _localizationService; From da91923577b28b56f15f953d26422d1e07dcfe95 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 12:48:26 +0100 Subject: [PATCH 090/605] Changes ObjectExtensions NormalizeNumberDecimalSeparator to use normal Culture (not UI Culture) --- src/Umbraco.Core/ObjectExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 90d173b49a..7758036f8b 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -339,7 +339,7 @@ namespace Umbraco.Core private static string NormalizeNumberDecimalSeparator(string s) { - var normalized = System.Threading.Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator[0]; + var normalized = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator[0]; return s.ReplaceMany(NumberDecimalSeparatorsToNormalize, normalized); } From bc98f5e8fc0fe8831db0da832ef7d9388d429513 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 12:49:18 +0100 Subject: [PATCH 091/605] code cleanup. Conflicts: src/Umbraco.Core/ObjectExtensions.cs --- src/Umbraco.Core/ObjectExtensions.cs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 7758036f8b..a8a1e80eb7 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -1,15 +1,10 @@ using System; using System.Collections; -using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; -using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Security; using System.Xml; namespace Umbraco.Core @@ -51,7 +46,7 @@ namespace Umbraco.Core public static Attempt TryConvertTo(this object input) { var result = TryConvertTo(input, typeof(T)); - if (!result.Success) + if (result.Success == false) { //just try a straight up conversion try @@ -64,7 +59,7 @@ namespace Umbraco.Core return Attempt.Fail(e); } } - return !result.Success ? Attempt.Fail() : Attempt.Succeed((T)result.Result); + return result.Success == false ? Attempt.Fail() : Attempt.Succeed((T)result.Result); } /// @@ -117,7 +112,7 @@ namespace Umbraco.Core } // we've already dealed with nullables, so any other generic types need to fall through - if (!destinationType.IsGenericType) + if (destinationType.IsGenericType == false) { if (input is string) { @@ -335,7 +330,7 @@ namespace Umbraco.Core return null; // we can't decide... } - private readonly static char[] NumberDecimalSeparatorsToNormalize = new[] {'.', ','}; + private static readonly char[] NumberDecimalSeparatorsToNormalize = new[] {'.', ','}; private static string NormalizeNumberDecimalSeparator(string s) { @@ -442,7 +437,7 @@ namespace Umbraco.Core { var props = TypeDescriptor.GetProperties(o); var d = new Dictionary(); - foreach (var prop in props.Cast().Where(x => !ignoreProperties.Contains(x.Name))) + foreach (var prop in props.Cast().Where(x => ignoreProperties.Contains(x.Name) == false)) { var val = prop.GetValue(o); if (val != null) @@ -478,13 +473,13 @@ namespace Umbraco.Core var items = (from object enumItem in enumerable let value = GetEnumPropertyDebugString(enumItem, levels) where value != null select value).Take(10).ToList(); - return items.Count() > 0 + return items.Any() ? "{{ {0} }}".InvariantFormat(String.Join(", ", items)) : null; } var props = obj.GetType().GetProperties(); - if ((props.Count() == 2) && props[0].Name == "Key" && props[1].Name == "Value" && levels > -2) + if ((props.Length == 2) && props[0].Name == "Key" && props[1].Name == "Value" && levels > -2) { try { @@ -500,12 +495,12 @@ namespace Umbraco.Core if (levels > -1) { var items = - from propertyInfo in props + (from propertyInfo in props let value = GetPropertyDebugString(propertyInfo, obj, levels) where value != null - select "{0}={1}".InvariantFormat(propertyInfo.Name, value); + select "{0}={1}".InvariantFormat(propertyInfo.Name, value)).ToArray(); - return items.Count() > 0 + return items.Any() ? "[{0}]:{{ {1} }}".InvariantFormat(obj.GetType().Name, String.Join(", ", items)) : null; } From 4c3258812cea1b910c885193d8a673a53268ea22 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 12:50:41 +0100 Subject: [PATCH 092/605] normalize culture for test --- .../PropertyEditors/PropertyEditorValueEditorTests.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs index 9ab275e5fb..25de1d7f55 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using Moq; using NUnit.Framework; using Umbraco.Core; @@ -11,6 +12,13 @@ namespace Umbraco.Tests.PropertyEditors [TestFixture] public class PropertyEditorValueEditorTests { + [SetUp] + public void Setup() + { + //normalize culture + Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture; + } + [TestCase("{prop1: 'val1', prop2: 'val2'}", true)] [TestCase("{1,2,3,4}", false)] [TestCase("[1,2,3,4]", true)] From 5767cea8f23e3fed0a55dd0d462808cc3b0cc247 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 12:58:05 +0100 Subject: [PATCH 093/605] fixes build/merge --- src/Umbraco.Web/Editors/ContentTypeController.cs | 6 +++--- src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs index aab169a8a2..4622fee1b5 100644 --- a/src/Umbraco.Web/Editors/ContentTypeController.cs +++ b/src/Umbraco.Web/Editors/ContentTypeController.cs @@ -4,15 +4,15 @@ using System.Net; using System.Web.Http; using AutoMapper; using Umbraco.Core.Models; -using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Constants = Umbraco.Core.Constants; using Umbraco.Core.Services; using Umbraco.Core.PropertyEditors; -using System; using System.Net.Http; -using Umbraco.Core.Services; +using Umbraco.Core; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors { diff --git a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs index 7ec7351038..0e4549811c 100644 --- a/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/TabsAndPropertiesResolver.cs @@ -231,7 +231,7 @@ namespace Umbraco.Web.Models.Mapping { Id = groupId, Alias = groupName, - Label = TranslateItem(groupName), + Label = _localizedTextService.UmbracoDictionaryTranslate(groupName), Properties = properties, IsActive = false }); From b04d0fc886634cdcb5be83fd0ca384f73190e50b Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 13:48:03 +0100 Subject: [PATCH 094/605] Adds Isolated cache to the CacheHelper, adds cache option: GetAllCacheAsCollection, changes the default repository cache to be an isolated cache (instead of part of the single main dictionary cache), adds the logic for the cache option GetAllCacheAsCollection to RepositoryBase, updates Language and Domain repositories to use GetAllCacheAsCollection, updates RepositoryFactory to be the one responsible for injecting a DeepCloneRuntimeCacheProvider and to use a single _noCache instance. --- src/Umbraco.Core/CacheHelper.cs | 103 ++++++++++-------- .../Repositories/DomainRepository.cs | 3 +- .../Repositories/LanguageRepository.cs | 3 +- .../Repositories/RepositoryBase.cs | 69 +++++++----- .../Repositories/RepositoryCacheOptions.cs | 11 ++ .../Persistence/RepositoryFactory.cs | 27 +++-- 6 files changed, 136 insertions(+), 80 deletions(-) diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs index 51cf37aa23..44a0a35f2b 100644 --- a/src/Umbraco.Core/CacheHelper.cs +++ b/src/Umbraco.Core/CacheHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,7 +12,6 @@ using Umbraco.Core.Logging; namespace Umbraco.Core { - /// /// Class that is exposed by the ApplicationContext for application wide caching purposes /// @@ -22,9 +22,10 @@ namespace Umbraco.Core private readonly ICacheProvider _nullRequestCache = new NullCacheProvider(); private readonly ICacheProvider _staticCache; private readonly ICacheProvider _nullStaticCache = new NullCacheProvider(); - private readonly IRuntimeCacheProvider _httpCache; - private readonly IRuntimeCacheProvider _nullHttpCache = new NullCacheProvider(); - + private readonly IRuntimeCacheProvider _runtimeCache; + private readonly IRuntimeCacheProvider _nullRuntimeCache = new NullCacheProvider(); + private readonly ConcurrentDictionary _isolatedCache = new ConcurrentDictionary(); + /// /// Creates a cache helper with disabled caches /// @@ -89,13 +90,13 @@ namespace Umbraco.Core { if (enableCache) { - _httpCache = httpCacheProvider; + _runtimeCache = httpCacheProvider; _staticCache = staticCacheProvider; _requestCache = requestCacheProvider; } else { - _httpCache = null; + _runtimeCache = null; _staticCache = null; _requestCache = null; } @@ -104,6 +105,22 @@ namespace Umbraco.Core } /// + /// Returns an isolated runtime cache for a given type + /// + /// + /// + /// + /// This is useful for repository level caches to ensure that cache lookups by key are fast so + /// that the repository doesn't need to search through all keys on a global scale. + /// + public IRuntimeCacheProvider GetIsolatedRuntimeCache() + { + return _enableCache == false + ? _nullRuntimeCache + : _isolatedCache.GetOrAdd(typeof (T), type => new ObjectCacheRuntimeCacheProvider()); + } + + /// /// Returns the current Request cache /// public ICacheProvider RequestCache @@ -124,7 +141,7 @@ namespace Umbraco.Core /// public IRuntimeCacheProvider RuntimeCache { - get { return _enableCache ? _httpCache : _nullHttpCache; } + get { return _enableCache ? _runtimeCache : _nullRuntimeCache; } } #region Legacy Runtime/Http Cache accessors @@ -137,11 +154,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearAllCache(); + _nullRuntimeCache.ClearAllCache(); } else { - _httpCache.ClearAllCache(); + _runtimeCache.ClearAllCache(); } } @@ -154,11 +171,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheItem(key); + _nullRuntimeCache.ClearCacheItem(key); } else { - _httpCache.ClearCacheItem(key); + _runtimeCache.ClearCacheItem(key); } } @@ -173,11 +190,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheObjectTypes(typeName); + _nullRuntimeCache.ClearCacheObjectTypes(typeName); } else { - _httpCache.ClearCacheObjectTypes(typeName); + _runtimeCache.ClearCacheObjectTypes(typeName); } } @@ -189,11 +206,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheObjectTypes(); + _nullRuntimeCache.ClearCacheObjectTypes(); } else { - _httpCache.ClearCacheObjectTypes(); + _runtimeCache.ClearCacheObjectTypes(); } } @@ -206,11 +223,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheByKeySearch(keyStartsWith); + _nullRuntimeCache.ClearCacheByKeySearch(keyStartsWith); } else { - _httpCache.ClearCacheByKeySearch(keyStartsWith); + _runtimeCache.ClearCacheByKeySearch(keyStartsWith); } } @@ -223,11 +240,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.ClearCacheByKeyExpression(regexString); + _nullRuntimeCache.ClearCacheByKeyExpression(regexString); } else { - _httpCache.ClearCacheByKeyExpression(regexString); + _runtimeCache.ClearCacheByKeyExpression(regexString); } } @@ -236,11 +253,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItemsByKeySearch(keyStartsWith); + return _nullRuntimeCache.GetCacheItemsByKeySearch(keyStartsWith); } else { - return _httpCache.GetCacheItemsByKeySearch(keyStartsWith); + return _runtimeCache.GetCacheItemsByKeySearch(keyStartsWith); } } @@ -255,11 +272,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey); + return _nullRuntimeCache.GetCacheItem(cacheKey); } else { - return _httpCache.GetCacheItem(cacheKey); + return _runtimeCache.GetCacheItem(cacheKey); } } @@ -275,11 +292,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem); } } @@ -297,11 +314,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem, timeout); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); } } @@ -321,11 +338,11 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); } } @@ -346,11 +363,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); } else { - return _httpCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); } } @@ -375,11 +392,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); @@ -406,11 +423,11 @@ namespace Umbraco.Core { if (!_enableCache) { - return _nullHttpCache.GetCacheItem(cacheKey, getCacheItem, null, false, priority, null, null); + return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, null, false, priority, null, null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency); @@ -433,11 +450,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); } else { - _httpCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); } } @@ -456,11 +473,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); } else { - _httpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); } } @@ -482,11 +499,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority, dependentFiles:null); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority, dependentFiles:null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency); @@ -515,11 +532,11 @@ namespace Umbraco.Core { if (_enableCache == false) { - _nullHttpCache.InsertCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); + _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); } else { - var cache = _httpCache as HttpRuntimeCacheProvider; + var cache = _runtimeCache as HttpRuntimeCacheProvider; if (cache != null) { cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); diff --git a/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs index 21ba8b4baf..75a592c7fe 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DomainRepository.cs @@ -27,7 +27,8 @@ namespace Umbraco.Core.Persistence.Repositories _cacheOptions = new RepositoryCacheOptions { GetAllCacheAllowZeroCount = true, - GetAllCacheValidateCount = false + GetAllCacheValidateCount = false, + GetAllCacheAsCollection = true }; } diff --git a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs index 2f379b4587..d1a28b7b4d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/LanguageRepository.cs @@ -25,7 +25,8 @@ namespace Umbraco.Core.Persistence.Repositories _cacheOptions = new RepositoryCacheOptions { GetAllCacheAllowZeroCount = true, - GetAllCacheValidateCount = false + GetAllCacheValidateCount = false, + GetAllCacheAsCollection = true }; } diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 124aaeb035..d5febf6e0f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using Umbraco.Core.Cache; @@ -22,11 +23,7 @@ namespace Umbraco.Core.Persistence.Repositories if (logger == null) throw new ArgumentNullException("logger"); Logger = logger; _work = work; - - //IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying - // runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks - // changes entities are reset. - _cache = new CacheHelper(new DeepCloneRuntimeCacheProvider(cache.RuntimeCache), cache.StaticCache, cache.RequestCache); + _cache = cache; } /// @@ -86,7 +83,13 @@ namespace Umbraco.Core.Persistence.Repositories private readonly RepositoryCacheOptions _cacheOptions = new RepositoryCacheOptions(); - #region IRepository Members + /// + /// The runtime cache used for this repo by default is the isolated cache for this type + /// + protected override IRuntimeCacheProvider RuntimeCache + { + get { return RepositoryCache.GetIsolatedRuntimeCache(); } + } /// /// Adds or Updates an entity of type TEntity @@ -167,9 +170,18 @@ namespace Umbraco.Core.Persistence.Repositories } else { - var allEntities = RuntimeCache.GetCacheItemsByKeySearch(GetCacheTypeKey()) - .WhereNotNull() - .ToArray(); + TEntity[] allEntities; + if (RepositoryCacheOptions.GetAllCacheAsCollection) + { + var found = RuntimeCache.GetCacheItem>(GetCacheTypeKey()); + allEntities = found == null ? new TEntity[] {} : found.WhereNotNull().ToArray(); + } + else + { + allEntities = RuntimeCache.GetCacheItemsByKeySearch(GetCacheTypeKey()) + .WhereNotNull() + .ToArray(); + } if (allEntities.Any()) { @@ -205,21 +217,32 @@ namespace Umbraco.Core.Persistence.Repositories //ensure we don't include any null refs in the returned collection! .WhereNotNull() .ToArray(); - - //We need to put a threshold here! IF there's an insane amount of items - // coming back here we don't want to chuck it all into memory, this added cache here - // is more for convenience when paging stuff temporarily - - if (entityCollection.Length > RepositoryCacheOptions.GetAllCacheThresholdLimit) - return entityCollection; - + if (entityCollection.Length == 0 && RepositoryCacheOptions.GetAllCacheAllowZeroCount) { //there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache // to signify that there is a zero count cache RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {}); + return entityCollection; } + if (RepositoryCacheOptions.GetAllCacheAsCollection) + { + //when this is true, we don't want to cache each item individually, we want to cache the result as a single collection + RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => entityCollection.ToList()); + return entityCollection; + } + + if (entityCollection.Length > RepositoryCacheOptions.GetAllCacheThresholdLimit) + { + //We need to put a threshold here! IF there's an insane amount of items + // coming back here we don't want to chuck it all into memory, this added cache here + // is more for convenience when paging stuff temporarily + return entityCollection; + } + + //This is the default behavior, we'll individually cache each item so that if/when these items are resolved + // by id, they are returned from the already existing cache. foreach (var entity in entityCollection) { if (entity != null) @@ -279,11 +302,7 @@ namespace Umbraco.Core.Persistence.Repositories { return PerformCount(query); } - - #endregion - - #region IUnitOfWorkRepository Members - + /// /// Unit of work method that tells the repository to persist the new entity /// @@ -345,16 +364,12 @@ namespace Umbraco.Core.Persistence.Repositories //If there's a GetAll zero count cache, ensure it is cleared RuntimeCache.ClearCacheItem(GetCacheTypeKey()); } - - #endregion - - #region Abstract IUnitOfWorkRepository Methods + protected abstract void PersistNewItem(TEntity item); protected abstract void PersistUpdatedItem(TEntity item); protected abstract void PersistDeletedItem(TEntity item); - #endregion /// /// Dispose disposable properties diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs index 9ac8aa6abd..b5abedac86 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryCacheOptions.cs @@ -10,6 +10,7 @@ namespace Umbraco.Core.Persistence.Repositories GetAllCacheValidateCount = true; GetAllCacheAllowZeroCount = false; GetAllCacheThresholdLimit = 100; + GetAllCacheAsCollection = false; } /// @@ -32,5 +33,15 @@ namespace Umbraco.Core.Persistence.Repositories /// The threshold entity count for which the GetAll method will cache entities /// public int GetAllCacheThresholdLimit { get; set; } + + /// + /// When set to true, the cache for the result of GetAll will be cached as a List/Collection rather than + /// individual entities in the dictionary + /// + /// + /// The default is false which means that if the result of GetAll is less than the GetAllCacheThresholdLimit, each entity + /// returned will be cached individually + /// + public bool GetAllCacheAsCollection { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index a22b2511ea..f3d1702946 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -18,6 +18,7 @@ namespace Umbraco.Core.Persistence private readonly ILogger _logger; private readonly ISqlSyntaxProvider _sqlSyntax; private readonly CacheHelper _cacheHelper; + private readonly CacheHelper _noCache; private readonly IUmbracoSettingsSection _settings; #region Ctors @@ -30,6 +31,15 @@ namespace Umbraco.Core.Persistence if (settings == null) throw new ArgumentNullException("settings"); _cacheHelper = cacheHelper; + //IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying + // runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks + // changes entities are reset. + if ((_cacheHelper.RuntimeCache is DeepCloneRuntimeCacheProvider) == false) + { + _cacheHelper = new CacheHelper(new DeepCloneRuntimeCacheProvider(_cacheHelper.RuntimeCache), _cacheHelper.StaticCache, _cacheHelper.RequestCache); + } + + _noCache = CacheHelper.CreateDisabledCacheHelper(); _logger = logger; _sqlSyntax = sqlSyntax; _settings = settings; @@ -53,6 +63,7 @@ namespace Umbraco.Core.Persistence { if (cacheHelper == null) throw new ArgumentNullException("cacheHelper"); _cacheHelper = cacheHelper; + _noCache = CacheHelper.CreateDisabledCacheHelper(); } [Obsolete("Use the ctor specifying all dependencies instead")] @@ -80,15 +91,15 @@ namespace Umbraco.Core.Persistence public virtual ITaskRepository CreateTaskRepository(IDatabaseUnitOfWork uow) { - return new TaskRepository(uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + return new TaskRepository(uow, + _noCache, //never cache _logger, _sqlSyntax); } public virtual IAuditRepository CreateAuditRepository(IDatabaseUnitOfWork uow) { return new AuditRepository(uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax); } @@ -175,7 +186,7 @@ namespace Umbraco.Core.Persistence { return new RelationRepository( uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax, CreateRelationTypeRepository(uow)); } @@ -184,7 +195,7 @@ namespace Umbraco.Core.Persistence { return new RelationTypeRepository( uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax); } @@ -222,7 +233,7 @@ namespace Umbraco.Core.Persistence { return new MigrationEntryRepository( uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + _noCache, //never cache _logger, _sqlSyntax); } @@ -299,8 +310,8 @@ namespace Umbraco.Core.Persistence public ITaskTypeRepository CreateTaskTypeRepository(IDatabaseUnitOfWork uow) { - return new TaskTypeRepository(uow, - CacheHelper.CreateDisabledCacheHelper(), //never cache + return new TaskTypeRepository(uow, + _noCache, //never cache _logger, _sqlSyntax); } } From 4f40fff5ee009a3830bb8770aa5ab66fe04be6ca Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 14:17:51 +0100 Subject: [PATCH 095/605] Moves DeepCloneRuntimeCacheProvider to Cache namespace. Creates DeepCloneableList + tests. Updates RepositoryBase to use DeepCloneableList when GetAllCacheAsCollection is used (so that all entries that get cached are deep cloned into and out-of the cache). Adds test for DeepCloneRuntimeCacheProvider for dealing with this list type. --- .../DeepCloneRuntimeCacheProvider.cs | 3 +- .../Collections/DeepCloneableList.cs | 108 ++++++++++++++ .../Repositories/RepositoryBase.cs | 5 +- .../Persistence/RepositoryFactory.cs | 1 + src/Umbraco.Core/Umbraco.Core.csproj | 3 +- .../DeepCloneRuntimeCacheProviderTests.cs | 19 +++ .../Collections/DeepCloneableListTests.cs | 139 ++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 8 files changed, 274 insertions(+), 5 deletions(-) rename src/Umbraco.Core/{Persistence/Repositories => Cache}/DeepCloneRuntimeCacheProvider.cs (98%) create mode 100644 src/Umbraco.Core/Collections/DeepCloneableList.cs create mode 100644 src/Umbraco.Tests/Collections/DeepCloneableListTests.cs diff --git a/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs similarity index 98% rename from src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs rename to src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs index 0b5b42660d..861c6b803e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DeepCloneRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs @@ -2,11 +2,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Web.Caching; -using Umbraco.Core.Cache; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; -namespace Umbraco.Core.Persistence.Repositories +namespace Umbraco.Core.Cache { /// /// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns diff --git a/src/Umbraco.Core/Collections/DeepCloneableList.cs b/src/Umbraco.Core/Collections/DeepCloneableList.cs new file mode 100644 index 0000000000..365bf53b06 --- /dev/null +++ b/src/Umbraco.Core/Collections/DeepCloneableList.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; + +namespace Umbraco.Core.Collections +{ + /// + /// A List that can be deep cloned with deep cloned elements and can reset the collection's items dirty flags + /// + /// + internal class DeepCloneableList : List, IDeepCloneable, IRememberBeingDirty + { + /// + /// Initializes a new instance of the class that is empty and has the default initial capacity. + /// + public DeepCloneableList() + { + } + + /// + /// Initializes a new instance of the class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied. + /// + /// The collection whose elements are copied to the new list. is null. + public DeepCloneableList(IEnumerable collection) : base(collection) + { + } + + /// + /// Creates a new list and adds each element as a deep cloned element if it is of type IDeepCloneable + /// + /// + public object DeepClone() + { + var newList = new DeepCloneableList(); + foreach (var item in this) + { + var dc = item as IDeepCloneable; + if (dc != null) + { + newList.Add((T) dc.DeepClone()); + } + else + { + newList.Add(item); + } + } + return newList; + } + + public bool IsDirty() + { + return this.OfType().Any(x => x.IsDirty()); + } + + public bool WasDirty() + { + return this.OfType().Any(x => x.WasDirty()); + } + + /// + /// Always returns false, the list has no properties we need to report + /// + /// + /// + public bool IsPropertyDirty(string propName) + { + return false; + } + + /// + /// Always returns false, the list has no properties we need to report + /// + /// + /// + public bool WasPropertyDirty(string propertyName) + { + return false; + } + + public void ResetDirtyProperties() + { + foreach (var dc in this.OfType()) + { + dc.ResetDirtyProperties(); + } + } + + public void ForgetPreviouslyDirtyProperties() + { + foreach (var dc in this.OfType()) + { + dc.ForgetPreviouslyDirtyProperties(); + } + } + + public void ResetDirtyProperties(bool rememberPreviouslyChangedProperties) + { + foreach (var dc in this.OfType()) + { + dc.ResetDirtyProperties(rememberPreviouslyChangedProperties); + } + } + } +} diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index d5febf6e0f..2ce3537bb9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using Umbraco.Core.Cache; +using Umbraco.Core.Collections; using Umbraco.Core.Logging; using Umbraco.Core.Models.EntityBase; @@ -173,7 +174,7 @@ namespace Umbraco.Core.Persistence.Repositories TEntity[] allEntities; if (RepositoryCacheOptions.GetAllCacheAsCollection) { - var found = RuntimeCache.GetCacheItem>(GetCacheTypeKey()); + var found = RuntimeCache.GetCacheItem>(GetCacheTypeKey()); allEntities = found == null ? new TEntity[] {} : found.WhereNotNull().ToArray(); } else @@ -229,7 +230,7 @@ namespace Umbraco.Core.Persistence.Repositories if (RepositoryCacheOptions.GetAllCacheAsCollection) { //when this is true, we don't want to cache each item individually, we want to cache the result as a single collection - RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => entityCollection.ToList()); + RuntimeCache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList(entityCollection)); return entityCollection; } diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index f3d1702946..d99ae8f464 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -1,5 +1,6 @@ using Umbraco.Core.Configuration; using System; +using Umbraco.Core.Cache; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.IO; using Umbraco.Core.Logging; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index bf28645754..d294bdaddf 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -176,6 +176,7 @@ + @@ -441,7 +442,7 @@ - + diff --git a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs index 44deb1da40..63225f6725 100644 --- a/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs +++ b/src/Umbraco.Tests/Cache/DeepCloneRuntimeCacheProviderTests.cs @@ -4,9 +4,11 @@ using System.Web; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Collections; using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Persistence.Repositories; +using Umbraco.Tests.Collections; namespace Umbraco.Tests.Cache { @@ -36,6 +38,23 @@ namespace Umbraco.Tests.Cache get { return _provider; } } + [Test] + public void Clones_List() + { + var original = new DeepCloneableList(); + original.Add(new DeepCloneableListTests.TestClone()); + original.Add(new DeepCloneableListTests.TestClone()); + original.Add(new DeepCloneableListTests.TestClone()); + + var val = _provider.GetCacheItem>("test", () => original); + + Assert.AreEqual(original.Count, val.Count); + foreach (var item in val) + { + Assert.IsTrue(item.IsClone); + } + } + [Test] public void Ensures_Cloned_And_Reset() { diff --git a/src/Umbraco.Tests/Collections/DeepCloneableListTests.cs b/src/Umbraco.Tests/Collections/DeepCloneableListTests.cs new file mode 100644 index 0000000000..fcc50df60c --- /dev/null +++ b/src/Umbraco.Tests/Collections/DeepCloneableListTests.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using Umbraco.Core.Collections; +using Umbraco.Core.Models; + +namespace Umbraco.Tests.Collections +{ + [TestFixture] + public class DeepCloneableListTests + { + [Test] + public void Deep_Clones_All_Elements() + { + var list = new DeepCloneableList(); + list.Add(new TestClone()); + list.Add(new TestClone()); + list.Add(new TestClone()); + + var cloned = list.DeepClone() as DeepCloneableList; + + Assert.IsNotNull(cloned); + Assert.AreNotSame(list, cloned); + Assert.AreEqual(list.Count, cloned.Count); + } + + [Test] + public void Clones_Each_Item() + { + var list = new DeepCloneableList(); + list.Add(new TestClone()); + list.Add(new TestClone()); + list.Add(new TestClone()); + + var cloned = (DeepCloneableList) list.DeepClone(); + + foreach (var item in cloned) + { + Assert.IsTrue(item.IsClone); + } + } + + [Test] + public void Cloned_Sequence_Equals() + { + var list = new DeepCloneableList(); + list.Add(new TestClone()); + list.Add(new TestClone()); + list.Add(new TestClone()); + + var cloned = (DeepCloneableList)list.DeepClone(); + + //Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID) + Assert.IsTrue(list.SequenceEqual(cloned)); + + //Test that each instance in the list is not the same one + foreach (var item in list) + { + var clone = cloned.Single(x => x.Id == item.Id); + Assert.AreNotSame(item, clone); + } + } + + public class TestClone : IDeepCloneable, IEquatable + { + public TestClone(Guid id) + { + Id = id; + IsClone = true; + } + + public TestClone() + { + Id = Guid.NewGuid(); + } + + public Guid Id { get; private set; } + public bool IsClone { get; private set; } + + public object DeepClone() + { + return new TestClone(Id); + } + + /// + /// Indicates whether the current object is equal to another object of the same type. + /// + /// + /// true if the current object is equal to the parameter; otherwise, false. + /// + /// An object to compare with this object. + public bool Equals(TestClone other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Id.Equals(other.Id); + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// + /// true if the specified object is equal to the current object; otherwise, false. + /// + /// The object to compare with the current object. + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((TestClone)obj); + } + + /// + /// Serves as the default hash function. + /// + /// + /// A hash code for the current object. + /// + public override int GetHashCode() + { + return Id.GetHashCode(); + } + + public static bool operator ==(TestClone left, TestClone right) + { + return Equals(left, right); + } + + public static bool operator !=(TestClone left, TestClone right) + { + return Equals(left, right) == false; + } + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 59a9166e5a..e689fe08f9 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -175,6 +175,7 @@ + From 649679cb30689115ccabb360ce6f07cdd207b125 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 6 Jan 2016 14:24:53 +0100 Subject: [PATCH 096/605] U4-7612 Properties Pane is empty when trying to add a new Property to a new or existing Document Type --- src/Umbraco.Web/Editors/DataTypeController.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Editors/DataTypeController.cs b/src/Umbraco.Web/Editors/DataTypeController.cs index c2d7ec37d2..931d00968b 100644 --- a/src/Umbraco.Web/Editors/DataTypeController.cs +++ b/src/Umbraco.Web/Editors/DataTypeController.cs @@ -299,14 +299,16 @@ namespace Umbraco.Web.Editors { var dataTypes = Services.DataTypeService .GetAllDataTypeDefinitions() - .Select(Mapper.Map); + .Select(Mapper.Map) + .ToArray(); var propertyEditors = PropertyEditorResolver.Current.PropertyEditors.ToArray(); foreach (var dataType in dataTypes) { - var propertyEditor = propertyEditors.Single(x => x.Alias == dataType.Alias); - dataType.HasPrevalues = propertyEditor.PreValueEditor.Fields.Any(); ; + var propertyEditor = propertyEditors.SingleOrDefault(x => x.Alias == dataType.Alias); + if(propertyEditor != null) + dataType.HasPrevalues = propertyEditor.PreValueEditor.Fields.Any(); ; } var grouped = dataTypes From 378479b4c1bacd07fc7faa3caaeed7c7e404bccb Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 14:48:37 +0100 Subject: [PATCH 097/605] Fixes: U4-7553 Importing Document Type doesn't respect property sort order Handling sortOrder property in both import/export. --- src/Umbraco.Core/Services/EntityXmlSerializer.cs | 1 + src/Umbraco.Core/Services/PackagingService.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index 16f33a1ce9..09c4dfcf48 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -379,6 +379,7 @@ namespace Umbraco.Core.Services new XElement("Type", propertyType.PropertyEditorAlias), new XElement("Definition", definition.Key), new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), + new XElement("SortOrder", propertyType.SortOrder), new XElement("Mandatory", propertyType.Mandatory.ToString()), propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null); diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 0d1d8388b6..de58e32f74 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -658,6 +658,7 @@ namespace Umbraco.Core.Services Description = property.Element("Description") != null ? property.Element("Description").Value : null, Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false, ValidationRegExp = property.Element("Validation") != null ? property.Element("Validation").Value : null, + SortOrder = property.Element("SortOrder") != null ? int.Parse(property.Element("SortOrder").Value) : 0 }; var tab = property.Element("Tab").Value; From c524d67a375cdecf0362d57629ae9b56d52fd292 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 6 Jan 2016 14:48:37 +0100 Subject: [PATCH 098/605] Fixes: U4-7553 Importing Document Type doesn't respect property sort order Handling sortOrder property in both import/export. (cherry picked from commit 378479b4c1bacd07fc7faa3caaeed7c7e404bccb) # Conflicts: # src/Umbraco.Core/Services/PackagingService.cs --- src/Umbraco.Core/Services/EntityXmlSerializer.cs | 1 + src/Umbraco.Core/Services/PackagingService.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index 712f98aeb2..4008eda0a2 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -379,6 +379,7 @@ namespace Umbraco.Core.Services new XElement("Type", propertyType.PropertyEditorAlias), new XElement("Definition", definition.Key), new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), + new XElement("SortOrder", propertyType.SortOrder), new XElement("Mandatory", propertyType.Mandatory.ToString()), new XElement("Validation", propertyType.ValidationRegExp), new XElement("Description", new XCData(propertyType.Description))); diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 8ca9d3e3da..6647e24317 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -658,6 +658,7 @@ namespace Umbraco.Core.Services Description = property.Element("Description").Value, Mandatory = property.Element("Mandatory").Value.ToLowerInvariant().Equals("true"), ValidationRegExp = property.Element("Validation").Value, + SortOrder = property.Element("SortOrder").Value }; var tab = property.Element("Tab").Value; From 7b33f85a5d8109d89b31abd457f6d2d2521aa67c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 6 Jan 2016 15:15:50 +0100 Subject: [PATCH 099/605] fixes: U4-7593 Removing a composite from an existing doctype - Need better UI/error reporting (your data goes with it!) --- .../overlays/umboverlay.directive.js | 28 +++-- .../components/umbgroupsbuilder.directive.js | 119 +++++++++++------- .../src/less/components/overlays.less | 51 ++++---- .../components/overlays/umb-overlay.html | 52 +++++++- 4 files changed, 165 insertions(+), 85 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js index a76162be24..4741458c90 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js @@ -11,6 +11,10 @@ function link(scope, el, attr, ctrl) { + scope.directive = { + enableConfirmButton: false + }; + var overlayNumber = 0; var numberOfOverlays = 0; var isRegistered = false; @@ -222,21 +226,23 @@ } scope.submitForm = function(model) { - if(scope.model.submit) { + if (formHelper.submitForm({scope: scope})) { + formHelper.resetForm({ scope: scope }); - if (formHelper.submitForm({scope: scope})) { + if(scope.model.confirmSubmit && scope.model.confirmSubmit.enable && !scope.directive.enableConfirmButton) { + scope.model.submit(model, modelCopy, scope.directive.enableConfirmButton); + } else { + unregisterOverlay(); + scope.model.submit(model, modelCopy, scope.directive.enableConfirmButton); + } - formHelper.resetForm({ scope: scope }); - - unregisterOverlay(); - - scope.model.submit(model); - - } - - } + } + } + }; + scope.cancelConfirmSubmit = function() { + scope.model.confirmSubmit.show = false; }; scope.closeOverLay = function() { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js index d18251da0b..5d3766f517 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js @@ -182,64 +182,95 @@ }; scope.openCompositionsDialog = function() { - scope.compositionsDialogModel = {}; - scope.compositionsDialogModel.title = "Compositions"; - scope.compositionsDialogModel.contentType = scope.model; - scope.compositionsDialogModel.availableCompositeContentTypes = scope.model.availableCompositeContentTypes; - scope.compositionsDialogModel.compositeContentTypes = scope.model.compositeContentTypes; - scope.compositionsDialogModel.view = "views/common/overlays/contenttypeeditor/compositions/compositions.html"; - scope.compositionsDialogModel.show = true; - scope.compositionsDialogModel.submit = function(model) { + scope.compositionsDialogModel = { + title: "Compositions", + contentType: scope.model, + availableCompositeContentTypes: scope.model.availableCompositeContentTypes, + compositeContentTypes: scope.model.compositeContentTypes, + view: "views/common/overlays/contenttypeeditor/compositions/compositions.html", + confirmSubmit: { + title: "Warning", + description: "Removing a composition will delete all the associated property data. Once you save the document type there's no way back, are you sure?", + checkboxLabel: "I know what I'm doing", + enable: true + }, + show: true, + submit: function(model, oldModel, confirmed) { - // make sure that all tabs has an init property - if (scope.model.groups.length !== 0) { - angular.forEach(scope.model.groups, function(group) { - addInitProperty(group); - }); - } + var compositionRemoved = false; - // remove overlay - scope.compositionsDialogModel.show = false; - scope.compositionsDialogModel = null; - }; + // check if any compositions has been removed + for(var i = 0; oldModel.compositeContentTypes.length > i; i++) { - scope.compositionsDialogModel.close = function(oldModel) { - // reset composition changes - scope.model.groups = oldModel.contentType.groups; - scope.model.compositeContentTypes = oldModel.contentType.compositeContentTypes; + var oldComposition = oldModel.compositeContentTypes[i]; - // remove overlay - scope.compositionsDialogModel.show = false; - scope.compositionsDialogModel = null; - }; + if(_.contains(model.compositeContentTypes, oldComposition) === false) { + compositionRemoved = true; + } - scope.compositionsDialogModel.selectCompositeContentType = function(compositeContentType) { + } - if (scope.model.compositeContentTypes.indexOf(compositeContentType.alias) === -1) { - //merge composition with content type + // show overlay confirm box if compositions has been removed. + if(compositionRemoved && confirmed === false) { - if(scope.contentType === "documentType") { + scope.compositionsDialogModel.confirmSubmit.show = true; - contentTypeResource.getById(compositeContentType.id).then(function(composition){ - contentTypeHelper.mergeCompositeContentType(scope.model, composition); - }); + // submit overlay if no compositions has been removed + // or the action has been confirmed + } else { + + // make sure that all tabs has an init property + if (scope.model.groups.length !== 0) { + angular.forEach(scope.model.groups, function(group) { + addInitProperty(group); + }); + } + + // remove overlay + scope.compositionsDialogModel.show = false; + scope.compositionsDialogModel = null; + } + + }, + close: function(oldModel) { + + // reset composition changes + scope.model.groups = oldModel.contentType.groups; + scope.model.compositeContentTypes = oldModel.contentType.compositeContentTypes; + + // remove overlay + scope.compositionsDialogModel.show = false; + scope.compositionsDialogModel = null; + + }, + selectCompositeContentType: function(compositeContentType) { + + if (scope.model.compositeContentTypes.indexOf(compositeContentType.alias) === -1) { + //merge composition with content type + + if(scope.contentType === "documentType") { + + contentTypeResource.getById(compositeContentType.id).then(function(composition){ + contentTypeHelper.mergeCompositeContentType(scope.model, composition); + }); - } else if(scope.contentType === "mediaType") { + } else if(scope.contentType === "mediaType") { - mediaTypeResource.getById(compositeContentType.id).then(function(composition){ - contentTypeHelper.mergeCompositeContentType(scope.model, composition); - }); + mediaTypeResource.getById(compositeContentType.id).then(function(composition){ + contentTypeHelper.mergeCompositeContentType(scope.model, composition); + }); + + } + + + } else { + // split composition from content type + contentTypeHelper.splitCompositeContentType(scope.model, compositeContentType); + } } - - - } else { - // split composition from content type - contentTypeHelper.splitCompositeContentType(scope.model, compositeContentType); - } - }; }; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less index eff17fb20a..40b6ddea99 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less @@ -7,11 +7,20 @@ box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); } +.umb-overlay__form { + display: flex; + flex-wrap: nowrap; + flex-direction: column; + height: 100%; +} + .umb-overlay .umb-overlay-header { background: @grayLighter; border-bottom: 1px solid @grayLight; padding: 10px; margin-top: 0; + flex-grow: 0; + flex-shrink: 0; } @@ -29,29 +38,31 @@ } .umb-overlay .umb-overlay-container { - top: 50px; - left: 7px; - right: 7px; - bottom: 7px; - position: absolute; + flex-grow: 1; + flex-shrink: 1; + flex-basis: auto; overflow-y: auto; overflow-x: hidden; + position: relative; + height: auto; } .umb-overlay .umb-overlay-drawer { - position: absolute; - right: 0; - bottom: 0; - left: 0; - height: 31px; - padding: 10px; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 31px; + padding: 10px 20px; margin: 0; background: @grayLighter; border-top: 1px solid @grayLight; } -.umb-overlay .umb-overlay-drawer .umb-overlay-drawer-content { +.umb-overlay .umb-overlay-drawer.-auto-height { + flex-basis: auto; +} + +.umb-overlay .umb-overlay-drawer .umb-overlay-drawer__align-right { display: flex; justify-content: flex-end; } @@ -76,7 +87,6 @@ } .umb-overlay.umb-overlay-center .umb-overlay-container { - top: 68px; padding: 20px; } @@ -92,8 +102,7 @@ } .umb-overlay.umb-overlay-target .umb-overlay-container { - top: 68px; - bottom: 58px; + padding: 10px; } /* ---------- OVERLAY RIGHT ---------- */ @@ -107,16 +116,12 @@ } .umb-overlay.umb-overlay-right .umb-overlay-header { - height: 100px; + flex-basis: 100px; padding: 20px; box-sizing: border-box; } .umb-overlay.umb-overlay-right .umb-overlay-container { - top: 100px; - left: 0; - right: 0; - bottom: 52px; padding: 20px; } @@ -132,16 +137,12 @@ } .umb-overlay.umb-overlay-left .umb-overlay-header { - height: 100px; + flex-basis: 100px; padding: 20px; box-sizing: border-box; } .umb-overlay.umb-overlay-left .umb-overlay-container { - top: 100px; - left: 0; - right: 0; - bottom: 51px; padding: 20px; } diff --git a/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html b/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html index ad115f1afd..4a15fc81c0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html @@ -1,5 +1,5 @@
        -
        +

        {{model.title}}

        @@ -21,11 +21,53 @@
        -
        -
        - - +
        + +
        + +
        {{ model.confirmSubmit.title }}
        +

        {{ model.confirmSubmit.description }}

        + + + +
        + + + + + +
        + +
        + + + + + +
        +
        From 48ab3f580c5066af9e3e24ee58d995b80c73e750 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 6 Jan 2016 15:21:45 +0100 Subject: [PATCH 100/605] Fixes the build --- src/Umbraco.Core/Services/PackagingService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 6647e24317..7d40ec99ac 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -652,13 +652,15 @@ namespace Umbraco.Core.Services if (dataTypeDefinition == null) continue; } + var sortOrder = 0; + int.TryParse(property.Element("SortOrder").Value, out sortOrder); var propertyType = new PropertyType(dataTypeDefinition, property.Element("Alias").Value) { Name = property.Element("Name").Value, Description = property.Element("Description").Value, Mandatory = property.Element("Mandatory").Value.ToLowerInvariant().Equals("true"), ValidationRegExp = property.Element("Validation").Value, - SortOrder = property.Element("SortOrder").Value + SortOrder = sortOrder }; var tab = property.Element("Tab").Value; From d2483159bcf666651f3a64f0184009216bd38c57 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 6 Jan 2016 15:59:23 +0100 Subject: [PATCH 101/605] Fixes unit tests, not all packages will have the sort order in there --- src/Umbraco.Core/Services/PackagingService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 7d40ec99ac..5b9bd8b7b0 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -653,7 +653,9 @@ namespace Umbraco.Core.Services } var sortOrder = 0; - int.TryParse(property.Element("SortOrder").Value, out sortOrder); + var sortOrderElement = property.Element("SortOrder"); + if (sortOrderElement != null) + int.TryParse(sortOrderElement.Value, out sortOrder); var propertyType = new PropertyType(dataTypeDefinition, property.Element("Alias").Value) { Name = property.Element("Name").Value, From ff829d49a3faa0dfe2a8876052ed30f003a087bc Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 6 Jan 2016 18:08:14 +0100 Subject: [PATCH 102/605] Updates all cache refreshers to reference the IsolatedRuntimeCache where required, refactors how IsolatedRuntimeCache is exposed on the CacheHelper, ensures that IsolatedRuntimeCache is used in all repositories instead of the global RuntimeCache, changes all obsolete usages of CacheHelper to the non obsolete equivalent, obsoletes many of the cache keys, obsoletes a couple cache refreshers that aren't used anymore in 7.3, simplifies CacheHelper with regards to it's 'disabled' cache state. --- src/Umbraco.Core/ApplicationContext.cs | 3 +- src/Umbraco.Core/Cache/CacheKeys.cs | 31 +- src/Umbraco.Core/Cache/CacheRefresherBase.cs | 11 + .../Cache/IsolatedRuntimeCache.cs | 91 +++++ src/Umbraco.Core/CacheHelper.cs | 313 ++++++------------ src/Umbraco.Core/CoreBootManager.cs | 10 +- .../DataTypeDefinitionRepository.cs | 14 +- .../Repositories/MemberGroupRepository.cs | 8 +- .../Repositories/PermissionRepository.cs | 7 +- .../Repositories/RepositoryBase.cs | 2 +- .../Persistence/RepositoryFactory.cs | 20 +- .../Services/ApplicationTreeService.cs | 2 +- src/Umbraco.Core/Services/SectionService.cs | 2 +- src/Umbraco.Core/Services/ServiceContext.cs | 1 + src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Tests/Macros/MacroTests.cs | 13 +- .../DataTypeDefinitionRepositoryTest.cs | 23 +- .../Repositories/MemberRepositoryTest.cs | 2 +- .../Cache/ApplicationCacheRefresher.cs | 4 +- .../Cache/ApplicationTreeCacheRefresher.cs | 4 +- .../Cache/ContentTypeCacheRefresher.cs | 22 +- .../Cache/DataTypeCacheRefresher.cs | 25 +- .../Cache/DictionaryCacheRefresher.cs | 4 +- src/Umbraco.Web/Cache/DistributedCache.cs | 3 + .../Cache/DistributedCacheExtensions.cs | 2 +- src/Umbraco.Web/Cache/DomainCacheRefresher.cs | 4 +- .../Cache/LanguageCacheRefresher.cs | 4 +- src/Umbraco.Web/Cache/MacroCacheRefresher.cs | 8 +- src/Umbraco.Web/Cache/MediaCacheRefresher.cs | 58 ++-- src/Umbraco.Web/Cache/MemberCacheRefresher.cs | 4 +- .../Cache/MemberGroupCacheRefresher.cs | 8 +- src/Umbraco.Web/Cache/PageCacheRefresher.cs | 6 +- .../Cache/PublicAccessCacheRefresher.cs | 8 +- .../Cache/StylesheetCacheRefresher.cs | 25 +- .../Cache/StylesheetPropertyCacheRefresher.cs | 27 +- .../Cache/TemplateCacheRefresher.cs | 6 +- .../Cache/UnpublishedPageCacheRefresher.cs | 33 +- src/Umbraco.Web/Cache/UserCacheRefresher.cs | 24 +- .../Cache/UserPermissionsCacheRefresher.cs | 12 +- .../Cache/UserTypeCacheRefresher.cs | 10 +- src/Umbraco.Web/CacheHelperExtensions.cs | 2 +- src/Umbraco.Web/Media/ImageUrl.cs | 2 +- .../umbraco.presentation/content.cs | 2 +- .../umbraco.presentation/library.cs | 12 +- src/Umbraco.Web/umbraco.presentation/macro.cs | 32 +- .../umbraco.presentation/template.cs | 2 +- .../developer/Packages/LoadNitros.ascx.cs | 3 +- .../umbraco/templateControls/ItemRenderer.cs | 10 +- src/umbraco.businesslogic/User.cs | 2 +- src/umbraco.cms/businesslogic/ContentType.cs | 20 +- src/umbraco.cms/businesslogic/cache/Cache.cs | 8 +- src/umbraco.cms/businesslogic/macro/Macro.cs | 12 +- .../businesslogic/member/Member.cs | 16 +- .../propertytype/propertytype.cs | 44 +-- src/umbraco.cms/businesslogic/web/Document.cs | 2 +- 55 files changed, 527 insertions(+), 497 deletions(-) create mode 100644 src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs index a05abe2a50..e47ef04650 100644 --- a/src/Umbraco.Core/ApplicationContext.cs +++ b/src/Umbraco.Core/ApplicationContext.cs @@ -406,7 +406,8 @@ namespace Umbraco.Core //clear the cache if (ApplicationCache != null) { - ApplicationCache.ClearAllCache(); + ApplicationCache.RuntimeCache.ClearAllCache(); + ApplicationCache.IsolatedRuntimeCache.ClearAllCaches(); } //reset all resolvers ResolverCollection.ResetAll(); diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs index 88d570beff..0c1a202b66 100644 --- a/src/Umbraco.Core/Cache/CacheKeys.cs +++ b/src/Umbraco.Core/Cache/CacheKeys.cs @@ -1,8 +1,9 @@ using System; +using System.ComponentModel; +using Umbraco.Core.CodeAnnotations; namespace Umbraco.Core.Cache { - /// /// Constants storing cache keys used in caching /// @@ -12,52 +13,78 @@ namespace Umbraco.Core.Cache public const string ApplicationsCacheKey = "ApplicationCache"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string UserTypeCacheKey = "UserTypeCache"; + [Obsolete("This is no longer used and will be removed from the codebase in the future - it is referenced but no cache is stored against this key")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string ContentItemCacheKey = "contentItem"; + [UmbracoWillObsolete("This cache key is only used for the legacy 'library' caching, remove in v8")] public const string MediaCacheKey = "UL_GetMedia"; public const string MacroXsltCacheKey = "macroXslt_"; + + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string MacroCacheKey = "UmbracoMacroCache"; + public const string MacroHtmlCacheKey = "macroHtml_"; public const string MacroControlCacheKey = "macroControl_"; public const string MacroHtmlDateAddedCacheKey = "macroHtml_DateAdded_"; public const string MacroControlDateAddedCacheKey = "macroControl_DateAdded_"; + [UmbracoWillObsolete("This cache key is only used for legacy 'library' member caching, remove in v8")] public const string MemberLibraryCacheKey = "UL_GetMember"; + + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string MemberBusinessLogicCacheKey = "MemberCacheItem_"; - + + [UmbracoWillObsolete("This cache key is only used for legacy template business logic caching, remove in v8")] public const string TemplateFrontEndCacheKey = "template"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache"; + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string UserContextCacheKey = "UmbracoUserContext"; + public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string UserCacheKey = "UmbracoUser"; public const string UserPermissionsCacheKey = "UmbracoUserPermissions"; + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string ContentTypeCacheKey = "UmbracoContentType"; + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:"; + [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")] public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string LanguageCacheKey = "UmbracoLanguageCache"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string DomainCacheKey = "UmbracoDomainList"; [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string StylesheetCacheKey = "UmbracoStylesheet"; + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty"; + [Obsolete("This is no longer used and will be removed from the codebase in the future")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string DataTypeCacheKey = "UmbracoDataTypeDefinition"; public const string DataTypePreValuesCacheKey = "UmbracoPreVal"; diff --git a/src/Umbraco.Core/Cache/CacheRefresherBase.cs b/src/Umbraco.Core/Cache/CacheRefresherBase.cs index 2931805b08..2ee7873ad0 100644 --- a/src/Umbraco.Core/Cache/CacheRefresherBase.cs +++ b/src/Umbraco.Core/Cache/CacheRefresherBase.cs @@ -2,6 +2,7 @@ using Umbraco.Core.Events; using Umbraco.Core.Sync; using umbraco.interfaces; +using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Cache { @@ -63,5 +64,15 @@ namespace Umbraco.Core.Cache { OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RefreshById)); } + + /// + /// Clears the cache for all repository entities of this type + /// + /// + protected void ClearAllCacheByRepositoryEntityType() + where TEntity : class, IAggregateRoot + { + ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.ClearCache(); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs b/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs new file mode 100644 index 0000000000..103f90345d --- /dev/null +++ b/src/Umbraco.Core/Cache/IsolatedRuntimeCache.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Concurrent; + +namespace Umbraco.Core.Cache +{ + /// + /// Used to get/create/manipulate isolated runtime cache + /// + /// + /// This is useful for repository level caches to ensure that cache lookups by key are fast so + /// that the repository doesn't need to search through all keys on a global scale. + /// + public class IsolatedRuntimeCache + { + private readonly Func _cacheFactory; + + /// + /// Constructor that allows specifying a factory for the type of runtime isolated cache to create + /// + /// + public IsolatedRuntimeCache(Func cacheFactory) + { + _cacheFactory = cacheFactory; + } + + private readonly ConcurrentDictionary _isolatedCache = new ConcurrentDictionary(); + + /// + /// Returns an isolated runtime cache for a given type + /// + /// + /// + public IRuntimeCacheProvider GetOrCreateCache() + { + return _isolatedCache.GetOrAdd(typeof(T), type => _cacheFactory(type)); + } + + /// + /// Returns an isolated runtime cache for a given type + /// + /// + public IRuntimeCacheProvider GetOrCreateCache(Type type) + { + return _isolatedCache.GetOrAdd(type, t => _cacheFactory(t)); + } + + /// + /// Tries to get a cache by the type specified + /// + /// + /// + public Attempt GetCache() + { + IRuntimeCacheProvider cache; + if (_isolatedCache.TryGetValue(typeof(T), out cache)) + { + return Attempt.Succeed(cache); + } + return Attempt.Fail(); + } + + /// + /// Clears all values inside this isolated runtime cache + /// + /// + /// + public void ClearCache() + { + IRuntimeCacheProvider cache; + if (_isolatedCache.TryGetValue(typeof(T), out cache)) + { + cache.ClearAllCache(); + } + } + + /// + /// Clears all of the isolated caches + /// + public void ClearAllCaches() + { + foreach (var key in _isolatedCache.Keys) + { + IRuntimeCacheProvider cache; + if (_isolatedCache.TryRemove(key, out cache)) + { + cache.ClearAllCache(); + } + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs index 44a0a35f2b..303cf234fd 100644 --- a/src/Umbraco.Core/CacheHelper.cs +++ b/src/Umbraco.Core/CacheHelper.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -17,14 +18,13 @@ namespace Umbraco.Core ///
        public class CacheHelper { - private readonly bool _enableCache; + private readonly IsolatedRuntimeCache _isolatedCacheManager; private readonly ICacheProvider _requestCache; - private readonly ICacheProvider _nullRequestCache = new NullCacheProvider(); + private static readonly ICacheProvider NullRequestCache = new NullCacheProvider(); private readonly ICacheProvider _staticCache; - private readonly ICacheProvider _nullStaticCache = new NullCacheProvider(); + private static readonly ICacheProvider NullStaticCache = new NullCacheProvider(); private readonly IRuntimeCacheProvider _runtimeCache; - private readonly IRuntimeCacheProvider _nullRuntimeCache = new NullCacheProvider(); - private readonly ConcurrentDictionary _isolatedCache = new ConcurrentDictionary(); + private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider(); /// /// Creates a cache helper with disabled caches @@ -35,7 +35,7 @@ namespace Umbraco.Core /// public static CacheHelper CreateDisabledCacheHelper() { - return new CacheHelper(null, null, null, false); + return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, new IsolatedRuntimeCache(t => NullRuntimeCache)); } /// @@ -45,7 +45,8 @@ namespace Umbraco.Core : this( new HttpRuntimeCacheProvider(HttpRuntime.Cache), new StaticCacheProvider(), - new HttpRequestCacheProvider()) + new HttpRequestCacheProvider(), + new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) { } @@ -57,83 +58,58 @@ namespace Umbraco.Core : this( new HttpRuntimeCacheProvider(cache), new StaticCacheProvider(), - new HttpRequestCacheProvider()) + new HttpRequestCacheProvider(), + new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) { } - /// - /// Initializes a new instance based on the provided providers - /// - /// - /// - /// + [Obsolete("Use the constructor the specifies all dependencies")] + [EditorBrowsable(EditorBrowsableState.Never)] public CacheHelper( IRuntimeCacheProvider httpCacheProvider, ICacheProvider staticCacheProvider, ICacheProvider requestCacheProvider) - : this(httpCacheProvider, staticCacheProvider, requestCacheProvider, true) + : this(httpCacheProvider, staticCacheProvider, requestCacheProvider, new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider())) { } - /// - /// Private ctor used for creating a disabled cache helper - /// - /// - /// - /// - /// - private CacheHelper( + /// + /// Initializes a new instance based on the provided providers + /// + /// + /// + /// + /// + public CacheHelper( IRuntimeCacheProvider httpCacheProvider, ICacheProvider staticCacheProvider, - ICacheProvider requestCacheProvider, - bool enableCache) + ICacheProvider requestCacheProvider, + IsolatedRuntimeCache isolatedCacheManager) { - if (enableCache) - { - _runtimeCache = httpCacheProvider; - _staticCache = staticCacheProvider; - _requestCache = requestCacheProvider; - } - else - { - _runtimeCache = null; - _staticCache = null; - _requestCache = null; - } - - _enableCache = enableCache; + if (httpCacheProvider == null) throw new ArgumentNullException("httpCacheProvider"); + if (staticCacheProvider == null) throw new ArgumentNullException("staticCacheProvider"); + if (requestCacheProvider == null) throw new ArgumentNullException("requestCacheProvider"); + if (isolatedCacheManager == null) throw new ArgumentNullException("isolatedCacheManager"); + _runtimeCache = httpCacheProvider; + _staticCache = staticCacheProvider; + _requestCache = requestCacheProvider; + _isolatedCacheManager = isolatedCacheManager; } /// - /// Returns an isolated runtime cache for a given type - /// - /// - /// - /// - /// This is useful for repository level caches to ensure that cache lookups by key are fast so - /// that the repository doesn't need to search through all keys on a global scale. - /// - public IRuntimeCacheProvider GetIsolatedRuntimeCache() - { - return _enableCache == false - ? _nullRuntimeCache - : _isolatedCache.GetOrAdd(typeof (T), type => new ObjectCacheRuntimeCacheProvider()); - } - - /// /// Returns the current Request cache /// public ICacheProvider RequestCache { - get { return _enableCache ? _requestCache : _nullRequestCache; } + get { return _requestCache; } } - + /// /// Returns the current Runtime cache /// public ICacheProvider StaticCache { - get { return _enableCache ? _staticCache : _nullStaticCache; } + get { return _staticCache; } } /// @@ -141,8 +117,16 @@ namespace Umbraco.Core /// public IRuntimeCacheProvider RuntimeCache { - get { return _enableCache ? _runtimeCache : _nullRuntimeCache; } + get { return _runtimeCache; } } + + /// + /// Returns the current Isolated Runtime cache manager + /// + public IsolatedRuntimeCache IsolatedRuntimeCache + { + get { return _isolatedCacheManager; } + } #region Legacy Runtime/Http Cache accessors @@ -150,16 +134,11 @@ namespace Umbraco.Core /// Clears the item in umbraco's runtime cache /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearAllCache() { - if (_enableCache == false) - { - _nullRuntimeCache.ClearAllCache(); - } - else - { - _runtimeCache.ClearAllCache(); - } + _runtimeCache.ClearAllCache(); + _isolatedCacheManager.ClearAllCaches(); } /// @@ -167,16 +146,10 @@ namespace Umbraco.Core /// /// Key [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheItem(string key) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheItem(key); - } - else - { - _runtimeCache.ClearCacheItem(key); - } + _runtimeCache.ClearCacheItem(key); } @@ -188,30 +161,17 @@ namespace Umbraco.Core [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] public void ClearCacheObjectTypes(string typeName) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheObjectTypes(typeName); - } - else - { - _runtimeCache.ClearCacheObjectTypes(typeName); - } + _runtimeCache.ClearCacheObjectTypes(typeName); } /// /// Clears all objects in the System.Web.Cache with the System.Type specified /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheObjectTypes() { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheObjectTypes(); - } - else - { - _runtimeCache.ClearCacheObjectTypes(); - } + _runtimeCache.ClearCacheObjectTypes(); } /// @@ -219,16 +179,10 @@ namespace Umbraco.Core /// /// The start of the key [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheByKeySearch(string keyStartsWith) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheByKeySearch(keyStartsWith); - } - else - { - _runtimeCache.ClearCacheByKeySearch(keyStartsWith); - } + _runtimeCache.ClearCacheByKeySearch(keyStartsWith); } /// @@ -236,29 +190,17 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void ClearCacheByKeyExpression(string regexString) { - if (_enableCache == false) - { - _nullRuntimeCache.ClearCacheByKeyExpression(regexString); - } - else - { - _runtimeCache.ClearCacheByKeyExpression(regexString); - } + _runtimeCache.ClearCacheByKeyExpression(regexString); } [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItemsByKeySearch(keyStartsWith); - } - else - { - return _runtimeCache.GetCacheItemsByKeySearch(keyStartsWith); - } + return _runtimeCache.GetCacheItemsByKeySearch(keyStartsWith); } /// @@ -268,16 +210,10 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey); - } + return _runtimeCache.GetCacheItem(cacheKey); } /// @@ -288,16 +224,11 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, Func getCacheItem) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem); + } /// @@ -309,17 +240,12 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout); + } /// @@ -332,18 +258,13 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan timeout, Func getCacheItem) { - if (!_enableCache) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, removedCallback: refreshAction); + } /// @@ -357,18 +278,13 @@ namespace Umbraco.Core /// /// [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public TT GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) - { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); - } - else - { - return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); - } + return _runtimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction); + } /// @@ -390,20 +306,13 @@ namespace Umbraco.Core TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); - return result == null ? default(TT) : result.TryConvertTo().Result; - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); + return result == null ? default(TT) : result.TryConvertTo().Result; } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } /// @@ -421,20 +330,13 @@ namespace Umbraco.Core CacheDependency cacheDependency, Func getCacheItem) { - if (!_enableCache) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - return _nullRuntimeCache.GetCacheItem(cacheKey, getCacheItem, null, false, priority, null, null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency); - return result == null ? default(TT) : result.TryConvertTo().Result; - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency); + return result == null ? default(TT) : result.TryConvertTo().Result; } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } /// @@ -444,18 +346,14 @@ namespace Umbraco.Core /// /// /// + [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void InsertCacheItem(string cacheKey, CacheItemPriority priority, Func getCacheItem) { - if (_enableCache == false) - { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); - } - else - { - _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); - } + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, priority: priority); + } /// @@ -466,19 +364,14 @@ namespace Umbraco.Core /// /// This will set an absolute expiration from now until the timeout /// + [Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")] + [EditorBrowsable(EditorBrowsableState.Never)] public void InsertCacheItem(string cacheKey, CacheItemPriority priority, TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) - { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); - } - else - { - _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); - } + _runtimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority); } /// @@ -497,19 +390,12 @@ namespace Umbraco.Core TimeSpan timeout, Func getCacheItem) { - if (_enableCache == false) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, priority: priority, dependentFiles:null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency); - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency); } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } /// @@ -530,19 +416,12 @@ namespace Umbraco.Core TimeSpan? timeout, Func getCacheItem) { - if (_enableCache == false) + var cache = _runtimeCache as HttpRuntimeCacheProvider; + if (cache != null) { - _nullRuntimeCache.InsertCacheItem(cacheKey, getCacheItem, timeout, false, priority, refreshAction, null); - } - else - { - var cache = _runtimeCache as HttpRuntimeCacheProvider; - if (cache != null) - { - cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); - } - throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); + cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency); } + throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider)); } #endregion diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs index b4e3d06273..17f909da8a 100644 --- a/src/Umbraco.Core/CoreBootManager.cs +++ b/src/Umbraco.Core/CoreBootManager.cs @@ -188,10 +188,16 @@ namespace Umbraco.Core protected virtual CacheHelper CreateApplicationCache() { var cacheHelper = new CacheHelper( - new ObjectCacheRuntimeCacheProvider(), + //we need to have the dep clone runtime cache provider to ensure + //all entities are cached properly (cloned in and cloned out) + new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()), new StaticCacheProvider(), //we have no request based cache when not running in web-based context - new NullCacheProvider()); + new NullCacheProvider(), + new IsolatedRuntimeCache(type => + //we need to have the dep clone runtime cache provider to ensure + //all entities are cached properly (cloned in and cloned out) + new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))); return cacheHelper; } diff --git a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs index 859c4e7ae7..244deaccb8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs @@ -24,17 +24,15 @@ namespace Umbraco.Core.Persistence.Repositories /// internal class DataTypeDefinitionRepository : PetaPocoRepositoryBase, IDataTypeDefinitionRepository { - private readonly CacheHelper _cacheHelper; private readonly IContentTypeRepository _contentTypeRepository; private readonly DataTypePreValueRepository _preValRepository; - public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, CacheHelper cacheHelper, ILogger logger, ISqlSyntaxProvider sqlSyntax, + public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, IContentTypeRepository contentTypeRepository) : base(work, cache, logger, sqlSyntax) { - _cacheHelper = cacheHelper; _contentTypeRepository = contentTypeRepository; - _preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax); + _preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax); } #region Overrides of RepositoryBase @@ -231,7 +229,7 @@ AND umbracoNode.id <> @id", //NOTE: This is a special case, we need to clear the custom cache for pre-values here so they are not stale if devs // are querying for them in the Saved event (before the distributed call cache is clearing it) - _cacheHelper.RuntimeCache.ClearCacheItem(GetPrefixedCacheKey(entity.Id)); + RuntimeCache.ClearCacheItem(GetPrefixedCacheKey(entity.Id)); entity.ResetDirtyProperties(); } @@ -270,7 +268,7 @@ AND umbracoNode.id <> @id", public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId) { - var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeySearch(GetPrefixedCacheKey(dataTypeId)); + var cached = RuntimeCache.GetCacheItemsByKeySearch(GetPrefixedCacheKey(dataTypeId)); if (cached != null && cached.Any()) { //return from the cache, ensure it's a cloned result @@ -289,7 +287,7 @@ AND umbracoNode.id <> @id", { //We need to see if we can find the cached PreValueCollection based on the cache key above - var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeyExpression(GetCacheKeyRegex(preValueId)); + var cached = RuntimeCache.GetCacheItemsByKeyExpression(GetCacheKeyRegex(preValueId)); if (cached != null && cached.Any()) { //return from the cache @@ -408,7 +406,7 @@ AND umbracoNode.id <> @id", + string.Join(",", collection.FormatAsDictionary().Select(x => x.Value.Id).ToArray()); //store into cache - _cacheHelper.RuntimeCache.InsertCacheItem(key, () => collection, + RuntimeCache.InsertCacheItem(key, () => collection, //30 mins new TimeSpan(0, 0, 30), //sliding is true diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs index 264409ddf4..40121223a2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs @@ -20,13 +20,9 @@ namespace Umbraco.Core.Persistence.Repositories internal class MemberGroupRepository : PetaPocoRepositoryBase, IMemberGroupRepository { - private readonly CacheHelper _cacheHelper; - - public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, CacheHelper cacheHelper) + public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax) : base(work, cache, logger, sqlSyntax) { - if (cacheHelper == null) throw new ArgumentNullException("cacheHelper"); - _cacheHelper = cacheHelper; } private readonly MemberGroupFactory _modelFactory = new MemberGroupFactory(); @@ -135,7 +131,7 @@ namespace Umbraco.Core.Persistence.Repositories public IMemberGroup GetByName(string name) { - return _cacheHelper.RuntimeCache.GetCacheItem( + return RuntimeCache.GetCacheItem( string.Format("{0}.{1}", typeof (IMemberGroup).FullName, name), () => { diff --git a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs index 0463312982..aa671dccec 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PermissionRepository.cs @@ -26,13 +26,14 @@ namespace Umbraco.Core.Persistence.Repositories where TEntity : class, IAggregateRoot { private readonly IDatabaseUnitOfWork _unitOfWork; - private readonly CacheHelper _cache; + private readonly IRuntimeCacheProvider _runtimeCache; private readonly ISqlSyntaxProvider _sqlSyntax; internal PermissionRepository(IDatabaseUnitOfWork unitOfWork, CacheHelper cache, ISqlSyntaxProvider sqlSyntax) { _unitOfWork = unitOfWork; - _cache = cache; + //Make this repository use an isolated cache + _runtimeCache = cache.IsolatedRuntimeCache.GetOrCreateCache(); _sqlSyntax = sqlSyntax; } @@ -45,7 +46,7 @@ namespace Umbraco.Core.Persistence.Repositories public IEnumerable GetUserPermissionsForEntities(int userId, params int[] entityIds) { var entityIdKey = string.Join(",", entityIds.Select(x => x.ToString(CultureInfo.InvariantCulture))); - return _cache.RuntimeCache.GetCacheItem>( + return _runtimeCache.GetCacheItem>( string.Format("{0}{1}{2}", CacheKeys.UserPermissionsCacheKey, userId, entityIdKey), () => { diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 2ce3537bb9..da02dcf3b4 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -89,7 +89,7 @@ namespace Umbraco.Core.Persistence.Repositories /// protected override IRuntimeCacheProvider RuntimeCache { - get { return RepositoryCache.GetIsolatedRuntimeCache(); } + get { return RepositoryCache.IsolatedRuntimeCache.GetOrCreateCache(); } } /// diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index d99ae8f464..e148bbe2fe 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -32,12 +32,26 @@ namespace Umbraco.Core.Persistence if (settings == null) throw new ArgumentNullException("settings"); _cacheHelper = cacheHelper; + //IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying // runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks // changes entities are reset. if ((_cacheHelper.RuntimeCache is DeepCloneRuntimeCacheProvider) == false) { - _cacheHelper = new CacheHelper(new DeepCloneRuntimeCacheProvider(_cacheHelper.RuntimeCache), _cacheHelper.StaticCache, _cacheHelper.RequestCache); + var originalHelper = cacheHelper; + + _cacheHelper = new CacheHelper( + new DeepCloneRuntimeCacheProvider(originalHelper.RuntimeCache), + originalHelper.StaticCache, + originalHelper.RequestCache, + new IsolatedRuntimeCache(type => + { + var cache = originalHelper.IsolatedRuntimeCache.GetOrCreateCache(type); + return (cache is DeepCloneRuntimeCacheProvider) == false + //wrap the original if it's not DeepCloneRuntimeCacheProvider + ? new DeepCloneRuntimeCacheProvider(cache) + : cache; + })); } _noCache = CacheHelper.CreateDisabledCacheHelper(); @@ -140,7 +154,6 @@ namespace Umbraco.Core.Persistence { return new DataTypeDefinitionRepository( uow, - _cacheHelper, _cacheHelper, _logger, _sqlSyntax, CreateContentTypeRepository(uow)); @@ -295,8 +308,7 @@ namespace Umbraco.Core.Persistence { return new MemberGroupRepository(uow, _cacheHelper, - _logger, _sqlSyntax, - _cacheHelper); + _logger, _sqlSyntax); } public virtual IEntityRepository CreateEntityRepository(IDatabaseUnitOfWork uow) diff --git a/src/Umbraco.Core/Services/ApplicationTreeService.cs b/src/Umbraco.Core/Services/ApplicationTreeService.cs index f640fa8d22..c9ce839450 100644 --- a/src/Umbraco.Core/Services/ApplicationTreeService.cs +++ b/src/Umbraco.Core/Services/ApplicationTreeService.cs @@ -315,7 +315,7 @@ namespace Umbraco.Core.Services //remove the cache now that it has changed SD: I'm leaving this here even though it // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); } } } diff --git a/src/Umbraco.Core/Services/SectionService.cs b/src/Umbraco.Core/Services/SectionService.cs index cc25387a00..b810840873 100644 --- a/src/Umbraco.Core/Services/SectionService.cs +++ b/src/Umbraco.Core/Services/SectionService.cs @@ -171,7 +171,7 @@ namespace Umbraco.Core.Services //remove the cache so it gets re-read ... SD: I'm leaving this here even though it // is taken care of by events as well, I think unit tests may rely on it being cleared here. - _cache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + _cache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); } } } diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index f8a78aed3d..9d0da8aca2 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -286,6 +286,7 @@ namespace Umbraco.Core.Services _entityService = new Lazy(() => new EntityService( provider, repositoryFactory, logger, eventMessagesFactory, _contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _memberService.Value, _memberTypeService.Value, + //TODO: Consider making this an isolated cache instead of using the global one cache.RuntimeCache)); if (_relationService == null) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d294bdaddf..dd83553074 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -162,6 +162,7 @@ + diff --git a/src/Umbraco.Tests/Macros/MacroTests.cs b/src/Umbraco.Tests/Macros/MacroTests.cs index 4f0b91d4ca..23c1c7f1f1 100644 --- a/src/Umbraco.Tests/Macros/MacroTests.cs +++ b/src/Umbraco.Tests/Macros/MacroTests.cs @@ -27,7 +27,8 @@ namespace Umbraco.Tests.Macros var cacheHelper = new CacheHelper( new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), - new NullCacheProvider()); + new NullCacheProvider(), + new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); ApplicationContext.Current = new ApplicationContext(cacheHelper, new ProfilingLogger(Mock.Of(), Mock.Of())); UmbracoConfig.For.SetUmbracoSettings(SettingsForTests.GetDefault()); @@ -36,7 +37,7 @@ namespace Umbraco.Tests.Macros [TearDown] public void TearDown() { - ApplicationContext.Current.ApplicationCache.ClearAllCache(); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearAllCache(); ApplicationContext.Current.DisposeIfDisposable(); ApplicationContext.Current = null; } @@ -136,11 +137,11 @@ namespace Umbraco.Tests.Macros public void Macro_Needs_Removing_Based_On_Macro_File(int minutesToNow, bool expectedResult) { var now = DateTime.Now; - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( "TestDate", - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, 60), - () => now.AddMinutes(minutesToNow)); //add a datetime value of 'now' with the minutes offset + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, 60), + getCacheItem: () => now.AddMinutes(minutesToNow)); //add a datetime value of 'now' with the minutes offset //now we need to update a file's date to 'now' to compare var path = Path.Combine(TestHelpers.TestHelper.CurrentAssemblyDirectory, "temp.txt"); diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs index 289bd628ee..f20de479a7 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs @@ -34,7 +34,6 @@ namespace Umbraco.Tests.Persistence.Repositories { var dataTypeDefinitionRepository = new DataTypeDefinitionRepository( unitOfWork, CacheHelper.CreateDisabledCacheHelper(), - CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, Mock.Of(), Mock.Of(), Mock.Of()))); @@ -376,10 +375,14 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - var cache = new CacheHelper(new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider()); + var cache = new CacheHelper( + new ObjectCacheRuntimeCacheProvider(), + new StaticCacheProvider(), + new StaticCacheProvider(), + new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); Func creator = () => new DataTypeDefinitionRepository( - unitOfWork, CacheHelper.CreateDisabledCacheHelper(), + unitOfWork, cache, Mock.Of(), SqlSyntax, new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, @@ -402,7 +405,8 @@ namespace Umbraco.Tests.Persistence.Repositories var collection = repository.GetPreValuesCollectionByDataTypeId(dtd.Id); } - var cached = cache.RuntimeCache.GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); + var cached = cache.IsolatedRuntimeCache.GetCache().Result + .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); Assert.IsNotNull(cached); Assert.AreEqual(1, cached.Count()); @@ -415,10 +419,14 @@ namespace Umbraco.Tests.Persistence.Repositories var provider = new PetaPocoUnitOfWorkProvider(Logger); var unitOfWork = provider.GetUnitOfWork(); - var cache = new CacheHelper(new ObjectCacheRuntimeCacheProvider(), new StaticCacheProvider(), new StaticCacheProvider()); + var cache = new CacheHelper( + new ObjectCacheRuntimeCacheProvider(), + new StaticCacheProvider(), + new StaticCacheProvider(), + new IsolatedRuntimeCache(type => new ObjectCacheRuntimeCacheProvider())); Func creator = () => new DataTypeDefinitionRepository( - unitOfWork, CacheHelper.CreateDisabledCacheHelper(), + unitOfWork, cache, Mock.Of(), SqlSyntax, new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, @@ -441,7 +449,8 @@ namespace Umbraco.Tests.Persistence.Repositories var val = repository.GetPreValueAsString(Convert.ToInt32(id)); } - var cached = cache.RuntimeCache.GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); + var cached = cache.IsolatedRuntimeCache.GetCache().Result + .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-"); Assert.IsNotNull(cached); Assert.AreEqual(1, cached.Count()); diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index 64e8587e00..0d3b4e4e47 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -37,7 +37,7 @@ namespace Umbraco.Tests.Persistence.Repositories private MemberRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out MemberTypeRepository memberTypeRepository, out MemberGroupRepository memberGroupRepository) { memberTypeRepository = new MemberTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); - memberGroupRepository = new MemberGroupRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, CacheHelper.CreateDisabledCacheHelper()); + memberGroupRepository = new MemberGroupRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); var tagRepo = new TagRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax); var repository = new MemberRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, memberTypeRepository, memberGroupRepository, tagRepo, Mock.Of()); return repository; diff --git a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs index 8b742b1b2c..5c1ec9e1d4 100644 --- a/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationCacheRefresher.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); base.RefreshAll(); } @@ -38,7 +38,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs index e267b441a2..2f1ab4b891 100644 --- a/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ApplicationTreeCacheRefresher.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); base.RefreshAll(); } @@ -38,7 +38,7 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.ApplicationTreeCacheKey); base.Remove(id); } diff --git a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs index 502e215c90..03b7e0ee59 100644 --- a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs @@ -126,9 +126,9 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + //all property type cache ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.PropertyTypeCacheKey); //all content type property cache @@ -179,7 +179,7 @@ namespace Umbraco.Web.Cache /// - InMemoryCacheProvider.Current.Clear(); /// - RoutesCache.Clear(); /// - private static void ClearContentTypeCache(JsonPayload[] payloads) + private void ClearContentTypeCache(JsonPayload[] payloads) { var needsContentRefresh = false; @@ -214,18 +214,18 @@ namespace Umbraco.Web.Cache { if (payloads.Any(x => x.Type == typeof (IContentType).Name)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); } if (payloads.Any(x => x.Type == typeof(IMediaType).Name)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); } if (payloads.Any(x => x.Type == typeof(IMemberType).Name)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); } @@ -291,7 +291,7 @@ namespace Umbraco.Web.Cache /// /// true if the entity was deleted, false if it is just an update /// - private static void ClearContentTypeCache(bool isDeleted, params int[] ids) + private void ClearContentTypeCache(bool isDeleted, params int[] ids) { ClearContentTypeCache( ids.Select( diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs index 86114d5f77..6a813df2fd 100644 --- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs @@ -92,27 +92,22 @@ namespace Umbraco.Web.Cache // db data type to store the value against and anytime a datatype changes, this also might change // we basically need to clear all sorts of runtime caches here because so many things depend upon a data type - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey); ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey); payloads.ForEach(payload => { - //clear both the Id and Unique Id cache since we cache both in the legacy classes :( - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, payload.Id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}{1}", CacheKeys.DataTypeCacheKey, payload.UniqueId)); - //clears the prevalue cache - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}{1}", CacheKeys.DataTypePreValuesCacheKey, payload.Id)); - + var dataTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (dataTypeCache) + dataTypeCache.Result.ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.DataTypePreValuesCacheKey, payload.Id)); + PublishedContentType.ClearDataType(payload.Id); }); diff --git a/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs b/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs index 8209d247a2..6dff68544a 100644 --- a/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DictionaryCacheRefresher.cs @@ -28,13 +28,13 @@ namespace Umbraco.Web.Cache public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } } diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs index 27c30d89e8..6848ce2496 100644 --- a/src/Umbraco.Web/Cache/DistributedCache.cs +++ b/src/Umbraco.Web/Cache/DistributedCache.cs @@ -38,6 +38,9 @@ namespace Umbraco.Web.Cache public const string ContentTypeCacheRefresherId = "6902E22C-9C10-483C-91F3-66B7CAE9E2F5"; public const string LanguageCacheRefresherId = "3E0F95D8-0BE5-44B8-8394-2B8750B62654"; public const string DomainCacheRefresherId = "11290A79-4B57-4C99-AD72-7748A3CF38AF"; + + [Obsolete("This is no longer used and will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] public const string StylesheetCacheRefresherId = "E0633648-0DEB-44AE-9A48-75C3A55CB670"; public const string StylesheetPropertyCacheRefresherId = "2BC7A3A4-6EB1-4FBC-BAA3-C9E7B6D36D38"; public const string DataTypeCacheRefresherId = "35B16C25-A17E-45D7-BC8F-EDAB1DCC28D2"; diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs index 66cb82ff7c..750872d8af 100644 --- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs +++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs @@ -442,7 +442,7 @@ namespace Umbraco.Web.Cache public static void ClearXsltCacheOnCurrentServer(this DistributedCache dc) { if (UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration <= 0) return; - ApplicationContext.Current.ApplicationCache.ClearCacheObjectTypes("MS.Internal.Xml.XPath.XPathSelectionIterator"); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes("MS.Internal.Xml.XPath.XPathSelectionIterator"); } #endregion diff --git a/src/Umbraco.Web/Cache/DomainCacheRefresher.cs b/src/Umbraco.Web/Cache/DomainCacheRefresher.cs index 51a2c79b2d..e5b1d9365d 100644 --- a/src/Umbraco.Web/Cache/DomainCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/DomainCacheRefresher.cs @@ -41,8 +41,8 @@ namespace Umbraco.Web.Cache } private void ClearCache() - { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + { + ClearAllCacheByRepositoryEntityType(); // SD: we need to clear the routes cache here! // diff --git a/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs index 019be66b15..13edcb3b68 100644 --- a/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/LanguageCacheRefresher.cs @@ -28,13 +28,13 @@ namespace Umbraco.Web.Cache public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } } diff --git a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs index a06501032f..6dd8aa9805 100644 --- a/src/Umbraco.Web/Cache/MacroCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MacroCacheRefresher.cs @@ -176,7 +176,7 @@ namespace Umbraco.Web.Cache prefix => ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(prefix)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.RefreshAll(); } @@ -191,7 +191,11 @@ namespace Umbraco.Web.Cache alias => ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(alias)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + var macroRepoCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (macroRepoCache) + { + macroRepoCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + } }); base.Refresh(jsonPayload); diff --git a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs index dce512b1dc..a0e037e110 100644 --- a/src/Umbraco.Web/Cache/MediaCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MediaCacheRefresher.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web.Cache public class MediaCacheRefresher : JsonCacheRefresherBase { #region Static helpers - + /// /// Converts the json to a JsonPayload object /// @@ -143,13 +143,13 @@ namespace Umbraco.Web.Cache } public override void Remove(int id) - { + { ClearCache(FromMedia(ApplicationContext.Current.Services.MediaService.GetById(id), //NOTE: we'll just default to trashed for this one. OperationType.Trashed)); base.Remove(id); } - + private static void ClearCache(params JsonPayload[] payloads) { if (payloads == null) return; @@ -159,40 +159,40 @@ namespace Umbraco.Web.Cache ApplicationContext.Current.ApplicationCache.ClearPartialViewCache(); payloads.ForEach(payload => + { + var mediaCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + + //if there's no path, then just use id (this will occur on permanent deletion like emptying recycle bin) + if (payload.Path.IsNullOrWhiteSpace()) { - - //if there's no path, then just use id (this will occur on permanent deletion like emptying recycle bin) - if (payload.Path.IsNullOrWhiteSpace()) + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( + string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); + } + else + { + foreach (var idPart in payload.Path.Split(',')) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); - } - else - { - foreach (var idPart in payload.Path.Split(',')) + int idPartAsInt; + if (int.TryParse(idPart, out idPartAsInt) && mediaCache) { - int idPartAsInt; - if (int.TryParse(idPart, out idPartAsInt)) - { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem( - RepositoryBase.GetCacheIdKey(idPartAsInt)); - } + mediaCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(idPartAsInt)); + } + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( + string.Format("{0}_{1}_True", CacheKeys.MediaCacheKey, idPart)); + + // Also clear calls that only query this specific item! + if (idPart == payload.Id.ToString(CultureInfo.InvariantCulture)) ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}_{1}_True", CacheKeys.MediaCacheKey, idPart)); - - // Also clear calls that only query this specific item! - if (idPart == payload.Id.ToString(CultureInfo.InvariantCulture)) - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch( - string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); - } + string.Format("{0}_{1}", CacheKeys.MediaCacheKey, payload.Id)); } + } + + // published cache... + PublishedMediaCache.ClearCache(payload.Id); + }); - // published cache... - PublishedMediaCache.ClearCache(payload.Id); - }); - } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs index a0167454a5..32e6a69717 100644 --- a/src/Umbraco.Web/Cache/MemberCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberCacheRefresher.cs @@ -69,7 +69,9 @@ namespace Umbraco.Web.Cache ApplicationContext.Current.ApplicationCache.RuntimeCache. ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.MemberBusinessLogicCacheKey, id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + var memberCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (memberCache) + memberCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs index e410ab560c..dc2ba39b9d 100644 --- a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs @@ -104,13 +104,13 @@ namespace Umbraco.Web.Cache { if (payloads == null) return; + var memberGroupCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); payloads.ForEach(payload => { - if (payload != null) + if (payload != null && memberGroupCache) { - ApplicationContext.Current.ApplicationCache.RuntimeCache - .ClearCacheByKeySearch(string.Format("{0}.{1}", typeof(IMemberGroup).FullName, payload.Name)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + memberGroupCache.Result.ClearCacheByKeySearch(string.Format("{0}.{1}", typeof(IMemberGroup).FullName, payload.Name)); + memberGroupCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); } }); diff --git a/src/Umbraco.Web/Cache/PageCacheRefresher.cs b/src/Umbraco.Web/Cache/PageCacheRefresher.cs index 73f525383e..8461f57d64 100644 --- a/src/Umbraco.Web/Cache/PageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/PageCacheRefresher.cs @@ -76,7 +76,7 @@ namespace Umbraco.Web.Cache content.Instance.ClearDocumentCache(id); DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } @@ -86,7 +86,7 @@ namespace Umbraco.Web.Cache content.Instance.UpdateDocumentCache(new Document(instance)); DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(instance); } @@ -96,7 +96,7 @@ namespace Umbraco.Web.Cache content.Instance.ClearDocumentCache(new Document(instance)); DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer(); DistributedCache.Instance.ClearXsltCacheOnCurrentServer(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(instance); } } diff --git a/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs b/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs index 09b38f1ac3..77d7314941 100644 --- a/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/PublicAccessCacheRefresher.cs @@ -27,25 +27,25 @@ namespace Umbraco.Web.Cache public override void Refresh(Guid id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Refresh(id); } public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.RefreshAll(); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } } diff --git a/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs b/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs index 5d98671a76..959a937e7b 100644 --- a/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/StylesheetCacheRefresher.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using Umbraco.Core; using Umbraco.Core.Cache; @@ -7,6 +8,8 @@ namespace Umbraco.Web.Cache /// /// A cache refresher to ensure stylesheet cache is refreshed when stylesheets change /// + [Obsolete("This is no longer used and will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] public sealed class StylesheetCacheRefresher : CacheRefresherBase { protected override StylesheetCacheRefresher Instance @@ -24,27 +27,5 @@ namespace Umbraco.Web.Cache get { return "Stylesheet cache refresher"; } } - public override void RefreshAll() - { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.StylesheetCacheKey); - base.RefreshAll(); - } - - public override void Refresh(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetCacheKey(id)); - base.Refresh(id); - } - - public override void Remove(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetCacheKey(id)); - base.Remove(id); - } - - private static string GetStylesheetCacheKey(int id) - { - return CacheKeys.StylesheetCacheKey + id; - } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs b/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs index d7006c8531..5b72e0384b 100644 --- a/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/StylesheetPropertyCacheRefresher.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using Umbraco.Core; using Umbraco.Core.Cache; @@ -7,6 +8,8 @@ namespace Umbraco.Web.Cache /// /// A cache refresher to ensure stylesheet property cache is refreshed when stylesheet properties change /// + [Obsolete("This is no longer used and will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] public sealed class StylesheetPropertyCacheRefresher : CacheRefresherBase { protected override StylesheetPropertyCacheRefresher Instance @@ -23,28 +26,6 @@ namespace Umbraco.Web.Cache { get { return "Stylesheet property cache refresher"; } } - - public override void RefreshAll() - { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.StylesheetPropertyCacheKey); - base.RefreshAll(); - } - - public override void Refresh(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetPropertyCacheKey(id)); - base.Refresh(id); - } - - public override void Remove(int id) - { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(GetStylesheetPropertyCacheKey(id)); - base.Remove(id); - } - - private static string GetStylesheetPropertyCacheKey(int id) - { - return CacheKeys.StylesheetPropertyCacheKey + id; - } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs index 22bce3d5bf..12988e921c 100644 --- a/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/TemplateCacheRefresher.cs @@ -52,8 +52,8 @@ namespace Umbraco.Web.Cache // all three of these types are referenced by templates, and the cache needs to be cleared on every server, // otherwise things like looking up content type's after a template is removed is still going to show that // it has an associated template. - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); base.Remove(id); } @@ -66,7 +66,7 @@ namespace Umbraco.Web.Cache string.Format("{0}{1}", CacheKeys.TemplateFrontEndCacheKey, id)); //need to clear the runtime cache for templates - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); } } diff --git a/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs b/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs index e3601188f4..d4efcb96c7 100644 --- a/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs @@ -77,16 +77,16 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); + ClearAllCacheByRepositoryEntityType(); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.RefreshAll(); } public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(id); + ClearAllCacheByRepositoryEntityType(); content.Instance.UpdateSortOrder(id); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Refresh(id); @@ -94,8 +94,8 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(id); + ClearAllCacheByRepositoryEntityType(); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Remove(id); } @@ -103,8 +103,8 @@ namespace Umbraco.Web.Cache public override void Refresh(IContent instance) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(instance.Id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(instance.Id); + ClearAllCacheByRepositoryEntityType(); content.Instance.UpdateSortOrder(instance); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Refresh(instance); @@ -112,8 +112,8 @@ namespace Umbraco.Web.Cache public override void Remove(IContent instance) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(instance.Id)); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearRepositoryCacheItemById(instance.Id); + ClearAllCacheByRepositoryEntityType(); DistributedCache.Instance.ClearDomainCacheOnCurrentServer(); base.Remove(instance); } @@ -124,11 +124,11 @@ namespace Umbraco.Web.Cache /// public void Refresh(string jsonPayload) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); foreach (var payload in DeserializeFromJsonPayload(jsonPayload)) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id)); + ClearRepositoryCacheItemById(payload.Id); content.Instance.UpdateSortOrder(payload.Id); } @@ -136,6 +136,15 @@ namespace Umbraco.Web.Cache OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson)); } + + private void ClearRepositoryCacheItemById(int id) + { + var contentCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (contentCache) + { + contentCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/UserCacheRefresher.cs b/src/Umbraco.Web/Cache/UserCacheRefresher.cs index 95a7fdac49..7efbef5f9a 100644 --- a/src/Umbraco.Web/Cache/UserCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserCacheRefresher.cs @@ -30,9 +30,9 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.UserContextCacheKey); + ClearAllCacheByRepositoryEntityType(); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); base.RefreshAll(); } @@ -44,16 +44,20 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); - - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); - - //we need to clear all UserContextCacheKey since we cannot invalidate based on ID since the cache is done so based - //on the current contextId stored in the database - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.UserContextCacheKey); + var userCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (userCache) + userCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); + base.Remove(id); } + private Attempt UserPermissionsCache + { + get { return ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs index db1baf1bcd..64744024ed 100644 --- a/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserPermissionsCacheRefresher.cs @@ -1,6 +1,7 @@ using System; using Umbraco.Core; using Umbraco.Core.Cache; +using Umbraco.Core.Models.Membership; namespace Umbraco.Web.Cache { @@ -31,7 +32,8 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheByKeySearch(CacheKeys.UserPermissionsCacheKey); base.RefreshAll(); } @@ -43,8 +45,14 @@ namespace Umbraco.Web.Cache public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); + if (UserPermissionsCache) + UserPermissionsCache.Result.ClearCacheItem(string.Format("{0}{1}", CacheKeys.UserPermissionsCacheKey, id)); base.Remove(id); } + + private Attempt UserPermissionsCache + { + get { return ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs index 2beaa4347d..d67865a188 100644 --- a/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs +++ b/src/Umbraco.Web/Cache/UserTypeCacheRefresher.cs @@ -29,19 +29,23 @@ namespace Umbraco.Web.Cache public override void RefreshAll() { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheObjectTypes(); + ClearAllCacheByRepositoryEntityType(); base.RefreshAll(); } public override void Refresh(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + var userTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (userTypeCache) + userTypeCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); base.Refresh(id); } public override void Remove(int id) { - ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); + var userTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache(); + if (userTypeCache) + userTypeCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(id)); base.Remove(id); } diff --git a/src/Umbraco.Web/CacheHelperExtensions.cs b/src/Umbraco.Web/CacheHelperExtensions.cs index f23bb6d070..1b0451a999 100644 --- a/src/Umbraco.Web/CacheHelperExtensions.cs +++ b/src/Umbraco.Web/CacheHelperExtensions.cs @@ -58,7 +58,7 @@ namespace Umbraco.Web /// public static void ClearPartialViewCache(this CacheHelper cacheHelper) { - cacheHelper.ClearCacheByKeySearch(PartialViewCacheKey); + cacheHelper.RuntimeCache.ClearCacheByKeySearch(PartialViewCacheKey); } } } diff --git a/src/Umbraco.Web/Media/ImageUrl.cs b/src/Umbraco.Web/Media/ImageUrl.cs index 8f56d8bfa4..dff9358a38 100644 --- a/src/Umbraco.Web/Media/ImageUrl.cs +++ b/src/Umbraco.Web/Media/ImageUrl.cs @@ -87,7 +87,7 @@ namespace Umbraco.Web.Media private static object GetContentFromCache(int nodeIdInt, string field) { - var content = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var content = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt.ToString(CultureInfo.InvariantCulture), field)); return content; } diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index 23e44896f4..0bee9e631a 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -297,7 +297,7 @@ namespace umbraco ClearContextCache(); var cachedFieldKeyStart = string.Format("{0}{1}_", CacheKeys.ContentItemCacheKey, d.Id); - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(cachedFieldKeyStart); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(cachedFieldKeyStart); FireAfterUpdateDocumentCache(d, e); } diff --git a/src/Umbraco.Web/umbraco.presentation/library.cs b/src/Umbraco.Web/umbraco.presentation/library.cs index cbfdafc56a..d9b1d520ed 100644 --- a/src/Umbraco.Web/umbraco.presentation/library.cs +++ b/src/Umbraco.Web/umbraco.presentation/library.cs @@ -493,11 +493,11 @@ namespace umbraco { if (UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration > 0) { - var xml = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var xml = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( string.Format( "{0}_{1}_{2}", CacheKeys.MediaCacheKey, MediaId, Deep), - TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), - () => GetMediaDo(MediaId, Deep)); + timeout: TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), + getCacheItem: () => GetMediaDo(MediaId, Deep)); if (xml != null) { @@ -552,11 +552,11 @@ namespace umbraco { if (UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration > 0) { - var xml = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var xml = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( string.Format( "{0}_{1}", CacheKeys.MemberLibraryCacheKey, MemberId), - TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), - () => GetMemberDo(MemberId)); + timeout: TimeSpan.FromSeconds(UmbracoConfig.For.UmbracoSettings().Content.UmbracoLibraryCacheDuration), + getCacheItem: () => GetMemberDo(MemberId)); if (xml != null) { diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs index e14cef4eb1..66ba6fea15 100644 --- a/src/Umbraco.Web/umbraco.presentation/macro.cs +++ b/src/Umbraco.Web/umbraco.presentation/macro.cs @@ -571,11 +571,11 @@ namespace umbraco } //insert the cache string result - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( CacheKeys.MacroHtmlCacheKey + Model.CacheIdentifier, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => outputCacheString); + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, Model.CacheDuration), + getCacheItem: () => outputCacheString); dateAddedCacheKey = CacheKeys.MacroHtmlDateAddedCacheKey + Model.CacheIdentifier; @@ -590,11 +590,11 @@ namespace umbraco else { //insert the cache control result - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( CacheKeys.MacroControlCacheKey + Model.CacheIdentifier, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => new MacroCacheContent(macroControl, macroControl.ID)); + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, Model.CacheDuration), + getCacheItem: () => new MacroCacheContent(macroControl, macroControl.ID)); dateAddedCacheKey = CacheKeys.MacroControlDateAddedCacheKey + Model.CacheIdentifier; @@ -603,11 +603,11 @@ namespace umbraco } //insert the date inserted (so we can check file modification date) - ApplicationContext.Current.ApplicationCache.InsertCacheItem( + ApplicationContext.Current.ApplicationCache.RuntimeCache.InsertCacheItem( dateAddedCacheKey, - CacheItemPriority.NotRemovable, - new TimeSpan(0, 0, Model.CacheDuration), - () => DateTime.Now); + priority: CacheItemPriority.NotRemovable, + timeout: new TimeSpan(0, 0, Model.CacheDuration), + getCacheItem: () => DateTime.Now); } @@ -640,7 +640,7 @@ namespace umbraco if (CacheMacroAsString(Model)) { - macroHtml = ApplicationContext.Current.ApplicationCache.GetCacheItem( + macroHtml = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( CacheKeys.MacroHtmlCacheKey + Model.CacheIdentifier); // FlorisRobbemont: @@ -666,7 +666,7 @@ namespace umbraco } else { - var cacheContent = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var cacheContent = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem( CacheKeys.MacroControlCacheKey + Model.CacheIdentifier); if (cacheContent != null) @@ -730,7 +730,7 @@ namespace umbraco { if (MacroIsFileBased(model)) { - var cacheResult = ApplicationContext.Current.ApplicationCache.GetCacheItem(dateAddedKey); + var cacheResult = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem(dateAddedKey); if (cacheResult != null) { @@ -864,7 +864,7 @@ namespace umbraco [Obsolete("This is no longer used in the codebase and will be removed in future versions")] public static void unloadXslt(string XsltFile) { - ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(CacheKeys.MacroXsltCacheKey + XsltFile); + ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.MacroXsltCacheKey + XsltFile); } #region LoadMacroXslt diff --git a/src/Umbraco.Web/umbraco.presentation/template.cs b/src/Umbraco.Web/umbraco.presentation/template.cs index 6c1e23a13e..dfdad324e2 100644 --- a/src/Umbraco.Web/umbraco.presentation/template.cs +++ b/src/Umbraco.Web/umbraco.presentation/template.cs @@ -494,7 +494,7 @@ namespace umbraco { var tId = templateID; - var t = ApplicationContext.Current.ApplicationCache.GetCacheItem( + var t = ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem