diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6ef293c3..ed3595ae 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,8 +1,10 @@ This project is governed by a [Code of Conduct](CODE_OF_CONDUCT.md). -First, before writing any code, [please open an issue](https://github.com/leekelleher/umbraco-contentment/issues), let's have a discussion about any features or ideas that you may have. +### General gist -Once the feature or idea is fleshed out, let's hack! +First, before writing any code, [please open an issue](https://github.com/leekelleher/umbraco-contentment/issues), or [let's have a discussion](https://github.com/leekelleher/umbraco-contentment/discussions) about any features or ideas that you may have. + +Once the feature or idea is fleshed out, it's hacking time! 1. Fork it 2. Branch it @@ -15,7 +17,18 @@ Once the feature or idea is fleshed out, let's hack! > The above is respectively taken from the [Clearwater framework repository](https://github.com/clearwater-rb/clearwater/blob/master/README.md#contributing).
> Kudos to [Jamie Gaskins](https://github.com/jgaskins) for framing the guidelines so succinctly. ---- -Further reading, I've been thinking a lot about Jeff Geerling's post ["Why I close PRs (OSS project maintainer notes)"](https://www.jeffgeerling.com/blog/2016/why-i-close-prs-oss-project-maintainer-notes) lately. If you do submit a PR and feel that I'm closing it down, this is probably the rationale behind it. +### Branching information + +Given there are now multiple versions of Contentment that support multiple versions of Umbraco, please make note of the branching structure. + +- The main [`develop`](https://github.com/leekelleher/umbraco-contentment/tree/develop) branch is where the latest work happens. This defaults to the most recent version of Contentment, (at the time of writing, this is v3.x). +- The [`dev/v1.x`](https://github.com/leekelleher/umbraco-contentment/tree/dev/v1.x) branch is for Contentment **v1.4.x** patch releases, this targets Umbraco **v8.6.1**. +- The [`dev/v2.x`](https://github.com/leekelleher/umbraco-contentment/tree/dev/v2.x) branch is for Contentment **v2.2.x** patch releases, this targets Umbraco **v8.14.0**. +- The [`dev/v3.x`](https://github.com/leekelleher/umbraco-contentment/tree/dev/v3.x) branch is for Contentment **v3.x** (current) releases, this targets both Umbraco **v8.17.0** and **v9.0.0**. + + +### Further reading + +I've been thinking a lot about Jeff Geerling's post ["Why I close PRs (OSS project maintainer notes)"](https://www.jeffgeerling.com/blog/2016/why-i-close-prs-oss-project-maintainer-notes) lately. If you do submit a PR and feel that I'm closing down the conversation, this is most likely the rationale behind it. diff --git a/.github/README.md b/.github/README.md index 6c4bc748..cd4c1416 100644 --- a/.github/README.md +++ b/.github/README.md @@ -46,11 +46,11 @@ Downloads are available on the [releases page](https://github.com/leekelleher/um _**Please note...**_ -- v3.x has been developed against **Umbraco v9.0-RC001** and will support that version and above. -- v2.x has been developed against **Umbraco v8.14.0** and will support that and future Umbraco v8.x releases. +- v3.x has been developed against **Umbraco v8.17.0** and **Umbraco v9.0.0** and will support those versions and above. +- v2.x has been developed against **Umbraco v8.14.0** and it will still work on current Umbraco v8.x releases. - v1.x has been developed against **Umbraco v8.6.1**, it will still work on current Umbraco v8.x releases. -With Contentment v3.x (Umbraco v9.0 / .NET 5), you can only install a package from the [NuGet package repository](https://www.nuget.org/packages/Our.Umbraco.Community.Contentment). For previous Contentment versions, the package can be installed from either [Our Umbraco](https://our.umbraco.com/packages/backoffice-extensions/contentment/) or NuGet package repositories, or build manually from the source-code: +With Contentment v3.x on Umbraco v9.0 (.NET 5), you can only install a package from the [NuGet package repository](https://www.nuget.org/packages/Our.Umbraco.Community.Contentment). For Umbraco v8.x, the package can still be installed from either [Our Umbraco](https://our.umbraco.com/packages/backoffice-extensions/contentment/) or NuGet package repositories. ##### NuGet package repository @@ -58,9 +58,13 @@ To [install from NuGet](https://www.nuget.org/packages/Our.Umbraco.Community.Con PM> Install-Package Our.Umbraco.Community.Contentment +...or if you are using the `dotnet` command line interface? + + dotnet add package Our.Umbraco.Community.Contentment + ##### Our Umbraco package repository -For Contentment v1.x and v2.x, you can install from Our Umbraco, please download the package from: +If you are using Umbraco v8.x, and prefer to install Contentment from the backoffice, the package can be downloaded from the Our Umbraco package repository: > @@ -69,6 +73,7 @@ For Contentment v1.x and v2.x, you can install from Our Umbraco, please download - **Data List** - When using the Umbraco Content data source with an XPath query, inside a Nested Content editor, it will not be able to identify the contextual containing node ID. e.g. your XPath query will not work. [See #30 for details.](https://github.com/leekelleher/umbraco-contentment/issues/30) - When using the Umbraco Content data source with an XPath query that contains a `$` prefix parameter, the preview will not display the items. [See #120 for details.](https://github.com/leekelleher/umbraco-contentment/issues/120) + - With Umbraco v9 (Contentment v3), SQL data source does not support querying SQL CE. [See #172 for details.]() ### Documentation @@ -135,7 +140,7 @@ For more information about the Mozilla Public License, please visit: -Current development effort: 1050+ hours (between 2019-03-13 to 2021-07-09) +Current development effort: 1097+ hours (between 2019-03-13 to 2021-10-15) _To give you an idea of how much human developer time/effort has been put into making this package._ diff --git a/.github/ROADMAP.md b/.github/ROADMAP.md index e7d46df2..ba2d658a 100644 --- a/.github/ROADMAP.md +++ b/.github/ROADMAP.md @@ -60,16 +60,16 @@ Property Editors are: - [Templated Label](https://github.com/leekelleher/umbraco-contentment/discussions/100) -### v2.3 - -- [Data List: Groups](https://github.com/leekelleher/umbraco-contentment/discussions/90) - ## v3 ### v3.0 -- A breaking-change release of latest v2.x features that compiles against Umbraco CMS v9.0 (.NET 5). +- _Under active development!_ [See my developer's journal for the latest updates.](https://github.com/leekelleher/umbraco-contentment/discussions/105) A breaking-change release _(following SemVer guidelines),_ of v2.x features that will compile against both Umbraco v8.17 and v9.0. + +### v3.1 + +- [Data List: Groups](https://github.com/leekelleher/umbraco-contentment/discussions/90) ## Future feature releases diff --git a/.gitignore b/.gitignore index b554183f..6f8d0fa5 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,5 @@ build/assets/ src/packages/*/** /tools/*.exe /build/__umb/* -/build/__nuget/* /build/build-push-nuget.ps1 /build/build-push-umb.ps1 diff --git a/VERSION b/VERSION index fae692e4..56fea8a0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.1 \ No newline at end of file +3.0.0 \ No newline at end of file diff --git a/build/_nuget-post-install.targets b/build/_nuget-post-install.targets new file mode 100644 index 00000000..605dc9dd --- /dev/null +++ b/build/_nuget-post-install.targets @@ -0,0 +1,35 @@ + + + + + $(MSBuildThisFileDirectory)..\content\App_Plugins\Contentment\**\*.* + + + + + + + + + + + + + + + + + + + diff --git a/build/build-assets.ps1 b/build/build-assets.ps1 index 914bb28c..4d7e5bb3 100644 --- a/build/build-assets.ps1 +++ b/build/build-assets.ps1 @@ -4,26 +4,27 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. param( - [string]$SolutionDir, + [string]$TargetFramework, [string]$TargetDir, [string]$ProjectName, [string]$ProjectDir, [string]$ConfigurationName ); -. "${SolutionDir}_vars.ps1"; +$rootDir = "${ProjectDir}..\.."; +. "${rootDir}\src\_vars.ps1"; Write-Host $ConfigurationName; if ($ConfigurationName -eq 'Debug') { - Write-Host $SolutionDir; + Write-Host $TargetFramework; Write-Host $TargetDir; Write-Host $ProjectName; Write-Host $ProjectDir; Write-Host $TargetDevWebsite; } -$targetFolder = "${SolutionDir}..\build\assets"; +$targetFolder = "${rootDir}\build\assets"; # If it already exists, delete it if (Test-Path -Path $targetFolder) { @@ -32,9 +33,11 @@ if (Test-Path -Path $targetFolder) { # Copy DLL / PDB $binFolder = "${targetFolder}\bin"; - if (!(Test-Path -Path $binFolder)) {New-Item -Path $binFolder -Type Directory;} -Copy-Item -Path "${TargetDir}${ProjectName}.*" -Destination $binFolder; +Copy-Item -Path "${ProjectDir}\bin\${ConfigurationName}\net472\${ProjectName}.*" -Destination $binFolder; +$net50Folder = "${targetFolder}\net50"; +if (!(Test-Path -Path $net50Folder)) {New-Item -Path $net50Folder -Type Directory;} +Copy-Item -Path "${ProjectDir}\bin\${ConfigurationName}\net50\${ProjectName}.*" -Destination $net50Folder; # Copy package front-end files assets $pluginFolder = "${targetFolder}\App_Plugins\Contentment\"; @@ -61,14 +64,14 @@ foreach($razorFile in $razorFiles){ # CSS - Bundle & Minify $targetCssPath = "${pluginFolder}contentment.css"; Get-Content -Raw -Path "${ProjectDir}**\**\*.css" | Set-Content -Encoding UTF8 -Path $targetCssPath; -& "${SolutionDir}..\tools\AjaxMinifier.exe" $targetCssPath -o $targetCssPath +& "${rootDir}\tools\AjaxMinifier.exe" $targetCssPath -o $targetCssPath # JS - Bundle & Minify $targetJsPath = "${pluginFolder}contentment.js"; Get-Content -Raw -Path "${ProjectDir}**\**\*.js" | Set-Content -Encoding UTF8 -Path $targetJsPath; -& "${SolutionDir}..\tools\AjaxMinifier.exe" $targetJsPath -o $targetJsPath +& "${rootDir}\tools\AjaxMinifier.exe" $targetJsPath -o $targetJsPath # In debug mode, copy the assets over to the local dev website if ($ConfigurationName -eq 'Debug' -AND -NOT($TargetDevWebsite -eq '')) { - Copy-Item -Path "${targetFolder}\*" -Force -Recurse -Destination $TargetDevWebsite; + Copy-Item -Path "${targetFolder}\*" -Force -Recurse -Destination $TargetDevWebsite | Where { $_.FullName -NotLike "*\net50\*" }; } \ No newline at end of file diff --git a/build/build-pkgs.ps1 b/build/build-pkgs.ps1 index 5d26d696..3c239bf2 100644 --- a/build/build-pkgs.ps1 +++ b/build/build-pkgs.ps1 @@ -10,14 +10,14 @@ $nugetPackageId = 'Our.Umbraco.Community.Contentment'; $projectNamespace = 'Umbraco.Community.Contentment'; $packageName = 'Contentment'; $nugetTitle = "${packageName} for Umbraco"; -$packageDescription = "${packageName}, a collection of components for Umbraco 8."; +$packageDescription = "${packageName}, a collection of components for Umbraco."; $packageUrl = 'https://github.com/leekelleher/umbraco-contentment'; $iconUrl = 'https://raw.githubusercontent.com/leekelleher/umbraco-contentment/master/docs/assets/img/logo.png'; $licenseName = 'Mozilla Public License Version 2.0'; $licenseUrl = 'https://mozilla.org/MPL/2.0/'; $authorName = 'Lee Kelleher'; $authorUrl = 'https://leekelleher.com/'; -$minUmbracoVersion = 8,14,0; +$minUmbracoVersion = 8,17,0; $copyright = "Copyright " + [char]0x00A9 + " " + (Get-Date).year + " $authorName"; $tags = "umbraco"; @@ -81,7 +81,7 @@ $umbracoPackageXml.umbPackage.info.readme."#cdata-section" = $packageDescription $filesXml = $umbracoPackageXml.CreateElement("files"); -$assetFiles = Get-ChildItem -Path $assetsFolder -File -Recurse; +$assetFiles = Get-ChildItem -Path $assetsFolder -File -Recurse | Where { $_.FullName -NotLike "*\net50\*" }; foreach($assetFile in $assetFiles){ $hash = Get-FileHash -Path $assetFile.FullName -Algorithm MD5; @@ -106,8 +106,9 @@ Compress-Archive -Path "${umbFolder}\*" -DestinationPath "${artifactsFolder}\Con # Populate the NuGet package manifest Copy-Item -Path "${rootFolder}\docs\assets\img\logo.png" -Destination "${assetsFolder}\icon.png"; -& $nuget_exe pack "${buildFolder}\manifest-nuget-core.nuspec" -BasePath $assetsFolder -OutputDirectory $artifactsFolder -Version "$version" -Properties "id=$nugetPackageId;version=$version;title=$nugetTitle;authors=$authorName;owners=$authorName;projectUrl=$packageUrl;requireLicenseAcceptance=false;description=$packageDescription;copyright=$copyright;license=MPL-2.0;language=en;tags=$tags;minUmbracoVersion=$($minUmbracoVersion[0]).$($minUmbracoVersion[1]).$($minUmbracoVersion[2]);repositoryUrl=$packageUrl;" -& $nuget_exe pack "${buildFolder}\manifest-nuget-web.nuspec" -BasePath $assetsFolder -OutputDirectory $artifactsFolder -Version "$version" -Properties "id=$nugetPackageId;version=$version;title=$nugetTitle;authors=$authorName;owners=$authorName;projectUrl=$packageUrl;requireLicenseAcceptance=false;description=$packageDescription;copyright=$copyright;license=MPL-2.0;language=en;tags=$tags;minUmbracoVersion=$($minUmbracoVersion[0]).$($minUmbracoVersion[1]).$($minUmbracoVersion[2]);repositoryUrl=$packageUrl;" +Copy-Item -Path "${buildFolder}\_nuget-post-install.targets" -Destination "${assetsFolder}\${nugetPackageId}.targets"; +& $nuget_exe pack "${buildFolder}\manifest-nuget-core.nuspec" -BasePath $assetsFolder -OutputDirectory $artifactsFolder -Version "$version" -Properties "id=$nugetPackageId;version=$version;title=$nugetTitle;authors=$authorName;owners=$authorName;projectUrl=$packageUrl;requireLicenseAcceptance=false;description=$packageDescription;copyright=$copyright;license=MPL-2.0;language=en;tags=$tags;repositoryUrl=$packageUrl;" +& $nuget_exe pack "${buildFolder}\manifest-nuget-web.nuspec" -BasePath $assetsFolder -OutputDirectory $artifactsFolder -Version "$version" -Properties "id=$nugetPackageId;version=$version;title=$nugetTitle;authors=$authorName;owners=$authorName;projectUrl=$packageUrl;requireLicenseAcceptance=false;description=$packageDescription;copyright=$copyright;license=MPL-2.0;language=en;tags=$tags;repositoryUrl=$packageUrl;" # Tidy up folders diff --git a/build/manifest-nuget-core.nuspec b/build/manifest-nuget-core.nuspec index ecfd2a75..cdfd481c 100644 --- a/build/manifest-nuget-core.nuspec +++ b/build/manifest-nuget-core.nuspec @@ -17,13 +17,17 @@ - - + + + + + - + + \ No newline at end of file diff --git a/build/manifest-nuget-web.nuspec b/build/manifest-nuget-web.nuspec index 1ad4282c..80edfb9c 100644 --- a/build/manifest-nuget-web.nuspec +++ b/build/manifest-nuget-web.nuspec @@ -21,6 +21,7 @@ + \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index f7a757cf..d0fda2fe 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,3 +38,6 @@ If you are unfamiliar with how to do this, then please refer to documentation, g Information about Contentment's [telemetry feature](../docs/telemetry.md). +#### Tree Dashboard + +Information about Contentment's [tree dashboard](../docs/tree-dashboard.md). diff --git a/docs/telemetry.md b/docs/telemetry.md index bbea8855..5f98a60a 100644 --- a/docs/telemetry.md +++ b/docs/telemetry.md @@ -35,6 +35,12 @@ For information about the data and analysis, please go to: { opts.DisableTelemetry = true; })` extension method in your `Startup.cs` file `ConfigureServices()` method. diff --git a/docs/tree-dashboard.md b/docs/tree-dashboard.md new file mode 100644 index 00000000..b01785c7 --- /dev/null +++ b/docs/tree-dashboard.md @@ -0,0 +1,53 @@ +Contentment for Umbraco logo + +## Contentment for Umbraco + +### Tree Dashboard + +By default, the package will display a Contentment tree item in the Settings section. Currently, this is used for promotional purposes, to give information about the package itself, newsletter sign-up, etc. + + +#### Disable tree dashboard + +If you would prefer to disable the tree dashboard completely, you can use this code snippet to disable it. + +##### For Umbraco v8 + +Code snippet to disable Contentment tree dashboard. + +Copy the C# class below. You can either save this to your `~/App_Code/` folder, or add it to your own code library. + +```csharp +using Umbraco.Core.Composing; + +namespace Our.Umbraco.Web +{ + public class DisableContentmentTreeComposer : IUserComposer + { + public void Compose(Composition composition) + { + composition.DisableContentmentTree(); + } + } +} +``` + +If you already have your own composer class, you can add the `composition.DisableContentmentTree();` line to it. + +##### For Umbraco v9+ + +Configuration to disable Contentment tree dashboard. + +In your `appsettings.json` file, add this option inside the `"Umbraco"` section, add the following. + +```json +{ + "Umbraco": { + "Contentment": { + "DisableTree": true + } + } +} +``` + +If you prefer to use a strongly-typed configuration in C# code, you can do this with the `.AddContentment(opts => { opts.DisableTree = true; })` extension method in your `Startup.cs` file `ConfigureServices()` method. diff --git a/src/.editorconfig b/src/.editorconfig index 8380e946..c548ed93 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -1,5 +1,5 @@ # This .editorconfig has been taken from Umbraco CMS, licensed under MIT. -# https://github.com/umbraco/Umbraco-CMS/blob/release-8.1.0/.editorconfig +# https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v9/dev/.editorconfig # top-most EditorConfig file root = true @@ -26,6 +26,7 @@ dotnet_naming_rule.private_members_with_underscore.severity = suggestion dotnet_naming_symbols.private_fields.applicable_kinds = field dotnet_naming_symbols.private_fields.applicable_accessibilities = private +# dotnet_naming_symbols.private_fields.required_modifiers = abstract,async,readonly,static # all except const dotnet_naming_style.prefix_underscore.capitalization = camel_case dotnet_naming_style.prefix_underscore.required_prefix = _ @@ -37,5 +38,8 @@ csharp_style_var_when_type_is_apparent = true:suggestion csharp_style_var_elsewhere = true:suggestion csharp_prefer_braces = false : none -[*.{js,less}] +[*.js] +trim_trailing_whitespace = true + +[*.less] trim_trailing_whitespace = false diff --git a/src/Umbraco.Community.Contentment.sln b/src/Umbraco.Community.Contentment.sln index 1e4d5b16..fa3ff480 100644 --- a/src/Umbraco.Community.Contentment.sln +++ b/src/Umbraco.Community.Contentment.sln @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{5297EC84-5180-4489-B642-E3453B51330F}" ProjectSection(SolutionItems) = preProject + ..\build\_nuget-post-install.targets = ..\build\_nuget-post-install.targets ..\build\build-assets.ps1 = ..\build\build-assets.ps1 ..\build\build-pkgs.ps1 = ..\build\build-pkgs.ps1 ..\build\manifest-nuget-core.nuspec = ..\build\manifest-nuget-core.nuspec @@ -37,6 +38,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentat ProjectSection(SolutionItems) = preProject ..\docs\README.md = ..\docs\README.md ..\docs\telemetry.md = ..\docs\telemetry.md + ..\docs\tree-dashboard.md = ..\docs\tree-dashboard.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Editors", "Editors", "{A5294B30-2ED5-4BBA-A2DE-A07103DAE78F}" diff --git a/src/Umbraco.Community.Contentment/Composing/CompositionExtensions.cs b/src/Umbraco.Community.Contentment/Composing/CompositionExtensions.cs index e82dc4d1..618974a9 100644 --- a/src/Umbraco.Community.Contentment/Composing/CompositionExtensions.cs +++ b/src/Umbraco.Community.Contentment/Composing/CompositionExtensions.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Community.Contentment.Composing; // NOTE: This extension method class is deliberately using the Umbraco namespace, @@ -23,3 +24,4 @@ public static Composition UnlockContentment(this Composition composition) } } } +#endif diff --git a/src/Umbraco.Community.Contentment/Composing/ContentmentComponent.cs b/src/Umbraco.Community.Contentment/Composing/ContentmentComponent.cs index 9601f668..02533227 100644 --- a/src/Umbraco.Community.Contentment/Composing/ContentmentComponent.cs +++ b/src/Umbraco.Community.Contentment/Composing/ContentmentComponent.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System.Collections.Generic; using Umbraco.Community.Contentment.Migrations; using Umbraco.Core; @@ -13,9 +14,19 @@ using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Web.JavaScript; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Migrations; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Infrastructure.Migrations.Upgrade; +using Umbraco.Community.Contentment.Migrations; +#endif namespace Umbraco.Community.Contentment.Composing { +#if NET472 internal sealed class ContentmentComponent : IComponent { private readonly IScopeProvider _scopeProvider; @@ -55,10 +66,43 @@ private void ServerVariablesParser_Parsing(object sender, Dictionary RuntimeLevel.Install) + { + var upgrader = new Upgrader(new ContentmentPlan()); + upgrader.Execute(_migrationPlanExecutor, _scopeProvider, _keyValueService); + } + } + + public void Terminate() + { } + } +#endif } diff --git a/src/Umbraco.Community.Contentment/Composing/ContentmentComposer.cs b/src/Umbraco.Community.Contentment/Composing/ContentmentComposer.cs index 3518c021..7fbb83df 100644 --- a/src/Umbraco.Community.Contentment/Composing/ContentmentComposer.cs +++ b/src/Umbraco.Community.Contentment/Composing/ContentmentComposer.cs @@ -3,14 +3,25 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Community.Contentment.DataEditors; using Umbraco.Community.Contentment.Telemetry; using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Web.Runtime; +#else +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Community.Contentment.DataEditors; +using Umbraco.Community.Contentment.Notifications; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.Composing { +#if NET472 [ComposeAfter(typeof(WebInitialComposer))] [RuntimeLevel(MinLevel = RuntimeLevel.Boot)] internal sealed class ContentmentComposer : IUserComposer @@ -22,6 +33,8 @@ public void Compose(Composition composition) .Add(() => composition.TypeLoader.GetTypes()) ; + composition.RegisterUnique(); + composition.RegisterUnique(); composition.RegisterUnique(); if (composition.RuntimeState.Level > RuntimeLevel.Install) @@ -41,4 +54,34 @@ public void Compose(Composition composition) } } } +#else + internal sealed class ContentmentComposer : IComposer + { + public void Compose(IUmbracoBuilder builder) + { + builder + .Services + .Configure(builder.Config.GetSection(Constants.Internals.ConfigurationSection)) + ; + + builder + .WithCollectionBuilder() + .Add(() => builder.TypeLoader.GetTypes()) + ; + + builder.Services.AddUnique(); + + builder + .Components() + .Append() + ; + + builder + .AddNotificationHandler() + .AddNotificationHandler() + .AddNotificationHandler() + ; + } + } +#endif } diff --git a/src/Umbraco.Community.Contentment/Composing/ContentmentListItemCollectionBuilder.cs b/src/Umbraco.Community.Contentment/Composing/ContentmentListItemCollectionBuilder.cs index 1687ce14..1e34290b 100644 --- a/src/Umbraco.Community.Contentment/Composing/ContentmentListItemCollectionBuilder.cs +++ b/src/Umbraco.Community.Contentment/Composing/ContentmentListItemCollectionBuilder.cs @@ -7,8 +7,13 @@ using System.Collections.Generic; using System.ComponentModel; using Umbraco.Community.Contentment.DataEditors; +#if NET472 using Umbraco.Core; using Umbraco.Core.Composing; +#else +using Umbraco.Cms.Core.Composing; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.Composing { @@ -23,8 +28,11 @@ public sealed class ContentmentListItemCollectionBuilder public sealed class ContentmentListItemCollection : BuilderCollectionBase { private readonly Dictionary _lookup; - +#if NET472 public ContentmentListItemCollection(IEnumerable items) +#else + public ContentmentListItemCollection(Func> items) +#endif : base(items) { _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/src/Umbraco.Community.Contentment/Composing/UmbracoBuilderExtensions.cs b/src/Umbraco.Community.Contentment/Composing/UmbracoBuilderExtensions.cs new file mode 100644 index 00000000..fc864726 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Composing/UmbracoBuilderExtensions.cs @@ -0,0 +1,36 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 == false +using System; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Community.Contentment; +using Umbraco.Community.Contentment.Composing; + +namespace Umbraco.Extensions +{ + public static partial class UmbracoBuilderExtensions + { + public static IUmbracoBuilder AddContentment( + this IUmbracoBuilder builder, + Action settings = default, + Action listItems = default) + { + if (settings is not null) + { + _ = builder.Services.PostConfigure(settings); + } + + if (listItems is not null) + { + listItems(builder.WithCollectionBuilder()); + } + + return builder; + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Configuration/ContentmentSettings.cs b/src/Umbraco.Community.Contentment/Configuration/ContentmentSettings.cs new file mode 100644 index 00000000..a82588e4 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Configuration/ContentmentSettings.cs @@ -0,0 +1,16 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 == false +namespace Umbraco.Community.Contentment +{ + public class ContentmentSettings + { + public bool DisableTree { get; set; } = false; + + public bool DisableTelemetry { get; set; } = false; + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Configuration/ContentmentVersion.cs b/src/Umbraco.Community.Contentment/Configuration/ContentmentVersion.cs index 25688e59..4e41099b 100644 --- a/src/Umbraco.Community.Contentment/Configuration/ContentmentVersion.cs +++ b/src/Umbraco.Community.Contentment/Configuration/ContentmentVersion.cs @@ -10,10 +10,14 @@ using System; using System.Reflection; +#if NET472 using Semver; using Umbraco.Core; +#else +using Umbraco.Cms.Core.Semver; +#endif -namespace Umbraco.Community.Contentment.Configuration +namespace Umbraco.Community.Contentment { public static class ContentmentVersion { diff --git a/src/Umbraco.Community.Contentment/Constants.cs b/src/Umbraco.Community.Contentment/Constants.cs index 82fa86be..5d13c838 100644 --- a/src/Umbraco.Community.Contentment/Constants.cs +++ b/src/Umbraco.Community.Contentment/Constants.cs @@ -28,6 +28,8 @@ internal static partial class Internals internal const string BackOfficePathRoot = PackagePathRoot + "backoffice/" + TreeAlias + "/"; internal const string TreeAlias = ProjectAlias; + + internal const string ConfigurationSection = "Umbraco:Contentment"; } internal static partial class Conventions @@ -109,7 +111,11 @@ internal static partial class Package public const string LicenseUrl = "https://mozilla.org/MPL/2.0/"; - public static readonly System.Version MinimumSupportedUmbracoVersion = new System.Version(8, 6, 1); +#if NET472 + public static readonly System.Version MinimumSupportedUmbracoVersion = new System.Version(8, 17, 0); +#else + public static readonly System.Version MinimumSupportedUmbracoVersion = new System.Version(9, 0, 0); +#endif public const string RepositoryUrl = "https://github.com/leekelleher/umbraco-contentment"; } diff --git a/src/Umbraco.Community.Contentment/Core/DictionaryExtensions.cs b/src/Umbraco.Community.Contentment/Core/DictionaryExtensions.cs index e9ffae3f..30bc37c1 100644 --- a/src/Umbraco.Community.Contentment/Core/DictionaryExtensions.cs +++ b/src/Umbraco.Community.Contentment/Core/DictionaryExtensions.cs @@ -5,7 +5,11 @@ using System.Collections.Generic; +#if NET472 namespace Umbraco.Core +#else +namespace Umbraco.Extensions +#endif { internal static class DictionaryExtensions { @@ -13,6 +17,11 @@ public static TValueOut GetValueAs(this IDictionary(this TreeCollection collection) + where TController : TreeControllerBase + { + var controllerType = typeof(TController); + var type = typeof(BuilderCollectionBase); + + // https://github.com/umbraco/Umbraco-CMS/blob/release-9.0.0/src/Umbraco.Core/Composing/BuilderCollectionBase.cs#L14 + var field = type.GetField("_items", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance); + if (field == null) + { + return collection; + } + + var trees = (Tree[])field.GetValue(collection); + if (trees == null) + { + return collection; + } + + if (typeof(TreeControllerBase).IsAssignableFrom(controllerType) == false) + { + throw new ArgumentException($"Type {controllerType} does not inherit from {nameof(TreeControllerBase)}."); + } + + var idx = Array.FindIndex(trees, x => x.TreeControllerType == controllerType); + if (idx > -1) + { + var tmp = new Tree[trees.Length - 1]; + + if (idx > 0) + { + Array.Copy(trees, 0, tmp, 0, idx); + } + else + { + Array.Copy(trees, idx + 1, tmp, idx, trees.Length - idx - 1); + } + + field.SetValue(collection, tmp); + } + + return collection; + } + } +} + +#endif diff --git a/src/Umbraco.Community.Contentment/Core/Xml/UmbracoXPathPathSyntaxParser.cs b/src/Umbraco.Community.Contentment/Core/Xml/UmbracoXPathPathSyntaxParser.cs index da52d87c..8d623157 100644 --- a/src/Umbraco.Community.Contentment/Core/Xml/UmbracoXPathPathSyntaxParser.cs +++ b/src/Umbraco.Community.Contentment/Core/Xml/UmbracoXPathPathSyntaxParser.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System; using System.Collections.Generic; using System.Reflection; @@ -32,3 +33,4 @@ public static string ParseXPathQuery( } } } +#endif diff --git a/src/Umbraco.Community.Contentment/DataEditors/Buttons/ButtonsDataListEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/Buttons/ButtonsDataListEditor.cs index 4ac78b4a..76a50cf4 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Buttons/ButtonsDataListEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Buttons/ButtonsDataListEditor.cs @@ -3,10 +3,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System.Collections.Generic; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using UmbConstants = Umbraco.Core.Constants; +#else +using System.Collections.Generic; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -14,7 +24,14 @@ public sealed class ButtonsDataListEditor : IDataListEditor { internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "buttons.html"; - public string Name => "Buttons"; + private readonly IIOHelper _ioHelper; + + public ButtonsDataListEditor(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + + public string Name => "Buttons"; public string Description => "Select multiple values from a group of buttons."; @@ -29,14 +46,14 @@ public sealed class ButtonsDataListEditor : IDataListEditor Key = "defaultIcon", Name = "Default icon", Description = "Select an icon to be displayed as the default icon,
(for when no icon is available).", - View = IOHelper.ResolveUrl("~/umbraco/views/propertyeditors/listview/icon.prevalues.html"), + View = _ioHelper.ResolveRelativeOrVirtualUrl("~/umbraco/views/propertyeditors/listview/icon.prevalues.html"), }, new ConfigurationField { Key = "size", Name = "Size", Description = "Select the button size. By default this is set to 'medium'.", - View = IOHelper.ResolveUrl(RadioButtonListDataListEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] @@ -54,7 +71,7 @@ public sealed class ButtonsDataListEditor : IDataListEditor Key = "labelStyle", Name = "Label style", Description = "Select the style of the button's label.", - View = IOHelper.ResolveUrl(RadioButtonListDataListEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] @@ -80,7 +97,7 @@ public sealed class ButtonsDataListEditor : IDataListEditor public Dictionary DefaultValues => new Dictionary { - { "defaultIcon", Core.Constants.Icons.DefaultIcon }, + { "defaultIcon", UmbConstants.Icons.DefaultIcon }, { "labelStyle", "both" }, }; diff --git a/src/Umbraco.Community.Contentment/DataEditors/Buttons/buttons.js b/src/Umbraco.Community.Contentment/DataEditors/Buttons/buttons.js index bd8b08c9..e16609f5 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Buttons/buttons.js +++ b/src/Umbraco.Community.Contentment/DataEditors/Buttons/buttons.js @@ -87,6 +87,8 @@ angular.module("umbraco").controller("Umbraco.Community.Contentment.DataEditors. function select(item) { + // TODO: [LK] Stop mutating the `items`. Have a `selectedValues` lookup. + item.selected = item.selected === false; $scope.model.value = []; diff --git a/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesConfigurationEditor.cs index 303284da..83e6813f 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesConfigurationEditor.cs @@ -4,8 +4,14 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -16,14 +22,14 @@ internal sealed class BytesConfigurationEditor : ConfigurationEditor internal const string Format = "format"; internal const string Kilo = "kilo"; - public BytesConfigurationEditor() + public BytesConfigurationEditor(IIOHelper ioHelper) { Fields.Add(new ConfigurationField { Key = Kilo, Name = "Kilobytes?", Description = "How many bytes do you prefer in your kilobyte?", - View = IOHelper.ResolveUrl(RadioButtonListDataListEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] @@ -42,7 +48,7 @@ public BytesConfigurationEditor() Key = Decimals, Name = "Decimal places", Description = "How many decimal places would you like?", - View = IOHelper.ResolveUrl("~/umbraco/views/propertyeditors/slider/slider.html"), + View = ioHelper.ResolveRelativeOrVirtualUrl("~/umbraco/views/propertyeditors/slider/slider.html"), Config = new Dictionary { { "initVal1", 2 }, diff --git a/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesDataEditor.cs index d9a0e921..ae186e87 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesDataEditor.cs @@ -3,8 +3,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -23,10 +29,22 @@ public sealed class BytesDataEditor : DataEditor internal const string DataEditorViewPath = "readonlyvalue"; internal const string DataEditorIcon = "icon-binarycode"; - public BytesDataEditor(ILogger logger) + private readonly IIOHelper _ioHelper; + +#if NET472 + public BytesDataEditor(IIOHelper ioHelper, ILogger logger) : base(logger) - { } + { + _ioHelper = ioHelper; + } +#else + public BytesDataEditor(IIOHelper ioHelper, IDataValueEditorFactory dataValueEditorFactory) + : base(dataValueEditorFactory) + { + _ioHelper = ioHelper; + } +#endif - protected override IConfigurationEditor CreateConfigurationEditor() => new BytesConfigurationEditor(); + protected override IConfigurationEditor CreateConfigurationEditor() => new BytesConfigurationEditor(_ioHelper); } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesValueConverter.cs index 9808efc7..34b41f50 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Bytes/BytesValueConverter.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/CheckboxList/CheckboxListDataListEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/CheckboxList/CheckboxListDataListEditor.cs index c44a2933..105aa372 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/CheckboxList/CheckboxListDataListEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/CheckboxList/CheckboxListDataListEditor.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorConfigurationEditor.cs index e3df5f7f..53555f02 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorConfigurationEditor.cs @@ -5,9 +5,17 @@ using System.Collections.Generic; using System.IO; +#if NET472 using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -20,11 +28,13 @@ internal sealed class CodeEditorConfigurationEditor : ConfigurationEditor internal const string MinLines = "minLines"; internal const string MaxLines = "maxLines"; - public CodeEditorConfigurationEditor() + public CodeEditorConfigurationEditor( + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) : base() { var targetPath = "~/umbraco/lib/ace-builds/src-min-noconflict/"; - var aceEditorPath = IOHelper.MapPath(targetPath); + var aceEditorPath = hostingEnvironment.MapPathWebRoot(targetPath); if (Directory.Exists(aceEditorPath) == true) { @@ -58,7 +68,7 @@ public CodeEditorConfigurationEditor() Key = Mode, Name = "Language mode", Description = "Select the programming language mode. The default mode is 'Razor'.", - View = IOHelper.ResolveUrl(DropdownListDataListEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(DropdownListDataListEditor.DataEditorViewPath), Config = new Dictionary { { DropdownListDataListEditor.AllowEmpty, Constants.Values.False }, @@ -75,7 +85,7 @@ public CodeEditorConfigurationEditor() Key = Theme, Name = nameof(Theme), Description = "Set the theme for the code editor. The default theme is 'Chrome'.", - View = IOHelper.ResolveUrl(DropdownListDataListEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(DropdownListDataListEditor.DataEditorViewPath), Config = new Dictionary { { DropdownListDataListEditor.AllowEmpty, Constants.Values.False }, @@ -86,7 +96,7 @@ public CodeEditorConfigurationEditor() if (modes.Count > 0 || themes.Count > 0) { - Fields.Add(new NotesConfigurationField($@"
+ Fields.Add(new NotesConfigurationField(ioHelper, $@"
Would you like to add more language modes and themes?

This property editor makes use of AWS Cloud 9's Ace editor library that is distributed with Umbraco. By default, Umbraco ships a streamlined set of programming language modes and themes.

If you would like to add more modes and themes, you can do this by downloading the latest pre-packaged version of the Ace editor and copy any of the mode-* or theme-* files from the src-min-noconflict folder over to the {targetPath} folder in this Umbraco installation.

@@ -102,7 +112,7 @@ public CodeEditorConfigurationEditor() Key = FontSize, Name = "Font size", Description = @"Set the font size. The value must be a valid CSS font-size value. The default size is 'small'.", - View = IOHelper.ResolveUrl(TextInputDataEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(TextInputDataEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] { @@ -149,7 +159,7 @@ public CodeEditorConfigurationEditor() Key = MinLines, Name = "Minimum lines", Description = "Set the minimum number of lines that the editor will be. The default is 12 lines.", - View = IOHelper.ResolveUrl(NumberInputDataEditor.DataEditorViewPath) + View = ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath) }); DefaultConfiguration.Add(MaxLines, 30); @@ -158,7 +168,7 @@ public CodeEditorConfigurationEditor() Key = MaxLines, Name = "Maximum lines", Description = "Set the maximum number of lines that the editor can be. If left empty, the editor will not auto-scale.", - View = IOHelper.ResolveUrl(NumberInputDataEditor.DataEditorViewPath) + View = ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath) }); } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorDataEditor.cs index bc0331de..c50cc19b 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorDataEditor.cs @@ -3,9 +3,22 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 +using Umbraco.Core.Hosting; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; using Umbraco.Web.PropertyEditors; +#else +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -24,12 +37,61 @@ internal sealed class CodeEditorDataEditor : DataEditor internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "code-editor.html"; internal const string DataEditorIcon = "icon-fa fa-code"; - public CodeEditorDataEditor(ILogger logger) + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IIOHelper _ioHelper; + +#if NET472 + public CodeEditorDataEditor( + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper, + ILogger logger) : base(logger) - { } + { + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; + } +#else + private readonly IDataTypeService _dataTypeService; + private readonly ILocalizationService _localizationService; + private readonly ILocalizedTextService _localizedTextService; + private readonly IShortStringHelper _shortStringHelper; + private readonly IJsonSerializer _jsonSerializer; + + public CodeEditorDataEditor( + IDataValueEditorFactory dataValueEditorFactory, + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper, + ILoggerFactory loggerFactory, + IDataTypeService dataTypeService, + ILocalizationService localizationService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(dataValueEditorFactory) + { + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; + _dataTypeService = dataTypeService; + _localizationService = localizationService; + _localizedTextService = localizedTextService; + _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; + } +#endif - protected override IConfigurationEditor CreateConfigurationEditor() => new CodeEditorConfigurationEditor(); + protected override IConfigurationEditor CreateConfigurationEditor() => new CodeEditorConfigurationEditor( + _hostingEnvironment, + _ioHelper); +#if NET472 protected override IDataValueEditor CreateValueEditor() => new TextOnlyValueEditor(Attribute); +#else + protected override IDataValueEditor CreateValueEditor() => new TextOnlyValueEditor( + Attribute, + _localizedTextService, + _shortStringHelper, + _jsonSerializer, + _ioHelper); +#endif } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorValueConverter.cs index 2c331f35..7771fdf8 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/CodeEditor/CodeEditorValueConverter.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorDataEditor.cs index e5f9dbb1..5dc2c356 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorDataEditor.cs @@ -3,6 +3,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 +using UmbConstants = Umbraco.Core.Constants; +#else +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif + namespace Umbraco.Community.Contentment.DataEditors { internal sealed class ConfigurationEditorDataEditor @@ -11,6 +17,6 @@ internal sealed class ConfigurationEditorDataEditor internal const string DataEditorName = Constants.Internals.DataEditorNamePrefix + "Configuration Editor"; internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "configuration-editor.html"; internal const string DataEditorOverlayViewPath = Constants.Internals.EditorsPathRoot + "configuration-editor.overlay.html"; - internal const string DataEditorIcon = Core.Constants.Icons.Macro; + internal const string DataEditorIcon = UmbConstants.Icons.Macro; } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorModel.cs b/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorModel.cs index 78505d1a..0005fcb1 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorModel.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorModel.cs @@ -7,7 +7,11 @@ using System.ComponentModel; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorUtility.cs b/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorUtility.cs index 5e248f66..d34c2785 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorUtility.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ConfigurationEditor/ConfigurationEditorUtility.cs @@ -8,8 +8,18 @@ using System.ComponentModel; using System.Linq; using Umbraco.Community.Contentment.Composing; +#if NET472 using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -40,13 +50,13 @@ public T GetConfigurationEditor(string key) return default; } - public ConfigurationEditorModel GetConfigurationEditorModel(bool ignoreFields = false) + public ConfigurationEditorModel GetConfigurationEditorModel(IShortStringHelper shortStringHelper, bool ignoreFields = false) where T : IContentmentEditorItem { - return GetConfigurationEditorModel(GetConfigurationEditor(typeof(T).GetFullNameWithAssembly()), ignoreFields); + return GetConfigurationEditorModel(GetConfigurationEditor(typeof(T).GetFullNameWithAssembly()), shortStringHelper, ignoreFields); } - public ConfigurationEditorModel GetConfigurationEditorModel(T item, bool ignoreFields = false) + public ConfigurationEditorModel GetConfigurationEditorModel(T item, IShortStringHelper shortStringHelper, bool ignoreFields = false) where T : IContentmentEditorItem { var type = item.GetType(); @@ -58,9 +68,9 @@ public ConfigurationEditorModel GetConfigurationEditorModel(T item, bool igno return new ConfigurationEditorModel { Key = type.GetFullNameWithAssembly(), - Name = item.Name ?? type.Name.SplitPascalCasing(), + Name = item.Name ?? type.Name.SplitPascalCasing(shortStringHelper), Description = item.Description, - Icon = item.Icon ?? Core.Constants.Icons.DefaultIcon, + Icon = item.Icon ?? UmbConstants.Icons.DefaultIcon, Group = item.Group, Fields = fields, DefaultValues = item.DefaultValues, @@ -68,8 +78,8 @@ public ConfigurationEditorModel GetConfigurationEditorModel(T item, bool igno }; } - public IEnumerable GetConfigurationEditorModels(bool ignoreFields = false) - where T : IContentmentEditorItem + public IEnumerable GetConfigurationEditorModels(IShortStringHelper shortStringHelper, bool ignoreFields = false) + where T : IContentmentEditorItem { var models = new List(); @@ -77,7 +87,7 @@ public IEnumerable GetConfigurationEditorModels(boo { if (item is T editorItem) { - models.Add(GetConfigurationEditorModel(editorItem, ignoreFields)); + models.Add(GetConfigurationEditorModel(editorItem, shortStringHelper, ignoreFields)); } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreview.cshtml b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreview.cshtml index 2426238d..4cd7bd3e 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreview.cshtml +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreview.cshtml @@ -2,7 +2,7 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. *@ -@inherits Umbraco.Web.Mvc.ContentBlockPreviewView +@inherits ContentBlockPreviewView
@Model.Element.Key
diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewModel.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewModel.cs index 4bf97bf9..463132c8 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewModel.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewModel.cs @@ -3,8 +3,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Models; +#else +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewView.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewView.cs index f8851469..2c7faede 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewView.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlockPreviewView.cs @@ -4,12 +4,23 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using System.Web.Mvc; using Umbraco.Community.Contentment.DataEditors; using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; +#else +using Microsoft.AspNetCore.Mvc.Rendering; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Community.Contentment.DataEditors; +using Umbraco.Extensions; +#endif +#if NET472 namespace Umbraco.Web.Mvc +#else +namespace Umbraco.Cms.Web.Common.Views +#endif { public abstract class ContentBlockPreviewView : ContentBlockPreviewView @@ -20,6 +31,7 @@ public abstract class ContentBlockPreviewView(string key, Action action) @@ -52,5 +64,45 @@ void setProperty(string key, Action action) base.SetViewData(viewData); } +#else + public override ViewContext ViewContext + { + get => base.ViewContext; + set => base.ViewContext = SetViewData(value); + } + + protected ViewContext SetViewData(ViewContext viewCtx) + { + void setProperty(string key, Action action) + { + if (viewCtx.ViewData.TryGetValueAs(key, out T value) == true) + { + action(value); + } + } + + var model = new ContentBlockPreviewModel(); + + setProperty("content", (x) => model.Content = x); + setProperty("element", (x) => model.Element = x); + setProperty("elementIndex", (x) => model.ElementIndex = x); + setProperty("contentIcon", (x) => model.ContentTypeIcon = x); + setProperty("elementIcon", (x) => model.ElementTypeIcon = x); + + if (model.Element == null && viewCtx.ViewData.Model is TPublishedElement element) + { + model.Element = element; + } + + if (model.Content == null && UmbracoContext?.PublishedRequest?.PublishedContent is TPublishedContent content) + { + model.Content = content; + } + + viewCtx.ViewData.Model = model; + + return viewCtx; + } +#endif } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksApiController.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksApiController.cs index 42503c2b..7cc451bd 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksApiController.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksApiController.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System; using System.Collections.Generic; using System.Net; @@ -15,9 +16,32 @@ using Umbraco.Web.Editors; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; +#else +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json.Linq; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Web.BackOffice.Controllers; +using Umbraco.Cms.Web.Common.Attributes; +using Umbraco.Community.Contentment.Web.PublishedCache; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { +#if NET472 [PluginController(Constants.Internals.PluginControllerName), IsBackOffice] public sealed class ContentBlocksApiController : UmbracoAuthorizedJsonController { @@ -83,7 +107,7 @@ public HttpResponseMessage GetPreviewMarkup([FromBody] JObject item, int element viewData.Add(nameof(elementIcon), elementIcon); } - var markup = default(string); + string markup; try { @@ -107,4 +131,160 @@ public HttpResponseMessage GetPreviewMarkup([FromBody] JObject item, int element return Request.CreateResponse(HttpStatusCode.OK, new { elementKey, markup }); } } +#else + [PluginController(Constants.Internals.PluginControllerName), IsBackOffice] + public sealed class ContentBlocksApiController : UmbracoAuthorizedJsonController + { + private readonly ILogger _logger; + private readonly IPublishedModelFactory _publishedModelFactory; + private readonly IContentTypeService _contentTypeService; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IModelMetadataProvider _modelMetadataProvider; + private readonly IRazorViewEngine _viewEngine; + private readonly ITempDataProvider _tempDataProvider; + + public ContentBlocksApiController( + ILogger logger, + IPublishedModelFactory publishedModelFactory, + IContentTypeService contentTypeService, + IUmbracoContextAccessor umbracoContextAccessor, + IModelMetadataProvider modelMetadataProvider, + IRazorViewEngine viewEngine, + ITempDataProvider tempDataProvider) + { + _logger = logger; + _publishedModelFactory = publishedModelFactory; + _contentTypeService = contentTypeService; + _umbracoContextAccessor = umbracoContextAccessor; + _modelMetadataProvider = modelMetadataProvider; + _viewEngine = viewEngine; + _tempDataProvider = tempDataProvider; + } + + [HttpPost] + public ActionResult GetPreviewMarkup([FromBody] JObject item, int elementIndex, Guid elementKey, int contentId) + { + var preview = true; + var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); + + var content = umbracoContext.Content.GetById(true, contentId); + if (content == null) + { + _logger.LogDebug($"Unable to retrieve content for ID '{contentId}', it is most likely a new unsaved page."); + } + + var element = default(IPublishedElement); + var block = item.ToObject(); + if (block != null && block.ElementType.Equals(Guid.Empty) == false) + { + if (ContentTypeCacheHelper.TryGetAlias(block.ElementType, out var alias, _contentTypeService) == true) + { + var contentType = umbracoContext.PublishedSnapshot.Content.GetContentType(alias); + if (contentType != null && contentType.IsElement == true) + { + var properties = new List(); + + foreach (var thing in block.Value) + { + var propType = contentType.GetPropertyType(thing.Key); + if (propType != null) + { + properties.Add(new DetachedPublishedProperty(propType, null, thing.Value, preview)); + } + } + + element = _publishedModelFactory.CreateModel(new DetachedPublishedElement(block.Key, contentType, properties)); + } + } + } + + var viewData = new ViewDataDictionary(_modelMetadataProvider, new ModelStateDictionary()) + { + Model = element, + [nameof(content)] = content, + [nameof(element)] = element, + [nameof(elementIndex)] = elementIndex, + + }; + + if (ContentTypeCacheHelper.TryGetIcon(content.ContentType.Alias, out var contentIcon, _contentTypeService) == true) + { + viewData.Add(nameof(contentIcon), contentIcon); + } + + if (ContentTypeCacheHelper.TryGetIcon(element.ContentType.Alias, out var elementIcon, _contentTypeService) == true) + { + viewData.Add(nameof(elementIcon), elementIcon); + } + + string markup; + + try + { + markup = RenderPartialViewToString(element.ContentType.Alias, viewData); + } + catch (InvalidCastException icex) + { + // NOTE: This type of exception happens on a new (unsaved) page, when the context becomes the parent page, + // and the preview view is strongly typed to the current page's model type. + markup = "

Unable to render the preview until the page has been saved.

"; + + _logger.LogError(icex, "Error rendering preview view."); + } + catch (Exception ex) + { + markup = $"
{ex}
"; + + _logger.LogError(ex, "Error rendering preview view."); + } + + return new ObjectResult(new { elementKey, markup }); + } + + // HACK: [v9] [LK:2021-05-13] Got it working. Future rewrite, make nicer. + // The following code has been hacked and butchered from: + // https://github.com/aspnet/Entropy/blob/master/samples/Mvc.RenderViewToString/RazorViewToStringRenderer.cs + // https://gist.github.com/ahmad-moussawi/1643d703c11699a6a4046e57247b4d09 + private string RenderPartialViewToString(string viewName, ViewDataDictionary viewData) + { + IView view = default; + + // TODO: [v9] [LK:2021-05-13] Implement the custom partial-view paths. + // e.g. "~/Views/Partials/Blocks/{0}.cshtml", "~/Views/Partials/Blocks/Default.cshtml", "~/App_Plugins/Contentment/render/ContentBlockPreview.cshtml" + + var getViewResult = _viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true); + if (getViewResult.Success) + { + view = getViewResult.View; + } + + var actionContext = new ActionContext(HttpContext, new RouteData(), new ActionDescriptor()); + var findViewResult = _viewEngine.FindView(actionContext, viewName, isMainPage: true); + if (findViewResult.Success) + { + view = findViewResult.View; + } + + if (view == default) + { + var messages = new List { $"Unable to find view '{viewName}'. The following locations were searched:" }; + messages.AddRange(getViewResult.SearchedLocations); + messages.AddRange(findViewResult.SearchedLocations); + + var errorMessage = string.Join(Environment.NewLine, messages); + + throw new InvalidOperationException(errorMessage); + } + + using var output = new StringWriter(); + + var tempDataDictionary = new TempDataDictionary(actionContext.HttpContext, _tempDataProvider); + var viewContext = new ViewContext(actionContext, view, viewData, tempDataDictionary, output, new HtmlHelperOptions()); + + view.RenderAsync(viewContext).GetAwaiter().GetResult(); + + return output.ToString(); + } + } +#endif } diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksConfigurationEditor.cs index 5f129175..ecb08c1f 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksConfigurationEditor.cs @@ -7,11 +7,21 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +using Umbraco.Core.Strings; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -20,6 +30,7 @@ internal sealed class ContentBlocksConfigurationEditor : ConfigurationEditor // TODO: expire the local cache `_elementTypes` when a new element type is added. [LK:2021-08-16] private readonly Dictionary _elementTypes; private readonly Lazy> _elementBlueprints; + private readonly IIOHelper _ioHelper; private readonly ConfigurationEditorUtility _utility; internal const string DisplayMode = "displayMode"; @@ -27,16 +38,19 @@ internal sealed class ContentBlocksConfigurationEditor : ConfigurationEditor public ContentBlocksConfigurationEditor( IContentService contentService, IContentTypeService contentTypeService, - ConfigurationEditorUtility utility) + ConfigurationEditorUtility utility, + IShortStringHelper shortStringHelper, + IIOHelper ioHelper) : base() { + _ioHelper = ioHelper; _utility = utility; // NOTE: Gets all the elementTypes and blueprints upfront, rather than several hits inside the loop. _elementTypes = contentTypeService.GetAllElementTypes().ToDictionary(x => x.Key); _elementBlueprints = new Lazy>(() => contentService.GetBlueprintsForContentTypes(_elementTypes.Values.Select(x => x.Id).ToArray()).ToLookup(x => x.ContentTypeId)); - var displayModes = utility.GetConfigurationEditorModels(); + var displayModes = utility.GetConfigurationEditorModels(shortStringHelper); // NOTE: Sets the default display mode to be the Blocks. var defaultDisplayMode = displayModes.FirstOrDefault(x => x.Key.InvariantEquals(typeof(BlocksDisplayMode).GetFullNameWithAssembly())); @@ -50,21 +64,21 @@ public ContentBlocksConfigurationEditor( Key = DisplayMode, Name = "Display mode", Description = "Select and configure how to display the blocks in the editor.", - View = IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorViewPath), Config = new Dictionary() { { Constants.Conventions.ConfigurationFieldAliases.AddButtonLabelKey, "contentment_configureDisplayMode" }, { Constants.Conventions.ConfigurationFieldAliases.Items, displayModes }, { MaxItemsConfigurationField.MaxItems, 1 }, { DisableSortingConfigurationField.DisableSorting, Constants.Values.True }, - { Constants.Conventions.ConfigurationFieldAliases.OverlayView, IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, + { Constants.Conventions.ConfigurationFieldAliases.OverlayView, ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, { EnableDevModeConfigurationField.EnableDevMode, Constants.Values.True }, } }); - Fields.Add(new ContentBlocksTypesConfigurationField(_elementTypes.Values)); + Fields.Add(new ContentBlocksTypesConfigurationField(_elementTypes.Values, ioHelper)); Fields.Add(new EnableFilterConfigurationField()); - Fields.Add(new MaxItemsConfigurationField()); + Fields.Add(new MaxItemsConfigurationField(ioHelper)); Fields.Add(new DisableSortingConfigurationField()); Fields.Add(new EnableDevModeConfigurationField()); } @@ -166,7 +180,7 @@ public override IDictionary ToValueEditor(object configuration) if (config.ContainsKey(Constants.Conventions.ConfigurationFieldAliases.OverlayView) == false) { - config.Add(Constants.Conventions.ConfigurationFieldAliases.OverlayView, IOHelper.ResolveUrl(ContentBlocksDataEditor.DataEditorOverlayViewPath)); + config.Add(Constants.Conventions.ConfigurationFieldAliases.OverlayView, _ioHelper.ResolveRelativeOrVirtualUrl(ContentBlocksDataEditor.DataEditorOverlayViewPath)); } return config; diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataEditor.cs index 24e9fa7a..a26422be 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataEditor.cs @@ -6,9 +6,23 @@ using System; using System.Collections.Generic; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +using Umbraco.Core.Strings; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -24,21 +38,54 @@ public sealed class ContentBlocksDataEditor : IDataEditor private readonly IContentTypeService _contentTypeService; private readonly IDataTypeService _dataTypeService; private readonly Lazy _propertyEditors; + private readonly IShortStringHelper _shortStringHelper; private readonly ConfigurationEditorUtility _utility; + private readonly IIOHelper _ioHelper; +#if NET472 public ContentBlocksDataEditor( IContentService contentService, IContentTypeService contentTypeService, IDataTypeService dataTypeService, Lazy propertyEditors, - ConfigurationEditorUtility utility) + IShortStringHelper shortStringHelper, + ConfigurationEditorUtility utility, + IIOHelper ioHelper) { _contentService = contentService; _contentTypeService = contentTypeService; _dataTypeService = dataTypeService; _propertyEditors = propertyEditors; + _shortStringHelper = shortStringHelper; _utility = utility; + _ioHelper = ioHelper; } +#else + private readonly ILocalizedTextService _localizedTextService; + private readonly IJsonSerializer _jsonSerializer; + + public ContentBlocksDataEditor( + IContentService contentService, + IContentTypeService contentTypeService, + Lazy propertyEditors, + IDataTypeService dataTypeService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + ConfigurationEditorUtility utility, + IIOHelper ioHelper) + { + _contentService = contentService; + _contentTypeService = contentTypeService; + _dataTypeService = dataTypeService; + _localizedTextService = localizedTextService; + _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; + _propertyEditors = propertyEditors; + _utility = utility; + _ioHelper = ioHelper; + } +#endif public string Alias => DataEditorAlias; @@ -48,7 +95,7 @@ public ContentBlocksDataEditor( public string Icon => DataEditorIcon; - public string Group => Core.Constants.PropertyEditors.Groups.RichContent; + public string Group => UmbConstants.PropertyEditors.Groups.RichContent; public bool IsDeprecated => false; @@ -56,20 +103,33 @@ public ContentBlocksDataEditor( public IPropertyIndexValueFactory PropertyIndexValueFactory => new DefaultPropertyIndexValueFactory(); - public IConfigurationEditor GetConfigurationEditor() => new ContentBlocksConfigurationEditor(_contentService, _contentTypeService, _utility); + public IConfigurationEditor GetConfigurationEditor() => new ContentBlocksConfigurationEditor(_contentService, _contentTypeService, _utility, _shortStringHelper, _ioHelper); public IDataValueEditor GetValueEditor() { - return new ContentBlocksDataValueEditor(_contentTypeService, _dataTypeService, _propertyEditors.Value) +#if NET472 + return new ContentBlocksDataValueEditor( + _contentTypeService, + _dataTypeService, + _propertyEditors.Value) +#else + return new ContentBlocksDataValueEditor( + _contentTypeService, + _propertyEditors.Value, + _dataTypeService, + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { ValueType = ValueTypes.Json, - View = DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(DataEditorViewPath), }; } public IDataValueEditor GetValueEditor(object configuration) { - var view = DataEditorViewPath; + var view = default(string); if (configuration is Dictionary config) { @@ -93,11 +153,21 @@ public IDataValueEditor GetValueEditor(object configuration) } } +#if NET472 return new ContentBlocksDataValueEditor(_contentTypeService, _dataTypeService, _propertyEditors.Value) +#else + return new ContentBlocksDataValueEditor( + _contentTypeService, + _propertyEditors.Value, + _dataTypeService, + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { Configuration = configuration, ValueType = ValueTypes.Json, - View = view, + View = _ioHelper.ResolveRelativeOrVirtualUrl(view ?? DataEditorViewPath), }; } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataValueEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataValueEditor.cs index 9b1f3e44..ca06b3c6 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataValueEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksDataValueEditor.cs @@ -15,11 +15,21 @@ using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +#else +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Editors; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -29,29 +39,53 @@ internal sealed class ContentBlocksDataValueEditor : DataValueEditor private readonly Lazy> _elementTypes; private readonly PropertyEditorCollection _propertyEditors; - public ContentBlocksDataValueEditor( +#if NET472 +public ContentBlocksDataValueEditor( IContentTypeService contentTypeService, IDataTypeService dataTypeService, PropertyEditorCollection propertyEditors) : base() +#else + public ContentBlocksDataValueEditor( + IContentTypeService contentTypeService, + PropertyEditorCollection propertyEditors, + IDataTypeService dataTypeService, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(localizedTextService, shortStringHelper, jsonSerializer) +#endif { _dataTypeService = dataTypeService; _elementTypes = new Lazy>(() => contentTypeService.GetAllElementTypes().ToDictionary(x => x.Key)); _propertyEditors = propertyEditors; } + +#if NET472 public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) +#else + public override object ToEditor(IProperty property, string culture = null, string segment = null) +#endif { var value = property.GetValue(culture, segment)?.ToString(); if (string.IsNullOrWhiteSpace(value) == true) { +#if NET472 return base.ToEditor(property, dataTypeService, culture, segment); +#else + return base.ToEditor(property, culture, segment); +#endif } var blocks = JsonConvert.DeserializeObject>(value); if (blocks == null) { +#if NET472 return base.ToEditor(property, dataTypeService, culture, segment); +#else + return base.ToEditor(property, culture, segment); +#endif } foreach (var block in blocks) @@ -86,7 +120,11 @@ public override object ToEditor(Property property, IDataTypeService dataTypeServ continue; } +#if NET472 var convertedValue = propertyEditor.GetValueEditor()?.ToEditor(fakeProperty, dataTypeService); +#else + var convertedValue = propertyEditor.GetValueEditor()?.ToEditor(fakeProperty); +#endif block.Value[key] = convertedValue != null ? JToken.FromObject(convertedValue) diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksTypesConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksTypesConfigurationField.cs index 0fdf4c3a..3c2ef2e0 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksTypesConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksTypesConfigurationField.cs @@ -5,10 +5,17 @@ using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -16,8 +23,12 @@ internal sealed class ContentBlocksTypesConfigurationField : ConfigurationField { internal const string ContentBlockTypes = "contentBlockTypes"; - public ContentBlocksTypesConfigurationField(IEnumerable elementTypes) + private readonly IIOHelper _ioHelper; + + public ContentBlocksTypesConfigurationField(IEnumerable elementTypes, IIOHelper ioHelper) { + _ioHelper = ioHelper; + var items = elementTypes .OrderBy(x => x.Name) .Select(x => new ConfigurationEditorModel @@ -37,13 +48,13 @@ public ContentBlocksTypesConfigurationField(IEnumerable elementTyp Key = ContentBlockTypes; Name = "Block types"; Description = "Configure the block types to use."; - View = IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorViewPath); + View = ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorViewPath); Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.AddButtonLabelKey, "contentment_configureElementType" }, { "allowDuplicates", Constants.Values.False }, { EnableFilterConfigurationField.EnableFilter, Constants.Values.True }, - { Constants.Conventions.ConfigurationFieldAliases.OverlayView, IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, + { Constants.Conventions.ConfigurationFieldAliases.OverlayView, ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, { Constants.Conventions.ConfigurationFieldAliases.Items, items }, { EnableDevModeConfigurationField.EnableDevMode, Constants.Values.True }, }; @@ -57,7 +68,7 @@ private IEnumerable GetConfigurationFields(IContentType cont { Key = "elementType", Name = "Element type", - View = IOHelper.ResolveUrl(Constants.Internals.EditorsPathRoot + "readonly-node-preview.html"), + View = _ioHelper.ResolveRelativeOrVirtualUrl(Constants.Internals.EditorsPathRoot + "readonly-node-preview.html"), Config = new Dictionary { { "name", contentType.Name }, @@ -78,7 +89,7 @@ private IEnumerable GetConfigurationFields(IContentType cont Key = "overlaySize", Name = "Editor overlay size", Description = "Select the size of the overlay editing panel. By default this is set to 'small'. However if the editor fields require a wider panel, please select 'medium' or 'large'.", - View = IOHelper.ResolveUrl(RadioButtonListDataListEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksValueConverter.cs index bb093bb3..6f206e9d 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksValueConverter.cs @@ -7,11 +7,19 @@ using System.Collections.Generic; using Newtonsoft.Json; using Umbraco.Community.Contentment.Web.PublishedCache; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Web.PublishedCache; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -62,7 +70,7 @@ public override object ConvertIntermediateToObject(IPublishedElement owner, IPub if (ContentTypeCacheHelper.TryGetAlias(item.ElementType, out var alias, _contentTypeService) == false) continue; - var contentType = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetContentType(alias); + var contentType = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot().Content.GetContentType(alias); if (contentType == null || contentType.IsElement == false) continue; diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksViewHelper.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksViewHelper.cs index d330e2ac..e3aa6da6 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksViewHelper.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentBlocksViewHelper.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System.IO; using System.Web; using System.Web.Mvc; @@ -49,3 +50,4 @@ internal static string RenderPartial(string partialName, ViewDataDictionary view } } } +#endif diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentTypeCacheHelper.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentTypeCacheHelper.cs index 9189a352..e999872c 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentTypeCacheHelper.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/ContentTypeCacheHelper.cs @@ -8,10 +8,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System; using System.Collections.Concurrent; using Umbraco.Core.Models; using Umbraco.Core.Services; +#else +using System; +using System.Collections.Concurrent; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/BlocksDisplayMode.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/BlocksDisplayMode.cs index 00f680ed..21ca4759 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/BlocksDisplayMode.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/BlocksDisplayMode.cs @@ -4,13 +4,27 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using UmbIcons = Umbraco.Core.Constants.Icons; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using UmbIcons = Umbraco.Cms.Core.Constants.Icons; +#endif namespace Umbraco.Community.Contentment.DataEditors { internal class BlocksDisplayMode : IContentBlocksDisplayMode { + private readonly IIOHelper _ioHelper; + + public BlocksDisplayMode(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + public string Name => "Blocks"; public string Description => "Blocks will be displayed in a list similar to the Block List editor."; @@ -36,7 +50,7 @@ internal class BlocksDisplayMode : IContentBlocksDisplayMode public IEnumerable Fields => new[] { - new NotesConfigurationField($@"
+ new NotesConfigurationField(_ioHelper, $@"
A note about block type previews.

Currently, the preview feature for block types has not been implemented for the {Name} display mode and has been temporarily disabled.

", true), diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/ListDisplayMode.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/ListDisplayMode.cs index 4601ff37..dcf34d8a 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/ListDisplayMode.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/ListDisplayMode.cs @@ -4,12 +4,25 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { internal class ListDisplayMode : IContentBlocksDisplayMode { + private readonly IIOHelper _ioHelper; + + public ListDisplayMode(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + public string Name => "List"; public string Description => "Blocks will be displayed in a list similar to a content picker."; @@ -29,7 +42,7 @@ internal class ListDisplayMode : IContentBlocksDisplayMode public IEnumerable Fields => new ConfigurationField[] { - new NotesConfigurationField($@"
+ new NotesConfigurationField(_ioHelper, $@"
A note about block type previews.

Unfortunately, the preview feature for block types is unsupported in the {Name} display mode and will be disabled.

", true), diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/StackDisplayMode.cs b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/StackDisplayMode.cs index e1b6f495..17e386eb 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/StackDisplayMode.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/DisplayModes/StackDisplayMode.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/content-blocks.overlay.js b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/content-blocks.overlay.js index d36583e5..14f75647 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/content-blocks.overlay.js +++ b/src/Umbraco.Community.Contentment/DataEditors/ContentBlocks/content-blocks.overlay.js @@ -111,7 +111,10 @@ angular.module("umbraco").controller("Umbraco.Community.Contentment.Overlays.Con icon: elementType.icon, key: String.CreateGuid() }; - + + // TODO: [v9] [LK] Review this, get error with blueprint API request, 404. + // "Failed to retrieve blueprint for id 1082" + // e.g. /umbraco/backoffice/umbracoapi/content/GetEmpty?blueprintId=1082&parentId=1076 var getScaffold = blueprint && blueprint.id > 0 ? contentResource.getBlueprintScaffold(config.currentPageId, blueprint.id) : contentResource.getScaffold(config.currentPageId, elementType.alias); diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListApiController.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListApiController.cs index 36d4b406..c90afc04 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListApiController.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListApiController.cs @@ -4,15 +4,23 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +using Newtonsoft.Json.Linq; +#if NET472 using System.Net; using System.Net.Http; using System.Web.Http; -using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Web.Editors; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; +#else +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Web.BackOffice.Controllers; +using Umbraco.Cms.Web.Common.Attributes; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -27,7 +35,11 @@ public DataListApiController(PropertyEditorCollection propertyEditors) } [HttpPost] +#if NET472 public HttpResponseMessage GetPreview([FromBody] JObject data) +#else + public ActionResult GetPreview([FromBody] JObject data) +#endif { var config = data.ToObject>(); @@ -38,10 +50,18 @@ public HttpResponseMessage GetPreview([FromBody] JObject data) var valueEditorConfig = configurationEditor.ToValueEditor(config); var valueEditor = propertyEditor.GetValueEditor(config); +#if NET472 return Request.CreateResponse(HttpStatusCode.OK, new { config = valueEditorConfig, view = valueEditor.View, alias }); +#else + return new ObjectResult(new { config = valueEditorConfig, view = valueEditor.View, alias }); +#endif } +#if NET472 return Request.CreateResponse(HttpStatusCode.NotFound); +#else + return new NotFoundResult(); +#endif } } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListConfigurationEditor.cs index 3cc8582b..a881feee 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListConfigurationEditor.cs @@ -6,9 +6,17 @@ using System; using System.Collections.Generic; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -22,22 +30,26 @@ internal sealed class DataListConfigurationEditor : ConfigurationEditor private readonly ConfigurationEditorUtility _utility; - public DataListConfigurationEditor(ConfigurationEditorUtility utility) + public DataListConfigurationEditor( + ConfigurationEditorUtility utility, + IShortStringHelper shortStringHelper, + IIOHelper ioHelper) : base() { _utility = utility; - var configEditorViewPath = IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorViewPath); + var configEditorViewPath = ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorViewPath); var defaultConfigEditorConfig = new Dictionary { { MaxItemsConfigurationField.MaxItems, 1 }, { DisableSortingConfigurationField.DisableSorting, Constants.Values.True }, - { Constants.Conventions.ConfigurationFieldAliases.OverlayView, IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, + { Constants.Conventions.ConfigurationFieldAliases.OverlayView, ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, { EnableDevModeConfigurationField.EnableDevMode, Constants.Values.True }, }; - var dataSources = new List(utility.GetConfigurationEditorModels()); - var listEditors = new List(utility.GetConfigurationEditorModels()); + var dataSources = new List(utility.GetConfigurationEditorModels(shortStringHelper)); + var listEditors = new List(utility.GetConfigurationEditorModels(shortStringHelper)); + Fields.Add(new ConfigurationField { @@ -76,7 +88,7 @@ public DataListConfigurationEditor(ConfigurationEditorUtility utility) { Key = "preview", Name = "Preview", - View = IOHelper.ResolveUrl(DataListDataEditor.DataEditorPreviewViewPath) + View = ioHelper.ResolveRelativeOrVirtualUrl(DataListDataEditor.DataEditorPreviewViewPath) }); } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListDataEditor.cs index 710155a4..5d866844 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListDataEditor.cs @@ -5,8 +5,23 @@ using System.Collections.Generic; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -20,9 +35,37 @@ public sealed class DataListDataEditor : IDataEditor internal const string DataEditorIcon = "icon-fa fa-list-ul"; private readonly ConfigurationEditorUtility _utility; - - public DataListDataEditor(ConfigurationEditorUtility utility) => _utility = utility; - + private readonly IShortStringHelper _shortStringHelper; + private readonly IIOHelper _ioHelper; + +#if NET472 + public DataListDataEditor( + ConfigurationEditorUtility utility, + IShortStringHelper shortStringHelper, + IIOHelper ioHelper) + { + _utility = utility; + _shortStringHelper = shortStringHelper; + _ioHelper = ioHelper; + } +#else + private readonly ILocalizedTextService _localizedTextService; + private readonly IJsonSerializer _jsonSerializer; + + public DataListDataEditor( + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + ConfigurationEditorUtility utility, + IIOHelper ioHelper) + { + _localizedTextService = localizedTextService; + _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; + _utility = utility; + _ioHelper = ioHelper; + } +#endif public string Alias => DataEditorAlias; public EditorType Type => EditorType.PropertyValue; @@ -31,7 +74,7 @@ public sealed class DataListDataEditor : IDataEditor public string Icon => DataEditorIcon; - public string Group => Core.Constants.PropertyEditors.Groups.Lists; + public string Group => UmbConstants.PropertyEditors.Groups.Lists; public bool IsDeprecated => false; @@ -39,14 +82,18 @@ public sealed class DataListDataEditor : IDataEditor public IPropertyIndexValueFactory PropertyIndexValueFactory => new DefaultPropertyIndexValueFactory(); - public IConfigurationEditor GetConfigurationEditor() => new DataListConfigurationEditor(_utility); + public IConfigurationEditor GetConfigurationEditor() => new DataListConfigurationEditor(_utility, _shortStringHelper, _ioHelper); public IDataValueEditor GetValueEditor() { +#if NET472 return new DataValueEditor +#else + return new DataValueEditor(_localizedTextService, _shortStringHelper, _jsonSerializer) +#endif { ValueType = ValueTypes.Json, - View = DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(DataEditorViewPath), }; } @@ -73,11 +120,15 @@ public IDataValueEditor GetValueEditor(object configuration) } } +#if NET472 return new DataValueEditor +#else + return new DataValueEditor(_localizedTextService, _shortStringHelper, _jsonSerializer) +#endif { Configuration = configuration, ValueType = ValueTypes.Json, - View = view ?? DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(view ?? DataEditorViewPath), }; } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListValueConverter.cs index fd85bf25..741983ce 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataListValueConverter.cs @@ -8,9 +8,15 @@ using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CountriesDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CountriesDataListSource.cs index d86f8137..fabe1dad 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CountriesDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CountriesDataListSource.cs @@ -6,8 +6,13 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CurrenciesDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CurrenciesDataListSource.cs index ae773753..e6d6ec74 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CurrenciesDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/CurrenciesDataListSource.cs @@ -6,8 +6,13 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/EnumDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/EnumDataListSource.cs index 777e9c96..d4a9364b 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/EnumDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/EnumDataListSource.cs @@ -11,19 +11,45 @@ using System.Runtime.Serialization; using Newtonsoft.Json.Linq; using Umbraco.Community.Contentment.Web.Controllers; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +#else +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class EnumDataListSource : IDataListSource, IDataListSourceValueConverter { - private readonly ILogger _logger; + private readonly IIOHelper _ioHelper; + private readonly IShortStringHelper _shortStringHelper; - public EnumDataListSource(ILogger logger) +#if NET472 + private readonly ILogger _logger; +#else + private readonly ILogger _logger; +#endif + + public EnumDataListSource( +#if NET472 + ILogger logger, +#else + ILogger logger, +#endif + IShortStringHelper shortStringHelper, + IIOHelper ioHelper) { _logger = logger; + _shortStringHelper = shortStringHelper; + _ioHelper = ioHelper; } public string Name => ".NET Enumeration"; @@ -45,7 +71,7 @@ public EnumDataListSource(ILogger logger) Key = "enumType", Name = "Enumeration type", Description = "Select the enumeration from an assembly type.", - View = CascadingDropdownListDataEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(CascadingDropdownListDataEditor.DataEditorViewPath), Config = new Dictionary { { CascadingDropdownListDataEditor.APIs, new[] @@ -93,7 +119,7 @@ public IEnumerable GetItems(Dictionary config) Description = attr?.Description ?? attr2?.Description, Disabled = attr?.Disabled ?? false, Icon = attr?.Icon, - Name = attr?.Name ?? field.Name.SplitPascalCasing(), + Name = attr?.Name ?? field.Name.SplitPascalCasing(_shortStringHelper), Value = attr3?.Value ?? attr?.Value ?? field.Name }); } @@ -114,11 +140,35 @@ public Type GetValueType(Dictionary config) if (enumType?.Length > 1) { var assembly = default(Assembly); - try { assembly = Assembly.Load(enumType[0]); } catch (Exception ex) { _logger.Error(ex); } + try + { + assembly = Assembly.Load(enumType[0]); + } + catch (Exception ex) + { +#if NET472 + _logger.Error(ex); +#else + _logger.LogError(ex, "Unable to load target type."); +#endif + } + if (assembly != null) { var type = default(Type); - try { type = assembly.GetType(enumType[1]); } catch (Exception ex) { _logger.Error(ex); } + try + { + type = assembly.GetType(enumType[1]); + } + catch (Exception ex) + { +#if NET472 + _logger.Error(ex); +#else + _logger.LogError(ex, "Unable to retrieve target type."); +#endif + } + if (type != null && type.IsEnum == true) { return type; @@ -149,7 +199,11 @@ public object ConvertValue(Type type, string value) } } +#if NET472 _logger.Debug($"Unable to find value '{value}' in enum '{type.FullName}'."); +#else + _logger.LogDebug($"Unable to find value '{value}' in enum '{type.FullName}'."); +#endif } return type.GetDefaultValue(); diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/ExamineDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/ExamineDataListSource.cs index f9b577f2..fac6e40c 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/ExamineDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/ExamineDataListSource.cs @@ -6,23 +6,34 @@ using System.Collections.Generic; using System.Linq; using Examine; -using Examine.LuceneEngine.Providers; using Examine.Search; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; -using Umbraco.Examine; +using Umbraco.Core.Strings; using UmbConstants = Umbraco.Core.Constants; +using UmbracoExamineFieldNames = Umbraco.Examine.UmbracoExamineIndex; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Infrastructure.Examine; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class ExamineDataListSource : IDataListSource { private readonly IExamineManager _examineManager; + private readonly IShortStringHelper _shortStringHelper; + private readonly IIOHelper _ioHelper; private const string _defaultNameField = "nodeName"; - private const string _defaultValueField = UmbracoExamineIndex.NodeKeyFieldName; - private const string _defaultIconField = UmbracoExamineIndex.IconFieldName; + private const string _defaultValueField = UmbracoExamineFieldNames.NodeKeyFieldName; + private const string _defaultIconField = UmbracoExamineFieldNames.IconFieldName; private readonly Dictionary _examineFieldConfig = new Dictionary { @@ -30,14 +41,14 @@ public sealed class ExamineDataListSource : IDataListSource Constants.Conventions.ConfigurationFieldAliases.Items, new[] { - LuceneIndex.CategoryFieldName, - LuceneIndex.ItemIdFieldName, - LuceneIndex.ItemTypeFieldName, - UmbracoExamineIndex.IconFieldName, - UmbracoExamineIndex.IndexPathFieldName, - UmbracoExamineIndex.NodeKeyFieldName, - UmbracoExamineIndex.PublishedFieldName, - UmbracoExamineIndex.UmbracoFileFieldName, + UmbracoExamineFieldNames.CategoryFieldName, + UmbracoExamineFieldNames.ItemIdFieldName, + UmbracoExamineFieldNames.ItemTypeFieldName, + UmbracoExamineFieldNames.IconFieldName, + UmbracoExamineFieldNames.IndexPathFieldName, + UmbracoExamineFieldNames.NodeKeyFieldName, + UmbracoExamineFieldNames.PublishedFieldName, + UmbracoExamineFieldNames.UmbracoFileFieldName, "createDate", "creatorID", "creatorName", @@ -57,9 +68,11 @@ public sealed class ExamineDataListSource : IDataListSource }, }; - public ExamineDataListSource(IExamineManager examineManager) + public ExamineDataListSource(IExamineManager examineManager, IShortStringHelper shortStringHelper, IIOHelper ioHelper) { _examineManager = examineManager; + _shortStringHelper = shortStringHelper; + _ioHelper = ioHelper; } public string Name => "Examine Query"; @@ -79,14 +92,18 @@ public ExamineDataListSource(IExamineManager examineManager) Key = "examineIndex", Name = "Examine Index", Description = "Select the Examine index.", - View = DropdownListDataListEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(DropdownListDataListEditor.DataEditorViewPath), Config = new Dictionary { { DropdownListDataListEditor.AllowEmpty, Constants.Values.False }, - { Constants.Conventions.ConfigurationFieldAliases.Items, _examineManager.Indexes.OrderBy(x => x.Name).Select(x => new DataListItem { Name = x.Name.SplitPascalCasing(), Value = x.Name }) }, + { Constants.Conventions.ConfigurationFieldAliases.Items, _examineManager.Indexes.OrderBy(x => x.Name).Select(x => new DataListItem + { + Name = x.Name.SplitPascalCasing(_shortStringHelper), + Value = x.Name + }) }, } }, - new NotesConfigurationField(@"
+ new NotesConfigurationField(_ioHelper, @"
Do you need help with Lucene query?

If you need assistance with Lucene query syntax, please refer to this resource on our.umbraco.com.

", true), @@ -95,7 +112,7 @@ public ExamineDataListSource(IExamineManager examineManager) Key = "luceneQuery", Name = "Lucene query", Description = "Enter your raw Lucene expression to query Examine with.", - View = CodeEditorDataEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(CodeEditorDataEditor.DataEditorViewPath), Config = new Dictionary { { CodeEditorConfigurationEditor.Mode, "text" }, @@ -108,7 +125,7 @@ public ExamineDataListSource(IExamineManager examineManager) Key = "nameField", Name = "Name Field", Description = "Enter the field name to select the name from the Examine record.", - View = IOHelper.ResolveUrl(TextInputDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(TextInputDataEditor.DataEditorViewPath), Config = _examineFieldConfig }, new ConfigurationField @@ -116,7 +133,7 @@ public ExamineDataListSource(IExamineManager examineManager) Key = "valueField", Name = "Value Field", Description = "Enter the field name to select the value (key) from the Examine record.", - View = IOHelper.ResolveUrl(TextInputDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(TextInputDataEditor.DataEditorViewPath), Config = _examineFieldConfig }, new ConfigurationField @@ -124,7 +141,7 @@ public ExamineDataListSource(IExamineManager examineManager) Key = "iconField", Name = "Icon Field", Description = "(optional) Enter the field name to select the icon from the Examine record.", - View = IOHelper.ResolveUrl(TextInputDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(TextInputDataEditor.DataEditorViewPath), Config = _examineFieldConfig }, new ConfigurationField @@ -132,7 +149,7 @@ public ExamineDataListSource(IExamineManager examineManager) Key = "descriptionField", Name = "Description Field", Description = "(optional) Enter the field name to select the description from the Examine record.", - View = IOHelper.ResolveUrl(TextInputDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(TextInputDataEditor.DataEditorViewPath), Config = _examineFieldConfig }, }; @@ -161,7 +178,11 @@ public IEnumerable GetItems(Dictionary config) var descriptionField = config.GetValueAs("descriptionField", string.Empty); var results = index +#if NET472 .GetSearcher() +#else + .Searcher +#endif .CreateQuery() .NativeQuery(luceneQuery) // NOTE: For any `OrderBy` complaints, refer to: https://github.com/Shazwazza/Examine/issues/126 diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/JsonDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/JsonDataListSource.cs index 7ad04880..7cae63ef 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/JsonDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/JsonDataListSource.cs @@ -10,20 +10,46 @@ using System.Net; using System.Text; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +#else +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class JsonDataListSource : IDataListSource { + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IIOHelper _ioHelper; + +#if NET472 private readonly ILogger _logger; - public JsonDataListSource(ILogger logger) + public JsonDataListSource( + ILogger logger, + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) +#else + private readonly ILogger _logger; + + public JsonDataListSource( + ILogger logger, + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) +#endif { _logger = logger; + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; } public string Name => "JSON Data"; @@ -38,12 +64,12 @@ public JsonDataListSource(ILogger logger) public IEnumerable Fields => new[] { - new NotesConfigurationField($@"
+ new NotesConfigurationField(_ioHelper, $@"
Do you need help with JSONPath expressions?

This data-source uses Newtonsoft's Json.NET library, with this we are limited to extracting only the 'value' from any key/value-pairs.

If you need assistance with JSONPath syntax, please refer to this resource: goessner.net/articles/JsonPath.


-

If you are a developer and have ideas on how to extract the `key` (name) from the items, please do let me know on GitHub issue: #40.

+

If you are a developer and have ideas on how to extract the key (name) from the items, please do let me know on GitHub issue: #40.

", true), new ConfigurationField { @@ -128,7 +154,11 @@ public IEnumerable GetItems(Dictionary config) if (tokens.Any() == false) { +#if NET472 _logger.Warn($"The JSONPath '{itemsJsonPath}' did not match any items in the JSON."); +#else + _logger.LogWarning($"The JSONPath '{itemsJsonPath}' did not match any items in the JSON."); +#endif return Enumerable.Empty(); } @@ -159,13 +189,21 @@ public IEnumerable GetItems(Dictionary config) // How should we log if either name or value is empty? Note that empty or missing values are totally legal according to json if (name == null) { +#if NET472 _logger.Warn($"The JSONPath '{nameJsonPath}' did not match a 'name' in the item JSON."); +#else + _logger.LogWarning($"The JSONPath '{nameJsonPath}' did not match a 'name' in the item JSON."); +#endif } // If value is missing we'll skip this specific item and log as a warning if (value == null) { +#if NET472 _logger.Warn($"The JSONPath '{valueJsonPath}' did not match a 'value' in the item XML. The item was skipped."); +#else + _logger.LogWarning($"The JSONPath '{valueJsonPath}' did not match a 'value' in the item XML. The item was skipped."); +#endif continue; } @@ -182,7 +220,11 @@ public IEnumerable GetItems(Dictionary config) } catch (Exception ex) { +#if NET472 _logger.Error(ex, "Error finding items in the JSON. Please check the syntax of your JSONPath expressions."); +#else + _logger.LogError(ex, "Error finding items in the JSON. Please check the syntax of your JSONPath expressions."); +#endif } return Enumerable.Empty(); @@ -203,27 +245,39 @@ private JToken GetJson(string url) } catch (WebException ex) { +#if NET472 _logger.Error(ex, $"Unable to fetch remote data from URL: {url}"); +#else + _logger.LogError(ex, $"Unable to fetch remote data from URL: {url}"); +#endif } } else { // assume local file - var path = IOHelper.MapPath(url); + var path = _hostingEnvironment.MapPathWebRoot(url); if (File.Exists(path) == true) { content = File.ReadAllText(path); } else { +#if NET472 _logger.Error(new FileNotFoundException(), $"Unable to find the local file path: {url}"); +#else + _logger.LogError(new FileNotFoundException(), $"Unable to find the local file path: {url}"); +#endif return null; } } if (string.IsNullOrWhiteSpace(content) == true) { +#if NET472 _logger.Warn($"The contents of '{url}' was empty. Unable to process JSON data."); +#else + _logger.LogWarning($"The contents of '{url}' was empty. Unable to process JSON data."); +#endif return default; } @@ -237,7 +291,11 @@ private JToken GetJson(string url) catch (Exception ex) { var trimmed = content.Substring(0, Math.Min(400, content.Length)); +#if NET472 _logger.Error(ex, $"Error parsing string to JSON: {trimmed}"); +#else + _logger.LogError(ex, $"Error parsing string to JSON: {trimmed}"); +#endif } return default; diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/LanguagesDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/LanguagesDataListSource.cs index 0fe90032..e55b93ff 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/LanguagesDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/LanguagesDataListSource.cs @@ -6,8 +6,13 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/NumberRangeDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/NumberRangeDataListSource.cs index a3ae72b6..a1b8fbfb 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/NumberRangeDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/NumberRangeDataListSource.cs @@ -6,15 +6,29 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class NumberRangeDataListSource : IDataListSource, IDataListSourceValueConverter { + private readonly IIOHelper _ioHelper; + + public NumberRangeDataListSource(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + public string Name => "Number Range"; public string Description => "Generates a sequence of numbers within a specified range."; @@ -30,7 +44,7 @@ public sealed class NumberRangeDataListSource : IDataListSource, IDataListSource Key = "start", Name = "Start", Description = "The value of the first number in the sequence.", - View = IOHelper.ResolveUrl(NumberInputDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), Config = new Dictionary { { "step", 0.1D }, @@ -42,7 +56,7 @@ public sealed class NumberRangeDataListSource : IDataListSource, IDataListSource Key = "end", Name = "End", Description = "The value of the last number in the sequence.", - View = IOHelper.ResolveUrl(NumberInputDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), Config = new Dictionary { { "step", 0.1D }, @@ -54,7 +68,7 @@ public sealed class NumberRangeDataListSource : IDataListSource, IDataListSource Key = "step", Name = "Step", Description = "The number of steps between each number.", - View = IOHelper.ResolveUrl(NumberInputDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), Config = new Dictionary { { "step", 0.1D }, @@ -66,7 +80,7 @@ public sealed class NumberRangeDataListSource : IDataListSource, IDataListSource Key = "decimals", Name = "Decimal places", Description = "How many decimal places would you like?", - View = IOHelper.ResolveUrl("~/umbraco/views/propertyeditors/slider/slider.html"), + View = _ioHelper.ResolveRelativeOrVirtualUrl("~/umbraco/views/propertyeditors/slider/slider.html"), Config = new Dictionary { { "initVal1", 0 }, diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/PhysicalFileSystemDataSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/PhysicalFileSystemDataSource.cs index 25526329..f5b1b454 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/PhysicalFileSystemDataSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/PhysicalFileSystemDataSource.cs @@ -5,14 +5,52 @@ using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +using UmbConstants = Umbraco.Core.Constants; +#else +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class PhysicalFileSystemDataSource : IDataListSource { + private readonly IShortStringHelper _shortStringHelper; + +#if NET472 + public PhysicalFileSystemDataSource( + IShortStringHelper shortStringHelper) + { + _shortStringHelper = shortStringHelper; + } +#else + private readonly IIOHelper _ioHelper; + private readonly IHostingEnvironment _hostingEnvironment; + private readonly ILogger _logger; + + public PhysicalFileSystemDataSource( + IIOHelper ioHelper, + IHostingEnvironment hostingEnvironment, + ILogger logger, + IShortStringHelper shortStringHelper) + { + _shortStringHelper = shortStringHelper; + _ioHelper = ioHelper; + _hostingEnvironment = hostingEnvironment; + _logger = logger; + } +#endif + public string Name => "File System"; public string Description => "Select paths from the physical file system as the data source."; @@ -29,7 +67,7 @@ public sealed class PhysicalFileSystemDataSource : IDataListSource { Key = "path", Name = "Folder path", - Description = "Enter the relative path of the folder. e.g. ~/css", + Description = "Enter the relative path of the folder. e.g. ~/css
Please note, this is relative to the web root folder, e.g. wwwroot.", View = "textstring", }, new ConfigurationField @@ -68,15 +106,19 @@ public IEnumerable GetItems(Dictionary config) ? filter : "*.*"; +#if NET472 var fs = new PhysicalFileSystem(virtualRoot); +#else + var fs = new PhysicalFileSystem(_ioHelper, _hostingEnvironment, _logger, _hostingEnvironment.MapPathWebRoot(virtualRoot), _hostingEnvironment.ToAbsolute(virtualRoot)); +#endif var files = fs.GetFiles(".", fileFilter); return files.Select(x => new DataListItem { - Name = friendlyName == true ? x.SplitPascalCasing().ToFriendlyName() : x, + Name = friendlyName == true ? x.SplitPascalCasing(_shortStringHelper).ToFriendlyName() : x, Value = virtualRoot + x, Description = virtualRoot + x, - Icon = Core.Constants.Icons.DefaultIcon, + Icon = UmbConstants.Icons.DefaultIcon, }); } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/SqlDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/SqlDataListSource.cs index 3dfdd03f..4fb1a315 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/SqlDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/SqlDataListSource.cs @@ -4,16 +4,28 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; -using System.Configuration; using System.Data.Common; using System.Data.SqlClient; -using System.Data.SqlServerCe; using System.IO; using System.Linq; +#if NET472 +using System.Configuration; +using System.Data.SqlServerCe; using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using UmbConstants = Umbraco.Core.Constants; +#else +using Microsoft.Extensions.Configuration; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Configuration; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -21,14 +33,24 @@ public sealed class SqlDataListSource : IDataListSource { private readonly string _codeEditorMode; private readonly IEnumerable _connectionStrings; - - public SqlDataListSource() + private readonly IIOHelper _ioHelper; +#if NET472 == false + private readonly IConfiguration _configuration; +#endif + + public SqlDataListSource( + IHostingEnvironment hostingEnvironment, +#if NET472 == false + IConfiguration configuration, +#endif + IIOHelper ioHelper) { // NOTE: Umbraco doesn't ship with SqlServer mode, so we check if its been added manually, otherwise defautls to Razor. - _codeEditorMode = File.Exists(IOHelper.MapPath("~/umbraco/lib/ace-builds/src-min-noconflict/mode-sqlserver.js")) + _codeEditorMode = File.Exists(hostingEnvironment.MapPathWebRoot("~/umbraco/lib/ace-builds/src-min-noconflict/mode-sqlserver.js")) ? "sqlserver" : "razor"; +#if NET472 _connectionStrings = ConfigurationManager.ConnectionStrings .Cast() .Select(x => new DataListItem @@ -36,6 +58,19 @@ public SqlDataListSource() Name = x.Name, Value = x.Name }); +#else + _connectionStrings = configuration + .GetSection("ConnectionStrings") + .GetChildren() + .Select(x => new DataListItem + { + Name = x.Key, + Value = x.Key + }); + + _configuration = configuration; +#endif + _ioHelper = ioHelper; } public string Name => "SQL Data"; @@ -50,7 +85,9 @@ public SqlDataListSource() public IEnumerable Fields => new ConfigurationField[] { - new NotesConfigurationField(@"
+ // TODO: [LK:2021-09-20] Add a note on v9 edition to inform the user about the lack of SQLCE support + a plea for help. + + new NotesConfigurationField(_ioHelper, @"
Important: A note about your SQL query.

Your SQL query should be designed to return a minimum of 2 columns, (and a maximum of 5 columns). These columns will be used to populate the List Editor items.

The columns will be mapped in the following order:

@@ -68,7 +105,7 @@ public SqlDataListSource() Key = "query", Name = "SQL query", Description = "Enter your SQL query.", - View = CodeEditorDataEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(CodeEditorDataEditor.DataEditorViewPath), Config = new Dictionary { { CodeEditorConfigurationEditor.Mode, _codeEditorMode }, @@ -81,7 +118,7 @@ public SqlDataListSource() Key = "connectionString", Name = "Connection string", Description = "Select the connection string.", - View = DropdownListDataListEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(DropdownListDataListEditor.DataEditorViewPath), Config = new Dictionary { { DropdownListDataListEditor.AllowEmpty, Constants.Values.False }, @@ -92,7 +129,7 @@ public SqlDataListSource() public Dictionary DefaultValues => new Dictionary { - { "query", $"-- This is an example query that will select all the content nodes that are at level 1.\r\nSELECT\r\n\t[text],\r\n\t[uniqueId]\r\nFROM\r\n\t[umbracoNode]\r\nWHERE\r\n\t[nodeObjectType] = '{Core.Constants.ObjectTypes.Strings.Document}'\r\n\tAND\r\n\t[level] = 1\r\nORDER BY\r\n\t[sortOrder] ASC\r\n;" }, + { "query", $"-- This is an example query that will select all the content nodes that are at level 1.\r\nSELECT\r\n\t[text],\r\n\t[uniqueId]\r\nFROM\r\n\t[umbracoNode]\r\nWHERE\r\n\t[nodeObjectType] = '{UmbConstants.ObjectTypes.Strings.Document}'\r\n\tAND\r\n\t[level] = 1\r\nORDER BY\r\n\t[sortOrder] ASC\r\n;" }, { "connectionString", UmbConstants.System.UmbracoConnectionName } }; @@ -101,19 +138,25 @@ public IEnumerable GetItems(Dictionary config) var items = new List(); var query = config.GetValueAs("query", string.Empty); - var connectionString = config.GetValueAs("connectionString", string.Empty); + var connectionStringName = config.GetValueAs("connectionString", string.Empty); - if (string.IsNullOrWhiteSpace(query) == true || string.IsNullOrWhiteSpace(connectionString) == true) + if (string.IsNullOrWhiteSpace(query) == true || string.IsNullOrWhiteSpace(connectionStringName) == true) { return items; } - var settings = ConfigurationManager.ConnectionStrings[connectionString]; +#if NET472 + var settings = ConfigurationManager.ConnectionStrings[connectionStringName]; if (settings == null) +#else + var connectionString = _configuration.GetConnectionString(connectionStringName); + if (string.IsNullOrWhiteSpace(connectionString) == true) +#endif { return items; } +#if NET472 // NOTE: SQLCE uses a different connection/command. I'm trying to keep this as generic as possible, without resorting to using NPoco. [LK] if (settings.ProviderName.InvariantEquals(UmbConstants.DatabaseProviders.SqlCe) == true) { @@ -123,6 +166,15 @@ public IEnumerable GetItems(Dictionary config) { items.AddRange(GetSqlItems(query, settings.ConnectionString)); } +#else + // TODO: [v9] [LK:2021-05-07] Review SQLCE + // NOTE: SQLCE uses a different connection/command. I'm trying to keep this as generic as possible, without resorting to using NPoco. [LK] + // I've tried digging around Umbraco's `IUmbracoDatabase` layer, but I couldn't get my head around it. + // At the end of the day, if the user has SQLCE configured, it'd be nice for them to query it. + // But I don't want to add an assembly dependency (for SQLCE) to Contentment itself. I'd like to leverage Umbraco's code. + + items.AddRange(GetSqlItems(query, connectionString)); +#endif return items; } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TextDelimitedDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TextDelimitedDataListSource.cs index 083e6591..bc0debc4 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TextDelimitedDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TextDelimitedDataListSource.cs @@ -7,21 +7,53 @@ using System.Collections.Generic; using System.IO; using System.Net; +#if NET472 using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +#else +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class TextDelimitedDataListSource : IDataListSource { + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IIOHelper _ioHelper; + +#if NET472 private readonly ILogger _logger; - public TextDelimitedDataListSource(ILogger logger) + public TextDelimitedDataListSource( + ILogger logger, + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) + { + _logger = logger; + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; + } +#else + private readonly ILogger _logger; + + public TextDelimitedDataListSource( + ILogger logger, + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) { _logger = logger; + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; } +#endif public string Name => "Text Delimited Data"; @@ -35,7 +67,7 @@ public TextDelimitedDataListSource(ILogger logger) public IEnumerable Fields => new[] { - new NotesConfigurationField(@"
+ new NotesConfigurationField(_ioHelper, @"
A note about using this data source.

The text contents will be retrieved and split into lines. Each line will be split into fields by the delimiting character.

The fields are then assigned by index position.

@@ -66,28 +98,28 @@ public TextDelimitedDataListSource(ILogger logger) Key = "nameIndex", Name = "Name Index", Description = "Enter the index position of the name field from the delimited line.
The default index position is 0.", - View = NumberInputDataEditor.DataEditorViewPath + View = _ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), }, new ConfigurationField { Key = "valueIndex", Name = "Value Index", Description = "Enter the index position of the value (key) field from the delimited line.
The default index position is 1.", - View = NumberInputDataEditor.DataEditorViewPath + View = _ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), }, new ConfigurationField { Key = "iconIndex", Name = "Icon Index", Description = "(optional) Enter the index position of the icon field from the delimited line. To ignore this option, set the value to -1.", - View = NumberInputDataEditor.DataEditorViewPath + View = _ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), }, new ConfigurationField { Key = "descriptionIndex", Name = "Description Index", Description = "(optional) Enter the index position of the description field from the delimited line. To ignore this option, set the value to -1.", - View = NumberInputDataEditor.DataEditorViewPath + View = _ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), } }; @@ -186,20 +218,28 @@ private string[] GetTextLines(string url) } catch (WebException ex) { +#if NET472 _logger.Error(ex, "Unable to fetch remote data."); +#else + _logger.LogError(ex, "Unable to fetch remote data."); +#endif } } else { // assume local file - var path = IOHelper.MapPath(url); + var path = _hostingEnvironment.MapPathWebRoot(url); if (File.Exists(path) == true) { return File.ReadAllLines(path); } else { +#if NET472 _logger.Warn("Unable to find the local file path."); +#else + _logger.LogWarning("Unable to find the local file path."); +#endif } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TimeZoneDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TimeZoneDataListSource.cs index 47bbd009..74a4ab61 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TimeZoneDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/TimeZoneDataListSource.cs @@ -6,7 +6,11 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentDataListSource.cs index 73fc8d21..407002b9 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentDataListSource.cs @@ -6,13 +6,26 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Xml; using Umbraco.Web; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Core.Xml; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -20,12 +33,33 @@ public sealed class UmbracoContentDataListSource : IDataListSource, IDataListSou { private readonly IContentTypeService _contentTypeService; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IIOHelper _ioHelper; - public UmbracoContentDataListSource(IContentTypeService contentTypeService, IUmbracoContextAccessor umbracoContextAccessor) +#if NET472 + public UmbracoContentDataListSource( + IContentTypeService contentTypeService, + IUmbracoContextAccessor umbracoContextAccessor, + IIOHelper ioHelper) { _contentTypeService = contentTypeService; _umbracoContextAccessor = umbracoContextAccessor; + _ioHelper = ioHelper; } +#else + private readonly IRequestAccessor _requestAccessor; + + public UmbracoContentDataListSource( + IContentTypeService contentTypeService, + IRequestAccessor requestAccessor, + IUmbracoContextAccessor umbracoContextAccessor, + IIOHelper ioHelper) + { + _contentTypeService = contentTypeService; + _requestAccessor = requestAccessor; + _umbracoContextAccessor = umbracoContextAccessor; + _ioHelper = ioHelper; + } +#endif public string Name => "Umbraco Content"; @@ -44,7 +78,7 @@ public UmbracoContentDataListSource(IContentTypeService contentTypeService, IUmb Key = "parentNode", Name = "Parent node", Description = "Set a parent node to use its child nodes as the data source items.", - View = ContentPickerDataEditor.DataEditorSourceViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(ContentPickerDataEditor.DataEditorSourceViewPath), } }; @@ -55,18 +89,26 @@ public IEnumerable GetItems(Dictionary config) var preview = true; var parentNode = config.GetValueAs("parentNode", string.Empty); var startNode = default(IPublishedContent); + var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); if (parentNode.InvariantStartsWith("umb://document/") == false) { var nodeContextId = default(int?); - var umbracoContext = _umbracoContextAccessor.UmbracoContext; // NOTE: First we check for "id" (if on a content page), then "parentId" (if editing an element). +#if NET472 if (int.TryParse(umbracoContext.HttpContext.Request.QueryString.Get("id"), out var currentId) == true) +#else + if (int.TryParse(_requestAccessor.GetQueryStringValue("id"), out var currentId) == true) +#endif { nodeContextId = currentId; } +#if NET472 else if (int.TryParse(umbracoContext.HttpContext.Request.QueryString.Get("parentId"), out var parentId) == true) +#else + else if (int.TryParse(_requestAccessor.GetQueryStringValue("parentId"), out var parentId) == true) +#endif { nodeContextId = parentId; } @@ -86,9 +128,9 @@ public IEnumerable GetItems(Dictionary config) startNode = umbracoContext.Content.GetSingleByXPath(preview, parsed); } } - else if (GuidUdi.TryParse(parentNode, out var udi) == true && udi.Guid != Guid.Empty) + else if (UdiParser.TryParse(parentNode, out GuidUdi udi) == true && udi.Guid != Guid.Empty) { - startNode = _umbracoContextAccessor.UmbracoContext.Content.GetById(preview, udi.Guid); + startNode = umbracoContext.Content.GetById(preview, udi.Guid); } if (startNode != null) @@ -111,8 +153,8 @@ public IEnumerable GetItems(Dictionary config) public object ConvertValue(Type type, string value) { - return Udi.TryParse(value, out var udi) == true - ? _umbracoContextAccessor.UmbracoContext.Content.GetById(udi) + return UdiParser.TryParse(value, out GuidUdi udi) == true + ? _umbracoContextAccessor.GetRequiredUmbracoContext().Content.GetById(udi) : default; } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentPropertiesDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentPropertiesDataListSource.cs index e0c5e907..d531a70a 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentPropertiesDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentPropertiesDataListSource.cs @@ -7,11 +7,20 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -19,12 +28,17 @@ public sealed class UmbracoContentPropertiesDataListSource : IDataListSource { private readonly IContentTypeService _contentTypeService; private readonly Lazy _dataEditors; + private readonly IIOHelper _ioHelper; private Dictionary _icons; - public UmbracoContentPropertiesDataListSource(IContentTypeService contentTypeService, Lazy dataEditors) + public UmbracoContentPropertiesDataListSource( + IContentTypeService contentTypeService, + Lazy dataEditors, + IIOHelper ioHelper) { _contentTypeService = contentTypeService; _dataEditors = dataEditors; + _ioHelper = ioHelper; } public string Name => "Umbraco Content Properties"; @@ -57,13 +71,13 @@ public IEnumerable Fields Key = "contentType", Name = "Content Type", Description = "Select a Content Type to list the properties from.", - View = ItemPickerDataListEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(ItemPickerDataListEditor.DataEditorViewPath), Config = new Dictionary { { "enableFilter", items.Count > 5 ? Constants.Values.True : Constants.Values.False }, { "items", items }, { "listType", "list" }, - { "overlayView", IOHelper.ResolveUrl(ItemPickerDataListEditor.DataEditorOverlayViewPath) }, + { "overlayView", _ioHelper.ResolveRelativeOrVirtualUrl(ItemPickerDataListEditor.DataEditorOverlayViewPath) }, { "maxItems", 1 }, } } @@ -81,7 +95,7 @@ public IEnumerable GetItems(Dictionary config) array.Count > 0 && array[0].Value() is string str && string.IsNullOrWhiteSpace(str) == false && - GuidUdi.TryParse(str, out var udi) == true) + UdiParser.TryParse(str, out GuidUdi udi) == true) { var contentType = _contentTypeService.Get(udi.Guid); if (contentType != null) diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentTypesDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentTypesDataListSource.cs index a70615dd..50182cfd 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentTypesDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentTypesDataListSource.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models.PublishedContent; @@ -15,6 +16,16 @@ using Umbraco.Core.Xml; using Umbraco.Web; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -22,11 +33,16 @@ public sealed class UmbracoContentTypesDataListSource : IDataListSource, IDataLi { private readonly IContentTypeService _contentTypeService; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IIOHelper _ioHelper; - public UmbracoContentTypesDataListSource(IContentTypeService contentTypeService, IUmbracoContextAccessor umbracoContextAccessor) + public UmbracoContentTypesDataListSource( + IContentTypeService contentTypeService, + IUmbracoContextAccessor umbracoContextAccessor, + IIOHelper ioHelper) { _contentTypeService = contentTypeService; _umbracoContextAccessor = umbracoContextAccessor; + _ioHelper = ioHelper; } public string Name => "Umbraco Content Types"; @@ -45,7 +61,7 @@ public UmbracoContentTypesDataListSource(IContentTypeService contentTypeService, { Key = "contentTypes", Name = "Content types", - View = IOHelper.ResolveUrl(CheckboxListDataListEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(CheckboxListDataListEditor.DataEditorViewPath), Description = "Select the types to use.", Config = new Dictionary { @@ -128,9 +144,9 @@ public IEnumerable GetItems(Dictionary config) public object ConvertValue(Type type, string value) { - if (GuidUdi.TryParse(value, out var udi) == true && ContentTypeCacheHelper.TryGetAlias(udi.Guid, out var alias, _contentTypeService) == true) + if (UdiParser.TryParse(value, out GuidUdi udi) == true && ContentTypeCacheHelper.TryGetAlias(udi.Guid, out var alias, _contentTypeService) == true) { - return _umbracoContextAccessor.UmbracoContext.Content.GetContentType(alias); + return _umbracoContextAccessor.GetRequiredUmbracoContext().Content.GetContentType(alias); } return default; diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentXPathDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentXPathDataListSource.cs index e6cfa604..3573c0c2 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentXPathDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoContentXPathDataListSource.cs @@ -6,13 +6,26 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Xml; using Umbraco.Web; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Core.Xml; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -20,12 +33,33 @@ public sealed class UmbracoContentXPathDataListSource : IDataListSource, IDataLi { private readonly IContentTypeService _contentTypeService; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly IIOHelper _ioHelper; - public UmbracoContentXPathDataListSource(IContentTypeService contentTypeService, IUmbracoContextAccessor umbracoContextAccessor) +#if NET472 + public UmbracoContentXPathDataListSource( + IContentTypeService contentTypeService, + IUmbracoContextAccessor umbracoContextAccessor, + IIOHelper ioHelper) { _contentTypeService = contentTypeService; _umbracoContextAccessor = umbracoContextAccessor; + _ioHelper = ioHelper; } +#else + private readonly IRequestAccessor _requestAccessor; + + public UmbracoContentXPathDataListSource( + IContentTypeService contentTypeService, + IRequestAccessor requestAccessor, + IUmbracoContextAccessor umbracoContextAccessor, + IIOHelper ioHelper) + { + _contentTypeService = contentTypeService; + _requestAccessor = requestAccessor; + _umbracoContextAccessor = umbracoContextAccessor; + _ioHelper = ioHelper; + } +#endif public string Name => "Umbraco Content by XPath"; @@ -46,7 +80,7 @@ public UmbracoContentXPathDataListSource(IContentTypeService contentTypeService, Description = "Enter the XPath expression to select the content.", View = "textstring", }, - new NotesConfigurationField($@"
+ new NotesConfigurationField(_ioHelper, $@"
Do you need help with XPath expressions?

If you need assistance with XPath syntax in general, please refer to this resource: w3schools.com/xml.


@@ -79,14 +113,22 @@ public IEnumerable GetItems(Dictionary config) { var nodeContextId = default(int?); var preview = true; - var umbracoContext = _umbracoContextAccessor.UmbracoContext; + var umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext(); // NOTE: First we check for "id" (if on a content page), then "parentId" (if editing an element). +#if NET472 if (int.TryParse(umbracoContext.HttpContext.Request.QueryString.Get("id"), out var currentId) == true) +#else + if (int.TryParse(_requestAccessor.GetQueryStringValue("id"), out var currentId) == true) +#endif { nodeContextId = currentId; } +#if NET472 else if (int.TryParse(umbracoContext.HttpContext.Request.QueryString.Get("parentId"), out var parentId) == true) +#else + else if (int.TryParse(_requestAccessor.GetQueryStringValue("parentId"), out var parentId) == true) +#endif { nodeContextId = parentId; } @@ -117,8 +159,8 @@ public IEnumerable GetItems(Dictionary config) public object ConvertValue(Type type, string value) { - return Udi.TryParse(value, out var udi) == true - ? _umbracoContextAccessor.UmbracoContext.Content.GetById(udi) + return UdiParser.TryParse(value, out var udi) == true + ? _umbracoContextAccessor.GetRequiredUmbracoContext().Content.GetById(udi) : default; } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoDictionaryDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoDictionaryDataListSource.cs index c4d66ff7..20a78db3 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoDictionaryDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoDictionaryDataListSource.cs @@ -7,19 +7,31 @@ using System.Globalization; using System.Linq; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class UmbracoDictionaryDataListSource : IDataListSource { private readonly ILocalizationService _localizationService; + private readonly IIOHelper _ioHelper; - public UmbracoDictionaryDataListSource(ILocalizationService localizationService) + public UmbracoDictionaryDataListSource( + ILocalizationService localizationService, + IIOHelper ioHelper) { _localizationService = localizationService; + _ioHelper = ioHelper; } public string Name => "Umbraco Dictionary Items"; @@ -37,7 +49,7 @@ public UmbracoDictionaryDataListSource(ILocalizationService localizationService) Key = "item", Name = "Dictionary item", Description = "Select a parent dictionary item to display the child items.", - View = DictionaryPickerDataEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(DictionaryPickerDataEditor.DataEditorViewPath), Config = new Dictionary { { MaxItemsConfigurationField.MaxItems, 1 } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoEntityDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoEntityDataListSource.cs index 665a67dd..8d169861 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoEntityDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoEntityDataListSource.cs @@ -6,12 +6,26 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +using Umbraco.Core.Strings; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.Entities; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -41,11 +55,18 @@ public sealed class UmbracoEntityDataListSource : IDataListSource, IDataListSour { nameof(UmbracoObjectTypes.MemberType), UmbConstants.Icons.MemberType }, }; - private readonly IEntityService _entityService; + private readonly IIOHelper _ioHelper; + private readonly Lazy _entityService; + private readonly IShortStringHelper _shortStringHelper; - public UmbracoEntityDataListSource(IEntityService entityService) + public UmbracoEntityDataListSource( + Lazy entityService, + IShortStringHelper shortStringHelper, + IIOHelper ioHelper) { _entityService = entityService; + _shortStringHelper = shortStringHelper; + _ioHelper = ioHelper; } public string Name => "Umbraco Entities"; @@ -58,7 +79,7 @@ public UmbracoEntityDataListSource(IEntityService entityService) public IEnumerable Fields => new ConfigurationField[] { - new NotesConfigurationField(@"
+ new NotesConfigurationField(_ioHelper, @"
A note about supported Umbraco entity types.

Umbraco's EntityService API (currently) has limited support for querying entity types by GUID or UDI.

Supported entity types are available in the list below.

@@ -68,11 +89,16 @@ public UmbracoEntityDataListSource(IEntityService entityService) Key = "entityType", Name = "Entity type", Description = "Select the Umbraco entity type to use.", - View = DropdownListDataListEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(DropdownListDataListEditor.DataEditorViewPath), Config = new Dictionary() { { "allowEmpty", Constants.Values.False }, - { "items", SupportedEntityTypes.Keys.Select(x => new DataListItem { Name = x.SplitPascalCasing(), Value = x }) }, + { "items", SupportedEntityTypes.Keys.Select(x => new DataListItem + { + Name = x.SplitPascalCasing(_shortStringHelper), + Value = x + }) + }, } } }; @@ -88,13 +114,14 @@ public IEnumerable GetItems(Dictionary config) var icon = EntityTypeIcons.GetValueAs(entityType, UmbConstants.Icons.DefaultIcon); return _entityService + .Value .GetAll(objectType) .OrderBy(x => x.Name) .Select(x => new DataListItem { Icon = icon, Name = x.Name, - Value = Udi.Create(UmbConstants.UdiEntityType.FromUmbracoObjectType(objectType), x.Key).ToString(), + Value = Udi.Create(objectType.GetUdiType(), x.Key).ToString(), }); } @@ -105,8 +132,8 @@ public IEnumerable GetItems(Dictionary config) public object ConvertValue(Type type, string value) { - return GuidUdi.TryParse(value, out var udi) == true && udi.Guid.Equals(Guid.Empty) == false - ? _entityService.Get(udi.Guid) + return UdiParser.TryParse(value, out GuidUdi udi) == true && udi.Guid.Equals(Guid.Empty) == false + ? _entityService.Value.Get(udi.Guid) : default; } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoImageCropDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoImageCropDataListSource.cs index 06d91155..1d2f69da 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoImageCropDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoImageCropDataListSource.cs @@ -5,21 +5,36 @@ using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class UmbracoImageCropDataListSource : IDataListSource { private readonly IDataTypeService _dataTypeService; + private readonly IIOHelper _ioHelper; - public UmbracoImageCropDataListSource(IDataTypeService dataTypeService) + public UmbracoImageCropDataListSource( + IDataTypeService dataTypeService, + IIOHelper ioHelper) { _dataTypeService = dataTypeService; + _ioHelper = ioHelper; } public string Name => "Umbraco Image Crops"; @@ -50,7 +65,7 @@ public IEnumerable Fields Key = "imageCropper", Name = "Image Cropper", Description = "Select a Data Type that uses the Image Cropper.", - View = RadioButtonListDataListEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, items }, @@ -71,7 +86,7 @@ public IEnumerable GetItems(Dictionary config) if (config.TryGetValue("imageCropper", out var obj) == true && obj is string str && string.IsNullOrWhiteSpace(str) == false && - GuidUdi.TryParse(str, out var udi) == true) + UdiParser.TryParse(str, out GuidUdi udi) == true) { return _dataTypeService .GetDataType(udi.Guid)? diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoLanguagesDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoLanguagesDataListSource.cs index e5c7d5fe..21afe54d 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoLanguagesDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoLanguagesDataListSource.cs @@ -5,9 +5,15 @@ using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMemberGroupDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMemberGroupDataListSource.cs index 5be1f843..84cf4d53 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMemberGroupDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMemberGroupDataListSource.cs @@ -6,10 +6,17 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMembersDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMembersDataListSource.cs index 120dd237..125d207a 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMembersDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoMembersDataListSource.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models; @@ -15,6 +16,17 @@ using Umbraco.Core.Services; using Umbraco.Web.PublishedCache; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -23,12 +35,18 @@ public sealed class UmbracoMembersDataListSource : IDataListSource, IDataListSou private readonly IMemberTypeService _memberTypeService; private readonly IMemberService _memberService; private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; + private readonly IIOHelper _ioHelper; - public UmbracoMembersDataListSource(IMemberTypeService memberTypeService, IMemberService memberService, IPublishedSnapshotAccessor publishedSnapshotAccessor) + public UmbracoMembersDataListSource( + IMemberTypeService memberTypeService, + IMemberService memberService, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IIOHelper ioHelper) { _memberTypeService = memberTypeService; _memberService = memberService; _publishedSnapshotAccessor = publishedSnapshotAccessor; + _ioHelper = ioHelper; } public string Name => "Umbraco Members"; @@ -56,7 +74,7 @@ public IEnumerable Fields return new[] { - new NotesConfigurationField($@"
+ new NotesConfigurationField(_ioHelper, $@"
Important note about Umbraco Members.

This data source is ideal for smaller number of members, e.g. under 50. Upwards of that, you will notice an unpleasant editor experience and rapidly diminished performance.

Remember...

@@ -70,14 +88,14 @@ public IEnumerable Fields Key = "memberType", Name = "Member Type", Description = "Select a member type to filter the members by. If left empty, all members will be used.", - View = ItemPickerDataListEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(ItemPickerDataListEditor.DataEditorViewPath), Config = new Dictionary { { "addButtonLabelKey", "defaultdialogs_selectMemberType" }, { "enableFilter", items.Count > 5 ? Constants.Values.True : Constants.Values.False }, { "items", items }, { "listType", "list" }, - { "overlayView", IOHelper.ResolveUrl(ItemPickerDataListEditor.DataEditorOverlayViewPath) }, + { "overlayView", _ioHelper.ResolveRelativeOrVirtualUrl(ItemPickerDataListEditor.DataEditorOverlayViewPath) }, { "maxItems", 1 }, } } @@ -107,7 +125,7 @@ DataListItem mapMember(IMember member) array.Count > 0 && array[0].Value() is string str && string.IsNullOrWhiteSpace(str) == false && - GuidUdi.TryParse(str, out var udi) == true) + UdiParser.TryParse(str, out GuidUdi udi) == true) { var memberType = _memberTypeService.Get(udi.Guid); if (memberType != null) @@ -123,9 +141,20 @@ DataListItem mapMember(IMember member) public object ConvertValue(Type type, string value) { - return GuidUdi.TryParse(value, out var udi) == true && udi.Guid.Equals(Guid.Empty) == false - ? _publishedSnapshotAccessor.PublishedSnapshot.Members.GetByProviderKey(udi.Guid) - : default; + if (UdiParser.TryParse(value, out GuidUdi udi) == true && udi.Guid.Equals(Guid.Empty) == false) + { +#if NET472 + return _publishedSnapshotAccessor.GetRequiredPublishedSnapshot()?.Members.GetByProviderKey(udi.Guid); +#else + var member = _memberService.GetByKey(udi.Guid); + if (member != null) + { + return _publishedSnapshotAccessor.GetRequiredPublishedSnapshot()?.Members.Get(_memberService.GetByKey(udi.Guid)); + } +#endif + } + + return default(IPublishedContent); } } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoTagsDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoTagsDataListSource.cs index 2f048af5..a2d22337 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoTagsDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoTagsDataListSource.cs @@ -6,9 +6,15 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.PropertyEditors; using Umbraco.Web; +#else +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PublishedCache; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -51,7 +57,11 @@ public IEnumerable GetItems(Dictionary config) { var tagGroup = config.GetValueAs("tagGroup", defaultValue: string.Empty); - return _tagQuery.Value + // TODO: [LK:2021-09-20] Error with Tags data source on v9. + // FIXME: Cannot resolve scoped service 'Umbraco.Cms.Core.PublishedCache.ITagQuery' from root provider. + + return _tagQuery + .Value .GetAllTags(tagGroup) .OrderBy(x => x.Text) .Select(x => new DataListItem diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUserGroupDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUserGroupDataListSource.cs index 221c6a43..9ca7c857 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUserGroupDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUserGroupDataListSource.cs @@ -6,10 +6,17 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core.Models.Membership; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUsersDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUsersDataListSource.cs index f2200e56..c9fe153f 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUsersDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UmbracoUsersDataListSource.cs @@ -7,21 +7,32 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Models.Membership; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class UmbracoUsersDataListSource : IDataListSource, IDataListSourceValueConverter { + private readonly IIOHelper _ioHelper; private readonly IUserService _userService; - public UmbracoUsersDataListSource(IUserService userService) + public UmbracoUsersDataListSource(IIOHelper ioHelper, IUserService userService) { + _ioHelper = ioHelper; _userService = userService; } @@ -55,13 +66,13 @@ public IEnumerable Fields Key = "userGroup", Name = "User Group", Description = "Select a user group to filter the users by. If left empty, all users will be used.", - View = ItemPickerDataListEditor.DataEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(ItemPickerDataListEditor.DataEditorViewPath), Config = new Dictionary { { "enableFilter", items.Count > 5 ? Constants.Values.True : Constants.Values.False }, { "items", items }, { "listType", "list" }, - { "overlayView", IOHelper.ResolveUrl(ItemPickerDataListEditor.DataEditorOverlayViewPath) }, + { "overlayView", _ioHelper.ResolveRelativeOrVirtualUrl(ItemPickerDataListEditor.DataEditorOverlayViewPath) }, { "maxItems", 1 }, } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UserDefinedDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UserDefinedDataListSource.cs index 5ffaee35..c03390e3 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UserDefinedDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/UserDefinedDataListSource.cs @@ -6,18 +6,34 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class UserDefinedDataListSource : IDataListSource { + private readonly IIOHelper _ioHelper; + + public UserDefinedDataListSource(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + public string Name => "User-defined List"; public string Description => "Manually configure the items for the data source."; - public string Icon => Core.Constants.Icons.DataType; + public string Icon => UmbConstants.Icons.DataType; public string Group => Constants.Conventions.DataSourceGroups.Data; @@ -28,18 +44,17 @@ public sealed class UserDefinedDataListSource : IDataListSource Key = "items", Name = "Options", Description = "Configure the option items for the data list.

Please try to avoid using duplicate values, as this may cause adverse issues with list editors.", - View = DataListDataEditor.DataEditorListEditorViewPath, + View = _ioHelper.ResolveRelativeOrVirtualUrl(DataListDataEditor.DataEditorListEditorViewPath), Config = new Dictionary() { { "confirmRemoval", Constants.Values.True }, { EnableDevModeConfigurationField.EnableDevMode, Constants.Values.True }, { MaxItemsConfigurationField.MaxItems, 0 }, - { NotesConfigurationField.Notes, @" -
- Advanced: Paste in the raw JSON? -

If you have copied the raw JSON from the Data List preview panel, .

-

The JSON format must be an array of the Data List item structure.
For example...

- [ + { NotesConfigurationField.Notes, @"
+Advanced: Paste in the raw JSON? +

If you have copied the raw JSON from the Data List preview panel, .

+

The JSON format must be an array of the Data List item structure.
For example...

+[ { ""name"": ""Ready"", ""value"": ""value1"", @@ -57,7 +72,7 @@ public sealed class UserDefinedDataListSource : IDataListSource ""description"": ""Three to get ready. Now go, cat, go."" } ] -
" }, +
" }, }, } }; diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlDataListSource.cs index c5b3eecb..2e78d4cb 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlDataListSource.cs @@ -7,23 +7,56 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http; using System.Xml; using System.Xml.XPath; +#if NET472 using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +#else +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { public sealed class XmlDataListSource : IDataListSource { + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IIOHelper _ioHelper; + +#if NET472 private readonly ILogger _logger; - public XmlDataListSource(ILogger logger) + public XmlDataListSource( + ILogger logger, + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) + { + _logger = logger; + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; + } +#else + private readonly ILogger _logger; + + public XmlDataListSource( + ILogger logger, + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) { _logger = logger; + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; } +#endif public string Name => "XML Data"; @@ -44,7 +77,7 @@ public XmlDataListSource(ILogger logger) Description = "Enter the URL of the XML data source.
This can be either a remote URL, or local relative file path.", View = "textstring" }, - new NotesConfigurationField(@"
+ new NotesConfigurationField(_ioHelper, @"
Do you need help with XPath expressions?

If you need assistance with XPath syntax, please refer to this resource: w3schools.com/xml.

@@ -109,7 +142,7 @@ public IEnumerable GetItems(Dictionary config) } var path = url.InvariantStartsWith("http") == false - ? IOHelper.MapPath(url) + ? _hostingEnvironment.MapPathWebRoot(url) : url; var doc = default(XPathDocument); @@ -118,13 +151,29 @@ public IEnumerable GetItems(Dictionary config) { doc = new XPathDocument(path); } + catch (HttpRequestException ex) + { +#if NET472 + _logger.Error(ex, $"Unable to retrieve data from '{path}'."); +#else + _logger.LogError(ex, $"Unable to retrieve data from '{path}'."); +#endif + } catch (WebException ex) { +#if NET472 _logger.Error(ex, $"Unable to retrieve data from '{path}'."); +#else + _logger.LogError(ex, $"Unable to retrieve data from '{path}'."); +#endif } catch (XmlException ex) { +#if NET472 _logger.Error(ex, "Unable to load XML data."); +#else + _logger.LogError(ex, $"Unable to load XML data from '{path}'."); +#endif } if (doc == null) @@ -158,7 +207,11 @@ public IEnumerable GetItems(Dictionary config) if (nodes.Count == 0) { +#if NET472 _logger.Warn($"The XPath '{itemsXPath}' did not match any items in the XML: {nav.OuterXml.Substring(0, Math.Min(300, nav.OuterXml.Length))}"); +#else + _logger.LogWarning($"The XPath '{itemsXPath}' did not match any items in the XML: {nav.OuterXml.Substring(0, Math.Min(300, nav.OuterXml.Length))}"); +#endif return Enumerable.Empty(); } @@ -198,12 +251,20 @@ public IEnumerable GetItems(Dictionary config) if (name == null) { +#if NET472 _logger.Warn($"The XPath '{nameXPath}' did not match a 'name' in the item XML: {outerXml}"); +#else + _logger.LogWarning($"The XPath '{nameXPath}' did not match a 'name' in the item XML: {outerXml}"); +#endif } if (value == null) { +#if NET472 _logger.Warn($"The XPath '{valueXPath}' did not match a 'value' in the item XML: {outerXml}"); +#else + _logger.LogWarning($"The XPath '{valueXPath}' did not match a 'value' in the item XML: {outerXml}"); +#endif } } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapChangeFrequencyDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapChangeFrequencyDataListSource.cs index 00633050..6c5cc68f 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapChangeFrequencyDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapChangeFrequencyDataListSource.cs @@ -5,8 +5,13 @@ using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapPriorityDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapPriorityDataListSource.cs index 246b5fd4..1e32d5ba 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapPriorityDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/XmlSitemapPriorityDataListSource.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/uCssClassNameDataListSource.cs b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/uCssClassNameDataListSource.cs index 609e93d9..45ed6bd3 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/uCssClassNameDataListSource.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DataList/DataSources/uCssClassNameDataListSource.cs @@ -7,14 +7,34 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +#if NET472 using Umbraco.Core; +using Umbraco.Core.Hosting; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { public class uCssClassNameDataListSource : IDataListSource { + private readonly IHostingEnvironment _hostingEnvironment; + private readonly IIOHelper _ioHelper; + + public uCssClassNameDataListSource( + IHostingEnvironment hostingEnvironment, + IIOHelper ioHelper) + { + _hostingEnvironment = hostingEnvironment; + _ioHelper = ioHelper; + } + public string Name => "uCssClassName"; public string Description => "A homage to @marcemarc's bingo-famous uCssClassNameDropdown package!"; @@ -25,7 +45,7 @@ public class uCssClassNameDataListSource : IDataListSource public IEnumerable Fields => new[] { - new NotesConfigurationField(@"
+ new NotesConfigurationField(_ioHelper, @"
uCssClassName? What sort of a name is that?

Welcome to a piece of Umbraco package history.

First released back in 2013 by Marc Goodson, uCssClassNameDropdown became one of the most popular packages for Umbraco v4.11.3.

@@ -86,7 +106,7 @@ public IEnumerable GetItems(Dictionary config) var items = new HashSet(); - var path = IOHelper.MapPath(cssPath); + var path = _hostingEnvironment.MapPathWebRoot(cssPath); if (File.Exists(path) == true) { diff --git a/src/Umbraco.Community.Contentment/DataEditors/DropdownList/DropdownListDataListEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/DropdownList/DropdownListDataListEditor.cs index 8bc0740e..e264996e 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/DropdownList/DropdownListDataListEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/DropdownList/DropdownListDataListEditor.cs @@ -4,7 +4,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -13,7 +19,14 @@ public sealed class DropdownListDataListEditor : IDataListEditor internal const string AllowEmpty = "allowEmpty"; internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "dropdown-list.html"; - public string Name => "Dropdown List"; + private readonly IIOHelper _ioHelper; + + public DropdownListDataListEditor(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + + public string Name => "Dropdown List"; public string Description => "Select a single value from a dropdown select list."; @@ -34,7 +47,7 @@ public sealed class DropdownListDataListEditor : IDataListEditor { "default", Constants.Values.True } } }, - new HtmlAttributesConfigurationField(), + new HtmlAttributesConfigurationField(_ioHelper), }; public Dictionary DefaultValues => new Dictionary diff --git a/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerConfigurationEditor.cs index 10a234d1..db04e879 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerConfigurationEditor.cs @@ -4,14 +4,20 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { internal sealed class IconPickerConfigurationEditor : ConfigurationEditor { - public IconPickerConfigurationEditor() + public IconPickerConfigurationEditor(IIOHelper ioHelper) : base() { Fields.Add(new ConfigurationField @@ -19,7 +25,7 @@ public IconPickerConfigurationEditor() Key = "defaultIcon", Name = "Default icon", Description = "Select an icon to be displayed as the default icon, (for when no icon has been selected).", - View = IOHelper.ResolveUrl(IconPickerDataEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(IconPickerDataEditor.DataEditorViewPath), Config = new Dictionary { { "defaultIcon", string.Empty }, diff --git a/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerDataEditor.cs index 383252a7..fd8072fa 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerDataEditor.cs @@ -3,8 +3,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -14,7 +22,7 @@ namespace Umbraco.Community.Contentment.DataEditors DataEditorName, DataEditorViewPath, ValueType = ValueTypes.String, - Group = Core.Constants.PropertyEditors.Groups.Pickers, + Group = UmbConstants.PropertyEditors.Groups.Pickers, Icon = DataEditorIcon)] public sealed class IconPickerDataEditor : DataEditor { @@ -23,10 +31,19 @@ public sealed class IconPickerDataEditor : DataEditor internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "icon-picker.html"; internal const string DataEditorIcon = "icon-fa fa-circle-o"; - public IconPickerDataEditor(ILogger logger) + private readonly IIOHelper _ioHelper; + +#if NET472 + public IconPickerDataEditor(IIOHelper ioHelper, ILogger logger) : base(logger) - { } +#else + public IconPickerDataEditor(IIOHelper ioHelper, IDataValueEditorFactory dataValueEditorFactory) + : base(dataValueEditorFactory) +#endif + { + _ioHelper = ioHelper; + } - protected override IConfigurationEditor CreateConfigurationEditor() => new IconPickerConfigurationEditor(); + protected override IConfigurationEditor CreateConfigurationEditor() => new IconPickerConfigurationEditor(_ioHelper); } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerValueConverter.cs index e118455b..7e51f7bb 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/IconPicker/IconPickerValueConverter.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/ItemPicker/ItemPickerDataListEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/ItemPicker/ItemPickerDataListEditor.cs index bdbc9819..186b165d 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ItemPicker/ItemPickerDataListEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ItemPicker/ItemPickerDataListEditor.cs @@ -4,9 +4,17 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -15,6 +23,13 @@ public sealed class ItemPickerDataListEditor : IDataListEditor internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "item-picker.html"; internal const string DataEditorOverlayViewPath = Constants.Internals.EditorsPathRoot + "item-picker.overlay.html"; + private readonly IIOHelper _ioHelper; + + public ItemPickerDataListEditor(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + public string Name => "Item Picker"; public string Description => "Select items from an Umbraco style overlay."; @@ -30,7 +45,7 @@ public sealed class ItemPickerDataListEditor : IDataListEditor Key = "overlaySize", Name = "Editor overlay size", Description = "Select the size of the overlay editing panel. By default this is set to 'small'. However if the editor fields require a wider panel, please select 'medium' or 'large'.", - View = IOHelper.ResolveUrl(RadioButtonListDataListEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] @@ -48,14 +63,14 @@ public sealed class ItemPickerDataListEditor : IDataListEditor Key = "defaultIcon", Name = "Default icon", Description = "Select an icon to be displayed as the default icon,
(for when no icon is available).", - View = IOHelper.ResolveUrl("~/umbraco/views/propertyeditors/listview/icon.prevalues.html"), + View = _ioHelper.ResolveRelativeOrVirtualUrl("~/umbraco/views/propertyeditors/listview/icon.prevalues.html"), }, new ConfigurationField { Key = "listType", Name = "List type", Description = "Select the style of list to be displayed in the overlay.", - View = IOHelper.ResolveUrl(RadioButtonListDataListEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] @@ -75,7 +90,7 @@ public sealed class ItemPickerDataListEditor : IDataListEditor { "default", Constants.Values.True } }, }, - new MaxItemsConfigurationField(), + new MaxItemsConfigurationField(_ioHelper), new AllowClearConfigurationField(), new ConfigurationField { @@ -104,14 +119,14 @@ public sealed class ItemPickerDataListEditor : IDataListEditor public Dictionary DefaultValues => new Dictionary { { "listType", "list" }, - { "defaultIcon", Core.Constants.Icons.DefaultIcon }, + { "defaultIcon", UmbConstants.Icons.DefaultIcon }, { EnableFilterConfigurationField.EnableFilter, Constants.Values.True }, { MaxItemsConfigurationField.MaxItems, "0" }, }; public Dictionary DefaultConfig => new Dictionary { - { Constants.Conventions.ConfigurationFieldAliases.OverlayView, IOHelper.ResolveUrl(DataEditorOverlayViewPath) }, + { Constants.Conventions.ConfigurationFieldAliases.OverlayView, _ioHelper.ResolveRelativeOrVirtualUrl(DataEditorOverlayViewPath) }, { "overlayOrderBy", string.Empty }, }; diff --git a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationEditor.cs index 641d067e..2e0cb522 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationEditor.cs @@ -4,8 +4,14 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -13,7 +19,7 @@ internal sealed class NotesConfigurationEditor : ConfigurationEditor { internal const string Notes = NotesConfigurationField.Notes; - public NotesConfigurationEditor() + public NotesConfigurationEditor(IIOHelper ioHelper) : base() { Fields.Add(new ConfigurationField @@ -21,7 +27,7 @@ public NotesConfigurationEditor() Key = Notes, Name = nameof(Notes), Description = "Enter the notes to be displayed for the content editor.", - View = IOHelper.ResolveUrl("~/umbraco/views/propertyeditors/rte/rte.html"), + View = ioHelper.ResolveRelativeOrVirtualUrl("~/umbraco/views/propertyeditors/rte/rte.html"), Config = new Dictionary { { "editor", Constants.Conventions.DefaultConfiguration.RichTextEditor } diff --git a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationField.cs index 9517446e..e7daca6b 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesConfigurationField.cs @@ -4,7 +4,14 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -12,12 +19,12 @@ internal class NotesConfigurationField : ConfigurationField { internal const string Notes = "notes"; - public NotesConfigurationField(string notes, bool hideLabel = true) + public NotesConfigurationField(IIOHelper ioHelper, string notes, bool hideLabel = true) : base() { Key = Notes; Name = nameof(Notes); - View = NotesDataEditor.DataEditorViewPath; + View = ioHelper.ResolveRelativeOrVirtualUrl(NotesDataEditor.DataEditorViewPath); Config = new Dictionary { { Notes, notes } }; HideLabel = hideLabel; } diff --git a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesDataEditor.cs index 463d4a0e..c99bd425 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesDataEditor.cs @@ -4,8 +4,19 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -16,6 +27,31 @@ public sealed class NotesDataEditor : IDataEditor internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "notes.html"; internal const string DataEditorIcon = "icon-fa fa-sticky-note-o"; + private readonly IIOHelper _ioHelper; + +#if NET472 + public NotesDataEditor(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } +#else + private readonly ILocalizedTextService _localizedTextService; + private readonly IShortStringHelper _shortStringHelper; + private readonly IJsonSerializer _jsonSerializer; + + public NotesDataEditor( + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + IIOHelper ioHelper) + { + _localizedTextService = localizedTextService; + _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; + _ioHelper = ioHelper; + } +#endif + public string Alias => DataEditorAlias; public EditorType Type => EditorType.PropertyValue; @@ -32,11 +68,18 @@ public sealed class NotesDataEditor : IDataEditor public IPropertyIndexValueFactory PropertyIndexValueFactory => new DefaultPropertyIndexValueFactory(); - public IConfigurationEditor GetConfigurationEditor() => new NotesConfigurationEditor(); + public IConfigurationEditor GetConfigurationEditor() => new NotesConfigurationEditor(_ioHelper); public IDataValueEditor GetValueEditor() { +#if NET472 return new ReadOnlyDataValueEditor +#else + return new ReadOnlyDataValueEditor( + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { ValueType = ValueTypes.Integer, View = DataEditorViewPath, @@ -52,7 +95,14 @@ public IDataValueEditor GetValueEditor(object configuration) hideLabel = config[HideLabelConfigurationField.HideLabelAlias].TryConvertTo().Result; } +#if NET472 return new ReadOnlyDataValueEditor +#else + return new ReadOnlyDataValueEditor( + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { Configuration = configuration, HideLabel = hideLabel, diff --git a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesValueConverter.cs index 2363f91e..07a48164 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Notes/NotesValueConverter.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputConfigurationEditor.cs index 262a8396..64dc1a24 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputConfigurationEditor.cs @@ -4,14 +4,20 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { internal sealed class NumberInputConfigurationEditor : ConfigurationEditor { - public NumberInputConfigurationEditor() + public NumberInputConfigurationEditor(IIOHelper ioHelper) : base() { DefaultConfiguration.Add("size", "s"); @@ -21,7 +27,7 @@ public NumberInputConfigurationEditor() Key = "size", Name = "Numeric size", Description = "How big will the number get?", - View = IOHelper.ResolveUrl(RadioButtonListDataListEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(RadioButtonListDataListEditor.DataEditorViewPath), Config = new Dictionary { { Constants.Conventions.ConfigurationFieldAliases.Items, new[] diff --git a/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputDataEditor.cs index e3db273f..4fc39cb2 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputDataEditor.cs @@ -3,8 +3,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -14,7 +22,7 @@ namespace Umbraco.Community.Contentment.DataEditors DataEditorName, DataEditorViewPath, ValueType = ValueTypes.Integer, - Group = Core.Constants.PropertyEditors.Groups.Common, + Group = UmbConstants.PropertyEditors.Groups.Common, Icon = DataEditorIcon)] internal sealed class NumberInputDataEditor : DataEditor { @@ -23,10 +31,23 @@ internal sealed class NumberInputDataEditor : DataEditor internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "number-input.html"; internal const string DataEditorIcon = "icon-coin"; - public NumberInputDataEditor(ILogger logger) + private readonly IIOHelper _ioHelper; + +#if NET472 + public NumberInputDataEditor(IIOHelper ioHelper, ILogger logger) : base(logger) - { } + { + _ioHelper = ioHelper; + } +#else + public NumberInputDataEditor(IIOHelper ioHelper, IDataValueEditorFactory dataValueEditorFactory) + : base(dataValueEditorFactory) + { + _ioHelper = ioHelper; + } +#endif + - protected override IConfigurationEditor CreateConfigurationEditor() => new NumberInputConfigurationEditor(); + protected override IConfigurationEditor CreateConfigurationEditor() => new NumberInputConfigurationEditor(_ioHelper); } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputValueConverter.cs index 66425714..527129f2 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/NumberInput/NumberInputValueConverter.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/RadioButtonList/RadioButtonListDataListEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/RadioButtonList/RadioButtonListDataListEditor.cs index 2ac3e3e5..066f04c6 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/RadioButtonList/RadioButtonListDataListEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/RadioButtonList/RadioButtonListDataListEditor.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/ReadOnly/ReadOnlyDataValueEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/ReadOnly/ReadOnlyDataValueEditor.cs index e86a4d60..4500aab5 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/ReadOnly/ReadOnlyDataValueEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/ReadOnly/ReadOnlyDataValueEditor.cs @@ -3,12 +3,28 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +#endif namespace Umbraco.Community.Contentment.DataEditors { internal sealed class ReadOnlyDataValueEditor : DataValueEditor { +#if NET472 == false + public ReadOnlyDataValueEditor( + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + : base(localizedTextService, shortStringHelper, jsonSerializer) + { } +#endif + public override bool IsReadOnly => true; } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroConfigurationEditor.cs index b656abea..911e2168 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroConfigurationEditor.cs @@ -4,8 +4,14 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -13,7 +19,7 @@ internal sealed class RenderMacroConfigurationEditor : ConfigurationEditor { internal const string Macro = "macro"; - public RenderMacroConfigurationEditor() + public RenderMacroConfigurationEditor(IIOHelper ioHelper) : base() { Fields.Add(new ConfigurationField @@ -21,7 +27,7 @@ public RenderMacroConfigurationEditor() Key = Macro, Name = nameof(Macro), Description = "Select and configure the macro to be displayed.", - View = IOHelper.ResolveUrl(MacroPickerDataEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(MacroPickerDataEditor.DataEditorViewPath), Config = new Dictionary { { MaxItemsConfigurationField.MaxItems, 1 } diff --git a/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroDataEditor.cs index 5858f4a1..c3fcc4ed 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroDataEditor.cs @@ -4,8 +4,21 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -14,7 +27,32 @@ public sealed class RenderMacroDataEditor : IDataEditor internal const string DataEditorAlias = Constants.Internals.DataEditorAliasPrefix + "RenderMacro"; internal const string DataEditorName = Constants.Internals.DataEditorNamePrefix + "Render Macro"; internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "render-macro.html"; - internal const string DataEditorIcon = Core.Constants.Icons.Macro; + internal const string DataEditorIcon = UmbConstants.Icons.Macro; + + private readonly IIOHelper _ioHelper; + +#if NET472 + public RenderMacroDataEditor(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } +#else + private readonly ILocalizedTextService _localizedTextService; + private readonly IShortStringHelper _shortStringHelper; + private readonly IJsonSerializer _jsonSerializer; + + public RenderMacroDataEditor( + IIOHelper ioHelper, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer) + { + _ioHelper = ioHelper; + _localizedTextService = localizedTextService; + _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; + } +#endif public string Alias => DataEditorAlias; @@ -32,11 +70,18 @@ public sealed class RenderMacroDataEditor : IDataEditor public IPropertyIndexValueFactory PropertyIndexValueFactory => new DefaultPropertyIndexValueFactory(); - public IConfigurationEditor GetConfigurationEditor() => new RenderMacroConfigurationEditor(); + public IConfigurationEditor GetConfigurationEditor() => new RenderMacroConfigurationEditor(_ioHelper); public IDataValueEditor GetValueEditor() { +#if NET472 return new ReadOnlyDataValueEditor +#else + return new ReadOnlyDataValueEditor( + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { ValueType = ValueTypes.Integer, View = DataEditorViewPath, @@ -52,7 +97,14 @@ public IDataValueEditor GetValueEditor(object configuration) hideLabel = config[HideLabelConfigurationField.HideLabelAlias].TryConvertTo().Result; } +#if NET472 return new ReadOnlyDataValueEditor +#else + return new ReadOnlyDataValueEditor( + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { Configuration = configuration, HideLabel = hideLabel, diff --git a/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroValueConverter.cs index 49af4063..cb899b78 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/RenderMacro/RenderMacroValueConverter.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/Tags/TagsDataListEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/Tags/TagsDataListEditor.cs index 48d2faff..448f7272 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/Tags/TagsDataListEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/Tags/TagsDataListEditor.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelConfigurationEditor.cs index 38bab5cf..113297d0 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelConfigurationEditor.cs @@ -4,15 +4,22 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { internal sealed class TemplatedLabelConfigurationEditor : ConfigurationEditor { - public TemplatedLabelConfigurationEditor() + public TemplatedLabelConfigurationEditor(IIOHelper ioHelper) : base() { var valueTypes = new[] @@ -36,7 +43,7 @@ public TemplatedLabelConfigurationEditor() Key = UmbConstants.PropertyEditors.ConfigurationKeys.DataValueType, Name = "Value type", Description = "Select the value's type. This defines how the underlying value is stored in the database.", - View = IOHelper.ResolveUrl(DropdownListDataListEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(DropdownListDataListEditor.DataEditorViewPath), Config = new Dictionary { { DropdownListDataListEditor.AllowEmpty, Constants.Values.False }, @@ -44,7 +51,7 @@ public TemplatedLabelConfigurationEditor() } }); - Fields.Add(new NotesConfigurationField(@"
+ Fields.Add(new NotesConfigurationField(ioHelper, @"
Do you need help with your custom template?

Your custom template will be used to display the label on the property from the underlying value.

If you are familiar with AngularJS template syntax, you can display the value using an expression: e.g. {{ model.value }}.

@@ -62,7 +69,7 @@ public TemplatedLabelConfigurationEditor() Key = "notes", Name = "Template", Description = "Enter the AngularJS template to be displayed for the label.", - View = IOHelper.ResolveUrl(CodeEditorDataEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(CodeEditorDataEditor.DataEditorViewPath), Config = new Dictionary { { CodeEditorConfigurationEditor.Mode, "razor" }, diff --git a/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelDataEditor.cs index 3c03bcc8..bd3d4d0b 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelDataEditor.cs @@ -4,8 +4,19 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Strings; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -16,6 +27,31 @@ public sealed class TemplatedLabelDataEditor : IDataEditor internal const string DataEditorViewPath = NotesDataEditor.DataEditorViewPath; internal const string DataEditorIcon = "icon-fa fa-codepen"; + private readonly IIOHelper _ioHelper; + +#if NET472 + public TemplatedLabelDataEditor(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } +#else + private readonly ILocalizedTextService _localizedTextService; + private readonly IShortStringHelper _shortStringHelper; + private readonly IJsonSerializer _jsonSerializer; + + public TemplatedLabelDataEditor( + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IJsonSerializer jsonSerializer, + IIOHelper ioHelper) + { + _localizedTextService = localizedTextService; + _shortStringHelper = shortStringHelper; + _jsonSerializer = jsonSerializer; + _ioHelper = ioHelper; + } +#endif + public string Alias => DataEditorAlias; public EditorType Type => EditorType.PropertyValue; @@ -32,11 +68,18 @@ public sealed class TemplatedLabelDataEditor : IDataEditor public IPropertyIndexValueFactory PropertyIndexValueFactory => new DefaultPropertyIndexValueFactory(); - public IConfigurationEditor GetConfigurationEditor() => new TemplatedLabelConfigurationEditor(); + public IConfigurationEditor GetConfigurationEditor() => new TemplatedLabelConfigurationEditor(_ioHelper); public IDataValueEditor GetValueEditor() { +#if NET472 return new DataValueEditor +#else + return new DataValueEditor( + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { View = DataEditorViewPath, }; @@ -51,7 +94,14 @@ public IDataValueEditor GetValueEditor(object configuration) hideLabel = config[HideLabelConfigurationField.HideLabelAlias].TryConvertTo().Result; } +#if NET472 return new DataValueEditor +#else + return new DataValueEditor( + _localizedTextService, + _shortStringHelper, + _jsonSerializer) +#endif { Configuration = configuration, HideLabel = hideLabel, diff --git a/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelValueConverter.cs index 9bf0bbe6..6571e066 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/TemplatedLabel/TemplatedLabelValueConverter.cs @@ -5,11 +5,19 @@ using System; using System.Collections.Generic; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.PropertyEditors.ValueConverters; +using UmbConstants = Umbraco.Cms.Core.Constants; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/TemplatedList/TemplatedListDataListEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/TemplatedList/TemplatedListDataListEditor.cs index c7fa2582..ad23fee3 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/TemplatedList/TemplatedListDataListEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/TemplatedList/TemplatedListDataListEditor.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -14,7 +20,14 @@ public sealed class TemplatedListDataListEditor : IDataListEditor { internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "templated-list.html"; - public string Name => "Templated List"; + private readonly IIOHelper _ioHelper; + + public TemplatedListDataListEditor(IIOHelper ioHelper) + { + _ioHelper = ioHelper; + } + + public string Name => "Templated List"; public string Description => "Select items from a list rendered with custom markup."; @@ -24,7 +37,7 @@ public sealed class TemplatedListDataListEditor : IDataListEditor public IEnumerable Fields => new ConfigurationField[] { - new NotesConfigurationField(@"
+ new NotesConfigurationField(_ioHelper, @"
Do you need help with your custom template?

Your custom template will be used to display an individual item from your configured data source.

The data for the item will be in the following format:

@@ -47,7 +60,7 @@ public sealed class TemplatedListDataListEditor : IDataListEditor { Key = "template", Name = "Template", - View = IOHelper.ResolveUrl(CodeEditorDataEditor.DataEditorViewPath), + View = _ioHelper.ResolveRelativeOrVirtualUrl(CodeEditorDataEditor.DataEditorViewPath), Config = new Dictionary { { CodeEditorConfigurationEditor.Mode, "razor" }, @@ -63,7 +76,7 @@ public sealed class TemplatedListDataListEditor : IDataListEditor Description = "Select to enable picking multiple items.", View = "boolean", }, - new HtmlAttributesConfigurationField(), + new HtmlAttributesConfigurationField(_ioHelper), }; public Dictionary DefaultConfig => default; diff --git a/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputConfigurationEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputConfigurationEditor.cs index ab576c66..31c5dd03 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputConfigurationEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputConfigurationEditor.cs @@ -6,9 +6,17 @@ using System; using System.Collections.Generic; using Newtonsoft.Json.Linq; +#if NET472 using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -16,12 +24,13 @@ internal sealed class TextInputConfigurationEditor : ConfigurationEditor { private readonly ConfigurationEditorUtility _utility; - public TextInputConfigurationEditor(ConfigurationEditorUtility utility) + public TextInputConfigurationEditor(ConfigurationEditorUtility utility, IIOHelper ioHelper, IShortStringHelper shortStringHelper) + : base() { _utility = utility; - var dataSources = new List(_utility.GetConfigurationEditorModels()); + var dataSources = new List(_utility.GetConfigurationEditorModels(shortStringHelper)); Fields.Add(new ConfigurationField { @@ -36,13 +45,13 @@ public TextInputConfigurationEditor(ConfigurationEditorUtility utility) Key = Constants.Conventions.ConfigurationFieldAliases.Items, Name = "Data list", Description = "(optional) Select and configure a data source to provide a HTML5 <datalist> for this text input.", - View = IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorViewPath), Config = new Dictionary() { { Constants.Conventions.ConfigurationFieldAliases.AddButtonLabelKey, "contentment_configureDataSource" }, { MaxItemsConfigurationField.MaxItems, 1 }, { DisableSortingConfigurationField.DisableSorting, Constants.Values.True }, - { Constants.Conventions.ConfigurationFieldAliases.OverlayView, IOHelper.ResolveUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, + { Constants.Conventions.ConfigurationFieldAliases.OverlayView, ioHelper.ResolveRelativeOrVirtualUrl(ConfigurationEditorDataEditor.DataEditorOverlayViewPath) }, { EnableDevModeConfigurationField.EnableDevMode, Constants.Values.True }, { EnableFilterConfigurationField.EnableFilter, dataSources.Count > 10 ? Constants.Values.True : Constants.Values.False }, { Constants.Conventions.ConfigurationFieldAliases.Items, dataSources }, @@ -54,7 +63,7 @@ public TextInputConfigurationEditor(ConfigurationEditorUtility utility) Name = "Maximum allowed characters", Key = "maxChars", Description = "Enter the maximum number of characters allowed for the text input.
The default limit is 500 characters.", - View = IOHelper.ResolveUrl(NumberInputDataEditor.DataEditorViewPath), + View = ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath), }); Fields.Add(new ConfigurationField diff --git a/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputDataEditor.cs b/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputDataEditor.cs index 2a2447a0..9668c18e 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputDataEditor.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputDataEditor.cs @@ -3,8 +3,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Strings; +using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Strings; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -14,7 +24,7 @@ namespace Umbraco.Community.Contentment.DataEditors DataEditorName, DataEditorViewPath, ValueType = ValueTypes.String, - Group = Core.Constants.PropertyEditors.Groups.Common, + Group = UmbConstants.PropertyEditors.Groups.Common, Icon = DataEditorIcon)] public sealed class TextInputDataEditor : DataEditor { @@ -23,14 +33,36 @@ public sealed class TextInputDataEditor : DataEditor internal const string DataEditorViewPath = Constants.Internals.EditorsPathRoot + "text-input.html"; internal const string DataEditorIcon = "icon-autofill"; + private readonly IIOHelper _ioHelper; + private readonly IShortStringHelper _shortStringHelper; private readonly ConfigurationEditorUtility _utility; - public TextInputDataEditor(ILogger logger, ConfigurationEditorUtility utility) +#if NET472 + public TextInputDataEditor( + ConfigurationEditorUtility utility, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + ILogger logger) : base(logger) { _utility = utility; + _ioHelper = ioHelper; + _shortStringHelper = shortStringHelper; } +#else + public TextInputDataEditor( + ConfigurationEditorUtility utility, + IIOHelper ioHelper, + IShortStringHelper shortStringHelper, + IDataValueEditorFactory dataValueEditorFactory) + : base(dataValueEditorFactory) + { + _utility = utility; + _ioHelper = ioHelper; + _shortStringHelper = shortStringHelper; + } +#endif - protected override IConfigurationEditor CreateConfigurationEditor() => new TextInputConfigurationEditor(_utility); + protected override IConfigurationEditor CreateConfigurationEditor() => new TextInputConfigurationEditor(_utility, _ioHelper, _shortStringHelper); } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputValueConverter.cs b/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputValueConverter.cs index 2f040060..0e659fbb 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputValueConverter.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/TextInput/TextInputValueConverter.cs @@ -4,9 +4,15 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/AllowClearConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/AllowClearConfigurationField.cs index 5ae52781..94151f88 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/AllowClearConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/AllowClearConfigurationField.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/DisableSortingConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/DisableSortingConfigurationField.cs index 865b6786..abd507cc 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/DisableSortingConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/DisableSortingConfigurationField.cs @@ -3,7 +3,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableDevModeConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableDevModeConfigurationField.cs index 95a30b63..933038eb 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableDevModeConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableDevModeConfigurationField.cs @@ -3,7 +3,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableFilterConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableFilterConfigurationField.cs index aca4fc7e..890fab0a 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableFilterConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/EnableFilterConfigurationField.cs @@ -3,7 +3,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HideLabelConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HideLabelConfigurationField.cs index 332f7342..c8ae62c2 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HideLabelConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HideLabelConfigurationField.cs @@ -3,7 +3,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HtmlAttributesConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HtmlAttributesConfigurationField.cs index a927a02f..58545408 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HtmlAttributesConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/HtmlAttributesConfigurationField.cs @@ -4,8 +4,14 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -13,7 +19,7 @@ internal sealed class HtmlAttributesConfigurationField : ConfigurationField { internal const string HtmlAttributes = "htmlAttributes"; - public HtmlAttributesConfigurationField() + public HtmlAttributesConfigurationField(IIOHelper ioHelper) : base() { var listFields = new[] @@ -35,7 +41,7 @@ public HtmlAttributesConfigurationField() Key = HtmlAttributes; Name = "HTML attributes"; Description = "(optional) Use this field to add any HTML attributes to the list editor."; - View = IOHelper.ResolveUrl(DataTableDataEditor.DataEditorViewPath); + View = ioHelper.ResolveRelativeOrVirtualUrl(DataTableDataEditor.DataEditorViewPath); Config = new Dictionary() { { DataTableConfigurationEditor.FieldItems, listFields }, diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/MaxItemsConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/MaxItemsConfigurationField.cs index cfa9abf3..3a59d037 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/MaxItemsConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/MaxItemsConfigurationField.cs @@ -3,8 +3,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.IO; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.IO; +using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.DataEditors { @@ -12,13 +18,13 @@ internal sealed class MaxItemsConfigurationField : ConfigurationField { internal const string MaxItems = "maxItems"; - public MaxItemsConfigurationField() + public MaxItemsConfigurationField(IIOHelper ioHelper) : base() { Key = MaxItems; Name = "Maximum items"; Description = "Enter the number for the maximum items allowed.
Use '0' for an unlimited amount."; - View = IOHelper.ResolveUrl(NumberInputDataEditor.DataEditorViewPath); + View = ioHelper.ResolveRelativeOrVirtualUrl(NumberInputDataEditor.DataEditorViewPath); } } } diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowDescriptionsConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowDescriptionsConfigurationField.cs index 048da91a..48a2ceba 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowDescriptionsConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowDescriptionsConfigurationField.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowIconsConfigurationField.cs b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowIconsConfigurationField.cs index 4890779d..f59c3f02 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowIconsConfigurationField.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/ConfigurationFields/ShowIconsConfigurationField.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.Collections.Generic; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentEditorItem.cs b/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentEditorItem.cs index 8cb9ebbc..c4e5e36c 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentEditorItem.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentEditorItem.cs @@ -5,7 +5,11 @@ using System.Collections.Generic; using System.ComponentModel; +#if NET472 using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentListItem.cs b/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentListItem.cs index 100626ff..8c4704de 100644 --- a/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentListItem.cs +++ b/src/Umbraco.Community.Contentment/DataEditors/_/IContentmentListItem.cs @@ -4,7 +4,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System.ComponentModel; +#if NET472 using Umbraco.Core.Composing; +#else +using Umbraco.Cms.Core.Composing; +#endif namespace Umbraco.Community.Contentment.DataEditors { diff --git a/src/Umbraco.Community.Contentment/Migrations/ContentmentPlan.cs b/src/Umbraco.Community.Contentment/Migrations/ContentmentPlan.cs index 15341e28..5d44898c 100644 --- a/src/Umbraco.Community.Contentment/Migrations/ContentmentPlan.cs +++ b/src/Umbraco.Community.Contentment/Migrations/ContentmentPlan.cs @@ -3,7 +3,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Core.Migrations; +#else +using Umbraco.Cms.Infrastructure.Migrations; +#endif namespace Umbraco.Community.Contentment.Migrations { diff --git a/src/Umbraco.Community.Contentment/Migrations/Install/RegisterUmbracoPackageEntry.cs b/src/Umbraco.Community.Contentment/Migrations/Install/RegisterUmbracoPackageEntry.cs index 3930120e..2e52f5be 100644 --- a/src/Umbraco.Community.Contentment/Migrations/Install/RegisterUmbracoPackageEntry.cs +++ b/src/Umbraco.Community.Contentment/Migrations/Install/RegisterUmbracoPackageEntry.cs @@ -3,13 +3,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System.Linq; using Umbraco.Core.Migrations; using Umbraco.Core.Models.Packaging; using Umbraco.Core.Services; +#else +using Umbraco.Cms.Infrastructure.Migrations; +#endif namespace Umbraco.Community.Contentment.Migrations { +#if NET472 internal sealed class RegisterUmbracoPackageEntry : MigrationBase { private readonly IPackagingService _packagingService; @@ -39,10 +44,26 @@ public override void Migrate() License = Constants.Package.License, LicenseUrl = Constants.Package.LicenseUrl, UmbracoVersion = Constants.Package.MinimumSupportedUmbracoVersion, - Version = Configuration.ContentmentVersion.Version.ToString(), + Version = ContentmentVersion.Version.ToString(), Readme = "", }); } } } +#else + internal sealed class RegisterUmbracoPackageEntry : MigrationBase + { + public const string State = "{contentment-reg-umb-pkg-entry}"; + + public RegisterUmbracoPackageEntry(IMigrationContext context) + : base(context) + { } + + protected override void Migrate() + { + // NOTE: This migration does nothing. It is a left over from code targeting Umbraco 8. + // It needs to remain, as Umbraco instances that have been upgraded from v8 to v9 will have reached this migrated state. + } + } +#endif } diff --git a/src/Umbraco.Community.Contentment/Notifications/ContentmentServerVariablesParsingNotification.cs b/src/Umbraco.Community.Contentment/Notifications/ContentmentServerVariablesParsingNotification.cs new file mode 100644 index 00000000..c919d226 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Notifications/ContentmentServerVariablesParsingNotification.cs @@ -0,0 +1,39 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 == false +using System.Collections.Generic; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Extensions; + +namespace Umbraco.Community.Contentment.Notifications +{ + internal sealed class ContentmentServerVariablesParsingNotification : INotificationHandler + { + private readonly ContentmentSettings _contentmentSettings; + + public ContentmentServerVariablesParsingNotification(IOptions contentmentSettings) + { + _contentmentSettings = contentmentSettings.Value; + } + + public void Handle(ServerVariablesParsingNotification notification) + { + if (notification.ServerVariables.TryGetValueAs("umbracoPlugins", out Dictionary umbracoPlugins) == true && + umbracoPlugins.ContainsKey(Constants.Internals.ProjectAlias) == false) + { + umbracoPlugins.Add(Constants.Internals.ProjectAlias, new + { + name = Constants.Internals.ProjectName, + version = ContentmentVersion.SemanticVersion.ToSemanticString(), + telemetry = _contentmentSettings.DisableTelemetry == false, + }); + } + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Notifications/ContentmentTelemetryNotification.cs b/src/Umbraco.Community.Contentment/Notifications/ContentmentTelemetryNotification.cs new file mode 100644 index 00000000..a5f43b20 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Notifications/ContentmentTelemetryNotification.cs @@ -0,0 +1,130 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 == false +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Mime; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Cms.Core.Configuration; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Community.Contentment.DataEditors; +using Umbraco.Extensions; + +namespace Umbraco.Community.Contentment.Notifications +{ + internal sealed class ContentmentTelemetryNotification : INotificationHandler + { + private readonly ContentmentSettings _contentmentSettings; + private readonly GlobalSettings _globalSettings; + private readonly IUmbracoVersion _umbracoVersion; + + public ContentmentTelemetryNotification( + IOptions contentmentSettings, + IOptions globalSettings, + IUmbracoVersion umbracoVersion) + { + _contentmentSettings = contentmentSettings.Value; + _globalSettings = globalSettings.Value; + _umbracoVersion = umbracoVersion; + } + + public void Handle(DataTypeSavedNotification notification) + { + if (_contentmentSettings.DisableTelemetry == true) + { + return; + } + + foreach (var entity in notification.SavedEntities) + { + if (entity.EditorAlias.InvariantStartsWith(Constants.Internals.DataEditorAliasPrefix) == true) + { + try + { + var dataTypeConfig = new Dictionary(); + + if (entity.Configuration is Dictionary config) + { + void AddConfigurationEditorKey(string alias) + { + if (config.ContainsKey(alias) == true && + config.TryGetValueAs(alias, out JArray array) == true && + array.Count > 0 && + array[0] is JObject item && + item.ContainsKey("key") == true) + { + var key = item.Value("key"); + + if (key.InvariantStartsWith(Constants.Internals.ProjectNamespace) == true && key.Length > 73) + { + // Strips off the namespace and assembly. + // e.g. "Umbraco.Community.Contentment.DataEditors.[DataSourceName], Umbraco.Community.Contentment" + key = key.Substring(42, key.Length - 73); + } + + dataTypeConfig.Add(alias, key); + } + }; + + switch (entity.EditorAlias) + { + case DataListDataEditor.DataEditorAlias: + AddConfigurationEditorKey(DataListConfigurationEditor.DataSource); + AddConfigurationEditorKey(DataListConfigurationEditor.ListEditor); + break; + + case ContentBlocksDataEditor.DataEditorAlias: + AddConfigurationEditorKey(ContentBlocksConfigurationEditor.DisplayMode); + break; + + case TextInputDataEditor.DataEditorAlias: + AddConfigurationEditorKey(Constants.Conventions.ConfigurationFieldAliases.Items); + break; + + default: + break; + } + } + + var umbracoId = Guid.TryParse(_globalSettings.Id, out var telemetrySiteIdentifier) == true + ? telemetrySiteIdentifier + : Guid.Empty; + + // No identifiable details, just a quick call home. + var data = new + { + dataType = entity.Key, + editorAlias = entity.EditorAlias.Substring(Constants.Internals.DataEditorAliasPrefix.Length), + umbracoId = umbracoId, + umbracoVersion = _umbracoVersion.SemanticVersion.ToString(), + contentmentVersion = ContentmentVersion.SemanticVersion.ToString(), + dataTypeConfig = dataTypeConfig, + }; + + using (var client = new WebClient()) + { + var address = new Uri("https://leekelleher.com/umbraco/contentment/telemetry/"); + var json = JsonConvert.SerializeObject(data, Formatting.Indented); + var payload = Convert.ToBase64String(Encoding.UTF8.GetBytes(json)); + + client.Headers.Add("Content-Type", MediaTypeNames.Text.Plain); + Task.Run(() => client.UploadStringAsync(address, payload)); + } + } + catch { /* ¯\_(ツ)_/¯ */ } + } + } + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Notifications/ContentmentUmbracoApplicationStartingNotification.cs b/src/Umbraco.Community.Contentment/Notifications/ContentmentUmbracoApplicationStartingNotification.cs new file mode 100644 index 00000000..23d22575 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Notifications/ContentmentUmbracoApplicationStartingNotification.cs @@ -0,0 +1,41 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 == false +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Trees; +using Umbraco.Community.Contentment.Trees; +using Umbraco.Extensions; + +namespace Umbraco.Community.Contentment.Notifications +{ + internal class ContentmentUmbracoApplicationStartingNotification : INotificationHandler + { + private readonly ContentmentSettings _contentmentSettings; + private readonly TreeCollection _treeCollection; + + public ContentmentUmbracoApplicationStartingNotification( + IOptions contentmentSettings, + TreeCollection treeCollection) + { + _contentmentSettings = contentmentSettings.Value; + _treeCollection = treeCollection; + } + + public void Handle(UmbracoApplicationStartingNotification notification) + { + if (notification.RuntimeLevel == RuntimeLevel.Run && + _contentmentSettings.DisableTree == true && + _treeCollection != null) + { + _treeCollection.RemoveTreeController(); + } + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Polyfill/IHostingEnvironment.cs b/src/Umbraco.Community.Contentment/Polyfill/IHostingEnvironment.cs new file mode 100644 index 00000000..749f49e8 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Polyfill/IHostingEnvironment.cs @@ -0,0 +1,30 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 +using System.ComponentModel; +using Umbraco.Core.IO; + +namespace Umbraco.Core.Hosting +{ + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IHostingEnvironment + { + string MapPathWebRoot(string path); + } +} + +namespace Umbraco.Community.Contentment.Polyfill +{ + [EditorBrowsable(EditorBrowsableState.Never)] + internal sealed class ContenmentHostingEnvironment : Core.Hosting.IHostingEnvironment + { + public string MapPathWebRoot(string path) + { + return IOHelper.MapPath(path); + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Polyfill/IIOHelper.cs b/src/Umbraco.Community.Contentment/Polyfill/IIOHelper.cs new file mode 100644 index 00000000..49663691 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Polyfill/IIOHelper.cs @@ -0,0 +1,29 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 +using System.ComponentModel; + +namespace Umbraco.Core.IO +{ + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IIOHelper + { + string ResolveRelativeOrVirtualUrl(string path); + } +} + +namespace Umbraco.Community.Contentment.Polyfill +{ + [EditorBrowsable(EditorBrowsableState.Never)] + internal sealed class ContenmentIOHelper : Core.IO.IIOHelper + { + public string ResolveRelativeOrVirtualUrl(string path) + { + return Core.IO.IOHelper.ResolveUrl(path); + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Polyfill/PublishedSnapshotAccessorExtensions.cs b/src/Umbraco.Community.Contentment/Polyfill/PublishedSnapshotAccessorExtensions.cs new file mode 100644 index 00000000..b824b445 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Polyfill/PublishedSnapshotAccessorExtensions.cs @@ -0,0 +1,20 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 +using System.ComponentModel; + +namespace Umbraco.Web.PublishedCache +{ + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class PublishedSnapshotAccessorExtensions + { + public static IPublishedSnapshot GetRequiredPublishedSnapshot(this IPublishedSnapshotAccessor accessor) + { + return accessor.PublishedSnapshot; + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Polyfill/README.md b/src/Umbraco.Community.Contentment/Polyfill/README.md new file mode 100644 index 00000000..b94e0dd1 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Polyfill/README.md @@ -0,0 +1,5 @@ +## Polyfills + +These polyfill classes are to support Contentment multi-targeting Umbraco v8 and v9. +Having this class injected for v8, will reduce the number of #if/#else directives needed. + diff --git a/src/Umbraco.Community.Contentment/Polyfill/StringExtensions.cs b/src/Umbraco.Community.Contentment/Polyfill/StringExtensions.cs new file mode 100644 index 00000000..722ccca0 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Polyfill/StringExtensions.cs @@ -0,0 +1,22 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 +using System.ComponentModel; +using Umbraco.Core.Strings; + +namespace Umbraco.Core +{ + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class StringExtensions + { + public static string SplitPascalCasing(this string phrase, IShortStringHelper shortStringHelper) + { + // https://github.com/umbraco/Umbraco-CMS/blob/release-8.17.0/src/Umbraco.Core/StringExtensions.cs#L1191 + return shortStringHelper.SplitPascalCasing(phrase, ' '); + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Polyfill/UdiParser.cs b/src/Umbraco.Community.Contentment/Polyfill/UdiParser.cs new file mode 100644 index 00000000..aa415fd6 --- /dev/null +++ b/src/Umbraco.Community.Contentment/Polyfill/UdiParser.cs @@ -0,0 +1,20 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 +using System.ComponentModel; + +namespace Umbraco.Core +{ + [EditorBrowsable(EditorBrowsableState.Never)] + internal sealed class UdiParser + { + public static bool TryParse(string s, out GuidUdi udi) + { + return GuidUdi.TryParse(s, out udi); + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Polyfill/UmbracoContextAccessorExtensions.cs b/src/Umbraco.Community.Contentment/Polyfill/UmbracoContextAccessorExtensions.cs new file mode 100644 index 00000000..c34108ad --- /dev/null +++ b/src/Umbraco.Community.Contentment/Polyfill/UmbracoContextAccessorExtensions.cs @@ -0,0 +1,20 @@ +/* Copyright © 2021 Lee Kelleher. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#if NET472 +using System.ComponentModel; + +namespace Umbraco.Web +{ + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class UmbracoContextAccessorExtensions + { + public static UmbracoContext GetRequiredUmbracoContext(this IUmbracoContextAccessor accessor) + { + return accessor.UmbracoContext; + } + } +} +#endif diff --git a/src/Umbraco.Community.Contentment/Telemetry/CompositionExtensions.cs b/src/Umbraco.Community.Contentment/Telemetry/CompositionExtensions.cs index 84b57a17..b396668a 100644 --- a/src/Umbraco.Community.Contentment/Telemetry/CompositionExtensions.cs +++ b/src/Umbraco.Community.Contentment/Telemetry/CompositionExtensions.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Community.Contentment.Telemetry; // NOTE: This extension method class is deliberately using the Umbraco namespace, @@ -36,3 +37,4 @@ public static Composition DisableContentmentTelemetry(this Composition compositi } } } +#endif diff --git a/src/Umbraco.Community.Contentment/Telemetry/ContentmentTelemetryComponent.cs b/src/Umbraco.Community.Contentment/Telemetry/ContentmentTelemetryComponent.cs index e202d5de..0dcb44dc 100644 --- a/src/Umbraco.Community.Contentment/Telemetry/ContentmentTelemetryComponent.cs +++ b/src/Umbraco.Community.Contentment/Telemetry/ContentmentTelemetryComponent.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System; using System.Collections.Generic; using System.Net; @@ -11,7 +12,6 @@ using System.Threading.Tasks; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Community.Contentment.Configuration; using Umbraco.Community.Contentment.DataEditors; using Umbraco.Core; using Umbraco.Core.Composing; @@ -134,3 +134,4 @@ array[0] is JObject item && } } } +#endif diff --git a/src/Umbraco.Community.Contentment/Trees/CompositionExtensions.cs b/src/Umbraco.Community.Contentment/Trees/CompositionExtensions.cs index b6d04d71..9e98f1af 100644 --- a/src/Umbraco.Community.Contentment/Trees/CompositionExtensions.cs +++ b/src/Umbraco.Community.Contentment/Trees/CompositionExtensions.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Community.Contentment.Trees; using Umbraco.Web; @@ -23,3 +24,4 @@ public static Composition DisableContentmentTree(this Composition composition) } } } +#endif diff --git a/src/Umbraco.Community.Contentment/Trees/ContentmentTreeController.cs b/src/Umbraco.Community.Contentment/Trees/ContentmentTreeController.cs index 19fa13c3..851869ff 100644 --- a/src/Umbraco.Community.Contentment/Trees/ContentmentTreeController.cs +++ b/src/Umbraco.Community.Contentment/Trees/ContentmentTreeController.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System.Net.Http.Formatting; using System.Web.Http.ModelBinding; using Umbraco.Web.Models.Trees; @@ -10,9 +11,22 @@ using Umbraco.Web.Trees; using Umbraco.Web.WebApi.Filters; using UmbConstants = Umbraco.Core.Constants; +#else +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Trees; +using Umbraco.Cms.Web.BackOffice.Trees; +using Umbraco.Cms.Web.Common.Attributes; +using Umbraco.Cms.Web.Common.ModelBinders; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Community.Contentment.Trees { +#if NET472 [Tree( UmbConstants.Applications.Settings, Constants.Internals.TreeAlias, @@ -39,4 +53,39 @@ protected override TreeNode CreateRootNode(FormDataCollection queryStrings) protected override TreeNodeCollection GetTreeNodes(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))] FormDataCollection queryStrings) => null; } +#else + [Tree( + UmbConstants.Applications.Settings, + Constants.Internals.TreeAlias, + IsSingleNodeTree = true, + TreeGroup = UmbConstants.Trees.Groups.ThirdParty, + TreeTitle = Constants.Internals.ProjectName, + TreeUse = TreeUse.Main)] + [PluginController(Constants.Internals.PluginControllerName)] + public sealed class ContentmentTreeController : TreeController + { + public ContentmentTreeController( + ILocalizedTextService localizedTextService, + UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, + IEventAggregator eventAggregator) + : base(localizedTextService, umbracoApiControllerTypeCollection, eventAggregator) + { } + + protected override ActionResult CreateRootNode(FormCollection queryStrings) + { + var root = base.CreateRootNode(queryStrings); + + root.Value.Icon = "icon-fa fa-cube"; + root.Value.HasChildren = false; + root.Value.RoutePath = $"{SectionAlias}/{TreeAlias}/index"; + root.Value.MenuUrl = null; + + return root.Value; + } + + protected override ActionResult GetMenuForNode(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))] FormCollection queryStrings) => null; + + protected override ActionResult GetTreeNodes(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))] FormCollection queryStrings) => null; + } +#endif } diff --git a/src/Umbraco.Community.Contentment/Umbraco.Community.Contentment.csproj b/src/Umbraco.Community.Contentment/Umbraco.Community.Contentment.csproj index 519754b0..5250a6cb 100644 --- a/src/Umbraco.Community.Contentment/Umbraco.Community.Contentment.csproj +++ b/src/Umbraco.Community.Contentment/Umbraco.Community.Contentment.csproj @@ -1,13 +1,13 @@  - net472 + net472;net50 Umbraco.Community.Contentment Our.Umbraco.Community.Contentment Contentment for Umbraco - Contentment, a collection of components for Umbraco 8. + Contentment, a collection of components for Umbraco. umbraco - 2.2.1 + 3.0.0 Umbrella Inc Ltd Lee Kelleher 2019 © Lee Kelleher @@ -16,10 +16,19 @@ https://github.com/leekelleher/umbraco-contentment git - - + + + + + + + + + + + - + diff --git a/src/Umbraco.Community.Contentment/Web/Controllers/EnumDataListSourceApiController.cs b/src/Umbraco.Community.Contentment/Web/Controllers/EnumDataListSourceApiController.cs index 81229659..17bdbb8c 100644 --- a/src/Umbraco.Community.Contentment/Web/Controllers/EnumDataListSourceApiController.cs +++ b/src/Umbraco.Community.Contentment/Web/Controllers/EnumDataListSourceApiController.cs @@ -6,12 +6,23 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.IO; using System.Reflection; using Umbraco.Community.Contentment.DataEditors; +#if NET472 +using System.Web.Http; using Umbraco.Core; +using Umbraco.Core.Strings; using Umbraco.Web.Editors; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; +#else +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Web.BackOffice.Controllers; +using Umbraco.Cms.Web.Common.Attributes; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.Web.Controllers { @@ -22,6 +33,14 @@ public sealed class EnumDataSourceApiController : UmbracoAuthorizedJsonControlle internal const string GetAssembliesUrl = "backoffice/Contentment/EnumDataSourceApi/GetAssemblies"; internal const string GetEnumsUrl = "backoffice/Contentment/EnumDataSourceApi/GetEnums?assembly={0}"; + private readonly IShortStringHelper _shortStringHelper; + + public EnumDataSourceApiController(IShortStringHelper shortStringHelper) + { + _shortStringHelper = shortStringHelper; + } + + [HttpGet] public IEnumerable GetAssemblies() { const string App_Code = "App_Code"; @@ -39,17 +58,23 @@ public IEnumerable GetAssemblies() } var hasEnums = false; - if (assembly.ExportedTypes != null) + try { - foreach (var exportedType in assembly.ExportedTypes) + var exportedTypes = assembly.GetExportedTypes(); + if (exportedTypes != null) { - if (exportedType.IsEnum == true) + foreach (var exportedType in exportedTypes) { - hasEnums = true; - break; + if (exportedType.IsEnum == true) + { + hasEnums = true; + break; + } } } } + catch (FileLoadException) { /* (╯°□°)╯︵ ┻━┻ */ } + catch (TypeLoadException) { /* ¯\_(ツ)_/¯ */ } if (hasEnums == false) { @@ -71,11 +96,13 @@ public IEnumerable GetAssemblies() return options.Values; } + [HttpGet] public IEnumerable GetEnums(string assembly) { var options = new SortedDictionary(); var types = Assembly.Load(assembly).GetTypes(); + foreach (var type in types) { if (type.IsEnum == false) @@ -83,7 +110,7 @@ public IEnumerable GetEnums(string assembly) continue; } - options.Add(type.FullName, new DataListItem { Name = type.Name.SplitPascalCasing(), Value = type.FullName }); + options.Add(type.FullName, new DataListItem { Name = type.Name.SplitPascalCasing(_shortStringHelper), Value = type.FullName }); } return options.Values; diff --git a/src/Umbraco.Community.Contentment/Web/Extensions/HtmlHelperExtensions.cs b/src/Umbraco.Community.Contentment/Web/Extensions/HtmlHelperExtensions.cs index 6bb2eb11..920bee4a 100644 --- a/src/Umbraco.Community.Contentment/Web/Extensions/HtmlHelperExtensions.cs +++ b/src/Umbraco.Community.Contentment/Web/Extensions/HtmlHelperExtensions.cs @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using System; using System.Collections.Generic; using System.Web.Mvc; @@ -83,3 +84,4 @@ public static HelperResult RenderElements( } } } +#endif diff --git a/src/Umbraco.Community.Contentment/Web/Extensions/PublishedContentTypeExtensions.cs b/src/Umbraco.Community.Contentment/Web/Extensions/PublishedContentTypeExtensions.cs index 8ea74232..05930a4e 100644 --- a/src/Umbraco.Community.Contentment/Web/Extensions/PublishedContentTypeExtensions.cs +++ b/src/Umbraco.Community.Contentment/Web/Extensions/PublishedContentTypeExtensions.cs @@ -3,10 +3,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#if NET472 using Umbraco.Community.Contentment.DataEditors; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; using UmbConstants = Umbraco.Core.Constants; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Services; +using Umbraco.Community.Contentment.DataEditors; +using UmbConstants = Umbraco.Cms.Core.Constants; +#endif namespace Umbraco.Web { diff --git a/src/Umbraco.Community.Contentment/Web/Extensions/PublishedElementExtensions.cs b/src/Umbraco.Community.Contentment/Web/Extensions/PublishedElementExtensions.cs index f1e8b93a..df1fa699 100644 --- a/src/Umbraco.Community.Contentment/Web/Extensions/PublishedElementExtensions.cs +++ b/src/Umbraco.Community.Contentment/Web/Extensions/PublishedElementExtensions.cs @@ -6,10 +6,19 @@ using System; using System.Linq.Expressions; using System.Reflection; +#if NET472 using Umbraco.Core.Models.PublishedContent; using Umbraco.ModelsBuilder.Embedded; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Infrastructure.ModelsBuilder; +#endif +#if NET472 namespace Umbraco.Web +#else +namespace Umbraco.Extensions +#endif { public static class PublishedElementExtensions { @@ -21,13 +30,18 @@ public static bool HasValueFor(this TModel model, Expression(TModel model, Expression> property) { try { var assembly = typeof(ApiVersion).Assembly; +#if NET472 var type = assembly.GetType("Umbraco.Web.PublishedElementExtensions"); +#else + var type = assembly.GetType("Umbraco.Extensions.PublishedElementExtensions"); +#endif var method = type.GetMethod(nameof(GetAlias), BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod); var generic = method.MakeGenericMethod(typeof(TModel), typeof(TValue)); return generic.Invoke(null, new object[] { model, property }) as string; diff --git a/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedElement.cs b/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedElement.cs index cd74a644..d260fb3f 100644 --- a/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedElement.cs +++ b/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedElement.cs @@ -11,7 +11,11 @@ using System; using System.Collections.Generic; using System.Linq; +#if NET472 using Umbraco.Core.Models.PublishedContent; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +#endif namespace Umbraco.Community.Contentment.Web.PublishedCache { diff --git a/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedProperty.cs b/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedProperty.cs index 76584a0f..19406269 100644 --- a/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedProperty.cs +++ b/src/Umbraco.Community.Contentment/Web/PublishedCache/DetachedPublishedProperty.cs @@ -9,8 +9,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; +#if NET472 using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.PropertyEditors; +#endif namespace Umbraco.Community.Contentment.Web.PublishedCache { diff --git a/src/Umbraco.Community.Contentment/Web/Serialization/PublishedContentContractResolver.cs b/src/Umbraco.Community.Contentment/Web/Serialization/PublishedContentContractResolver.cs index f17d84f8..4f6073bf 100644 --- a/src/Umbraco.Community.Contentment/Web/Serialization/PublishedContentContractResolver.cs +++ b/src/Umbraco.Community.Contentment/Web/Serialization/PublishedContentContractResolver.cs @@ -17,7 +17,12 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; +#if NET472 using Umbraco.Core.Models.PublishedContent; +#else +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Extensions; +#endif namespace Umbraco.Community.Contentment.Web.Serialization { @@ -31,6 +36,9 @@ public sealed class PublishedContentContractResolver : DefaultContractResolver private readonly HashSet _ignoreFromContent; private readonly HashSet _ignoreFromProperty; private readonly HashSet _systemProperties; +#if NET472 == false + private readonly Dictionary> _systemMethods; +#endif public PublishedContentContractResolver() : base() @@ -73,9 +81,13 @@ public PublishedContentContractResolver() _systemProperties = new HashSet(StringComparer.OrdinalIgnoreCase) { nameof(IPublishedContent.CreateDate), +#if NET472 #pragma warning disable CS0618 // Type or member is obsolete nameof(IPublishedContent.CreatorName), #pragma warning restore CS0618 // Type or member is obsolete +#else + nameof(FriendlyPublishedContentExtensions.CreatorName), +#endif nameof(IPublishedContent.Id), nameof(IPublishedContent.ItemType), nameof(IPublishedElement.Key), @@ -84,14 +96,31 @@ public PublishedContentContractResolver() nameof(IPublishedContent.Path), nameof(IPublishedContent.SortOrder), nameof(IPublishedContent.UpdateDate), +#if NET472 #pragma warning disable CS0618 // Type or member is obsolete nameof(IPublishedContent.Url), #pragma warning restore CS0618 // Type or member is obsolete +#else + nameof(FriendlyPublishedContentExtensions.Url), +#endif nameof(IPublishedContent.UrlSegment), +#if NET472 #pragma warning disable CS0618 // Type or member is obsolete nameof(IPublishedContent.WriterName), #pragma warning restore CS0618 // Type or member is obsolete +#else + nameof(FriendlyPublishedContentExtensions.WriterName), +#endif }; + +#if NET472 == false + _systemMethods = new Dictionary> + { + { nameof(FriendlyPublishedContentExtensions.CreatorName), x => x.CreatorName() }, + { nameof(FriendlyPublishedContentExtensions.Url), x => x.Url() }, + { nameof(FriendlyPublishedContentExtensions.WriterName), x => x.WriterName() }, + }; +#endif } public string[] PropertiesToIgnore @@ -117,7 +146,32 @@ public Dictionary PropertyTypeConverters protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) { +#if NET472 return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList(); +#else + var properties = base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList(); + + if (typeof(IPublishedContent).IsAssignableFrom(type) == true) + { + var noAttributeProvider = new NoAttributeProvider(); + + properties.AddRange(_systemMethods.Select(x => new JsonProperty + { + DeclaringType = type, + PropertyName = ResolvePropertyName(x.Key), + UnderlyingName = x.Key, + PropertyType = typeof(string), + ValueProvider = new PublishedContentValueProvider(x.Value), + AttributeProvider = noAttributeProvider, + Readable = true, + Writable = false, + ItemIsReference = false, + TypeNameHandling = TypeNameHandling.None, + })); + } + + return properties; +#endif } protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) @@ -153,5 +207,32 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ return property; } + +#if NET472 == false + protected override string ResolvePropertyName(string propertyName) + { + return PrefixSystemPropertyNamesWithUnderscore == true && _systemProperties.Contains(propertyName) == true + ? "_" + base.ResolvePropertyName(propertyName) + : base.ResolvePropertyName(propertyName); + } + + private class PublishedContentValueProvider : IValueProvider + { + private readonly Func _func; + + public PublishedContentValueProvider(Func func) => _func = func; + + public object GetValue(object target) => _func((IPublishedContent)target); + + public void SetValue(object target, object value) => throw new NotImplementedException(); + } + + private class NoAttributeProvider : IAttributeProvider + { + public IList GetAttributes(bool inherit) => Array.Empty(); + + public IList GetAttributes(Type attributeType, bool inherit) => Array.Empty(); + } +#endif } } diff --git a/src/Umbraco.Community.Contentment/Web/UI/App_Plugins/Contentment/backoffice/contentment/index.html b/src/Umbraco.Community.Contentment/Web/UI/App_Plugins/Contentment/backoffice/contentment/index.html index 6d96a3ee..a028948a 100644 --- a/src/Umbraco.Community.Contentment/Web/UI/App_Plugins/Contentment/backoffice/contentment/index.html +++ b/src/Umbraco.Community.Contentment/Web/UI/App_Plugins/Contentment/backoffice/contentment/index.html @@ -32,7 +32,7 @@
- + Vote up @@ -40,7 +40,7 @@
- + Vote down @@ -69,15 +69,7 @@
Telemetry

By default, the package sends telemetry data about which property-editors are being used (from Contentment only). For more details about the data being captured and transparency on the analysis, please visit leekelleher.com/umbraco/contentment/telemetry.

-

If you would prefer to opt-out and disable the telemetry feature, you can use the following code snippet to do so.

-
-
- Code snippet to disable Contentment telemetry -

Copy the C# class below. You can either save this to your ~/App_Code/ folder, or add it to your own code library.

- {{vm.disableTelemetryCode}} -

If you are already using a composer class, you can add the composition.DisableContentmentTelemetry(); line to it.

-
-
+

If you would prefer to opt-out and disable the telemetry feature, you can find a code snippet on the telemetry documentation page.

Telemetry
@@ -88,15 +80,7 @@
Telemetry
Tree dashboard
-

If you would like to remove this page and tree item from the Settings section, you can use the following code snippet to do so.

-
-
- Code snippet to disable Contentment tree dashboard -

Copy the C# class below. You can either save this to your ~/App_Code/ folder, or add it to your own code library.

- {{vm.disableTreeCode}} -

If you are already using a composer class, you can add the composition.DisableContentmentTree(); line to it.

-
-
+

If you would like to remove this page and tree item from the Settings section, you can find a code snippet on the tree dashboard documentation page.

diff --git a/src/Umbraco.Community.Contentment/Web/UI/backoffice.js b/src/Umbraco.Community.Contentment/Web/UI/backoffice.js index 1cac7b64..f7dadd43 100644 --- a/src/Umbraco.Community.Contentment/Web/UI/backoffice.js +++ b/src/Umbraco.Community.Contentment/Web/UI/backoffice.js @@ -85,32 +85,7 @@ angular.module("umbraco").controller("Umbraco.Community.Contentment.Tree.Control } }; - vm.csharp = "csharp"; vm.telemetryEnabled = config.telemetry === true; - vm.disableTelemetryCode = `using Umbraco.Core.Composing; - -namespace Our.Umbraco.Web -{ - public class DisableContentmentTelemetryComposer : IUserComposer - { - public void Compose(Composition composition) - { - composition.DisableContentmentTelemetry(); - } - } -}`; - vm.disableTreeCode = `using Umbraco.Core.Composing; - -namespace Our.Umbraco.Web -{ - public class DisableContentmentTreeComposer : IUserComposer - { - public void Compose(Composition composition) - { - composition.DisableContentmentTree(); - } - } -}`; }; init(); diff --git a/src/_vars.ps1 b/src/_vars.ps1 index 4862f6dc..fde02072 100644 --- a/src/_vars.ps1 +++ b/src/_vars.ps1 @@ -4,4 +4,4 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. # Sets the path for development site. -$TargetDevWebsite = "C:\path\to\umbraco"; +$TargetDevWebsite = ""; diff --git a/tools/AjaxMinifier.exe b/tools/AjaxMinifier.exe deleted file mode 100644 index 75f96484..00000000 Binary files a/tools/AjaxMinifier.exe and /dev/null differ