Compare commits

..

64 Commits

Author SHA1 Message Date
Sebastiaan Janssen 5a07e34fb4 Bump version to 8.0.2 2019-04-26 15:15:17 +02:00
Stephan 1b5d614f5a Fix recycle bin moves
(cherry picked from commit 173df80e3d)

# Conflicts:
#	src/Umbraco.Core/Services/Implement/MediaService.cs
2019-04-26 15:03:09 +02:00
Sebastiaan Janssen abb08260eb v8: Imagepicker prevalue and grid setting/styles as infinite editor (#4971)
(cherry picked from commit f82dff597b)

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.controller.js
2019-04-25 13:43:03 +02:00
Stephan 57c567c570 Fix paging error in NuCache
(cherry picked from commit 5d0010a993)
2019-04-23 14:08:19 +02:00
Stephan 424f4601ae Merge commit 'a2a247b413' into v8/8.0 2019-04-23 13:51:29 +02:00
Shannon a2a247b413 removes the enforcement of non duplicate property type aliases for now 2019-04-17 21:00:15 +10:00
Shannon 0b6a369047 When removing a property group, we need to first remove the group and then re-assign the property types so that duplicates are not added 2019-04-17 17:12:34 +10:00
Shannon 522fdefb8c Ensures that ALL membership properties are created by the installer, removes the logic that updates a membertype while fetching it, fixes the logic of mapping membership properties when fetching and they don't exist. 2019-04-17 16:42:17 +10:00
Shannon 4d8d10f07a adds comments, ignores test for now 2019-04-17 16:03:36 +10:00
Shannon 6f17129364 Make DropDownFlexibleConfiguration class public to allow configuration to be set when creating a new data type 2019-04-17 15:23:35 +10:00
Shannon 6f44e4fd09 Fixes INotifyCollectionChanged collections to raise the correct events, ensures that no duplicate property type aliases can be added/updated to 2019-04-16 17:37:42 +10:00
Shannon 02ddf80014 Adds a unit test 2019-04-16 15:39:28 +10:00
Shannon 723d9eddd1 unbreaks a ctor change preventing 8.0.2 from being dropped into the bin 2019-04-15 18:15:52 +10:00
Shannon fa655b812c Fix composers ordering 2019-04-15 17:55:22 +10:00
Shannon 576c10cd50 NuCache: fix vanishing content when refreshing content types 2019-04-15 12:56:45 +10:00
Kenn Jacobsen 179afe7e0d Add IsVisible extension on IPublishedElement 2019-04-11 17:44:16 +02:00
Shannon be7f42c454 Don't show the recycle bin in tree pickers/dialogs 2019-04-10 09:52:06 +10:00
Shannon 7e1ee26dee Fix spelling mistake 2019-04-09 10:34:59 +10:00
Stephan 1c9b449c46 Log more details about boot environment 2019-04-07 16:25:06 +02:00
Shannon e38095b727 NuCache: fix loading the media cache from local files, was missing media 2019-04-05 10:49:19 +11:00
Shannon b5796ad237 Enable configuration of NuCache BTree block size #5114 2019-04-05 10:44:36 +11:00
Stephan f985c437b5 Add content.SetValue overload for posted files 2019-04-04 09:28:34 +02:00
Andrew Deans 63fb8f5933 Fix case of query parameter 2019-04-04 09:12:40 +02:00
Shannon eb529783c4 Don't allow move in members listview 2019-04-03 16:22:13 +11:00
Shannon a8265db5f0 Reload listview after moving items 2019-04-03 10:45:04 +11:00
Shannon 7dcf2b1abb infinity editing dim-layer for umb-modelcolumn 2019-04-01 17:05:13 +11:00
Stephan 514452ddb9 Better ServerMessenger configuration 2019-04-01 16:30:37 +11:00
Stephan 1eb55a83c0 Merge branch 'patch-8.0.1' into v8/8.0 2019-03-30 12:13:12 +01:00
Stephan dfe6f2029a NuCache: better fixing, cleanup 2019-03-26 10:25:05 +01:00
Stephan 851c844c8b NuCache: fix panic exception 2019-03-26 10:25:05 +01:00
Stephan 7e413ed406 NuCache: troubleshooting 2019-03-26 10:25:05 +01:00
Stephan c56b8863ee NuCache: reorg some classes 2019-03-26 10:25:05 +01:00
Stephan 13a8548d3a NuCache: rename things 2019-03-26 10:25:05 +01:00
Stephan a70cb51559 NuCache: cleanup scoped objects 2019-03-26 10:25:05 +01:00
Kenn Jacobsen 8a56b3db16 Fix the "Language" dropdown in the "Culture and Hostnames" dialog 2019-03-26 20:10:50 +11:00
Bjarke Berg 4fcf2ce7bd Fixed issue when creating variant content templates, but the properties is invariant. Before this change an exception was thrown 2019-03-26 20:10:03 +11:00
Shannon 080ace90b2 Bugfix: https://github.com/umbraco/Umbraco-CMS/issues/4827 - Fixed MediaPickerValueConverter when config is Only Images 2019-03-26 20:09:12 +11:00
Shannon 2bfa81c707 fixes 4627 + makes front-end validations appear as soon as they are invalid again. 2019-03-26 20:07:42 +11:00
Sebastiaan Janssen 44cb5fd96b Apparently the highest minClientVersion allowed is 4.1.0 for now - see https://github.com/NuGet/NuGetGallery/blob/master/src/NuGetGallery/GalleryConstants.cs#L36 2019-03-19 09:24:41 +01:00
Robert b0b987f9cd Merge pull request #4710 from umbraco/temp8-4708-fix-for-exit-preview-with-null-culture
Fix for exit preview with null culture

(cherry picked from commit 9b25cdaa14)
2019-03-14 13:21:28 +01:00
Sebastiaan Janssen 3961e2533d Fix JS unit tests 2019-03-11 15:50:16 +01:00
Stephan b46f842400 Do not inject IEnumerable but Collection in UmbracoContextFactory
(cherry picked from commit 7e67bbea13)
2019-03-11 15:41:40 +01:00
Kenn Jacobsen 930acfeb68 Show the content app for media folders with content properties
(cherry picked from commit 9062b400d4)
2019-03-11 14:58:13 +01:00
Shannon b004c616ad Removes faulty CustomRouteUrlProvider
(cherry picked from commit 52beb01110)
2019-03-11 14:54:43 +01:00
Sebastiaan Janssen 9d64c4e551 Bugfix CoreRuntime
(cherry picked from commit 2209b37a4a and 7f31ddc250)
2019-03-11 14:45:48 +01:00
Sebastiaan Janssen 9a0aacd45a Upgrade to ModelsBuilder 8.0.2, support Custom Tool (#4881)
* Upgrade to ModelsBuilder 8.0.2, support Custom Tool

* Upgrade to ModelsBuilder 8.0.3

* Fix controllers

* Upgrade MB

* Fix previous commit

(cherry picked from commit c85c055424)
2019-03-11 14:37:59 +01:00
Kenn Jacobsen 29ff7bc340 Handle checkbox value conversion from Nested Content
(cherry picked from commit 2352b50d97)
2019-03-08 15:09:54 +01:00
Shannon 39a97fb768 Enable adding api controllers 2019-03-07 19:09:13 +11:00
Kenn Jacobsen 0852bd90d0 Always update URLs on save no matter which app is active
(cherry picked from commit 869d088e4b)
2019-03-06 17:26:36 +01:00
Niels Lyngsø e28365a0e5 hack for not using scope() in grid redordering
(cherry picked from commit a67163fd03)
2019-03-06 16:58:57 +01:00
Sebastiaan Janssen 0d16c79d0c Require higher NuGet version so we don't target VS15 any more (unsupported)
Making backups before we upgrade is no longer needed, removed from install.ps1
If people include the bin folder in their solution they will get errors upgrading now, we shouldn't need to try and fix this, there's no reason to include the bin folder in the solution - therefore install.core.ps1 is removed

(cherry picked from commit 82b78c7530)
2019-03-06 14:57:53 +01:00
Sebastiaan Janssen 7cc8983a25 Fix NuCache url segments
(cherry picked from commits 7a0f11bc6f and cfa94b1bb8)
2019-03-06 10:25:21 +01:00
Shannon e7f8baeca4 fixed correct destination url instead of #. 2019-03-05 16:14:06 +11:00
Stephan e716d14a0a Fix distributed cache handler for medias (#4751)
(cherry picked from commit 31b293aa4d)
2019-03-04 16:51:15 +01:00
Robert Foster 4c6a742007 Changed all references of umbracoUseSSL to Umbraco.Core.UseHttps to fix issue #4749
(cherry picked from commit 5aa38c1f43)
2019-03-04 15:33:08 +01:00
Sebastiaan Janssen 410241b61d 4766 fixed up other instances where nodeSelectHandler was being passed incorrect number of arguments
(cherry picked from commit 553bf6d304 and 4503967778)
2019-03-04 15:13:30 +01:00
Kenn Jacobsen 4e47fa9a70 Fix the "selected" checkmark in tree picker search results
(cherry picked from commit 09dc908332)
2019-03-04 15:10:55 +01:00
Robert Foster 9c5fb1fead Fix for Content App badges not being displayed (#4787)
(cherry picked from commit 055f983cbf)
2019-03-04 15:10:09 +01:00
Sebastiaan Janssen dc41db5fc1 Bumps version to 8.0.1 2019-03-04 15:08:23 +01:00
Sebastiaan Janssen 11b6a98df8 Bugfix exception during install, live models collision
(cherry picked from commit aa86dfa956)
2019-03-04 15:05:17 +01:00
Sebastiaan Janssen da9fc1e147 Make it possible to upload the same file twice or more (#4755)
(cherry picked from commit b5bda772af)
2019-03-04 15:04:27 +01:00
Sebastiaan Janssen 319c75757a Bugfix: Don't use ToString :'(
(cherry picked from commit ed6d54e64a)
2019-03-04 15:01:54 +01:00
Pete Duncanson 6e81e57c8e Removed System.Web.WebPages reference in nonodes.aspx as was failing a clean build
(cherry picked from commit f1d1c95709)
2019-03-04 14:58:05 +01:00
Sebastiaan Janssen 9ebe282ba6 Ensure we dont double insert
(cherry picked from commit 578eb8b32c and b86e7dc0e8)
2019-03-04 14:57:13 +01:00
143 changed files with 1861 additions and 1442 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/dev-v8/.github/V8_GETTING_STARTED.md) to go to the v8 branch_
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/temp8/.github/V8_GETTING_STARTED.md) to go to the v8 branch_
# Contributing to Umbraco CMS
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
+2 -4
View File
@@ -1,9 +1,7 @@
[![Build status](https://umbraco.visualstudio.com/Umbraco%20Cms/_apis/build/status/Cms%208%20Continuous?branchName=dev-v8)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [![pullreminders](https://pullreminders.com/badge.svg)](https://pullreminders.com?ref=badge)
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
[![pullreminders](https://pullreminders.com/badge.svg)](https://pullreminders.com?ref=badge)
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS/tree/dev-v7) to go to the v7 branch._
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS) to go to the v7 branch._
_Ready to try out Version 8? [See the quick start guide](V8_GETTING_STARTED.md)._
+1 -1
View File
@@ -5,7 +5,7 @@
* [Visual Studio 2017 Community (Free)](https://www.visualstudio.com/vs/community/), or Professional, Enterprise, etc... _(**Minimum of Version 15.7** or higher, this is important, you WILL get issues with lesser versions)_
* .NET Framework 4.7.2 installed, get it here: https://www.microsoft.com/net/download/thank-you/net472?survey=false
* .NET Framework 4.7.2 developer pack, get it here: https://www.microsoft.com/net/download/thank-you/net472-developer-pack _(be sure this is the ENU file which will be named `NDP472-DevPack-ENU.exe`)_
* Clone the Umbraco repository using the `dev-v8` branch. If your git client doesn't support specifying the branch as you clone then use the command `git clone --single-branch -b dev-v8 <your fork url>`. _(If you clone the repo using the default v7 branch and then checkout the `dev-v8` branch you **might** get problems)_
* Clone the Umbraco repository using the `temp8` branch. If your git client doesn't support specifying the branch as you clone then use the command `git clone --single-branch -b temp8 <your fork url>`. _(If you clone the repo using the default v7 branch and then checkout the `temp8` branch you **might** get problems)_
### Start the solution
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<metadata minClientVersion="4.1.0">
<id>UmbracoCms.Core</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
+2 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<metadata minClientVersion="4.1.0">
<id>UmbracoCms.Web</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
@@ -27,7 +27,7 @@
<dependency id="ClientDependency" version="[1.9.7,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.0.1,1.999999)" />
<dependency id="Examine" version="[1.0.0,1.999999)" />
<dependency id="HtmlAgilityPack" version="[1.8.14,1.999999)" />
<dependency id="ImageProcessor" version="[2.7.0.100,2.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
+2 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="3.4.4">
<metadata minClientVersion="4.1.0">
<id>UmbracoCms</id>
<version>8.0.0</version>
<title>Umbraco Cms</title>
@@ -25,7 +25,7 @@
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.4.0, 2.999999)" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.1]" />
<dependency id="Umbraco.ModelsBuilder.Ui" version="[8.0.4]" />
<dependency id="ImageProcessor.Web" version="[4.10.0.100,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.5.0.100,2.999999)" />
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.1,2.999999)" />
-93
View File
@@ -1,93 +0,0 @@
param($installPath, $toolsPath, $package, $project)
Write-Host "installPath:" "${installPath}"
Write-Host "toolsPath:" "${toolsPath}"
Write-Host " "
if ($project) {
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
# Create paths and list them
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
Write-Host "projectPath:" "${projectPath}"
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
Write-Host "backupPath:" "${backupPath}"
$copyLogsPath = Join-Path $backupPath "CopyLogs"
Write-Host "copyLogsPath:" "${copyLogsPath}"
$umbracoBinFolder = Join-Path $projectPath "bin"
Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
# Create backup folder and logs folder if it doesn't exist yet
New-Item -ItemType Directory -Force -Path $backupPath
New-Item -ItemType Directory -Force -Path $copyLogsPath
# After backing up, remove all umbraco dlls from bin folder in case dll files are included in the VS project
# See: http://issues.umbraco.org/issue/U4-4930
if(Test-Path $umbracoBinFolder) {
$umbracoBinBackupPath = Join-Path $backupPath "bin"
New-Item -ItemType Directory -Force -Path $umbracoBinBackupPath
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
# Delete files Umbraco ships with
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Core.dll) { Remove-Item $umbracoBinFolder\Umbraco.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Examine.dll) { Remove-Item $umbracoBinFolder\Umbraco.Examine.dll -Force -Confirm:$false }
# Delete files Umbraco depends upon
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
$x86Folder = Join-Path $umbracoBinFolder "x86"
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
if(Test-Path $umbracoBinFolder\AutoMapper.dll) { Remove-Item $umbracoBinFolder\AutoMapper.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\AutoMapper.Net4.dll) { Remove-Item $umbracoBinFolder\AutoMapper.Net4.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ClientDependency.Core.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ClientDependency.Core.Mvc.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.Mvc.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\CookComputing.XmlRpcV2.dll) { Remove-Item $umbracoBinFolder\CookComputing.XmlRpcV2.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Examine.dll) { Remove-Item $umbracoBinFolder\Examine.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\HtmlAgilityPack.dll) { Remove-Item $umbracoBinFolder\HtmlAgilityPack.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ICSharpCode.SharpZipLib.dll) { Remove-Item $umbracoBinFolder\ICSharpCode.SharpZipLib.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ImageProcessor.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ImageProcessor.Web.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.Web.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll) { Remove-Item $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.Cookies.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.Cookies.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.OAuth.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.OAuth.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Infrastructure.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Infrastructure.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll) { Remove-Item $umbracoBinFolder\Microsoft.Web.Mvc.FixedDisplayModes.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\MiniProfiler.dll) { Remove-Item $umbracoBinFolder\MiniProfiler.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Owin.dll) { Remove-Item $umbracoBinFolder\Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Semver.dll) { Remove-Item $umbracoBinFolder\Semver.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Collections.Immutable.dll) { Remove-Item $umbracoBinFolder\System.Collections.Immutable.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Reflection.Metadata.dll) { Remove-Item $umbracoBinFolder\System.Reflection.Metadata.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Extensions.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Extensions.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Net.Http.Primitives.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Primitives.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\System.Web.Helpers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Http.WebHost.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.WebHost.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Mvc.dll) { Remove-Item $umbracoBinFolder\System.Web.Mvc.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.Razor.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Deployment.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Deployment.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
}
}
-27
View File
@@ -11,37 +11,15 @@ if ($project) {
# Create paths and list them
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
Write-Host "projectPath:" "${projectPath}"
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
Write-Host "backupPath:" "${backupPath}"
$copyLogsPath = Join-Path $backupPath "CopyLogs"
Write-Host "copyLogsPath:" "${copyLogsPath}"
$webConfigSource = Join-Path $projectPath "Web.config"
Write-Host "webConfigSource:" "${webConfigSource}"
$configFolder = Join-Path $projectPath "Config"
Write-Host "configFolder:" "${configFolder}"
# Create backup folder and logs folder if it doesn't exist yet
New-Item -ItemType Directory -Force -Path $backupPath
New-Item -ItemType Directory -Force -Path $copyLogsPath
# Create a backup of original web.config
Copy-Item $webConfigSource $backupPath -Force
# Backup config files folder
if(Test-Path $configFolder) {
$umbracoBackupPath = Join-Path $backupPath "Config"
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
robocopy $configFolder $umbracoBackupPath /e /LOG:$copyLogsPath\ConfigBackup.log
}
# Copy umbraco and umbraco_files from package to project folder
$umbracoFolder = Join-Path $projectPath "Umbraco"
New-Item -ItemType Directory -Force -Path $umbracoFolder
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
$copyWebconfig = $true
@@ -100,11 +78,6 @@ if ($project) {
}
}
$installFolder = Join-Path $projectPath "Install"
if(Test-Path $installFolder) {
Remove-Item $installFolder -Force -Recurse -Confirm:$false
}
# Open appropriate readme
if($copyWebconfig -eq $true)
{
+2 -2
View File
@@ -18,5 +18,5 @@ using System.Resources;
[assembly: AssemblyVersion("8.0.0")]
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.1.0")]
[assembly: AssemblyInformationalVersion("8.1.0")]
[assembly: AssemblyFileVersion("8.0.2")]
[assembly: AssemblyInformationalVersion("8.0.2")]
+95 -38
View File
@@ -70,7 +70,23 @@ namespace Umbraco.Core.Composing
}
}
private IEnumerable<Type> PrepareComposerTypes()
internal IEnumerable<Type> PrepareComposerTypes()
{
var requirements = GetRequirements();
// only for debugging, this is verbose
//_logger.Debug<Composers>(GetComposersReport(requirements));
var sortedComposerTypes = SortComposers(requirements);
// bit verbose but should help for troubleshooting
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
return sortedComposerTypes;
}
internal Dictionary<Type, List<Type>> GetRequirements(bool throwOnMissing = true)
{
// create a list, remove those that cannot be enabled due to runtime level
var composerTypeList = _composerTypes
@@ -89,25 +105,69 @@ namespace Umbraco.Core.Composing
// enable or disable composers
EnableDisableComposers(composerTypeList);
// sort the composers according to their dependencies
var requirements = new Dictionary<Type, List<Type>>();
foreach (var type in composerTypeList) requirements[type] = null;
foreach (var type in composerTypeList)
void GatherInterfaces<TAttribute>(Type type, Func<TAttribute, Type> getTypeInAttribute, HashSet<Type> iset, List<Type> set2)
where TAttribute : Attribute
{
GatherRequirementsFromRequireAttribute(type, composerTypeList, requirements);
GatherRequirementsFromRequiredByAttribute(type, composerTypeList, requirements);
foreach (var attribute in type.GetCustomAttributes<TAttribute>())
{
var typeInAttribute = getTypeInAttribute(attribute);
if (typeInAttribute != null && // if the attribute references a type ...
typeInAttribute.IsInterface && // ... which is an interface ...
typeof(IComposer).IsAssignableFrom(typeInAttribute) && // ... which implements IComposer ...
!iset.Contains(typeInAttribute)) // ... which is not already in the list
{
// add it to the new list
iset.Add(typeInAttribute);
set2.Add(typeInAttribute);
// add all its interfaces implementing IComposer
foreach (var i in typeInAttribute.GetInterfaces().Where(x => typeof(IComposer).IsAssignableFrom(x)))
{
iset.Add(i);
set2.Add(i);
}
}
}
}
// only for debugging, this is verbose
//_logger.Debug<Composers>(GetComposersReport(requirements));
// gather interfaces too
var interfaces = new HashSet<Type>(composerTypeList.SelectMany(x => x.GetInterfaces().Where(y => typeof(IComposer).IsAssignableFrom(y))));
composerTypeList.AddRange(interfaces);
var list1 = composerTypeList;
while (list1.Count > 0)
{
var list2 = new List<Type>();
foreach (var t in list1)
{
GatherInterfaces<ComposeAfterAttribute>(t, a => a.RequiredType, interfaces, list2);
GatherInterfaces<ComposeBeforeAttribute>(t, a => a.RequiringType, interfaces, list2);
}
composerTypeList.AddRange(list2);
list1 = list2;
}
// sort the composers according to their dependencies
var requirements = new Dictionary<Type, List<Type>>();
foreach (var type in composerTypeList)
requirements[type] = null;
foreach (var type in composerTypeList)
{
GatherRequirementsFromAfterAttribute(type, composerTypeList, requirements, throwOnMissing);
GatherRequirementsFromBeforeAttribute(type, composerTypeList, requirements);
}
return requirements;
}
internal IEnumerable<Type> SortComposers(Dictionary<Type, List<Type>> requirements)
{
// sort composers
var graph = new TopoGraph<Type, KeyValuePair<Type, List<Type>>>(kvp => kvp.Key, kvp => kvp.Value);
graph.AddItems(requirements);
List<Type> sortedComposerTypes;
try
{
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).ToList();
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).Where(x => !x.IsInterface).ToList();
}
catch (Exception e)
{
@@ -117,40 +177,37 @@ namespace Umbraco.Core.Composing
throw;
}
// bit verbose but should help for troubleshooting
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
return sortedComposerTypes;
}
private static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
internal static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
{
var text = new StringBuilder();
text.AppendLine("Composers & Dependencies:");
text.AppendLine(" < compose before");
text.AppendLine(" > compose after");
text.AppendLine(" : implements");
text.AppendLine(" = depends");
text.AppendLine();
bool HasReq(IEnumerable<Type> types, Type type)
=> types.Any(x => type.IsAssignableFrom(x) && !x.IsInterface);
foreach (var kvp in requirements)
{
var type = kvp.Key;
text.AppendLine(type.FullName);
foreach (var attribute in type.GetCustomAttributes<ComposeAfterAttribute>())
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
: ""));
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" -< " + attribute.RequiringType);
foreach (var i in type.GetInterfaces())
{
text.AppendLine(" : " + i.FullName);
foreach (var attribute in i.GetCustomAttributes<ComposeAfterAttribute>())
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
: ""));
foreach (var attribute in i.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" -< " + attribute.RequiringType);
var weak = !(attribute.RequiredType.IsInterface ? attribute.Weak == false : attribute.Weak != true);
text.AppendLine(" > " + attribute.RequiredType +
(weak ? " (weak" : " (strong") + (HasReq(requirements.Keys, attribute.RequiredType) ? ", found" : ", missing") + ")");
}
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" < " + attribute.RequiringType);
foreach (var i in type.GetInterfaces())
text.AppendLine(" : " + i.FullName);
if (kvp.Value != null)
foreach (var t in kvp.Value)
text.AppendLine(" = " + t);
@@ -221,16 +278,16 @@ namespace Umbraco.Core.Composing
types.Remove(kvp.Key);
}
private static void GatherRequirementsFromRequireAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
private static void GatherRequirementsFromAfterAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements, bool throwOnMissing = true)
{
// get 'require' attributes
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
var requireAttributes = type
var afterAttributes = type
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeAfterAttribute>()) // those marking interfaces
.Concat(type.GetCustomAttributes<ComposeAfterAttribute>()); // those marking the composer
// what happens in case of conflicting attributes (different strong/weak for same type) is not specified.
foreach (var attr in requireAttributes)
foreach (var attr in afterAttributes)
{
if (attr.RequiredType == type) continue; // ignore self-requirements (+ exclude in implems, below)
@@ -238,13 +295,13 @@ namespace Umbraco.Core.Composing
// unless strong, and then require at least one enabled composer implementing that interface
if (attr.RequiredType.IsInterface)
{
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x)).ToList();
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x) && !x.IsInterface).ToList();
if (implems.Count > 0)
{
if (requirements[type] == null) requirements[type] = new List<Type>();
requirements[type].AddRange(implems);
}
else if (attr.Weak == false) // if explicitly set to !weak, is strong, else is weak
else if (attr.Weak == false && throwOnMissing) // if explicitly set to !weak, is strong, else is weak
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
}
// requiring a class = require that the composer is enabled
@@ -256,28 +313,28 @@ namespace Umbraco.Core.Composing
if (requirements[type] == null) requirements[type] = new List<Type>();
requirements[type].Add(attr.RequiredType);
}
else if (attr.Weak != true) // if not explicitly set to weak, is strong
else if (attr.Weak != true && throwOnMissing) // if not explicitly set to weak, is strong
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
}
}
}
private static void GatherRequirementsFromRequiredByAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
private static void GatherRequirementsFromBeforeAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
{
// get 'required' attributes
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
var requiredAttributes = type
var beforeAttributes = type
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeBeforeAttribute>()) // those marking interfaces
.Concat(type.GetCustomAttributes<ComposeBeforeAttribute>()); // those marking the composer
foreach (var attr in requiredAttributes)
foreach (var attr in beforeAttributes)
{
if (attr.RequiringType == type) continue; // ignore self-requirements (+ exclude in implems, below)
// required by an interface = by any enabled composer implementing this that interface
if (attr.RequiringType.IsInterface)
{
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x)).ToList();
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x) && !x.IsInterface).ToList();
foreach (var implem in implems)
{
if (requirements[implem] == null) requirements[implem] = new List<Type>();
+1 -2
View File
@@ -8,7 +8,6 @@
/// <summary>
/// Compose.
/// </summary>
/// <param name="composition"></param>
void Compose(Composition composition);
}
}
}
+2 -4
View File
@@ -4,10 +4,8 @@
/// Represents a core <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All core composers are required by (compose before) all user composers,
/// and require (compose after) all runtime composers.</para>
/// <para>Core composers compose after the initial composer, and before user composers.</para>
/// </remarks>
[ComposeAfter(typeof(IRuntimeComposer))]
public interface ICoreComposer : IComposer
{ }
}
}
@@ -1,11 +0,0 @@
namespace Umbraco.Core.Composing
{
/// <summary>
/// Represents a runtime <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All runtime composers are required by (compose before) all core composers</para>
/// </remarks>
public interface IRuntimeComposer : IComposer
{ }
}
+2 -2
View File
@@ -4,9 +4,9 @@
/// Represents a user <see cref="IComposer"/>.
/// </summary>
/// <remarks>
/// <para>All user composers require (compose after) all core composers.</para>
/// <para>User composers compose after core composers, and before the final composer.</para>
/// </remarks>
[ComposeAfter(typeof(ICoreComposer))]
public interface IUserComposer : IComposer
{ }
}
}
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Composing
{
/// <summary>
/// Provides a base class for collections of types.
/// </summary>
public abstract class TypeCollectionBuilderBase<TCollection, TConstraint> : ICollectionBuilder<TCollection, Type>
where TCollection : class, IBuilderCollection<Type>
{
private readonly HashSet<Type> _types = new HashSet<Type>();
private Type Validate(Type type, string action)
{
if (!typeof(TConstraint).IsAssignableFrom(type))
throw new InvalidOperationException($"Cannot {action} type {type.FullName} as it does not inherit from/implement {typeof(TConstraint).FullName}.");
return type;
}
public void Add(Type type) => _types.Add(Validate(type, "add"));
public void Add<T>() => Add(typeof(T));
public void Add(IEnumerable<Type> types)
{
foreach (var type in types) Add(type);
}
public void Remove(Type type) => _types.Remove(Validate(type, "remove"));
public void Remove<T>() => Remove(typeof(T));
public TCollection CreateCollection(IFactory factory)
{
return factory.CreateInstance<TCollection>(_types);
}
public void RegisterWith(IRegister register)
{
register.Register(CreateCollection, Lifetime.Singleton);
}
}
}
+22
View File
@@ -203,6 +203,28 @@ namespace Umbraco.Core
composition.RegisterUnique(_ => registrar);
}
/// <summary>
/// Sets the database server messenger options.
/// </summary>
/// <param name="composition">The composition.</param>
/// <param name="factory">A function creating the options.</param>
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
public static void SetDatabaseServerMessengerOptions(this Composition composition, Func<IFactory, DatabaseServerMessengerOptions> factory)
{
composition.RegisterUnique(factory);
}
/// <summary>
/// Sets the database server messenger options.
/// </summary>
/// <param name="composition">The composition.</param>
/// <param name="options">Options.</param>
/// <remarks>Use DatabaseServerRegistrarAndMessengerComposer.GetDefaultOptions to get the options that Umbraco would use by default.</remarks>
public static void SetDatabaseServerMessengerOptions(this Composition composition, DatabaseServerMessengerOptions options)
{
composition.RegisterUnique(_ => options);
}
/// <summary>
/// Sets the short string helper.
/// </summary>
+11 -5
View File
@@ -7,6 +7,7 @@ using System.Web;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPoco.Expressions;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
@@ -52,8 +53,8 @@ namespace Umbraco.Core
return ContentStatus.Unpublished;
}
#endregion
/// <summary>
@@ -134,9 +135,14 @@ namespace Umbraco.Core
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
/// <remarks>This really is for FileUpload fields only, and should be obsoleted. For anything else,
/// you need to store the file by yourself using Store and then figure out
/// how to deal with auto-fill properties (if any) and thumbnails (if any) by yourself.</remarks>
public static void SetValue(this IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, HttpPostedFileBase postedFile, string culture = null, string segment = null)
{
content.SetValue(contentTypeBaseServiceProvider, propertyTypeAlias, postedFile.FileName, postedFile.InputStream, culture, segment);
}
/// <summary>
/// Sets the posted file value of a property.
/// </summary>
public static void SetValue(this IContentBase content, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, string propertyTypeAlias, string filename, Stream filestream, string culture = null, string segment = null)
{
if (filename == null || filestream == null) return;
+17
View File
@@ -10,6 +10,23 @@ namespace Umbraco.Core
///</summary>
public static class EnumerableExtensions
{
internal static bool HasDuplicates<T>(this IEnumerable<T> items, bool includeNull)
{
var hs = new HashSet<T>();
foreach (var item in items)
{
if (item != null || includeNull)
{
if (!hs.Add(item))
{
return true;
}
}
}
return false;
}
/// <summary>
/// Wraps this object instance into an IEnumerable{T} consisting of a single item.
/// </summary>
@@ -8,9 +8,12 @@ namespace Umbraco.Core.IO.MediaPathSchemes
/// </summary>
/// <remarks>
/// <para>Path is "{combinedGuid}/{filename}" where combinedGuid is a combination of itemGuid and propertyGuid.</para>
/// <para>This scheme is dangerous, as it does not prevent potential collisions.</para>
/// </remarks>
public class CombinedGuidsMediaPathScheme : IMediaPathScheme
{
private const int DirectoryLength = 8;
/// <inheritdoc />
public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null)
{
@@ -18,7 +21,7 @@ namespace Umbraco.Core.IO.MediaPathSchemes
// for a single content cannot store two different files with the same name
var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid);
var directory = HexEncoder.Encode(combinedGuid.ToByteArray()/*'/', 2, 4*/); // could use ext to fragment path eg 12/e4/f2/...
var directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength); // see also HexEncoder, we may want to fragment path eg 12/e4/f3...
return Path.Combine(directory, filename).Replace('\\', '/');
}
@@ -7,7 +7,7 @@ namespace Umbraco.Core.IO.MediaPathSchemes
/// Implements a unique directory media path scheme.
/// </summary>
/// <remarks>
/// <para>This scheme provides deterministic short paths, with potential collisions.</para>
/// <para>This scheme provides short paths, yet handle potential collisions.</para>
/// </remarks>
public class UniqueMediaPathScheme : IMediaPathScheme
{
@@ -16,22 +16,23 @@ namespace Umbraco.Core.IO.MediaPathSchemes
/// <inheritdoc />
public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null)
{
var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid);
var directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength);
string directory;
// no point "combining" guids if all we want is some random guid - just get a new one
// and then, because we don't want collisions, ensure that the directory does not already exist
// (should be quite rare, but eh...)
do
{
var combinedGuid = Guid.NewGuid();
directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength); // see also HexEncoder, we may want to fragment path eg 12/e4/f3...
} while (fileSystem.DirectoryExists(directory));
return Path.Combine(directory, filename).Replace('\\', '/');
}
/// <inheritdoc />
/// <remarks>
/// <para>Returning null so that <see cref="MediaFileSystem.DeleteMediaFiles"/> does *not*
/// delete any directory. This is because the above shortening of the Guid to 8 chars
/// means we're increasing the risk of collision, and we don't want to delete files
/// belonging to other media items.</para>
/// <para>And, at the moment, we cannot delete directory "only if it is empty" because of
/// race conditions. We'd need to implement locks in <see cref="MediaFileSystem"/> for
/// this.</para>
/// </remarks>
public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) => null;
public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) => Path.GetDirectoryName(filepath);
}
}
}
@@ -226,6 +226,8 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
}
@@ -5,6 +5,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
namespace Umbraco.Core.Migrations.Upgrade
{
@@ -137,6 +138,8 @@ namespace Umbraco.Core.Migrations.Upgrade
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
//FINAL
@@ -167,7 +170,7 @@ namespace Umbraco.Core.Migrations.Upgrade
From("{init-7.12.4}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.0}").To("{init-7.10.0}"); // same as 7.12.0
From("{init-7.13.1}").To("{init-7.10.0}"); // same as 7.12.0
// 7.14.0 has migrations, handle it...
// clone going from 7.10 to 1350617A (the last one before we started to merge 7.12 migrations), then
// clone going from CF51B39B (after 7.12 migrations) to 0009109C (the last one before we started to merge 7.12 migrations),
@@ -0,0 +1,16 @@
using Umbraco.Core.Migrations.PostMigrations;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_1
{
public class ChangeNuCacheJsonFormat : MigrationBase
{
public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
{ }
public override void Migrate()
{
// nothing - just adding the post-migration
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
}
}
+19 -3
View File
@@ -95,6 +95,21 @@ namespace Umbraco.Core.Models
protected void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//enable this to detect duplicate property aliases. We do want this, however making this change in a
//patch release might be a little dangerous
////detect if there are any duplicate aliases - this cannot be allowed
//if (e.Action == NotifyCollectionChangedAction.Add
// || e.Action == NotifyCollectionChangedAction.Replace)
//{
// var allAliases = _noGroupPropertyTypes.Concat(PropertyGroups.SelectMany(x => x.PropertyTypes)).Select(x => x.Alias);
// if (allAliases.HasDuplicates(false))
// {
// var newAliases = string.Join(", ", e.NewItems.Cast<PropertyType>().Select(x => x.Alias));
// throw new InvalidOperationException($"Other property types already exist with the aliases: {newAliases}");
// }
//}
OnPropertyChanged(nameof(PropertyTypes));
}
@@ -397,15 +412,16 @@ namespace Umbraco.Core.Models
var group = PropertyGroups[propertyGroupName];
if (group == null) return;
// re-assign the group's properties to no group
// first remove the group
PropertyGroups.RemoveItem(propertyGroupName);
// Then re-assign the group's properties to no group
foreach (var property in group.PropertyTypes)
{
property.PropertyGroupId = null;
_noGroupPropertyTypes.Add(property);
}
// actually remove the group
PropertyGroups.RemoveItem(propertyGroupName);
OnPropertyChanged(nameof(PropertyGroups));
}
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged, IDeepCloneable
{
private readonly object _addLocker = new object();
internal Action OnAdd;
internal Func<Property, bool> AdditionValidator { get; set; }
/// <summary>
@@ -49,10 +49,12 @@ namespace Umbraco.Core.Models
/// </summary>
internal void Reset(IEnumerable<Property> properties)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var property in properties)
Add(property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
@@ -60,8 +62,9 @@ namespace Umbraco.Core.Models
/// </summary>
protected override void SetItem(int index, Property property)
{
var oldItem = index >= 0 ? this[index] : property;
base.SetItem(index, property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property, index));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, property, oldItem));
}
/// <summary>
@@ -120,10 +123,8 @@ namespace Umbraco.Core.Models
}
}
//collection events will be raised in InsertItem with Add
base.Add(property);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property));
}
}
@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
{
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
// TODO: this doesn't seem to be used anywhere
internal Action OnAdd;
internal PropertyGroupCollection()
{ }
@@ -37,16 +34,19 @@ namespace Umbraco.Core.Models
/// <remarks></remarks>
internal void Reset(IEnumerable<PropertyGroup> groups)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var group in groups)
Add(group);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected override void SetItem(int index, PropertyGroup item)
{
var oldItem = index >= 0 ? this[index] : item;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
}
protected override void RemoveItem(int index)
@@ -84,6 +84,7 @@ namespace Umbraco.Core.Models
if (keyExists)
throw new Exception($"Naming conflict: Changing the name of PropertyGroup '{item.Name}' would result in duplicates");
//collection events will be raised in SetItem
SetItem(IndexOfKey(item.Id), item);
return;
}
@@ -96,16 +97,14 @@ namespace Umbraco.Core.Models
var exists = Contains(key);
if (exists)
{
//collection events will be raised in SetItem
SetItem(IndexOfKey(key), item);
return;
}
}
}
//collection events will be raised in InsertItem
base.Add(item);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
finally
{
@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
// TODO: This doesn't seem to be used
[IgnoreDataMember]
internal Action OnAdd;
internal PropertyTypeCollection(bool supportsPublishing)
{
@@ -43,36 +40,44 @@ namespace Umbraco.Core.Models
/// <remarks></remarks>
internal void Reset(IEnumerable<PropertyType> properties)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var property in properties)
Add(property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
Add(property);
}
protected override void SetItem(int index, PropertyType item)
{
item.SupportsPublishing = SupportsPublishing;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
var oldItem = index >= 0 ? this[index] : item;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
item.PropertyChanged += Item_PropertyChanged;
}
protected override void RemoveItem(int index)
{
var removed = this[index];
base.RemoveItem(index);
removed.PropertyChanged -= Item_PropertyChanged;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
}
protected override void InsertItem(int index, PropertyType item)
{
item.SupportsPublishing = SupportsPublishing;
base.InsertItem(index, item);
base.InsertItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
item.PropertyChanged += Item_PropertyChanged;
}
protected override void ClearItems()
{
base.ClearItems();
foreach (var item in this)
item.PropertyChanged -= Item_PropertyChanged;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
@@ -91,6 +96,7 @@ namespace Umbraco.Core.Models
var exists = Contains(key);
if (exists)
{
//collection events will be raised in SetItem
SetItem(IndexOfKey(key), item);
return;
}
@@ -103,10 +109,8 @@ namespace Umbraco.Core.Models
item.SortOrder = this.Max(x => x.SortOrder) + 1;
}
//collection events will be raised in InsertItem
base.Add(item);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
finally
{
@@ -115,6 +119,17 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Occurs when a property changes on a PropertyType that exists in this collection
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var propType = (PropertyType)sender;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, propType, propType));
}
/// <summary>
/// Determines whether this collection contains a <see cref="Property"/> whose alias matches the specified PropertyType.
/// </summary>
@@ -11,14 +11,14 @@ namespace Umbraco.Core.Models.PublishedContent
/// <summary>
/// Initializes a new instance of the <see cref="PublishedCultureInfo"/> class.
/// </summary>
public PublishedCultureInfo(string culture, string name, DateTime date)
public PublishedCultureInfo(string culture, string name, string urlSegment, DateTime date)
{
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentNullOrEmptyException(nameof(culture));
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullOrEmptyException(nameof(name));
Culture = culture;
Name = name;
UrlSegment = name.ToUrlSegment(culture);
UrlSegment = urlSegment;
Date = date;
}
@@ -9,11 +9,10 @@ namespace Umbraco.Core.Persistence.Factories
{
internal static class MemberTypeReadOnlyFactory
{
public static IMemberType BuildEntity(MemberTypeReadOnlyDto dto, out bool needsSaving)
public static IMemberType BuildEntity(MemberTypeReadOnlyDto dto)
{
var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
needsSaving = false;
var memberType = new MemberType(dto.ParentId);
try
@@ -41,27 +40,29 @@ namespace Umbraco.Core.Persistence.Factories
var propertyTypeGroupCollection = GetPropertyTypeGroupCollection(dto, memberType, standardPropertyTypes);
memberType.PropertyGroups = propertyTypeGroupCollection;
var propertyTypes = GetPropertyTypes(dto, memberType, standardPropertyTypes);
memberType.NoGroupPropertyTypes = GetNoGroupPropertyTypes(dto, memberType, standardPropertyTypes);
//By Convention we add 9 standard PropertyTypes - This is only here to support loading of types that didn't have these conventions before.
// By Convention we add 9 standard PropertyTypes - This is only here to support loading of types that didn't have these conventions before.
// In theory this should not happen! The only reason this did happen was because:
// A) we didn't install all of the default membership properties by default
// B) the existing data is super old when we didn't store membership properties at all (very very old)
// So what to do? We absolutely do not want to update the database when only a read was requested, this will cause problems
// so we should just add these virtual properties, they will have no ids but they will have aliases and this should be perfectly
// fine for any membership provider logic to work since neither membership providers or asp.net identity care about whether a property
// has an ID or not.
// When the member type is saved, all the properties will correctly be added.
//This will add this group if it doesn't exist, no need to error check here
memberType.AddPropertyGroup(Constants.Conventions.Member.StandardPropertiesGroupName);
foreach (var standardPropertyType in standardPropertyTypes)
{
if (dto.PropertyTypes.Any(x => x.Alias.Equals(standardPropertyType.Key))) continue;
//This will add the property if it doesn't exist, no need to error check here
memberType.AddPropertyType(standardPropertyType.Value, Constants.Conventions.Member.StandardPropertiesGroupName);
// beware!
// means that we can return a memberType "from database" that has some property types
// that do *not* come from the database and therefore are incomplete eg have no key,
// no id, no dataTypeDefinitionId - ouch! - better notify caller of the situation
needsSaving = true;
//Add the standard PropertyType to the current list
propertyTypes.Add(standardPropertyType.Value);
//Internal dictionary for adding "MemberCanEdit", "VisibleOnProfile", "IsSensitive" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key,
new MemberTypePropertyProfileAccess(false, false, false));
if (!memberType.MemberTypePropertyTypes.TryGetValue(standardPropertyType.Key, out var memberTypePropertyProfile))
memberType.MemberTypePropertyTypes[standardPropertyType.Key] = new MemberTypePropertyProfileAccess(false, false, false);
}
memberType.NoGroupPropertyTypes = propertyTypes;
return memberType;
}
@@ -147,13 +148,14 @@ namespace Umbraco.Core.Persistence.Factories
return propertyGroups;
}
private static List<PropertyType> GetPropertyTypes(MemberTypeReadOnlyDto dto, MemberType memberType, Dictionary<string, PropertyType> standardProps)
private static List<PropertyType> GetNoGroupPropertyTypes(MemberTypeReadOnlyDto dto, MemberType memberType, Dictionary<string, PropertyType> standardProps)
{
//Find PropertyTypes that does not belong to a PropertyTypeGroup
var propertyTypes = new List<PropertyType>();
foreach (var typeDto in dto.PropertyTypes.Where(x => (x.PropertyTypeGroupId.HasValue == false || x.PropertyTypeGroupId.Value == 0) && x.Id.HasValue))
{
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(typeDto.Alias,
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit, typeDto.IsSensitive));
@@ -46,7 +46,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override IIdentityUserLogin PerformGet(int id)
{
var sql = GetBaseQuery(false);
sql.Where(GetBaseWhereClause(), new { Id = id });
sql.Where(GetBaseWhereClause(), new { id = id });
var dto = Database.Fetch<ExternalLoginDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
if (dto == null)
@@ -308,13 +308,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (dtos == null || dtos.Any() == false)
return Enumerable.Empty<IMemberType>();
return dtos.Select(x =>
{
bool needsSaving;
var memberType = MemberTypeReadOnlyFactory.BuildEntity(x, out needsSaving);
if (needsSaving) PersistUpdatedItem(memberType);
return memberType;
}).ToList();
return dtos.Select(MemberTypeReadOnlyFactory.BuildEntity).ToList();
}
/// <summary>
@@ -1,8 +1,8 @@
namespace Umbraco.Core.PropertyEditors
{
internal class DropDownFlexibleConfiguration : ValueListConfiguration
public class DropDownFlexibleConfiguration : ValueListConfiguration
{
[ConfigurationField("multiple", "Enable multiple choice", "boolean", Description = "When checked, the dropdown will be a select multiple / combo box style dropdown.")]
public bool Multiple { get; set; }
}
}
}
@@ -36,6 +36,10 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
if (source is int)
return (int)source == 1;
// this is required for correct true/false handling in nested content elements
if (source is long)
return (long)source == 1;
if (source is bool)
return (bool)source;
@@ -5,11 +5,11 @@ using Umbraco.Core.IO;
namespace Umbraco.Core.Runtime
{
public class CoreRuntimeComponent : IComponent
public class CoreInitialComponent : IComponent
{
private readonly IEnumerable<Profile> _mapperProfiles;
public CoreRuntimeComponent(IEnumerable<Profile> mapperProfiles)
public CoreInitialComponent(IEnumerable<Profile> mapperProfiles)
{
_mapperProfiles = mapperProfiles;
}
@@ -24,7 +24,9 @@ using IntegerValidator = Umbraco.Core.PropertyEditors.Validators.IntegerValidato
namespace Umbraco.Core.Runtime
{
public class CoreRuntimeComposer : ComponentComposer<CoreRuntimeComponent>, IRuntimeComposer
// core's initial composer composes before all core composers
[ComposeBefore(typeof(ICoreComposer))]
public class CoreInitialComposer : ComponentComposer<CoreInitialComponent>
{
public override void Compose(Composition composition)
{
+9 -3
View File
@@ -5,6 +5,7 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
@@ -70,10 +71,15 @@ namespace Umbraco.Core.Runtime
// objects.
using (var timer = profilingLogger.TraceDuration<CoreRuntime>(
$"Booting Umbraco {UmbracoVersion.SemanticVersion.ToSemanticString()} on {NetworkHelper.MachineName}.",
$"Booting Umbraco {UmbracoVersion.SemanticVersion.ToSemanticString()}.",
"Booted.",
"Boot failed."))
{
logger.Info<CoreRuntime>("Booting site '{HostingSiteName}', app '{HostingApplicationID}', path '{HostingPhysicalPath}', server '{MachineName}'.",
HostingEnvironment.SiteName,
HostingEnvironment.ApplicationID,
HostingEnvironment.ApplicationPhysicalPath,
NetworkHelper.MachineName);
logger.Debug<CoreRuntime>("Runtime: {Runtime}", GetType().FullName);
// application environment
@@ -168,7 +174,7 @@ namespace Umbraco.Core.Runtime
_state.BootFailedException = bfe;
}
timer.Fail(exception: bfe); // be sure to log the exception - even if we repeat ourselves
timer?.Fail(exception: bfe); // be sure to log the exception - even if we repeat ourselves
// if something goes wrong above, we may end up with no factory
// meaning nothing can get the runtime state, etc - so let's try
@@ -242,7 +248,7 @@ namespace Umbraco.Core.Runtime
}
catch
{
timer.Fail();
timer?.Fail();
throw;
}
}
@@ -2,39 +2,61 @@
namespace Umbraco.Core.Scoping
{
// base class for an object that will be enlisted in scope context, if any. it
// must be used in a 'using' block, and if not scoped, released when disposed,
// else when scope context runs enlisted actions
/// <summary>
/// Provides a base class for scope contextual objects.
/// </summary>
/// <remarks>
/// <para>A scope contextual object is enlisted in the current scope context,
/// if any, and released when the context exists. It must be used in a 'using'
/// block, and will be released when disposed, if not part of a scope.</para>
/// </remarks>
public abstract class ScopeContextualBase : IDisposable
{
private bool _using, _scoped;
private bool _scoped;
/// <summary>
/// Gets a contextual object.
/// </summary>
/// <typeparam name="T">The type of the object.</typeparam>
/// <param name="scopeProvider">A scope provider.</param>
/// <param name="key">A context key for the object.</param>
/// <param name="ctor">A function producing the contextual object.</param>
/// <returns>The contextual object.</returns>
/// <remarks>
/// <para></para>
/// </remarks>
public static T Get<T>(IScopeProvider scopeProvider, string key, Func<bool, T> ctor)
where T : ScopeContextualBase
{
// no scope context = create a non-scoped object
var scopeContext = scopeProvider.Context;
if (scopeContext == null)
return ctor(false);
// create & enlist the scoped object
var w = scopeContext.Enlist("ScopeContextualBase_" + key,
() => ctor(true),
(completed, item) => { item.Release(completed); });
if (w._using) throw new InvalidOperationException("panic: used.");
w._using = true;
w._scoped = true;
return w;
}
/// <inheritdoc />
/// <remarks>
/// <para>If not scoped, then this releases the contextual object.</para>
/// </remarks>
public void Dispose()
{
_using = false;
if (_scoped == false)
Release(true);
}
/// <summary>
/// Releases the contextual object.
/// </summary>
/// <param name="completed">A value indicating whether the scoped operation completed.</param>
public abstract void Release(bool completed);
}
}
@@ -1902,9 +1902,8 @@ namespace Umbraco.Core.Services.Implement
content.ParentId = parentId;
// get the level delta (old pos to new pos)
var levelDelta = parent == null
? 1 - content.Level + (parentId == Constants.System.RecycleBinContent ? 1 : 0)
: parent.Level + 1 - content.Level;
// note that recycle bin (id:-20) level is 0!
var levelDelta = 1 - content.Level + (parent?.Level ?? 0);
var paths = new Dictionary<int, string>();
@@ -2862,7 +2861,7 @@ namespace Umbraco.Core.Services.Implement
{
if (blueprint == null) throw new ArgumentNullException(nameof(blueprint));
var contentType = GetContentType(blueprint.ContentType.Alias);
var contentType = _contentTypeRepository.Get(blueprint.ContentType.Id);
var content = new Content(name, -1, contentType);
content.Path = string.Concat(content.ParentId.ToString(), ",", content.Id);
@@ -2875,7 +2874,14 @@ namespace Umbraco.Core.Services.Implement
{
foreach (var property in blueprint.Properties)
{
content.SetValue(property.Alias, property.GetValue(culture), culture);
if (property.PropertyType.VariesByCulture())
{
content.SetValue(property.Alias, property.GetValue(culture), culture);
}
else
{
content.SetValue(property.Alias, property.GetValue());
}
}
content.Name = blueprint.Name;
@@ -289,7 +289,7 @@ namespace Umbraco.Core.Services.Implement
scope.Events.Dispatch(Saved, this, saveEventArgs);
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IMedia>(media, TreeChangeTypes.RefreshNode).ToEventArgs());
}
if (withIdentity == false)
return;
@@ -716,7 +716,7 @@ namespace Umbraco.Core.Services.Implement
#endregion
#region Delete
/// <summary>
/// Permanently deletes an <see cref="IMedia"/> object
/// </summary>
@@ -975,9 +975,8 @@ namespace Umbraco.Core.Services.Implement
media.ParentId = parentId;
// get the level delta (old pos to new pos)
var levelDelta = parent == null
? 1 - media.Level + (parentId == Constants.System.RecycleBinMedia ? 1 : 0)
: parent.Level + 1 - media.Level;
// note that recycle bin (id:-20) level is 0!
var levelDelta = 1 - media.Level + (parent?.Level ?? 0);
var paths = new Dictionary<int, string>();
@@ -1024,6 +1023,7 @@ namespace Umbraco.Core.Services.Implement
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
/// </summary>
/// <param name="userId">Optional Id of the User emptying the Recycle Bin</param>
public OperationResult EmptyRecycleBin()
{
var nodeObjectType = Constants.ObjectTypes.Media;
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Strings
/// Converts an Utf8 string into an Ascii string.
/// </summary>
/// <param name="text">The text to convert.</param>
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
/// <returns>The converted text.</returns>
public static string ToAsciiString(string text, char fail = '?')
{
@@ -39,7 +39,7 @@ namespace Umbraco.Core.Strings
/// Converts an Utf8 string into an array of Ascii characters.
/// </summary>
/// <param name="text">The text to convert.</param>
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
/// <returns>The converted text.</returns>
public static char[] ToAsciiCharArray(string text, char fail = '?')
{
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Strings
/// </summary>
/// <param name="input">The input array.</param>
/// <param name="output">The output array.</param>
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
/// <returns>The number of characters in the output array.</returns>
/// <remarks>The caller must ensure that the output array is big enough.</remarks>
/// <exception cref="OverflowException">The output array is not big enough.</exception>
@@ -112,7 +112,7 @@ namespace Umbraco.Core.Strings
/// <param name="ipos">The input position.</param>
/// <param name="output">The output array.</param>
/// <param name="opos">The output position.</param>
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
/// <remarks>
/// <para>Adapted from various sources on the 'net including <c>Lucene.Net.Analysis.ASCIIFoldingFilter</c>.</para>
/// <para>Input should contain Utf8 characters exclusively and NOT Unicode.</para>
+4 -3
View File
@@ -168,7 +168,6 @@
<Compile Include="Composing\EnableComposerAttribute.cs" />
<Compile Include="Composing\IComposer.cs" />
<Compile Include="Composing\ICoreComposer.cs" />
<Compile Include="Composing\IRuntimeComposer.cs" />
<Compile Include="Composing\IComponent.cs" />
<Compile Include="Composing\IUserComposer.cs" />
<Compile Include="Compose\ManifestWatcherComposer.cs" />
@@ -209,11 +208,13 @@
<Compile Include="Composing\TypeLoader.cs" />
<Compile Include="IO\MediaPathSchemes\UniqueMediaPathScheme.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_1\ChangeNuCacheJsonFormat.cs" />
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
<Compile Include="PropertyEditors\DateTimeConfiguration.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
<Compile Include="PublishedModelFactoryExtensions.cs" />
<Compile Include="Services\PropertyValidationService.cs" />
<Compile Include="Composing\TypeCollectionBuilderBase.cs" />
<Compile Include="TypeLoaderExtensions.cs" />
<Compile Include="Composing\WeightAttribute.cs" />
<Compile Include="Composing\WeightedCollectionBuilderBase.cs" />
@@ -530,7 +531,7 @@
<Compile Include="RuntimeLevelReason.cs" />
<Compile Include="RuntimeOptions.cs" />
<Compile Include="Runtime\CoreRuntime.cs" />
<Compile Include="Runtime\CoreRuntimeComponent.cs" />
<Compile Include="Runtime\CoreInitialComponent.cs" />
<Compile Include="CustomBooleanTypeConverter.cs" />
<Compile Include="Migrations\Expressions\Common\ExecutableBuilder.cs" />
<Compile Include="Migrations\Expressions\Common\IExecutableBuilder.cs" />
@@ -1311,7 +1312,7 @@
<Compile Include="ReflectionUtilities.cs" />
<Compile Include="RuntimeLevel.cs" />
<Compile Include="RuntimeState.cs" />
<Compile Include="Runtime\CoreRuntimeComposer.cs" />
<Compile Include="Runtime\CoreInitialComposer.cs" />
<Compile Include="SafeCallContext.cs" />
<Compile Include="Scoping\IInstanceIdentifiable.cs" />
<Compile Include="Scoping\IScope.cs" />
+1 -1
View File
@@ -48,7 +48,7 @@
</ItemGroup>
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Examine" Version="1.0.1" />
<PackageReference Include="Examine" Version="1.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="NPoco" Version="3.9.4" />
</ItemGroup>
@@ -158,7 +158,7 @@ namespace Umbraco.Tests.Cache
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
TestObjects.GetGlobalSettings(),
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
// just assert it does not throw
+214 -28
View File
@@ -5,6 +5,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Core.Scoping;
using Umbraco.Web.PublishedCache.NuCache;
using Umbraco.Web.PublishedCache.NuCache.Snap;
namespace Umbraco.Tests.Cache
{
@@ -388,8 +389,7 @@ namespace Umbraco.Tests.Cache
// collect liveGen
GC.Collect();
SnapDictionary<int, string>.GenerationObject genObj;
Assert.IsTrue(d.Test.GenerationObjects.TryPeek(out genObj));
Assert.IsTrue(d.Test.GenObjs.TryPeek(out var genObj));
genObj = null;
// in Release mode, it works, but in Debug mode, the weak reference is still alive
@@ -399,14 +399,14 @@ namespace Umbraco.Tests.Cache
GC.Collect();
#endif
Assert.IsTrue(d.Test.GenerationObjects.TryPeek(out genObj));
Assert.IsFalse(genObj.WeakReference.IsAlive); // snapshot is gone, along with its reference
Assert.IsTrue(d.Test.GenObjs.TryPeek(out genObj));
Assert.IsFalse(genObj.WeakGenRef.IsAlive); // snapshot is gone, along with its reference
await d.CollectAsync();
Assert.AreEqual(0, d.Test.GetValues(1).Length); // null value is gone
Assert.AreEqual(0, d.Count); // item is gone
Assert.AreEqual(0, d.Test.GenerationObjects.Count);
Assert.AreEqual(0, d.Test.GenObjs.Count);
Assert.AreEqual(0, d.SnapCount); // snapshot is gone
Assert.AreEqual(0, d.GenCount); // and generation has been dequeued
}
@@ -632,7 +632,7 @@ namespace Umbraco.Tests.Cache
Assert.AreEqual(1, d.Test.LiveGen);
Assert.IsTrue(d.Test.NextGen);
using (d.GetWriter(GetScopeProvider()))
using (d.GetScopedWriteLock(GetScopeProvider()))
{
var s1 = d.CreateSnapshot();
@@ -685,7 +685,7 @@ namespace Umbraco.Tests.Cache
Assert.IsFalse(d.Test.NextGen);
Assert.AreEqual("uno", s2.Get(1));
using (d.GetWriter(GetScopeProvider()))
using (d.GetScopedWriteLock(GetScopeProvider()))
{
// gen 3
Assert.AreEqual(2, d.Test.GetValues(1).Length);
@@ -712,16 +712,102 @@ namespace Umbraco.Tests.Cache
}
[Test]
public void NestedWriteLocking()
public void NestedWriteLocking1()
{
var d = new SnapDictionary<int, string>();
var t = d.Test;
t.CollectAuto = false;
Assert.AreEqual(0, d.CreateSnapshot().Gen);
// no scope context: writers nest, last one to be disposed commits
var scopeProvider = GetScopeProvider();
using (var w1 = d.GetScopedWriteLock(scopeProvider))
{
Assert.AreEqual(1, t.LiveGen);
Assert.AreEqual(1, t.WLocked);
Assert.IsTrue(t.NextGen);
using (var w2 = d.GetScopedWriteLock(scopeProvider))
{
Assert.AreEqual(1, t.LiveGen);
Assert.AreEqual(2, t.WLocked);
Assert.IsTrue(t.NextGen);
Assert.AreNotSame(w1, w2); // get a new writer each time
d.Set(1, "one");
Assert.AreEqual(0, d.CreateSnapshot().Gen);
}
Assert.AreEqual(1, t.LiveGen);
Assert.AreEqual(1, t.WLocked);
Assert.IsTrue(t.NextGen);
Assert.AreEqual(0, d.CreateSnapshot().Gen);
}
Assert.AreEqual(1, t.LiveGen);
Assert.AreEqual(0, t.WLocked);
Assert.IsTrue(t.NextGen);
Assert.AreEqual(1, d.CreateSnapshot().Gen);
}
[Test]
public void NestedWriteLocking2()
{
var d = new SnapDictionary<int, string>();
d.Test.CollectAuto = false;
var scopeProvider = GetScopeProvider();
using (d.GetWriter(scopeProvider))
Assert.AreEqual(0, d.CreateSnapshot().Gen);
// scope context: writers enlist
var scopeContext = new ScopeContext();
var scopeProvider = GetScopeProvider(scopeContext);
using (var w1 = d.GetScopedWriteLock(scopeProvider))
{
using (d.GetWriter(scopeProvider))
using (var w2 = d.GetScopedWriteLock(scopeProvider))
{
Assert.AreSame(w1, w2);
d.Set(1, "one");
}
}
}
[Test]
public void NestedWriteLocking3()
{
var d = new SnapDictionary<int, string>();
var t = d.Test;
t.CollectAuto = false;
Assert.AreEqual(0, d.CreateSnapshot().Gen);
var scopeContext = new ScopeContext();
var scopeProvider1 = GetScopeProvider();
var scopeProvider2 = GetScopeProvider(scopeContext);
using (var w1 = d.GetScopedWriteLock(scopeProvider1))
{
Assert.AreEqual(1, t.LiveGen);
Assert.AreEqual(1, t.WLocked);
Assert.IsTrue(t.NextGen);
using (var w2 = d.GetScopedWriteLock(scopeProvider2))
{
Assert.AreEqual(1, t.LiveGen);
Assert.AreEqual(2, t.WLocked);
Assert.IsTrue(t.NextGen);
Assert.AreNotSame(w1, w2);
d.Set(1, "one");
}
}
@@ -764,7 +850,7 @@ namespace Umbraco.Tests.Cache
var scopeProvider = GetScopeProvider();
using (d.GetWriter(scopeProvider))
using (d.GetScopedWriteLock(scopeProvider))
{
// gen 3
Assert.AreEqual(2, d.Test.GetValues(1).Length);
@@ -809,7 +895,7 @@ namespace Umbraco.Tests.Cache
var scopeProvider = GetScopeProvider();
using (d.GetWriter(scopeProvider))
using (d.GetScopedWriteLock(scopeProvider))
{
// creating a snapshot in a write-lock does NOT return the "current" content
// it uses the previous snapshot, so new snapshot created only on release
@@ -846,9 +932,10 @@ namespace Umbraco.Tests.Cache
Assert.AreEqual(2, s2.Gen);
Assert.AreEqual("uno", s2.Get(1));
var scopeProvider = GetScopeProvider(true);
var scopeContext = new ScopeContext();
var scopeProvider = GetScopeProvider(scopeContext);
using (d.GetWriter(scopeProvider))
using (d.GetScopedWriteLock(scopeProvider))
{
// creating a snapshot in a write-lock does NOT return the "current" content
// it uses the previous snapshot, so new snapshot created only on release
@@ -867,7 +954,7 @@ namespace Umbraco.Tests.Cache
Assert.AreEqual(2, s4.Gen);
Assert.AreEqual("uno", s4.Get(1));
((ScopeContext) scopeProvider.Context).ScopeExit(true);
scopeContext.ScopeExit(true);
var s5 = d.CreateSnapshot();
Assert.AreEqual(3, s5.Gen);
@@ -878,7 +965,8 @@ namespace Umbraco.Tests.Cache
public void ScopeLocking2()
{
var d = new SnapDictionary<int, string>();
d.Test.CollectAuto = false;
var t = d.Test;
t.CollectAuto = false;
// gen 1
d.Set(1, "one");
@@ -891,12 +979,13 @@ namespace Umbraco.Tests.Cache
Assert.AreEqual(2, s2.Gen);
Assert.AreEqual("uno", s2.Get(1));
var scopeProviderMock = new Mock<IScopeProvider>();
var scopeContext = new ScopeContext();
scopeProviderMock.Setup(x => x.Context).Returns(scopeContext);
var scopeProvider = scopeProviderMock.Object;
Assert.AreEqual(2, t.LiveGen);
Assert.IsFalse(t.NextGen);
using (d.GetWriter(scopeProvider))
var scopeContext = new ScopeContext();
var scopeProvider = GetScopeProvider(scopeContext);
using (d.GetScopedWriteLock(scopeProvider))
{
// creating a snapshot in a write-lock does NOT return the "current" content
// it uses the previous snapshot, so new snapshot created only on release
@@ -905,18 +994,35 @@ namespace Umbraco.Tests.Cache
Assert.AreEqual(2, s3.Gen);
Assert.AreEqual("uno", s3.Get(1));
// we made some changes, so a next gen is required
Assert.AreEqual(3, t.LiveGen);
Assert.IsTrue(t.NextGen);
Assert.AreEqual(1, t.WLocked);
// but live snapshot contains changes
var ls = d.Test.LiveSnapshot;
var ls = t.LiveSnapshot;
Assert.AreEqual("ein", ls.Get(1));
Assert.AreEqual(3, ls.Gen);
}
// nothing is committed until scope exits
Assert.AreEqual(3, t.LiveGen);
Assert.IsTrue(t.NextGen);
Assert.AreEqual(1, t.WLocked);
// no changes until exit
var s4 = d.CreateSnapshot();
Assert.AreEqual(2, s4.Gen);
Assert.AreEqual("uno", s4.Get(1));
scopeContext.ScopeExit(false);
// now things have changed
Assert.AreEqual(2, t.LiveGen);
Assert.IsFalse(t.NextGen);
Assert.AreEqual(0, t.WLocked);
// no changes since not completed
var s5 = d.CreateSnapshot();
Assert.AreEqual(2, s5.Gen);
Assert.AreEqual("uno", s5.Get(1));
@@ -955,12 +1061,92 @@ namespace Umbraco.Tests.Cache
Assert.AreEqual("four", all[3]);
}
private IScopeProvider GetScopeProvider(bool withContext = false)
[Test]
public void DontPanic()
{
var scopeProviderMock = new Mock<IScopeProvider>();
var scopeContext = withContext ? new ScopeContext() : null;
scopeProviderMock.Setup(x => x.Context).Returns(scopeContext);
var scopeProvider = scopeProviderMock.Object;
var d = new SnapDictionary<int, string>();
d.Test.CollectAuto = false;
Assert.IsNull(d.Test.GenObj);
// gen 1
d.Set(1, "one");
Assert.IsTrue(d.Test.NextGen);
Assert.AreEqual(1, d.Test.LiveGen);
Assert.IsNull(d.Test.GenObj);
var s1 = d.CreateSnapshot();
Assert.IsFalse(d.Test.NextGen);
Assert.AreEqual(1, d.Test.LiveGen);
Assert.IsNotNull(d.Test.GenObj);
Assert.AreEqual(1, d.Test.GenObj.Gen);
Assert.AreEqual(1, s1.Gen);
Assert.AreEqual("one", s1.Get(1));
d.Set(1, "uno");
Assert.IsTrue(d.Test.NextGen);
Assert.AreEqual(2, d.Test.LiveGen);
Assert.IsNotNull(d.Test.GenObj);
Assert.AreEqual(1, d.Test.GenObj.Gen);
var scopeContext = new ScopeContext();
var scopeProvider = GetScopeProvider(scopeContext);
// scopeProvider.Context == scopeContext -> writer is scoped
// writer is scope contextual and scoped
// when disposed, nothing happens
// when the context exists, the writer is released
using (d.GetScopedWriteLock(scopeProvider))
{
d.Set(1, "ein");
Assert.IsTrue(d.Test.NextGen);
Assert.AreEqual(3, d.Test.LiveGen);
Assert.IsNotNull(d.Test.GenObj);
Assert.AreEqual(2, d.Test.GenObj.Gen);
}
// writer has not released
Assert.AreEqual(1, d.Test.WLocked);
Assert.IsNotNull(d.Test.GenObj);
Assert.AreEqual(2, d.Test.GenObj.Gen);
// nothing changed
Assert.IsTrue(d.Test.NextGen);
Assert.AreEqual(3, d.Test.LiveGen);
// panic!
var s2 = d.CreateSnapshot();
Assert.AreEqual(1, d.Test.WLocked);
Assert.IsNotNull(d.Test.GenObj);
Assert.AreEqual(2, d.Test.GenObj.Gen);
Assert.AreEqual(3, d.Test.LiveGen);
Assert.IsTrue(d.Test.NextGen);
// release writer
scopeContext.ScopeExit(true);
Assert.AreEqual(0, d.Test.WLocked);
Assert.IsNotNull(d.Test.GenObj);
Assert.AreEqual(2, d.Test.GenObj.Gen);
Assert.AreEqual(3, d.Test.LiveGen);
Assert.IsTrue(d.Test.NextGen);
var s3 = d.CreateSnapshot();
Assert.AreEqual(0, d.Test.WLocked);
Assert.IsNotNull(d.Test.GenObj);
Assert.AreEqual(3, d.Test.GenObj.Gen);
Assert.AreEqual(3, d.Test.LiveGen);
Assert.IsFalse(d.Test.NextGen);
}
private IScopeProvider GetScopeProvider(ScopeContext scopeContext = null)
{
var scopeProvider = Mock.Of<IScopeProvider>();
Mock.Get(scopeProvider)
.Setup(x => x.Context).Returns(scopeContext);
return scopeProvider;
}
}
@@ -4,6 +4,7 @@ using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Compose;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
@@ -299,11 +300,19 @@ namespace Umbraco.Tests.Components
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
Assert.Throws<Exception>(() => composers.Compose());
Console.WriteLine("throws:");
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
var requirements = composers.GetRequirements(false);
Console.WriteLine(Composers.GetComposersReport(requirements));
types = new[] { typeof(Composer2) };
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
Assert.Throws<Exception>(() => composers.Compose());
Console.WriteLine("throws:");
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
requirements = composers.GetRequirements(false);
Console.WriteLine(Composers.GetComposersReport(requirements));
types = new[] { typeof(Composer12) };
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
@@ -349,6 +358,25 @@ namespace Umbraco.Tests.Components
Assert.AreEqual(typeof(Composer27), Composed[1]);
}
[Test]
public void AllComposers()
{
var typeLoader = new TypeLoader(AppCaches.Disabled.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), Mock.Of<IProfilingLogger>());
var register = MockRegister();
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
var types = typeLoader.GetTypes<IComposer>().Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web"));
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
var requirements = composers.GetRequirements();
var report = Composers.GetComposersReport(requirements);
Console.WriteLine(report);
var composerTypes = composers.SortComposers(requirements);
foreach (var type in composerTypes)
Console.WriteLine(type);
}
#region Compothings
public class TestComposerBase : IComposer
+3 -13
View File
@@ -112,19 +112,9 @@ namespace Umbraco.Tests.IO
fs.DeleteMediaFiles(new[] { virtPath });
Assert.IsFalse(File.Exists(physPath));
var scheme = Current.Factory.GetInstance<IMediaPathScheme>();
if (scheme is UniqueMediaPathScheme)
{
// ~/media/1234 is *not* gone
physPath = Path.GetDirectoryName(physPath);
Assert.IsTrue(Directory.Exists(physPath));
}
else
{
// ~/media/1234 is gone
physPath = Path.GetDirectoryName(physPath);
Assert.IsFalse(Directory.Exists(physPath));
}
// ~/media/1234 is gone
physPath = Path.GetDirectoryName(physPath);
Assert.IsFalse(Directory.Exists(physPath));
// ~/media exists
physPath = Path.GetDirectoryName(physPath);
+43 -9
View File
@@ -15,13 +15,47 @@ namespace Umbraco.Tests.Models
[TestFixture]
public class ContentTypeTests : UmbracoTestBase
{
[Test]
[Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")]
public void Cannot_Add_Duplicate_Property_Aliases()
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.PropertyGroups.Add(new PropertyGroup(new PropertyTypeCollection(false, new[]
{
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar){ Alias = "myPropertyType" }
})));
Assert.Throws<InvalidOperationException>(() =>
contentType.PropertyTypeCollection.Add(
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar) { Alias = "myPropertyType" }));
}
[Test]
[Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")]
public void Cannot_Update_Duplicate_Property_Aliases()
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.PropertyGroups.Add(new PropertyGroup(new PropertyTypeCollection(false, new[]
{
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar){ Alias = "myPropertyType" }
})));
contentType.PropertyTypeCollection.Add(new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar) { Alias = "myPropertyType2" });
var toUpdate = contentType.PropertyTypeCollection["myPropertyType2"];
Assert.Throws<InvalidOperationException>(() => toUpdate.Alias = "myPropertyType");
}
[Test]
public void Can_Deep_Clone_Content_Type_Sort()
{
var contentType = new ContentTypeSort(new Lazy<int>(() => 3), 4, "test");
var clone = (ContentTypeSort) contentType.DeepClone();
var clone = (ContentTypeSort)contentType.DeepClone();
Assert.AreNotSame(clone, contentType);
Assert.AreEqual(clone, contentType);
Assert.AreEqual(clone.Id.Value, contentType.Id.Value);
@@ -54,7 +88,7 @@ namespace Umbraco.Tests.Models
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -117,12 +151,12 @@ namespace Umbraco.Tests.Models
{
group.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -167,12 +201,12 @@ namespace Umbraco.Tests.Models
{
group.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] {new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2")};
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -264,12 +298,12 @@ namespace Umbraco.Tests.Models
{
propertyType.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -232,6 +232,35 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
/// <summary>
/// This demonstates an issue found: https://github.com/umbraco/Umbraco-CMS/issues/4963#issuecomment-483516698
/// </summary>
[Test]
[Ignore("Still testing")]
public void Bug_Changing_Built_In_Member_Type_Property_Type_Aliases_Results_In_Exception()
{
//TODO: Fix this bug and then change this test
var provider = TestObjects.GetScopeProvider(Logger);
using (var scope = provider.CreateScope())
{
var repository = CreateRepository(provider);
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
repository.Save(memberType);
foreach (var stub in Constants.Conventions.Member.GetStandardPropertyTypeStubs())
{
var prop = memberType.PropertyTypes.First(x => x.Alias == stub.Key);
prop.Alias = prop.Alias + "__0000";
}
repository.Save(memberType);
//Assert.Throws<ArgumentException>(() => );
}
}
[Test]
public void Built_In_Member_Type_Properties_Are_Automatically_Added_When_Creating()
{
@@ -15,6 +15,7 @@ using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Changes;
using Umbraco.Core.Strings;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing.Objects;
using Umbraco.Tests.Testing.Objects.Accessors;
@@ -181,7 +182,8 @@ namespace Umbraco.Tests.PublishedContent
globalSettings,
new SiteDomainHelper(),
Mock.Of<IEntityXmlSerializer>(),
Mock.Of<IPublishedModelFactory>());
Mock.Of<IPublishedModelFactory>(),
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }));
// invariant is the current default
_variationAccesor.VariationContext = new VariationContext();
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Routing
{
base.SetUp();
WebRuntimeComponent.CreateRoutes(
WebFinalComponent.CreateRoutes(
new TestUmbracoContextAccessor(),
TestObjects.GetGlobalSettings(),
new SurfaceControllerTypeCollection(Enumerable.Empty<Type>()),
@@ -81,7 +81,7 @@ namespace Umbraco.Tests.Runtimes
var composerTypes = typeLoader.GetTypes<IComposer>() // all of them
.Where(x => !x.FullName.StartsWith("Umbraco.Tests.")) // exclude test components
.Where(x => x != typeof(WebRuntimeComposer)); // exclude web runtime
.Where(x => x != typeof(WebInitialComposer)); // exclude web runtime
var composers = new Composers(composition, composerTypes, profilingLogger);
composers.Compose();
@@ -18,7 +18,7 @@ namespace Umbraco.Tests.Runtimes
new PluginViewEngine()
};
WebRuntimeComponent.WrapViewEngines(engines);
WebInitialComponent.WrapViewEngines(engines);
Assert.That(engines.Count, Is.EqualTo(2));
Assert.That(engines[0], Is.InstanceOf<ProfilingViewEngine>());
@@ -34,7 +34,7 @@ namespace Umbraco.Tests.Runtimes
new PluginViewEngine()
};
WebRuntimeComponent.WrapViewEngines(engines);
WebInitialComponent.WrapViewEngines(engines);
Assert.That(engines.Count, Is.EqualTo(2));
Assert.That(((ProfilingViewEngine)engines[0]).Inner, Is.InstanceOf<RenderViewEngine>());
@@ -50,7 +50,7 @@ namespace Umbraco.Tests.Runtimes
profiledEngine
};
WebRuntimeComponent.WrapViewEngines(engines);
WebInitialComponent.WrapViewEngines(engines);
Assert.That(engines[0], Is.SameAs(profiledEngine));
}
@@ -58,7 +58,7 @@ namespace Umbraco.Tests.Runtimes
[Test]
public void WrapViewEngines_CollectionIsNull_DoesNotThrow()
{
Assert.DoesNotThrow(() => WebRuntimeComponent.WrapViewEngines(null));
Assert.DoesNotThrow(() => WebInitialComponent.WrapViewEngines(null));
}
}
}
@@ -17,6 +17,7 @@ using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
@@ -99,7 +100,8 @@ namespace Umbraco.Tests.Scoping
new DatabaseDataSource(),
Factory.GetInstance<IGlobalSettings>(), new SiteDomainHelper(),
Factory.GetInstance<IEntityXmlSerializer>(),
Mock.Of<IPublishedModelFactory>());
Mock.Of<IPublishedModelFactory>(),
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }));
}
protected UmbracoContext GetUmbracoContextNu(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable<IUrlProvider> urlProviders = null)
@@ -15,6 +15,7 @@ using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Core.Sync;
using Umbraco.Tests.Testing;
using Umbraco.Web;
@@ -72,7 +73,8 @@ namespace Umbraco.Tests.Services
new DatabaseDataSource(),
Factory.GetInstance<IGlobalSettings>(), new SiteDomainHelper(),
Factory.GetInstance<IEntityXmlSerializer>(),
Mock.Of<IPublishedModelFactory>());
Mock.Of<IPublishedModelFactory>(),
new UrlSegmentProviderCollection(new[] { new DefaultUrlSegmentProvider() }));
}
public class LocalServerMessenger : ServerMessengerBase
@@ -116,7 +116,7 @@ namespace Umbraco.Tests.TestHelpers
var umbracoSettings = GetUmbracoSettings();
var globalSettings = GetGlobalSettings();
var urlProviders = Enumerable.Empty<IUrlProvider>();
var urlProviders = new UrlProviderCollection(Enumerable.Empty<IUrlProvider>());
if (accessor == null) accessor = new TestUmbracoContextAccessor();
+1 -1
View File
@@ -80,7 +80,7 @@
<ItemGroup>
<PackageReference Include="AutoMapper" Version="8.0.0" />
<PackageReference Include="Castle.Core" Version="4.3.1" />
<PackageReference Include="Examine" Version="1.0.1" />
<PackageReference Include="Examine" Version="1.0.0" />
<PackageReference Include="HtmlAgilityPack">
<Version>1.8.14</Version>
</PackageReference>
@@ -71,7 +71,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -100,7 +100,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -129,7 +129,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -158,7 +158,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -46,7 +46,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -73,7 +73,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
TestObjects.GetUmbracoSettings(),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -103,7 +103,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -140,7 +140,7 @@ namespace Umbraco.Tests.Web.Mvc
new TestDefaultCultureAccessor(),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == webRoutingSettings),
globalSettings,
Enumerable.Empty<IUrlProvider>(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -104,7 +104,7 @@ namespace Umbraco.Tests.Web
new TestDefaultCultureAccessor(),
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
new[] { testUrlProvider.Object },
new UrlProviderCollection(new[] { testUrlProvider.Object }),
Mock.Of<IUserService>());
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
+7 -21
View File
@@ -5210,14 +5210,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5232,20 +5230,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@@ -5362,8 +5357,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@@ -5375,7 +5369,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -5390,7 +5383,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -5398,14 +5390,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -5424,7 +5414,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -5505,8 +5494,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@@ -5518,7 +5506,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -5640,7 +5627,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -344,8 +344,8 @@
loadAuditTrail(true);
loadRedirectUrls();
setNodePublishStatus();
updateCurrentUrls();
}
updateCurrentUrls();
});
//ensure to unregister from all events!
@@ -42,7 +42,7 @@
item: '=',
onOpen: '&',
onOpenAnchor: '&',
hotkey: '<'
index: '@'
}
});
@@ -62,8 +62,8 @@ function valPropertyMsg(serverValidationManager) {
if (!watcher) {
watcher = scope.$watch("currentProperty.value",
function (newValue, oldValue) {
if (!newValue || angular.equals(newValue, oldValue)) {
if (angular.equals(newValue, oldValue)) {
return;
}
@@ -78,10 +78,12 @@ function valPropertyMsg(serverValidationManager) {
// based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg
// is the only one, then we'll clear.
if ((errCount === 1 && angular.isArray(formCtrl.$error.valPropertyMsg)) || (formCtrl.$invalid && angular.isArray(formCtrl.$error.valServer))) {
if (errCount === 0 || (errCount === 1 && angular.isArray(formCtrl.$error.valPropertyMsg)) || (formCtrl.$invalid && angular.isArray(formCtrl.$error.valServer))) {
scope.errorMsg = "";
formCtrl.$setValidity('valPropertyMsg', true);
stopWatch();
} else if (showValidation && scope.errorMsg === "") {
formCtrl.$setValidity('valPropertyMsg', false);
scope.errorMsg = getErrorMsg();
}
}, true);
}
@@ -152,6 +154,7 @@ function valPropertyMsg(serverValidationManager) {
showValidation = true;
if (hasError && scope.errorMsg === "") {
scope.errorMsg = getErrorMsg();
startWatch();
}
else if (!hasError) {
scope.errorMsg = "";
@@ -112,6 +112,7 @@ When building a custom infinite editor view you can use the same components as a
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
@@ -26,8 +26,6 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
navReadyPromise.resolve(mainTreeApi);
});
//A list of query strings defined that when changed will not cause a reload of the route
var nonRoutingQueryStrings = ["mculture", "cculture", "lq"];
var retainedQueryStrings = ["mculture"];
@@ -350,9 +350,6 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
parent.children.splice(parent.children.indexOf(treeNode), 1);
parent.hasChildren = parent.children.length !== 0;
//Notify that the node has been removed
eventsService.emit("treeService.removeNode", { node: treeNode });
},
/**
@@ -9,7 +9,7 @@
*
* @param {navigationService} navigationService A reference to the navigationService
*/
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource, editorState) {
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource) {
//this is used to trigger the tree to start loading once everything is ready
var treeInitPromise = $q.defer();
@@ -249,20 +249,6 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
$scope.infiniteMode = args && args.editors.length > 0 ? true : false;
}));
evts.push(eventsService.on("treeService.removeNode", function (e, args) {
//check to see if the current page has been removed
var currentEditorState = editorState.getCurrent()
if (currentEditorState && currentEditorState.id.toString() === args.node.id.toString()) {
//current page is loaded, so navigate to root
var section = appState.getSectionState("currentSection");
$location.path("/" + section);
}
}));
/**
* Based on the current state of the application, this configures the scope variables that control the main tree and language drop down
*/
@@ -55,6 +55,16 @@
position: absolute;;
}
.--notInFront .umb-modalcolumn::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: rgba(0,0,0,.4);
}
/* re-align loader */
.umb-modal .umb-loader-wrapper, .umb-modalcolumn .umb-loader-wrapper, .umb-dialog .umb-loader-wrapper{
position:relative;
@@ -113,7 +113,12 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
$scope.exitPreview = function () {
var culture = $location.search().culture || getParameterByName("culture");
var relativeUrl = "/" + $scope.pageId +'?culture='+ culture;
var relativeUrl = "/" + $scope.pageId;
if(culture){
relativeUrl +='?culture='+ culture;
}
window.top.location.href = "../preview/end?redir=" + encodeURIComponent(relativeUrl);
};
@@ -1,4 +1,5 @@
<div ng-controller="Umbraco.Overlays.UserController">
<div class="umb-control-group" ng-if="!showPasswordFields">
<h5><localize key="user_yourProfile" /></h5>
@@ -78,7 +79,7 @@
</div>
<div class="umb-control-group" ng-if="!showPasswordFields && history.length">
<div class="umb-control-group" ng-if="!showPasswordFields">
<h5><localize key="user_yourHistory" /></h5>
<ul class="umb-tree">
<li ng-repeat="item in history | orderBy:'time':true">
@@ -126,7 +127,7 @@
</div>
<div class="umb-control-group" ng-if="tab.length">
<div class="umb-control-group">
<div ng-repeat="tab in dashboard">
<div ng-repeat="property in tab.properties">
<div>
@@ -1,10 +1,10 @@
<a data-element="sub-view-{{vm.item.alias}}"
tabindex="-1"
ng-href=""
ng-click="vm.clicked()"
hotkey="{{::vm.hotkey}}"
hotkey-when-hidden="true"
ng-class="{'is-active': vm.item.active, '-has-error': vm.item.hasError}">
tabindex="-1"
ng-href=""
ng-click="vm.clicked()"
hotkey="{{vm.index+1}}"
hotkey-when-hidden="true"
ng-class="{'is-active': vm.item.active, '-has-error': vm.item.hasError}">
<i class="icon {{ vm.item.icon }}"></i>
<span class="umb-sub-views-nav-item-text">{{ vm.item.name }}</span>
<div ng-show="vm.item.badge" class="badge -type-{{vm.item.badge.type}}">{{vm.item.badge.count}}</div>
@@ -7,7 +7,7 @@
item="navItem"
on-open="openNavigationItem(item)"
on-open-anchor="openAnchorItem(item, anchor)"
hotkey="$index + 1">
index="{{$index}}">
</umb-editor-navigation-item>
</div>
</li>
@@ -46,8 +46,7 @@
if (data.language !== "undefined") {
var lang = vm.languages.filter(function (l) {
return matchLanguageById(l, data.language.Id);
return matchLanguageById(l, data.language);
});
if (lang.length > 0) {
vm.language = lang[0];
@@ -24,20 +24,21 @@
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<span class="db umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</span>
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
<span class="db umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
</span>
<span class="db" ng-repeat="notification in variant.notifications">
<span class="db umb-permission__description" style="color: #1FB572;">{{notification.message}}</span>
</span>
</label>
<div class="umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</div>
<div ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
@@ -50,20 +50,21 @@
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 0;">
<span>{{ variant.language.name }}</span>
<span class="db umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</span>
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
<span class="db umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
</span>
<span class="db" ng-repeat="notification in variant.notifications">
<span class="db umb-permission__description" style="color: #1FB572;">{{notification.message}}</span>
</span>
</label>
<div class="umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</div>
<div ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
@@ -28,19 +28,20 @@
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db" ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</span>
<span class="db" ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<span class="db umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</span>
</span>
<span class="db" ng-repeat="notification in variant.notifications">
<span class="db umb-permission__description" style="color: #1FB572;">{{notification.message}}</span>
</span>
</label>
<div ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
@@ -71,19 +72,20 @@
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db" ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</span>
<span class="db" ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<span class="db umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</span>
</span>
<span class="db" ng-repeat="notification in variant.notifications">
<span class="db umb-permission__description" style="color: #1FB572;">{{notification.message}}</span>
</span>
</label>
<div ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
@@ -97,14 +97,14 @@
<label for="{{'saveVariantSelector_' + variant.language.culture}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<span class="db umb-permission__description"
ng-if="!scheduleSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-show="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</span>
</label>
<div class="umb-permission__description"
ng-if="!scheduleSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-show="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</div>
<div class="flex items-center" style="margin-top: 10px; margin-bottom: 10px;">
<div class="flex items-center" ng-if="variant.releaseDate || variant.save">
@@ -23,12 +23,6 @@
if (vm.variants.length !== 0) {
_.each(vm.variants,
function (variant) {
variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : "");
variant.htmlId = "_content_variant_" + variant.compositeId;
});
//now sort it so that the current one is at the top
vm.variants = _.sortBy(vm.variants, function (v) {
return v.active ? 0 : 1;
@@ -24,19 +24,20 @@
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
<span class="db" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</span>
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
<span class="db umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
</span>
<span class="db" ng-repeat="notification in variant.notifications">
<span class="db umb-permission__description" style="color: #1FB572;">{{notification.message}}</span>
</span>
</label>
<div ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
</div>
<div ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</div>
</div>
<div ng-repeat="notification in variant.notifications">
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
</div>
</div>
</div>
@@ -21,12 +21,6 @@
});
}
_.each(vm.variants,
function (variant) {
variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : "");
variant.htmlId = "_content_variant_" + variant.compositeId;
});
// node has variants
if (vm.variants.length !== 1) {
//now sort it so that the current one is at the top
@@ -27,12 +27,13 @@
<div>
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
<span>{{ variant.language.name }}</span>
<span class="db umb-permission__description">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</span>
</label>
</label>
<div class="umb-permission__description">
<umb-variant-state variant="variant"></umb-variant-state>
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
</div>
</div>
</div>
@@ -167,7 +167,7 @@ function FormsController($scope, $cookies, packageResource, localizationService)
return packageResource.installData(pack);
}, vm.error)
.then(function(pack) {
vm.state = labels.installStateComplete;
vm.state = installStateComplete;
return packageResource.cleanUp(pack);
}, vm.error)
.then(vm.complete, vm.error);
@@ -22,6 +22,7 @@ function DataTypeDeleteController($scope, dataTypeResource, treeService, navigat
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
});
};
$scope.performContainerDelete = function () {
@@ -20,8 +20,7 @@ function DocumentTypesDeleteController($scope, dataTypeResource, contentTypeReso
// TODO: Need to sync tree, etc...
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
navigationService.hideMenu();
});
};
@@ -39,7 +38,6 @@ function DocumentTypesDeleteController($scope, dataTypeResource, contentTypeReso
// TODO: Need to sync tree, etc...
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
});
};
@@ -6,7 +6,7 @@
* @description
* The controller for deleting macro items
*/
function MacrosDeleteController($scope, macroResource, navigationService, treeService) {
function MacrosDeleteController($scope, $location, macroResource, navigationService, treeService) {
var vm = this;
vm.name = $scope.currentNode.name;
@@ -6,7 +6,7 @@
* @description
* The controller for the media type delete dialog
*/
function MediaTypesDeleteController($scope, mediaTypeResource, treeService, navigationService) {
function MediaTypesDeleteController($scope, dataTypeResource, mediaTypeResource, treeService, navigationService) {
$scope.performDelete = function() {
@@ -21,7 +21,6 @@ function MemberTypesDeleteController($scope, memberTypeResource, treeService, na
// TODO: Need to sync tree, etc...
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
});
};
@@ -94,7 +94,7 @@
<div class="umb-info-local-item">
<strong><localize key="packager_packageReadme">Read me</localize></strong>
<br>
<small ng-bind-html="vm.package.readme"></small>
<small> {{ vm.package.readme }} </small>
</div>
<div class="umb-info-local-item mt4 flex items-center flex-column" ng-if="vm.installState.status == ''">
@@ -250,7 +250,7 @@
<umb-box>
<umb-box-content>
<div class="umb-package-details__section-title"><localize key="packager_packageCompatibility">Compatibility</localize></div>
<div class="umb-package-details__section-description"><localize key="packager_packageCompatibilityDescription">This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be gauranteed for versions reported below 100%</localize></div>
<div class="umb-package-details__section-description"><localize key="packager_packageCompatibilityDescription">This package is compatible with the following versions of Umbraco, as reported by community members. Full compatability cannot be guaranteed for versions reported below 100%</localize></div>
<div class="umb-package-details__compatability" ng-repeat="compatibility in vm.package.compatibility | filter:percentage > 0">
<div class="umb-package-details__compatability-label">
<span class="umb-package-details__information-item-label">{{compatibility.version}}</span>
@@ -21,7 +21,6 @@ function PartialViewMacrosDeleteController($scope, codefileResource, treeService
// TODO: Need to sync tree, etc...
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
});
};
@@ -24,7 +24,6 @@ function PartialViewsDeleteController($scope, codefileResource, treeService, nav
// TODO: Need to sync tree, etc...
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
}, function (err) {
$scope.currentNode.loading = false;
$scope.error = err;
@@ -1,21 +1,21 @@
function imageFilePickerController($scope) {
function imageFilePickerController($scope, editorService) {
$scope.add = function() {
$scope.mediaPickerOverlay = {
var mediaPickerOptions = {
view: "mediapicker",
multiPicker: false,
disableFolderSelect: true,
onlyImages: true,
show: true,
submit: function (model) {
$scope.model.value = model.selection[0].image;
$scope.mediaPickerOverlay.show = false;
$scope.mediaPickerOverlay = null;
editorService.close();
},
close: function () {
$scope.mediaPickerOverlay.show = false;
$scope.mediaPickerOverlay = null;
}
editorService.close();
}
};
editorService.mediaPicker(mediaPickerOptions);
};
$scope.remove = function () {
@@ -19,11 +19,4 @@
<i class="icon icon-add large"></i>
</a>
<umb-overlay
ng-if="mediaPickerOverlay.show"
model="mediaPickerOverlay"
view="mediaPickerOverlay.view"
position="right">
</umb-overlay>
</div>
@@ -0,0 +1,22 @@
function ConfigController($scope) {
var vm = this;
vm.submit = submit;
vm.close = close;
function submit() {
if ($scope.model && $scope.model.submit) {
$scope.model.submit($scope.model);
}
}
function close() {
if ($scope.model.close) {
$scope.model.close();
}
}
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.ConfigController", ConfigController);
@@ -1,16 +1,61 @@
<div ng-if="model.config">
<umb-property
property="configValue"
ng-repeat="configValue in model.config">
<umb-property-editor model="configValue" is-pre-value="true"></umb-property-editor>
</umb-property>
</div>
<div ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.ConfigController as vm">
<umb-editor-view>
<umb-editor-header
name="model.title"
name-locked="true"
hide-alias="true"
hide-icon="true"
hide-description="true">
</umb-editor-header>
<umb-editor-container>
<ng-form name="gridItemConfigEditor" val-form-manager>
<umb-box ng-if="model.config">
<umb-box-header title-key="grid_settings" />
<umb-box-content>
<div>
<umb-property property="configValue"
ng-repeat="configValue in model.config">
<umb-property-editor model="configValue" is-pre-value="true"></umb-property-editor>
</umb-property>
</div>
</umb-box-content>
</umb-box>
<umb-box ng-if="model.styles">
<umb-box-header title-key="grid_styles" />
<umb-box-content>
<div>
<umb-property property="styleValue"
ng-repeat="styleValue in model.styles">
<umb-property-editor model="styleValue" is-pre-value="true"></umb-property-editor>
</umb-property>
</div>
</umb-box-content>
</umb-box>
</ng-form>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button type="button"
button-style="success"
label-key="general_submit"
action="vm.submit()">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
<div ng-if="model.styles">
<h4>Style</h4>
<umb-property
property="styleValue"
ng-repeat="styleValue in model.styles">
<umb-property-editor model="styleValue" is-pre-value="true"></umb-property-editor>
</umb-property>
</div>
@@ -1,16 +1,22 @@
function EditConfigController($scope) {
$scope.close = function() {
if($scope.model.close) {
$scope.model.close();
}
}
$scope.submit = function() {
if($scope.model && $scope.model.submit) {
var vm = this;
vm.submit = submit;
vm.close = close;
function submit() {
if ($scope.model && $scope.model.submit) {
$scope.model.submit($scope.model);
}
}
function close() {
if ($scope.model.close) {
$scope.model.close();
}
}
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.EditConfigController", EditConfigController);
@@ -1,10 +1,8 @@
<div class="usky-grid usky-grid-configuration" ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.EditConfigController">
<div class="usky-grid usky-grid-configuration" ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.EditConfigController as vm">
<umb-editor-view>
<umb-editor-view>
<form novalidate name="EditConfigForm" val-form-manager>
<form novalidate name="EditConfigForm" val-form-manager>
<umb-editor-header
name="model.title"
@@ -18,44 +16,39 @@
<umb-box>
<umb-box-content>
<ng-form name="gridConfigEditor">
<h4>{{model.name}}</h4>
<p>Settings will only save if the entered json configuration is valid</p>
<textarea name="configSource"
validate-on="'blur'"
rows="20" class="umb-property-editor umb-textarea"
umb-raw-model="model.config"></textarea>
<form name="gridConfigEditor">
<div class="alert alert-error" ng-show="gridConfigEditor.$invalid === true">
This configuration is not valid json, and will not be saved.
</div>
<h4>{{model.name}}</h4>
<p>Settings will only save if the entered json configuration is valid</p>
<textarea name="configSource"
validate-on="'blur'"
rows="20" class="umb-property-editor umb-textarea"
umb-raw-model="model.config"></textarea>
</ng-form>
<div class="alert alert-error" ng-show="gridConfigEditor.$invalid === true">
This configuration is not valid json, and will not be saved.
</div>
</umb-box-content>
</umb-box>
</umb-editor-container>
</form>
</umb-box-content>
</umb-box>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="close()">
action="vm.close()">
</umb-button>
<umb-button
type="button"
button-style="success"
label-key="general_submit"
action="submit()">
action="vm.submit()">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
@@ -8,17 +8,20 @@ angular.module("umbraco")
umbRequestHelper,
angularHelper,
$element,
eventsService
eventsService,
editorService
) {
// Grid status variables
var placeHolder = "";
var currentForm = angularHelper.getCurrentForm($scope);
$scope.currentRow = null;
$scope.currentCell = null;
$scope.currentToolsControl = null;
$scope.currentControl = null;
$scope.openRTEToolbarId = null;
$scope.hasSettings = false;
$scope.showRowConfigurations = true;
@@ -122,24 +125,25 @@ angular.module("umbraco")
},
over: function (event, ui) {
var area = $(event.target).scope().area;
var area = event.target.getScope_HackForSortable().area;
var allowedEditors = area.allowed;
if (($.inArray(ui.item.scope().control.editor.alias, allowedEditors) < 0 && allowedEditors) ||
if (($.inArray(ui.item[0].getScope_HackForSortable().control.editor.alias, allowedEditors) < 0 && allowedEditors) ||
(startingArea != area && area.maxItems != '' && area.maxItems > 0 && area.maxItems < area.controls.length + 1)) {
$scope.$apply(function () {
$(event.target).scope().area.dropNotAllowed = true;
event.target.getScope_HackForSortable().area.dropNotAllowed = true;
});
ui.placeholder.hide();
cancelMove = true;
}
else {
if ($(event.target).scope().area.controls.length == 0){
if (event.target.getScope_HackForSortable().area.controls.length == 0){
$scope.$apply(function () {
$(event.target).scope().area.dropOnEmpty = true;
event.target.getScope_HackForSortable().area.dropOnEmpty = true;
});
ui.placeholder.hide();
} else {
@@ -151,8 +155,9 @@ angular.module("umbraco")
out: function(event, ui) {
$scope.$apply(function () {
$(event.target).scope().area.dropNotAllowed = false;
$(event.target).scope().area.dropOnEmpty = false;
var dropArea = event.target.getScope_HackForSortable().area;
dropArea.dropNotAllowed = false;
dropArea.dropOnEmpty = false;
});
},
@@ -178,10 +183,9 @@ angular.module("umbraco")
currentForm.$setDirty();
},
start: function (e, ui) {
start: function (event, ui) {
//Get the starting area for reference
var area = $(e.target).scope().area;
var area = event.target.getScope_HackForSortable().area;
startingArea = area;
// fade out control when sorting
@@ -207,7 +211,7 @@ angular.module("umbraco")
});
},
stop: function (e, ui) {
stop: function (event, ui) {
// Fade in control when sorting stops
ui.item[0].style.opacity = "1";
@@ -236,9 +240,11 @@ angular.module("umbraco")
$scope.$apply(function () {
var cell = $(e.target).scope().area;
var cell = event.target.getScope_HackForSortable().area;
cell.hasActiveChild = hasActiveChild(cell, cell.controls);
cell.active = false;
});
}
@@ -272,7 +278,7 @@ angular.module("umbraco")
localizationService.localize("grid_insertControl").then(function(value){
title = value;
$scope.editorOverlay = {
view: "itempicker",
view: "itempicker",
filter: area.$allowedEditors.length > 15,
title: title,
availableItems: area.$allowedEditors,
@@ -313,6 +319,7 @@ angular.module("umbraco")
$scope.clickOutsideRow = function(index, rows) {
rows[index].active = false;
};
function getAllowedLayouts(section) {
@@ -430,44 +437,46 @@ angular.module("umbraco")
});
}
$scope.gridItemSettingsDialog = {};
$scope.gridItemSettingsDialog.view = "views/propertyeditors/grid/dialogs/config.html";
$scope.gridItemSettingsDialog.title = "Settings";
$scope.gridItemSettingsDialog.styles = styles;
$scope.gridItemSettingsDialog.config = config;
var dialogOptions = {
view: "views/propertyeditors/grid/dialogs/config.html",
size: "small",
styles: styles,
config: config,
submit: function (model) {
var styleObject = {};
var configObject = {};
$scope.gridItemSettingsDialog.show = true;
_.each(model.styles, function (style) {
if (style.value) {
styleObject[style.key] = addModifier(style.value, style.modifier);
}
});
_.each(model.config, function (cfg) {
cfg.alias = cfg.key;
cfg.label = cfg.value;
$scope.gridItemSettingsDialog.submit = function(model) {
if (cfg.value) {
configObject[cfg.key] = addModifier(cfg.value, cfg.modifier);
}
});
var styleObject = {};
var configObject = {};
gridItem.styles = styleObject;
gridItem.config = configObject;
gridItem.hasConfig = gridItemHasConfig(styleObject, configObject);
_.each(model.styles, function(style){
if(style.value){
styleObject[style.key] = addModifier(style.value, style.modifier);
currentForm.$setDirty();
editorService.close();
},
close: function () {
editorService.close();
}
});
_.each(model.config, function (cfg) {
if (cfg.value) {
configObject[cfg.key] = addModifier(cfg.value, cfg.modifier);
}
});
gridItem.styles = styleObject;
gridItem.config = configObject;
gridItem.hasConfig = gridItemHasConfig(styleObject, configObject);
currentForm.$setDirty();
$scope.gridItemSettingsDialog.show = false;
$scope.gridItemSettingsDialog = null;
};
$scope.gridItemSettingsDialog.close = function(oldModel) {
$scope.gridItemSettingsDialog.show = false;
$scope.gridItemSettingsDialog = null;
};
localizationService.localize("general_settings").then(value => {
dialogOptions.title = value;
editorService.open(dialogOptions);
});
};
@@ -537,6 +546,7 @@ angular.module("umbraco")
// Control management functions
// *********************************************
$scope.clickControl = function (index, controls, cell) {
controls[index].active = true;
cell.hasActiveChild = true;
};
@@ -0,0 +1,25 @@
(function () {
"use strict";
function umbGridHackScope() {
function link($scope, $element) {
// Since the grid used the el.scope() method, which should only be used by debugging, and only are avilable in debug-mode. I had to make a replica method doig the same:
$element[0].getScope_HackForSortable = function() {
return $scope;
}
}
var directive = {
restrict: "A",
link: link
};
return directive;
}
angular.module("umbraco").directive("umbGridHackScope", umbGridHackScope);
})();
@@ -159,7 +159,7 @@
</div>
</div>
<div class="umb-cell-inner" ui-sortable="sortableOptionsCell" ng-model="area.controls">
<div class="umb-cell-inner" ui-sortable="sortableOptionsCell" umb-grid-hack-scope ng-model="area.controls">
<!-- Control placeholder -->
<div class="umb-cell-placeholder" ng-if="area.controls.length === 0" ng-click="openEditorOverlay($event, area, 0, area.$uniqueId);">
@@ -171,6 +171,7 @@
<!-- for each control in areas -->
<div class="umb-control"
umb-grid-hack-scope
ng-repeat="control in area.controls"
ng-click="clickControl($index, area.controls, area)"
ng-class="{'-active': control.active}"
@@ -304,11 +305,4 @@
position="target">
</umb-overlay>
<umb-overlay
ng-if="gridItemSettingsDialog.show"
model="gridItemSettingsDialog"
view="gridItemSettingsDialog.view"
position="right">
</umb-overlay>
</div>

Some files were not shown because too many files have changed in this diff Show More