Compare commits
240 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a181bd281 | |||
| 4a0cd87a38 | |||
| 1e2598a3a3 | |||
| 19241995e8 | |||
| 3097a46ab3 | |||
| c63156fcd8 | |||
| 84a90884e3 | |||
| d29b7311fa | |||
| 17b59cc20f | |||
| 4423571eaa | |||
| 28eb4ff03a | |||
| 79517f171c | |||
| e76c42f874 | |||
| 151c35bc47 | |||
| 84265a9716 | |||
| 6618388973 | |||
| b280bf73aa | |||
| a6d57a5f6d | |||
| 6b7a83c6c9 | |||
| eb5f2e29a3 | |||
| cf86409e3f | |||
| 134f5e2601 | |||
| 37ac524e8e | |||
| 43af2f8e55 | |||
| a20584e3de | |||
| 19ec26fef9 | |||
| 527f98189a | |||
| 78c289a559 | |||
| 646abb3aea | |||
| 2af59471a2 | |||
| b76b09026b | |||
| 090f89e5b6 | |||
| 4870afd2d3 | |||
| 80257b6684 | |||
| 8f3a0b6919 | |||
| 9fd2f34343 | |||
| e774717346 | |||
| 5f5759c8a3 | |||
| 0b90097aad | |||
| 7cd540c37e | |||
| 83595ecaf5 | |||
| e07c5e6ff8 | |||
| 67ff827d67 | |||
| 3f7159797f | |||
| 6f81b7fe24 | |||
| f2819f61e5 | |||
| 2107e9d9e3 | |||
| c623b448ba | |||
| 8bb49f57e8 | |||
| da0b1c2f23 | |||
| a288fc62eb | |||
| 82e50ccd3a | |||
| 15b0dc9f29 | |||
| 8057d09fc2 | |||
| 8877100bf0 | |||
| 41c96e6e26 | |||
| abdd117264 | |||
| 6272dac698 | |||
| 7a4b5fa796 | |||
| c962132ee0 | |||
| 0780979469 | |||
| a42e568fdf | |||
| e62661cc6a | |||
| 6841b2ac61 | |||
| f7f4276485 | |||
| bb9e23ca3e | |||
| 10db9363f4 | |||
| 7d5d69e2e3 | |||
| 06897aa8c6 | |||
| ee75158dd0 | |||
| c022397d86 | |||
| e25f6e82ed | |||
| d104525a50 | |||
| b0a64aa4b5 | |||
| ca86385269 | |||
| fb8368267e | |||
| ef4322a9b3 | |||
| 7032e137b8 | |||
| e99643ecfd | |||
| a325529eb8 | |||
| c68f832be6 | |||
| 4ab1c51327 | |||
| 6f39bac32a | |||
| e007a37c36 | |||
| ab9e029525 | |||
| d298388a7b | |||
| 4463abe9bb | |||
| d1db38182f | |||
| e808360653 | |||
| c5df712471 | |||
| 2f67008987 | |||
| 1672e284c5 | |||
| 60ce36a7f2 | |||
| 05c12d1f27 | |||
| 72e2cacc87 | |||
| 4285102422 | |||
| 5ffdf4dd60 | |||
| abbcf0e26b | |||
| 347b25472f | |||
| b745948dc6 | |||
| 8007c8869f | |||
| b51a328ead | |||
| f61437cc7c | |||
| f3b8f2eb5f | |||
| de4628f450 | |||
| b0a64655b4 | |||
| 48d88ec8fa | |||
| 7ca151a3fa | |||
| 363c8fab2c | |||
| 8d4fd9d1cf | |||
| 24071eb3b1 | |||
| 62ffbe7cf0 | |||
| f2d6b47e47 | |||
| f3541908c7 | |||
| 4e57e1cc18 | |||
| 410afffaa9 | |||
| 936e94789d | |||
| 468a56e5de | |||
| 468ec8824a | |||
| cad913b7a1 | |||
| 382103d99d | |||
| cbb6b9bca0 | |||
| a1b90a50cd | |||
| 9ea5855073 | |||
| 4a37433042 | |||
| 91469812d3 | |||
| 68a8eb7f3f | |||
| 2e7baabb94 | |||
| 57745fe71d | |||
| de6f9236e7 | |||
| a00c59e8b5 | |||
| 05c2da807f | |||
| 0fd8ca43d6 | |||
| 87f09b2ee6 | |||
| e466878925 | |||
| 7adf917570 | |||
| 7c41db4bcc | |||
| 5caaef7795 | |||
| 3b72945b1f | |||
| 71eb22d0e8 | |||
| 9d780a2e8f | |||
| 55b00069cb | |||
| b304728f4e | |||
| 319acc199e | |||
| 2a982f21a7 | |||
| 3ff455f11d | |||
| 41ad1bf27b | |||
| f49d939a2d | |||
| c7e80fc532 | |||
| b47d691841 | |||
| 7e1e83b493 | |||
| f6971185f8 | |||
| 244429b972 | |||
| 80ceba36dc | |||
| d33b617851 | |||
| 2b5f370c92 | |||
| 4a0cf81d7d | |||
| fef743517f | |||
| b3cbcebf5b | |||
| 3d90c2b83f | |||
| 3b8b5b6dfa | |||
| 85f95cf067 | |||
| 23be0134e7 | |||
| 355fb64d8b | |||
| 42959a1db5 | |||
| 5b754b3958 | |||
| cba31986fe | |||
| 07b0267668 | |||
| a83291cc6e | |||
| a1cd22208b | |||
| 59d75277c2 | |||
| 69e193e887 | |||
| c3116d5df7 | |||
| b0b874212e | |||
| 19086ab3a1 | |||
| 069594c3ac | |||
| 0bc4c7e2aa | |||
| 7f12cff3bd | |||
| 56adab43d6 | |||
| 83294b6594 | |||
| e0c89eb1ea | |||
| 9ad8e6a876 | |||
| 14b58386e5 | |||
| e26cbccfe0 | |||
| 7dc06c1bea | |||
| effa984bdc | |||
| fa058f348d | |||
| 62d9a1a132 | |||
| 9284269428 | |||
| f8c4481eb1 | |||
| d7f2041ee9 | |||
| 9f6e6e4701 | |||
| 34ba3f3351 | |||
| dcfb8b94d8 | |||
| 0876004d9a | |||
| 700b71f9fb | |||
| bba58ea0c0 | |||
| d0d4885812 | |||
| ce11a377e6 | |||
| c6443c477f | |||
| eb94572361 | |||
| fd8317493e | |||
| 3642ff72a4 | |||
| 6e830c1171 | |||
| ab523baf4f | |||
| 2dec03f441 | |||
| 9ada0d9c97 | |||
| df553140e8 | |||
| 0b898f2e32 | |||
| f5f3676a56 | |||
| f69f68e2b5 | |||
| 3858656015 | |||
| a5ec5f46ac | |||
| ea70e18a91 | |||
| 0cfd5773c3 | |||
| b15def99c7 | |||
| bc828fc6f3 | |||
| dc7b83ca6c | |||
| 8188e4ff55 | |||
| fcf9dcd803 | |||
| 070fa11f8c | |||
| 3556043b55 | |||
| fef9e3fde0 | |||
| e849d2d0d0 | |||
| 9a6123579f | |||
| 591a881283 | |||
| 1554d52ea9 | |||
| 60924d93fb | |||
| 50335723b0 | |||
| 58697eaa04 | |||
| ce58ad91b5 | |||
| e14aba3875 | |||
| 77162e4b51 | |||
| 0df7767f4a | |||
| 6c172702be | |||
| 7566546fd7 | |||
| 59b8b397b7 | |||
| 7c72e70967 | |||
| 75b74a6687 | |||
| 7dcb4435d8 |
+11
-5
@@ -1,10 +1,16 @@
|
||||
root=true
|
||||
# editorconfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Default settings:
|
||||
# A newline ending every file
|
||||
# Use 4 spaces as indentation
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{cs,cshtml,csx,vb,vbx,vbhtml,fs,fsx,txt,ps1,sql}]
|
||||
indent_size = 4
|
||||
# Trim trailing whitespace, limited support.
|
||||
# https://github.com/editorconfig/editorconfig/wiki/Property-research:-Trim-trailing-spaces
|
||||
trim_trailing_whitespace = true
|
||||
@@ -0,0 +1,49 @@
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
*.jpg binary
|
||||
*.png binary
|
||||
*.gif binary
|
||||
|
||||
*.cs text=auto diff=csharp
|
||||
*.vb text=auto
|
||||
*.c text=auto
|
||||
*.cpp text=auto
|
||||
*.cxx text=auto
|
||||
*.h text=auto
|
||||
*.hxx text=auto
|
||||
*.py text=auto
|
||||
*.rb text=auto
|
||||
*.java text=auto
|
||||
*.html text=auto
|
||||
*.htm text=auto
|
||||
*.css text=auto
|
||||
*.scss text=auto
|
||||
*.sass text=auto
|
||||
*.less text=auto
|
||||
*.js text=auto
|
||||
*.lisp text=auto
|
||||
*.clj text=auto
|
||||
*.sql text=auto
|
||||
*.php text=auto
|
||||
*.lua text=auto
|
||||
*.m text=auto
|
||||
*.asm text=auto
|
||||
*.erl text=auto
|
||||
*.fs text=auto
|
||||
*.fsx text=auto
|
||||
*.hs text=auto
|
||||
|
||||
*.csproj text=auto merge=union
|
||||
*.vbproj text=auto merge=union
|
||||
*.fsproj text=auto merge=union
|
||||
*.dbproj text=auto merge=union
|
||||
*.sln text=auto eol=crlf merge=union
|
||||
@@ -44,7 +44,7 @@ function Build-UmbracoDocs
|
||||
# change baseUrl
|
||||
$baseUrl = "https://our.umbraco.org/apidocs/ui/"
|
||||
$indexPath = "$src/Umbraco.Web.UI.Client/docs/api/index.html"
|
||||
(Get-Content $indexPath).Replace("location.href.replace(rUrl, indexFile)", "'$baseUrl'") `
|
||||
(Get-Content $indexPath).Replace("origin + location.href.substr(origin.length).replace(rUrl, indexFile)", "'$baseUrl'") `
|
||||
| Set-Content $indexPath
|
||||
|
||||
# restore
|
||||
@@ -100,8 +100,9 @@ function Get-DocFx($uenv, $buildTemp)
|
||||
$docFx = "$buildTemp\docfx"
|
||||
if (-not (test-path $docFx))
|
||||
{
|
||||
Write-Host "Download DocFx..."
|
||||
$source = "https://github.com/dotnet/docfx/releases/download/v2.19.2/docfx.zip"
|
||||
Write-Host "Download DocFx from $source"
|
||||
|
||||
Invoke-WebRequest $source -OutFile "$buildTemp\docfx.zip"
|
||||
|
||||
&$uenv.Zip x "$buildTemp\docfx.zip" -o"$buildTemp\docfx" -aos > $nul
|
||||
|
||||
@@ -239,18 +239,18 @@ function Prepare-Tests
|
||||
|
||||
# data
|
||||
Write-Host "Copy data files"
|
||||
if( -Not (Test-Path -Path "$tmp\tests\Packaging" ) )
|
||||
if (-Not (Test-Path -Path "$tmp\tests\Packaging" ) )
|
||||
{
|
||||
Write-Host "Create packaging directory"
|
||||
New-Item -ItemType directory -Path "$tmp\tests\Packaging"
|
||||
mkdir "$tmp\tests\Packaging" > $null
|
||||
}
|
||||
Copy-Files "$src\Umbraco.Tests\Packaging\Packages" "*" "$tmp\tests\Packaging\Packages"
|
||||
|
||||
# required for package install tests
|
||||
if( -Not (Test-Path -Path "$tmp\tests\bin" ) )
|
||||
if (-Not (Test-Path -Path "$tmp\tests\bin" ) )
|
||||
{
|
||||
Write-Host "Create bin directory"
|
||||
New-Item -ItemType directory -Path "$tmp\tests\bin"
|
||||
mkdir "$tmp\tests\bin" > $null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.9.5, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.9.9, 7.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.2, 2.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.9.6, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.8, 4.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.10, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.1, 3.0.0)" />
|
||||
</dependencies>
|
||||
@@ -32,7 +32,7 @@
|
||||
<file src="$BuildTmp$\WebApp\bin\amd64\**" target="UmbracoFiles\bin\amd64" />
|
||||
<file src="$BuildTmp$\WebApp\bin\x86\**" target="UmbracoFiles\bin\x86" />
|
||||
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
|
||||
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="UmbracoFiles\Config\BackOfficeTours" />
|
||||
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
|
||||
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
|
||||
<file src="$BuildTmp$\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
|
||||
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
|
||||
|
||||
@@ -98,10 +98,51 @@ if ($project) {
|
||||
$umbracoUIXMLDestination = Join-Path $projectPath "Umbraco\Config\Create\UI.xml"
|
||||
Copy-Item $umbracoUIXMLSource $umbracoUIXMLDestination -Force
|
||||
} else {
|
||||
# This part only runs for upgrades
|
||||
|
||||
$upgradeViewSource = Join-Path $umbracoFolderSource "Views\install\*"
|
||||
$upgradeView = Join-Path $umbracoFolder "Views\install\"
|
||||
Write-Host "Copying2 ${upgradeViewSource} to ${upgradeView}"
|
||||
Copy-Item $upgradeViewSource $upgradeView -Force
|
||||
|
||||
Try
|
||||
{
|
||||
# Disable tours for upgrades, presumably Umbraco experience is already available
|
||||
$umbracoSettingsConfigPath = Join-Path $configFolder "umbracoSettings.config"
|
||||
$content = (Get-Content $umbracoSettingsConfigPath).Replace('<tours enable="true">','<tours enable="false">')
|
||||
# Saves with UTF-8 encoding without BOM which makes sure Umbraco can still read it
|
||||
# Reference: https://stackoverflow.com/a/32951824/5018
|
||||
[IO.File]::WriteAllLines($umbracoSettingsConfigPath, $content)
|
||||
}
|
||||
Catch
|
||||
{
|
||||
# Not a big problem if this fails, let it go
|
||||
}
|
||||
|
||||
Try
|
||||
{
|
||||
$uiXmlConfigPath = Join-Path $umbracoFolder -ChildPath "Config" | Join-Path -ChildPath "create" | Join-Path -ChildPath "UI.xml"
|
||||
$uiXmlFile = Join-Path $umbracoFolder -ChildPath "Config" | Join-Path -ChildPath "create" | Join-Path -ChildPath "UI.xml"
|
||||
|
||||
$uiXml = New-Object System.Xml.XmlDocument
|
||||
$uiXml.PreserveWhitespace = $true
|
||||
|
||||
$uiXml.Load($uiXmlFile)
|
||||
$createExists = $uiXml.SelectNodes("//nodeType[@alias='macros']/tasks/create")
|
||||
|
||||
if($createExists.Count -eq 0)
|
||||
{
|
||||
$macrosTasksNode = $uiXml.SelectNodes("//nodeType[@alias='macros']/tasks")
|
||||
|
||||
#Creating: <create assembly="umbraco" type="macroTasks" />
|
||||
$createNode = $uiXml.CreateElement("create")
|
||||
$createNode.SetAttribute("assembly", "umbraco")
|
||||
$createNode.SetAttribute("type", "macroTasks")
|
||||
$macrosTasksNode.AppendChild($createNode)
|
||||
$uiXml.Save($uiXmlFile)
|
||||
}
|
||||
}
|
||||
Catch { }
|
||||
}
|
||||
|
||||
$installFolder = Join-Path $projectPath "Install"
|
||||
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.8.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.8.0-beta003")]
|
||||
[assembly: AssemblyFileVersion("7.8.3")]
|
||||
[assembly: AssemblyInformationalVersion("7.8.3")]
|
||||
@@ -146,7 +146,7 @@ namespace Umbraco.Core.Cache
|
||||
#region Insert
|
||||
#endregion
|
||||
|
||||
private class NoopLocker : DisposableObject
|
||||
private class NoopLocker : DisposableObjectSlim
|
||||
{
|
||||
protected override void DisposeResources()
|
||||
{ }
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a composite key of (Type, Type) for fast dictionaries.
|
||||
/// </summary>
|
||||
internal struct CompositeTypeTypeKey : IEquatable<CompositeTypeTypeKey>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CompositeTypeTypeKey"/> struct.
|
||||
/// </summary>
|
||||
public CompositeTypeTypeKey(Type type1, Type type2) : this()
|
||||
{
|
||||
Type1 = type1;
|
||||
Type2 = type2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first type.
|
||||
/// </summary>
|
||||
public Type Type1 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the second type.
|
||||
/// </summary>
|
||||
public Type Type2 { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(CompositeTypeTypeKey other)
|
||||
{
|
||||
return Type1 == other.Type1 && Type2 == other.Type2;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = obj is CompositeTypeTypeKey ? (CompositeTypeTypeKey)obj : default(CompositeTypeTypeKey);
|
||||
return Type1 == other.Type1 && Type2 == other.Type2;
|
||||
}
|
||||
|
||||
public static bool operator ==(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
|
||||
{
|
||||
return key1.Type1 == key2.Type1 && key1.Type2 == key2.Type2;
|
||||
}
|
||||
|
||||
public static bool operator !=(CompositeTypeTypeKey key1, CompositeTypeTypeKey key2)
|
||||
{
|
||||
return key1.Type1 != key2.Type1 || key1.Type2 != key2.Type2;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Type1.GetHashCode() * 397) ^ Type2.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.8.0");
|
||||
private static readonly Version Version = new Version("7.8.3");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -11,17 +11,53 @@
|
||||
/// The integer identifier for global system root node.
|
||||
/// </summary>
|
||||
public const int Root = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The string identifier for global system root node.
|
||||
/// </summary>
|
||||
/// <remarks>Use this instead of re-creating the string everywhere.</remarks>
|
||||
public const string RootString = "-1";
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for content's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinContent = -20;
|
||||
|
||||
/// <summary>
|
||||
/// The string identifier for content's recycle bin.
|
||||
/// </summary>
|
||||
/// <remarks>Use this instead of re-creating the string everywhere.</remarks>
|
||||
public const string RecycleBinContentString = "-20";
|
||||
|
||||
/// <summary>
|
||||
/// The string path prefix of the content's recycle bin.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Everything that is in the content recycle bin, has a path that starts with the prefix.</para>
|
||||
/// <para>Use this instead of re-creating the string everywhere.</para>
|
||||
/// </remarks>
|
||||
public const string RecycleBinContentPathPrefix = "-1,-20,";
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for media's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinMedia = -21;
|
||||
|
||||
/// <summary>
|
||||
/// The string identifier for media's recycle bin.
|
||||
/// </summary>
|
||||
/// <remarks>Use this instead of re-creating the string everywhere.</remarks>
|
||||
public const string RecycleBinMediaString = "-21";
|
||||
|
||||
/// <summary>
|
||||
/// The string path prefix of the media's recycle bin.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Everything that is in the media recycle bin, has a path that starts with the prefix.</para>
|
||||
/// <para>Use this instead of re-creating the string everywhere.</para>
|
||||
/// </remarks>
|
||||
public const string RecycleBinMediaPathPrefix = "-1,-21,";
|
||||
|
||||
public const int DefaultContentListViewDataTypeId = -95;
|
||||
public const int DefaultMediaListViewDataTypeId = -96;
|
||||
public const int DefaultMembersListViewDataTypeId = -97;
|
||||
@@ -29,6 +65,6 @@
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";
|
||||
public const string UmbracoMigrationName = "Umbraco";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,9 @@ namespace Umbraco.Core
|
||||
public static DateTime TruncateTo(this DateTime dt, DateTruncate truncateTo)
|
||||
{
|
||||
if (truncateTo == DateTruncate.Year)
|
||||
return new DateTime(dt.Year, 0, 0);
|
||||
return new DateTime(dt.Year, 1, 1);
|
||||
if (truncateTo == DateTruncate.Month)
|
||||
return new DateTime(dt.Year, dt.Month, 0);
|
||||
return new DateTime(dt.Year, dt.Month, 1);
|
||||
if (truncateTo == DateTruncate.Day)
|
||||
return new DateTime(dt.Year, dt.Month, dt.Day);
|
||||
if (truncateTo == DateTruncate.Hour)
|
||||
@@ -41,43 +41,43 @@ namespace Umbraco.Core
|
||||
Hour,
|
||||
Minute,
|
||||
Second
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
|
||||
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
|
||||
/// date time is before the time, calculate onto next day)
|
||||
/// </summary>
|
||||
/// <param name="fromDateTime">Date to start from</param>
|
||||
/// <param name="scheduledTime">Time to compare against (in Hmm form, e.g. 330, 2200)</param>
|
||||
/// <returns></returns>
|
||||
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
|
||||
{
|
||||
// Ensure time provided is 4 digits long
|
||||
if (scheduledTime.Length == 3)
|
||||
{
|
||||
scheduledTime = "0" + scheduledTime;
|
||||
}
|
||||
|
||||
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
|
||||
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
|
||||
|
||||
DateTime scheduledDateTime;
|
||||
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
|
||||
{
|
||||
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nextDay = fromDateTime.AddDays(1);
|
||||
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
|
||||
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
|
||||
}
|
||||
|
||||
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
|
||||
{
|
||||
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
|
||||
/// <returns></returns>
|
||||
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
|
||||
{
|
||||
// Ensure time provided is 4 digits long
|
||||
if (scheduledTime.Length == 3)
|
||||
{
|
||||
scheduledTime = "0" + scheduledTime;
|
||||
}
|
||||
|
||||
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
|
||||
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
|
||||
|
||||
DateTime scheduledDateTime;
|
||||
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
|
||||
{
|
||||
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nextDay = fromDateTime.AddDays(1);
|
||||
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
|
||||
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
|
||||
}
|
||||
|
||||
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
|
||||
{
|
||||
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,60 +2,60 @@ using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract implementation of IDisposable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Can also be used as a pattern for when inheriting is not possible.
|
||||
///
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract implementation of IDisposable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Can also be used as a pattern for when inheriting is not possible.
|
||||
///
|
||||
/// See also: https://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.110%29.aspx
|
||||
/// See also: https://lostechies.com/chrispatterson/2012/11/29/idisposable-done-right/
|
||||
///
|
||||
/// Note: if an object's ctor throws, it will never be disposed, and so if that ctor
|
||||
/// has allocated disposable objects, it should take care of disposing them.
|
||||
/// </remarks>
|
||||
public abstract class DisposableObject : IDisposable
|
||||
{
|
||||
private bool _disposed;
|
||||
private readonly object _locko = new object();
|
||||
|
||||
// gets a value indicating whether this instance is disposed.
|
||||
/// </remarks>
|
||||
public abstract class DisposableObject : IDisposable
|
||||
{
|
||||
private bool _disposed;
|
||||
private readonly object _locko = new object();
|
||||
|
||||
// gets a value indicating whether this instance is disposed.
|
||||
// for internal tests only (not thread safe)
|
||||
//TODO make this internal + rename "Disposed" when we can break compatibility
|
||||
public bool IsDisposed { get { return _disposed; } }
|
||||
|
||||
// implements IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// finalizer
|
||||
~DisposableObject()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
public bool IsDisposed { get { return _disposed; } }
|
||||
|
||||
// implements IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// finalizer
|
||||
~DisposableObject()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
//TODO make this private, non-virtual when we can break compatibility
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
DisposeUnmanagedResources();
|
||||
|
||||
if (disposing)
|
||||
DisposeResources();
|
||||
}
|
||||
|
||||
protected abstract void DisposeResources();
|
||||
|
||||
protected virtual void DisposeUnmanagedResources()
|
||||
{ }
|
||||
}
|
||||
DisposeResources();
|
||||
}
|
||||
|
||||
protected abstract void DisposeResources();
|
||||
|
||||
protected virtual void DisposeUnmanagedResources()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// This should not be use if there are ubmanaged resources to be disposed, use DisposableObject instead
|
||||
/// </summary>
|
||||
public abstract class DisposableObjectSlim : IDisposable
|
||||
{
|
||||
private bool _disposed;
|
||||
private readonly object _locko = new object();
|
||||
|
||||
// gets a value indicating whether this instance is disposed.
|
||||
// for internal tests only (not thread safe)
|
||||
internal bool Disposed { get { return _disposed; } }
|
||||
|
||||
// implements IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
lock (_locko)
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
DisposeResources();
|
||||
}
|
||||
|
||||
protected abstract void DisposeResources();
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Starts the timer and invokes a callback upon disposal. Provides a simple way of timing an operation by wrapping it in a <code>using</code> (C#) statement.
|
||||
/// </summary>
|
||||
public class DisposableTimer : DisposableObject
|
||||
{
|
||||
public class DisposableTimer : DisposableObjectSlim
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly LogType? _logType;
|
||||
private readonly IProfiler _profiler;
|
||||
@@ -209,13 +209,13 @@ namespace Umbraco.Core
|
||||
loggerType,
|
||||
startMessage(),
|
||||
completeMessage());
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObject"/> which handles common required locking logic.
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
|
||||
/// <summary>
|
||||
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObjectSlim"/> which handles common required locking logic.
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
if (_profiler != null)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Events
|
||||
/// <summary>
|
||||
/// Event messages collection
|
||||
/// </summary>
|
||||
public sealed class EventMessages : DisposableObject
|
||||
public sealed class EventMessages : DisposableObjectSlim
|
||||
{
|
||||
private readonly List<EventMessage> _msgs = new List<EventMessage>();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Packaging.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
@@ -7,18 +8,27 @@ namespace Umbraco.Core.Events
|
||||
public class ImportPackageEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportPackageEventArgs<TEntity>>
|
||||
{
|
||||
private readonly MetaData _packageMetaData;
|
||||
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the overload specifying packageMetaData instead")]
|
||||
public ImportPackageEventArgs(TEntity eventObject, bool canCancel)
|
||||
: base(new[] { eventObject }, canCancel)
|
||||
{
|
||||
}
|
||||
|
||||
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
|
||||
: base(new[] { eventObject })
|
||||
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData, bool canCancel)
|
||||
: base(new[] { eventObject }, canCancel)
|
||||
{
|
||||
if (packageMetaData == null) throw new ArgumentNullException("packageMetaData");
|
||||
_packageMetaData = packageMetaData;
|
||||
}
|
||||
|
||||
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
|
||||
: this(eventObject, packageMetaData, true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MetaData PackageMetaData
|
||||
{
|
||||
get { return _packageMetaData; }
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Core
|
||||
/// This will use the crypto libs to generate the hash and will try to ensure that
|
||||
/// strings, etc... are not re-allocated so it's not consuming much memory.
|
||||
/// </remarks>
|
||||
internal class HashGenerator : DisposableObject
|
||||
internal class HashGenerator : DisposableObjectSlim
|
||||
{
|
||||
public HashGenerator()
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Manifest
|
||||
{
|
||||
internal class ManifestWatcher : DisposableObject
|
||||
internal class ManifestWatcher : DisposableObjectSlim
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly List<FileSystemWatcher> _fws = new List<FileSystemWatcher>();
|
||||
|
||||
@@ -95,8 +95,10 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedTemplates; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector,
|
||||
Ps.Value.TemplateComparer);
|
||||
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector, Ps.Value.TemplateComparer);
|
||||
|
||||
if (_allowedTemplates.Any(x => x.Id == _defaultTemplate) == false)
|
||||
DefaultTemplateId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -394,7 +394,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// WARNING! Do not use this unless you know what you are doing, clear all types registered and instances
|
||||
/// created. Typically only used if a resolver is no longer used in an application and memory is to be GC'd
|
||||
/// </summary>
|
||||
internal void ResetCollections()
|
||||
internal virtual void ResetCollections()
|
||||
{
|
||||
using (new WriteLock(_lock))
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// it will create one per context, otherwise it will be a global singleton object which is NOT thread safe
|
||||
/// since we need (at least) a new instance of the database object per thread.
|
||||
/// </remarks>
|
||||
internal class DefaultDatabaseFactory : DisposableObject, IDatabaseFactory2
|
||||
internal class DefaultDatabaseFactory : DisposableObjectSlim, IDatabaseFactory2
|
||||
{
|
||||
private readonly string _connectionStringName;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
@@ -402,7 +402,7 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
|
||||
// Helper to handle named parameters from object properties
|
||||
static Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
|
||||
{
|
||||
return rxParams.Replace(_sql, m =>
|
||||
@@ -545,7 +545,7 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
|
||||
// Create a command
|
||||
static Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
static readonly Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
public IDbCommand CreateCommand(IDbConnection connection, string sql, params object[] args)
|
||||
{
|
||||
// Perform named argument replacements
|
||||
@@ -666,8 +666,8 @@ namespace Umbraco.Core.Persistence
|
||||
return ExecuteScalar<T>(sql.SQL, sql.Arguments);
|
||||
}
|
||||
|
||||
Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
static readonly Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
static readonly Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
string AddSelectClause<T>(string sql)
|
||||
{
|
||||
if (sql.StartsWith(";"))
|
||||
@@ -701,9 +701,9 @@ namespace Umbraco.Core.Persistence
|
||||
return Fetch<T>(sql.SQL, sql.Arguments);
|
||||
}
|
||||
|
||||
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static readonly Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static readonly Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
|
||||
{
|
||||
sqlSelectRemoved = null;
|
||||
@@ -2546,5 +2546,4 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <remarks>
|
||||
/// This is limited to objects that are based in the umbracoNode-table.
|
||||
/// </remarks>
|
||||
internal class EntityRepository : DisposableObject, IEntityRepository
|
||||
internal class EntityRepository : DisposableObjectSlim, IEntityRepository
|
||||
{
|
||||
private readonly IDatabaseUnitOfWork _work;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal abstract class FileRepository<TId, TEntity> : DisposableObject, IUnitOfWorkRepository, IRepository<TId, TEntity>
|
||||
internal abstract class FileRepository<TId, TEntity> : DisposableObjectSlim, IUnitOfWorkRepository, IRepository<TId, TEntity>
|
||||
where TEntity : IFile
|
||||
{
|
||||
private IUnitOfWork _work;
|
||||
|
||||
@@ -10,7 +10,7 @@ using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal abstract class RepositoryBase : DisposableObject
|
||||
internal abstract class RepositoryBase : DisposableObjectSlim
|
||||
{
|
||||
private readonly IScopeUnitOfWork _work;
|
||||
private readonly CacheHelper _globalCache;
|
||||
|
||||
@@ -20,6 +20,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
var name = Name;
|
||||
|
||||
// cater for instances where node has no name.
|
||||
if(string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return _numPos;
|
||||
}
|
||||
|
||||
if (name[name.Length - 1] != ')')
|
||||
return _numPos = -1;
|
||||
|
||||
@@ -106,7 +112,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueing ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
|
||||
return uniqueing || string.IsNullOrWhiteSpace(nodeName) ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
/// <summary>
|
||||
/// Represents a scoped unit of work.
|
||||
/// </summary>
|
||||
internal class ScopeUnitOfWork : DisposableObject, IScopeUnitOfWork
|
||||
internal class ScopeUnitOfWork : DisposableObjectSlim, IScopeUnitOfWork
|
||||
{
|
||||
private readonly Queue<Operation> _operations = new Queue<Operation>();
|
||||
private readonly IsolationLevel _isolationLevel;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -176,6 +176,12 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <returns></returns>
|
||||
internal Attempt<object> TryConvertValueToCrlType(object value)
|
||||
{
|
||||
var jv = value as JValue;
|
||||
if (jv != null)
|
||||
{
|
||||
value = value.ToString();
|
||||
}
|
||||
|
||||
//this is a custom check to avoid any errors, if it's a string and it's empty just make it null
|
||||
var s = value as string;
|
||||
if (s != null)
|
||||
@@ -391,4 +397,4 @@ namespace Umbraco.Core.PropertyEditors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -18,6 +18,8 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
return Constants.PropertyEditors.MultipleTextstringAlias.Equals(propertyType.PropertyEditorAlias);
|
||||
}
|
||||
|
||||
private static readonly string[] NewLineDelimiters = { "\r\n", "\r", "\n" };
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// data is (both in database and xml):
|
||||
@@ -53,7 +55,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
// Fall back on normal behaviour
|
||||
if (values.Any() == false)
|
||||
{
|
||||
return sourceString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
|
||||
return sourceString.Split(NewLineDelimiters, StringSplitOptions.None);
|
||||
}
|
||||
|
||||
return values.ToArray();
|
||||
|
||||
@@ -401,9 +401,10 @@ namespace Umbraco.Core.Publishing
|
||||
content.Name, content.Id));
|
||||
}
|
||||
|
||||
// if newest is published, unpublish
|
||||
if (content.Published)
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
// make sure we dirty .Published and always unpublish
|
||||
// the version we have here could be the newest, !Published
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
content.ChangePublishedState(PublishedState.Unpublished);
|
||||
|
||||
_logger.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Umbraco.Core.Scoping
|
||||
public NoScope(ScopeProvider scopeProvider)
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
Timestamp = DateTime.Now;
|
||||
#if DEBUG_SCOPES
|
||||
_scopeProvider.RegisterScope(this);
|
||||
#endif
|
||||
@@ -28,6 +29,8 @@ namespace Umbraco.Core.Scoping
|
||||
private readonly Guid _instanceId = Guid.NewGuid();
|
||||
public Guid InstanceId { get { return _instanceId; } }
|
||||
|
||||
public DateTime Timestamp { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CallContext { get { return false; } }
|
||||
|
||||
|
||||
@@ -374,7 +374,7 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
|
||||
var parent = ParentScope;
|
||||
_scopeProvider.AmbientScope = parent;
|
||||
_scopeProvider.AmbientScope = parent; // might be null = this is how scopes are removed from context objects
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
_scopeProvider.Disposed(this);
|
||||
|
||||
@@ -116,5 +116,19 @@ namespace Umbraco.Core.Scoping
|
||||
Enlisted[key] = enlistedOfT;
|
||||
return enlistedOfT.Item;
|
||||
}
|
||||
|
||||
public T GetEnlisted<T>(string key)
|
||||
{
|
||||
var enlistedObjects = _enlisted;
|
||||
if (enlistedObjects == null) return default (T);
|
||||
|
||||
IEnlistedObject enlisted;
|
||||
if (enlistedObjects.TryGetValue(key, out enlisted) == false)
|
||||
return default (T);
|
||||
|
||||
var enlistedAs = enlisted as EnlistedObject<T>;
|
||||
if (enlistedAs == null) throw new InvalidOperationException("An item with the key exists, but with a different type.");
|
||||
return enlistedAs.Item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
#if DEBUG_SCOPES
|
||||
using System.Linq;
|
||||
@@ -66,22 +68,38 @@ namespace Umbraco.Core.Scoping
|
||||
// tests, any other things (see https://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx),
|
||||
// but we don't want to make all of our objects serializable since they are *not* meant to be
|
||||
// used in cross-AppDomain scenario anyways.
|
||||
//
|
||||
// in addition, whatever goes into the logical call context is serialized back and forth any
|
||||
// time cross-AppDomain code executes, so if we put an "object" there, we'll can *another*
|
||||
// "object" instance - and so we cannot use a random object as a key.
|
||||
// time cross-AppDomain code executes, so if we put an "object" there, we'll get *another*
|
||||
// "object" instance back - and so we cannot use a random object as a key.
|
||||
//
|
||||
// so what we do is: we register a guid in the call context, and we keep a table mapping those
|
||||
// guids to the actual objects. the guid serializes back and forth without causing any issue,
|
||||
// and we can retrieve the actual objects from the table.
|
||||
// only issue: how are we supposed to clear the table? we can't, really. objects should take
|
||||
// care of de-registering themselves from context.
|
||||
// everything we use does, except the NoScope scope, which just stays there
|
||||
//
|
||||
// during tests, NoScope can to into call context... nothing much we can do about it
|
||||
// so far, the only objects that go into this table are scopes (using ScopeItemKey) and
|
||||
// scope contexts (using ContextItemKey).
|
||||
|
||||
private static readonly object StaticCallContextObjectsLock = new object();
|
||||
private static readonly Dictionary<Guid, object> StaticCallContextObjects
|
||||
= new Dictionary<Guid, object>();
|
||||
|
||||
// normal scopes and scope contexts take greate care removing themselves when disposed, so it
|
||||
// is all safe. OTOH the NoScope *CANNOT* remove itself, this is by design, it *WILL* leak and
|
||||
// there is little (nothing) we can do about it - NoScope exists for backward compatibility
|
||||
// reasons and relying on it is greatly discouraged.
|
||||
//
|
||||
// however... we can *try* at protecting the app against memory leaks, by collecting NoScope
|
||||
// instances that are too old. if anything actually *need* to retain a NoScope instance for
|
||||
// a long time, it will break. but that's probably ok. so: the constants below define how
|
||||
// long a NoScope instance can stay in the table before being removed, and how often we should
|
||||
// collect the table - and collecting happens anytime SetCallContextObject is invoked
|
||||
|
||||
private static readonly TimeSpan StaticCallContextNoScopeLifeSpan = TimeSpan.FromMinutes(30);
|
||||
private static readonly TimeSpan StaticCallContextCollectPeriod = TimeSpan.FromMinutes(4);
|
||||
private static DateTime _staticCallContextLastCollect = DateTime.MinValue;
|
||||
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
public Dictionary<Guid, object> CallContextObjects
|
||||
{
|
||||
@@ -156,6 +174,7 @@ namespace Umbraco.Core.Scoping
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
StaticCallContextObjects.Remove(objectKey);
|
||||
CollectStaticCallContextObjectsLocked();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -171,11 +190,37 @@ namespace Umbraco.Core.Scoping
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
StaticCallContextObjects.Add(objectKey, value);
|
||||
CollectStaticCallContextObjectsLocked();
|
||||
}
|
||||
CallContext.LogicalSetData(key, objectKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectStaticCallContextObjectsLocked()
|
||||
{
|
||||
// is it time to collect?
|
||||
var now = DateTime.Now;
|
||||
if (now - _staticCallContextLastCollect <= StaticCallContextCollectPeriod)
|
||||
return;
|
||||
|
||||
// disable warning: this method is invoked from within a lock
|
||||
// ReSharper disable InconsistentlySynchronizedField
|
||||
var threshold = now.Add(-StaticCallContextNoScopeLifeSpan);
|
||||
var guids = StaticCallContextObjects
|
||||
.Where(x => x.Value is NoScope noScope && noScope.Timestamp < threshold)
|
||||
.Select(x => x.Key)
|
||||
.ToList();
|
||||
if (guids.Count > 0)
|
||||
{
|
||||
LogHelper.Warn<ScopeProvider>($"Collected {guids.Count} NoScope instances from StaticCallContextObjects.");
|
||||
foreach (var guid in guids)
|
||||
StaticCallContextObjects.Remove(guid);
|
||||
}
|
||||
// ReSharper restore InconsistentlySynchronizedField
|
||||
|
||||
_staticCallContextLastCollect = now;
|
||||
}
|
||||
|
||||
// this is for tests exclusively until we have a proper accessor in v8
|
||||
internal static Func<IDictionary> HttpContextItemsGetter { get; set; }
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
public class BackOfficeUserStore : DisposableObject,
|
||||
public class BackOfficeUserStore : DisposableObjectSlim,
|
||||
IUserStore<BackOfficeIdentityUser, int>,
|
||||
IUserPasswordStore<BackOfficeIdentityUser, int>,
|
||||
IUserEmailStore<BackOfficeIdentityUser, int>,
|
||||
@@ -58,7 +58,7 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObject"/> which handles common required locking logic.
|
||||
/// Handles the disposal of resources. Derived from abstract class <see cref="DisposableObjectSlim"/> which handles common required locking logic.
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
|
||||
@@ -692,7 +692,7 @@ namespace Umbraco.Core.Services
|
||||
totalChildren = 0;
|
||||
return Enumerable.Empty<IContent>();
|
||||
}
|
||||
query.Where(x => x.Path.SqlStartsWith(string.Format("{0},", contentPath[0]), TextColumnType.NVarchar));
|
||||
query.Where(x => x.Path.SqlStartsWith(string.Format("{0},", contentPath[0].Path), TextColumnType.NVarchar));
|
||||
}
|
||||
|
||||
|
||||
@@ -737,7 +737,7 @@ namespace Umbraco.Core.Services
|
||||
totalChildren = 0;
|
||||
return Enumerable.Empty<IContent>();
|
||||
}
|
||||
query.Where(x => x.Path.SqlStartsWith(string.Format("{0},", contentPath[0]), TextColumnType.NVarchar));
|
||||
query.Where(x => x.Path.SqlStartsWith(string.Format("{0},", contentPath[0].Path), TextColumnType.NVarchar));
|
||||
}
|
||||
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
|
||||
@@ -884,8 +884,8 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
var query = Query<IContent>.Builder.Where(x => x.Published && x.ExpireDate <= DateTime.Now);
|
||||
return repository.GetByQuery(query);
|
||||
var query = Query<IContent>.Builder.Where(x => x.ExpireDate <= DateTime.Now);
|
||||
return repository.GetByQuery(query).Where(x => x.HasPublishedVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,13 +912,11 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.Contains(Constants.System.RecycleBinContent.ToInvariantString()));
|
||||
var query = Query<IContent>.Builder.Where(x => x.Path.StartsWith(Constants.System.RecycleBinContentPathPrefix));
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether an <see cref="IContent"/> item has any children
|
||||
/// </summary>
|
||||
@@ -1344,6 +1342,40 @@ namespace Umbraco.Core.Services
|
||||
return content;
|
||||
}
|
||||
|
||||
public void DeleteBlueprintsOfTypes(IEnumerable<int> contentTypeIds, int userId = 0)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = RepositoryFactory.CreateContentBlueprintRepository(uow);
|
||||
|
||||
var contentTypeIdsA = contentTypeIds.ToArray();
|
||||
var query = new Query<IContent>();
|
||||
if (contentTypeIdsA.Length > 0)
|
||||
{
|
||||
query.Where(x => contentTypeIdsA.Contains(x.ContentTypeId));
|
||||
}
|
||||
var blueprints = repository.GetByQuery(query).Select(x =>
|
||||
{
|
||||
((Content) x).IsBlueprint = true;
|
||||
return x;
|
||||
}).ToArray();
|
||||
|
||||
foreach (var blueprint in blueprints)
|
||||
{
|
||||
repository.Delete(blueprint);
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(DeletedBlueprint, this, new DeleteEventArgs<IContent>(blueprints), "DeletedBlueprint");
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteBlueprintsOfType(int contentTypeId, int userId = 0)
|
||||
{
|
||||
DeleteBlueprintsOfTypes(new[] {contentTypeId}, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
|
||||
@@ -920,7 +920,9 @@ namespace Umbraco.Core.Services
|
||||
var deletedContentTypes = new List<IContentType> { contentType };
|
||||
deletedContentTypes.AddRange(GetDescendants(contentType));
|
||||
|
||||
_contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId);
|
||||
var ids = deletedContentTypes.Select(x => x.Id).ToArray();
|
||||
_contentService.DeleteContentOfTypes(ids, userId);
|
||||
_contentService.DeleteBlueprintsOfTypes(ids);
|
||||
|
||||
repository.Delete(contentType);
|
||||
deleteEventArgs.DeletedEntities = deletedContentTypes.DistinctBy(x => x.Id);
|
||||
|
||||
@@ -101,7 +101,9 @@ namespace Umbraco.Core.Services
|
||||
IContent GetBlueprintById(Guid id);
|
||||
void SaveBlueprint(IContent content, int userId = 0);
|
||||
void DeleteBlueprint(IContent content, int userId = 0);
|
||||
IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0);
|
||||
IContent CreateContentFromBlueprint(IContent blueprint, string name, int userId = 0);
|
||||
void DeleteBlueprintsOfType(int contentTypeId, int userId = 0);
|
||||
void DeleteBlueprintsOfTypes(IEnumerable<int> contentTypeIds, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all XML entries found in the cmsContentXml table based on the given path
|
||||
|
||||
@@ -39,8 +39,16 @@ namespace Umbraco.Core.Services
|
||||
int? val;
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
|
||||
new { id = key, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
|
||||
//if it's unknown don't include the nodeObjectType in the query
|
||||
if (umbracoObjectType == UmbracoObjectTypes.Unknown)
|
||||
{
|
||||
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id", new { id = key});
|
||||
}
|
||||
else
|
||||
{
|
||||
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
|
||||
new { id = key, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
@@ -92,8 +100,16 @@ namespace Umbraco.Core.Services
|
||||
Guid? val;
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
|
||||
new { id, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
|
||||
//if it's unknown don't include the nodeObjectType in the query
|
||||
if (umbracoObjectType == UmbracoObjectTypes.Unknown)
|
||||
{
|
||||
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id", new { id });
|
||||
}
|
||||
else
|
||||
{
|
||||
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
|
||||
new { id, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
|
||||
@@ -389,7 +389,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateMediaRepository(uow);
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Level == level && x.Path.StartsWith("-21") == false);
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Level == level && x.Path.StartsWith(Constants.System.RecycleBinMediaPathPrefix) == false);
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
@@ -440,7 +440,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
public IEnumerable<IMedia> GetAncestors(IMedia media)
|
||||
{
|
||||
var ids = media.Path.Split(',').Where(x => x != "-1" && x != media.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray();
|
||||
var ids = media.Path.Split(',').Where(x => x != Constants.System.RootString && x != media.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray();
|
||||
if (ids.Any() == false)
|
||||
return new List<IMedia>();
|
||||
|
||||
@@ -609,7 +609,7 @@ namespace Umbraco.Core.Services
|
||||
totalChildren = 0;
|
||||
return Enumerable.Empty<IMedia>();
|
||||
}
|
||||
query.Where(x => x.Path.SqlStartsWith(string.Format("{0},", mediaPath[0]), TextColumnType.NVarchar));
|
||||
query.Where(x => x.Path.SqlStartsWith(string.Format("{0},", mediaPath[0].Path), TextColumnType.NVarchar));
|
||||
}
|
||||
IQuery<IMedia> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
@@ -673,7 +673,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>Parent <see cref="IMedia"/> object</returns>
|
||||
public IMedia GetParent(IMedia media)
|
||||
{
|
||||
if (media.ParentId == -1 || media.ParentId == -21)
|
||||
if (media.ParentId == Constants.System.Root || media.ParentId == Constants.System.RecycleBinMedia)
|
||||
return null;
|
||||
|
||||
return GetById(media.ParentId);
|
||||
@@ -703,7 +703,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateMediaRepository(uow);
|
||||
var query = Query<IMedia>.Builder.Where(x => x.ParentId == -1);
|
||||
var query = Query<IMedia>.Builder.Where(x => x.ParentId == Constants.System.Root);
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
@@ -717,7 +717,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateMediaRepository(uow);
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Path.Contains("-21"));
|
||||
var query = Query<IMedia>.Builder.Where(x => x.Path.StartsWith(Constants.System.RecycleBinMediaPathPrefix));
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
@@ -767,7 +767,7 @@ namespace Umbraco.Core.Services
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
//This ensures that the correct method is called if this method is used to Move to recycle bin.
|
||||
if (parentId == -21)
|
||||
if (parentId == Constants.System.RecycleBinMedia)
|
||||
{
|
||||
MoveToRecycleBin(media, userId);
|
||||
return;
|
||||
@@ -868,7 +868,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = RepositoryFactory.CreateMediaRepository(uow);
|
||||
repository.Delete(media);
|
||||
deleteEventArgs.CanCancel = false;
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Deleted, this, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Delete Media performed by user", userId, media.Id);
|
||||
@@ -1003,7 +1003,7 @@ namespace Umbraco.Core.Services
|
||||
recycleBinEventArgs.RecycleBinEmptiedSuccessfully = success;
|
||||
uow.Events.Dispatch(EmptiedRecycleBin, this, recycleBinEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Empty Media Recycle Bin performed by user", 0, -21);
|
||||
Audit(uow, AuditType.Delete, "Empty Media Recycle Bin performed by user", 0, Constants.System.RecycleBinMedia);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -695,7 +695,7 @@ namespace Umbraco.Core.Services
|
||||
IQuery<IMember> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter));
|
||||
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter) || x.Email.Contains(filter));
|
||||
}
|
||||
|
||||
var repository = RepositoryFactory.CreateMemberRepository(uow);
|
||||
|
||||
@@ -1748,9 +1748,10 @@ namespace Umbraco.Core.Services
|
||||
|
||||
internal InstallationSummary InstallPackage(string packageFilePath, int userId = 0, bool raiseEvents = false)
|
||||
{
|
||||
var metaData = GetPackageMetaData(packageFilePath);
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
var metaData = GetPackageMetaData(packageFilePath);
|
||||
{
|
||||
if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs<string>(packageFilePath, metaData), this))
|
||||
{
|
||||
var initEmpty = new InstallationSummary().InitEmpty();
|
||||
@@ -1762,7 +1763,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, false), this);
|
||||
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, metaData, false), this);
|
||||
}
|
||||
|
||||
return installationSummary;
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Umbraco.Core.Strings
|
||||
{
|
||||
foreach (var node in _umbracoSettings.RequestHandler.CharCollection)
|
||||
{
|
||||
if(string.IsNullOrEmpty(node.Char) == false)
|
||||
if (string.IsNullOrEmpty(node.Char) == false)
|
||||
_urlReplaceCharacters[node.Char] = node.Replacement;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ namespace Umbraco.Core.Strings
|
||||
private void EnsureNotFrozen()
|
||||
{
|
||||
if (_frozen)
|
||||
throw new InvalidOperationException("Cannot configure the helper once it is frozen.");
|
||||
throw new InvalidOperationException("Cannot configure the helper once it is frozen.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -176,7 +176,7 @@ namespace Umbraco.Core.Strings
|
||||
}).WithConfig(CleanStringType.Alias, new Config
|
||||
{
|
||||
PreFilter = ApplyUrlReplaceCharacters,
|
||||
IsTerm = (c, leading) => leading
|
||||
IsTerm = (c, leading) => leading
|
||||
? char.IsLetter(c) // only letters
|
||||
: (char.IsLetterOrDigit(c) || c == '_'), // letter, digit or underscore
|
||||
StringType = CleanStringType.Ascii | CleanStringType.UmbracoCase,
|
||||
@@ -215,12 +215,12 @@ namespace Umbraco.Core.Strings
|
||||
return new Config
|
||||
{
|
||||
PreFilter = PreFilter,
|
||||
PostFilter = PostFilter,
|
||||
PostFilter = PostFilter,
|
||||
IsTerm = IsTerm,
|
||||
StringType = StringType,
|
||||
BreakTermsOnUpper = BreakTermsOnUpper,
|
||||
CutAcronymOnNonUpper = CutAcronymOnNonUpper,
|
||||
GreedyAcronyms = GreedyAcronyms,
|
||||
CutAcronymOnNonUpper = CutAcronymOnNonUpper,
|
||||
GreedyAcronyms = GreedyAcronyms,
|
||||
Separator = Separator
|
||||
};
|
||||
}
|
||||
@@ -338,9 +338,9 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Gets the JavaScript code defining client-side short string services.
|
||||
/// </summary>
|
||||
public string GetShortStringServicesJavaScript(string controllerPath)
|
||||
{
|
||||
return string.Format(SssjsFormat,
|
||||
_umbracoSettings.Content.ForceSafeAliases ? "true" : "false", controllerPath);
|
||||
{
|
||||
return string.Format(SssjsFormat,
|
||||
_umbracoSettings.Content.ForceSafeAliases ? "true" : "false", controllerPath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -467,7 +467,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <returns>The clean string.</returns>
|
||||
/// <remarks>The string is cleaned in the context of the default culture.</remarks>
|
||||
@@ -480,7 +480,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string, using a specified separator.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <returns>The clean string.</returns>
|
||||
@@ -494,7 +494,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string in the context of a specified culture.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <param name="culture">The culture.</param>
|
||||
/// <returns>The clean string.</returns>
|
||||
@@ -507,7 +507,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// Cleans a string in the context of a specified culture, using a specified separator.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to clean.</param>
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// <param name="stringType">A flag indicating the target casing and encoding of the string. By default,
|
||||
/// strings are cleaned up to camelCase and Ascii.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <param name="culture">The culture.</param>
|
||||
@@ -554,7 +554,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
text = Utf8ToAsciiConverter.ToAsciiString(text);
|
||||
break;
|
||||
case CleanStringType.TryAscii:
|
||||
const char ESC = (char) 27;
|
||||
const char ESC = (char)27;
|
||||
var ctext = Utf8ToAsciiConverter.ToAsciiString(text, ESC);
|
||||
if (ctext.Contains(ESC) == false) text = ctext;
|
||||
break;
|
||||
@@ -568,8 +568,8 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
|
||||
// apply post-filter
|
||||
if (config.PostFilter != null)
|
||||
text = config.PostFilter(text);
|
||||
|
||||
text = config.PostFilter(text);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -839,7 +839,7 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
{
|
||||
term = term.Substring(i);
|
||||
term.CopyTo(0, output, opos, term.Length);
|
||||
opos += term.Length;
|
||||
opos += term.Length;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -914,21 +914,22 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// <returns>The filtered string.</returns>
|
||||
public virtual string ReplaceMany(string text, IDictionary<string, string> replacements)
|
||||
{
|
||||
// be safe
|
||||
if (text == null)
|
||||
{
|
||||
throw new ArgumentNullException("text");
|
||||
}
|
||||
|
||||
if (replacements == null)
|
||||
{
|
||||
throw new ArgumentNullException("replacements");
|
||||
}
|
||||
|
||||
// Have done various tests, implementing my own "super fast" state machine to handle
|
||||
// replacement of many items, or via regexes, but on short strings and not too
|
||||
// many replacements (which prob. is going to be our case) nothing can beat this...
|
||||
// (at least with safe and checked code -- we don't want unsafe/unchecked here)
|
||||
foreach (KeyValuePair<string, string> item in replacements)
|
||||
{
|
||||
text = text.Replace(item.Key, item.Value);
|
||||
}
|
||||
|
||||
// Note that it will do chained-replacements ie replaced items can be replaced
|
||||
// in turn by another replacement (ie the order of replacements is important)
|
||||
|
||||
return replacements.Aggregate(text, (current, kvp) => current.Replace(kvp.Key, kvp.Value));
|
||||
return text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -940,15 +941,22 @@ function validateSafeAlias(input, value, immediate, callback) {{
|
||||
/// <returns>The filtered string.</returns>
|
||||
public virtual string ReplaceMany(string text, char[] chars, char replacement)
|
||||
{
|
||||
// be safe
|
||||
if (text == null)
|
||||
{
|
||||
throw new ArgumentNullException("text");
|
||||
}
|
||||
|
||||
if (chars == null)
|
||||
{
|
||||
throw new ArgumentNullException("chars");
|
||||
}
|
||||
|
||||
// see note above
|
||||
for (int i = 0; i < chars.Length; i++)
|
||||
{
|
||||
text = text.Replace(chars[i], replacement);
|
||||
}
|
||||
|
||||
return chars.Aggregate(text, (current, c) => current.Replace(c, replacement));
|
||||
return text;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Sync
|
||||
if (newApplicationUrl)
|
||||
{
|
||||
appContext._umbracoApplicationDomains.Add(applicationUrl);
|
||||
LogHelper.Info(typeof(ApplicationUrlHelper), $"New ApplicationUrl detected: {applicationUrl}");
|
||||
LogHelper.Info(typeof(ApplicationUrlHelper), string.Format("New ApplicationUrl detected: {0}", applicationUrl));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,4 +169,4 @@ namespace Umbraco.Core.Sync
|
||||
return url.TrimEnd('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.6\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
@@ -349,6 +349,7 @@
|
||||
<Compile Include="Deploy\Direction.cs" />
|
||||
<Compile Include="Deploy\IFileType.cs" />
|
||||
<Compile Include="Deploy\IFileTypeCollection.cs" />
|
||||
<Compile Include="DisposableObjectSlim.cs" />
|
||||
<Compile Include="EmailSender.cs" />
|
||||
<Compile Include="Events\EventDefinitionFilter.cs" />
|
||||
<Compile Include="Events\IDeletingMediaFilesEventArgs.cs" />
|
||||
@@ -1546,6 +1547,7 @@
|
||||
<Compile Include="ReadLock.cs" />
|
||||
<Compile Include="TypeFinder.cs" />
|
||||
<Compile Include="TypeHelper.cs" />
|
||||
<Compile Include="Collections\CompositeTypeTypeKey.cs" />
|
||||
<Compile Include="Udi.cs" />
|
||||
<Compile Include="UdiDefinitionAttribute.cs" />
|
||||
<Compile Include="UdiEntityType.cs" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.9.2" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.9.6" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.6" targetFramework="net45" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net45" />
|
||||
|
||||
@@ -3,43 +3,24 @@ using System.Collections.Generic;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.IO;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using ILogger = Umbraco.Core.Logging.ILogger;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class BulkInsertBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
//Add(ExecutionValidator.FailOnError);
|
||||
|
||||
//The 'quick and dirty' settings, so it runs a little quicker
|
||||
// see benchmarkdotnet FAQ
|
||||
Add(Job.Default
|
||||
.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(100) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] _initDbBytes = null;
|
||||
|
||||
[Setup]
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
var logger = new DebugDiagnosticsLogger();
|
||||
@@ -51,8 +32,8 @@ namespace Umbraco.Tests.Benchmarks
|
||||
SetupSqlCe(path, logger);
|
||||
SetupSqlServer(logger);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void SetupSqlServer(ILogger logger)
|
||||
{
|
||||
@@ -75,7 +56,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
[lastNotifiedDate] [datetime] NOT NULL,
|
||||
[isActive] [bit] NOT NULL,
|
||||
[isMaster] [bit] NOT NULL,
|
||||
CONSTRAINT [PK_umbracoServer] PRIMARY KEY CLUSTERED
|
||||
CONSTRAINT [PK_umbracoServer] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[id] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
|
||||
@@ -87,7 +68,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var dbName = string.Concat("Umb", Guid.NewGuid(), ".sdf");
|
||||
AppDomain.CurrentDomain.SetData("DataDirectory", path);
|
||||
var sqlCeConnectionString = $"Datasource=|DataDirectory|\\{dbName};Flush Interval=1;";
|
||||
|
||||
|
||||
_dbFile = Path.Combine(path, dbName);
|
||||
|
||||
//only create the db one time
|
||||
@@ -107,12 +88,12 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var creation = new DatabaseSchemaCreation(_dbSqlCe, logger, _sqlCeSyntax);
|
||||
creation.InitializeDatabaseSchema();
|
||||
}
|
||||
_initDbBytes = File.ReadAllBytes(_dbFile);
|
||||
_initDbBytes = File.ReadAllBytes(_dbFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.WriteAllBytes(_dbFile, _initDbBytes);
|
||||
}
|
||||
}
|
||||
|
||||
//create the db
|
||||
_dbSqlCe = new UmbracoDatabase(
|
||||
@@ -138,7 +119,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
return data;
|
||||
}
|
||||
|
||||
[Cleanup]
|
||||
[GlobalCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
_dbSqlCe.Dispose();
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Collections;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
public class ConcurrentDictionaryBenchmarks
|
||||
{
|
||||
private static readonly ConcurrentDictionary<CompositeTypeTypeKey, bool> AssignableTypeCache = new ConcurrentDictionary<CompositeTypeTypeKey, bool>();
|
||||
|
||||
private static object input = new Bar();
|
||||
|
||||
private static Type source = typeof(Bar);
|
||||
|
||||
private static Type target = typeof(Foo);
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public bool GetCachedCanAssignFactory()
|
||||
{
|
||||
return AssignableTypeCache.GetOrAdd(new CompositeTypeTypeKey(source, target), k =>
|
||||
{
|
||||
var ksource = k.Type1;
|
||||
var ktarget = k.Type2;
|
||||
|
||||
return ktarget.IsAssignableFrom(ksource) && typeof(IConvertible).IsAssignableFrom(ksource);
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public bool GetCachedCanAssignNoFactory()
|
||||
{
|
||||
// This method is 10% faster
|
||||
var key = new CompositeTypeTypeKey(source, target);
|
||||
bool canConvert;
|
||||
if (AssignableTypeCache.TryGetValue(key, out canConvert))
|
||||
{
|
||||
return canConvert;
|
||||
}
|
||||
|
||||
// "is" is faster than "IsAssignableFrom"
|
||||
if (input is IConvertible && target.IsAssignableFrom(source))
|
||||
{
|
||||
return AssignableTypeCache[key] = true;
|
||||
}
|
||||
|
||||
return AssignableTypeCache[key] = false;
|
||||
}
|
||||
|
||||
private class Foo : IConvertible
|
||||
{
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return TypeCode.Object;
|
||||
}
|
||||
|
||||
public bool ToBoolean(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public byte ToByte(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public char ToChar(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public DateTime ToDateTime(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public decimal ToDecimal(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public double ToDouble(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public short ToInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int ToInt32(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public long ToInt64(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public sbyte ToSByte(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public float ToSingle(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object ToType(Type conversionType, IFormatProvider provider)
|
||||
{
|
||||
if (conversionType == typeof(Foo))
|
||||
{
|
||||
return new Foo();
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ushort ToUInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public uint ToUInt32(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ulong ToUInt64(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class Bar : Foo
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Horology;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the benchmark to run with less warmup and a shorter iteration time than the standard benchmark.
|
||||
/// </summary>
|
||||
public class QuickRunConfigAttribute : Attribute, IConfigSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuickRunConfigAttribute"/> class.
|
||||
/// </summary>
|
||||
public QuickRunConfigAttribute()
|
||||
{
|
||||
Config = (ManualConfig) ManualConfig.CreateEmpty()
|
||||
.With(Job.Default.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(new TimeInterval(100, TimeUnit.Millisecond)) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the manual configuration.
|
||||
/// </summary>
|
||||
protected ManualConfig Config { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
IConfig IConfigSource.Config => Config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks.Config
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the benchmark to run with less warmup and a shorter iteration time than the standard benchmark,
|
||||
/// and include memory usage diagnosis.
|
||||
/// </summary>
|
||||
public class QuickRunWithMemoryDiagnoserConfigAttribute : QuickRunConfigAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuickRunWithMemoryDiagnoserConfigAttribute"/> class.
|
||||
/// </summary>
|
||||
public QuickRunWithMemoryDiagnoserConfigAttribute()
|
||||
{
|
||||
Config.Add(new MemoryDiagnoser());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
/// <summary>
|
||||
/// Want to check what is faster OfType or Cast when a enurable all has the same items
|
||||
/// </summary>
|
||||
[Config(typeof(Config))]
|
||||
[MemoryDiagnoser]
|
||||
public class LinqCastBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
}
|
||||
}
|
||||
|
||||
public LinqCastBenchmarks()
|
||||
{
|
||||
_array = new List<object>();
|
||||
|
||||
@@ -1,47 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Columns;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Loggers;
|
||||
using BenchmarkDotNet.Reports;
|
||||
using BenchmarkDotNet.Running;
|
||||
using BenchmarkDotNet.Validators;
|
||||
using Moq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using ILogger = Umbraco.Core.Logging.ILogger;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[MemoryDiagnoser]
|
||||
public class ModelToSqlExpressionHelperBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
}
|
||||
}
|
||||
|
||||
public ModelToSqlExpressionHelperBenchmarks()
|
||||
{
|
||||
var contentMapper = new ContentMapper(_syntaxProvider);
|
||||
@@ -51,7 +23,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
mappingResolver.Setup(resolver => resolver.ResolveMapperByType(It.IsAny<Type>())).Returns(contentMapper);
|
||||
_mappingResolver = mappingResolver.Object;
|
||||
}
|
||||
|
||||
|
||||
private readonly ISqlSyntaxProvider _syntaxProvider = new SqlCeSyntaxProvider();
|
||||
private readonly CachedExpression _cachedExpression;
|
||||
private readonly MappingResolver _mappingResolver;
|
||||
@@ -62,18 +34,15 @@ namespace Umbraco.Tests.Benchmarks
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
var a = i;
|
||||
var b = i*10;
|
||||
var b = i * 10;
|
||||
Expression<Func<IContent, bool>> predicate = content =>
|
||||
content.Path.StartsWith("-1") && content.Published && (content.ContentTypeId == a || content.ContentTypeId == b);
|
||||
|
||||
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _mappingResolver);
|
||||
var result = modelToSqlExpressionHelper.Visit(predicate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Benchmark()]
|
||||
public void WithCachedExpression()
|
||||
{
|
||||
@@ -83,7 +52,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var b = i * 10;
|
||||
Expression<Func<IContent, bool>> predicate = content =>
|
||||
content.Path.StartsWith("-1") && content.Published && (content.ContentTypeId == a || content.ContentTypeId == b);
|
||||
|
||||
|
||||
var modelToSqlExpressionHelper = new ModelToSqlExpressionVisitor<IContent>(_syntaxProvider, _mappingResolver);
|
||||
|
||||
//wrap it!
|
||||
@@ -92,6 +61,5 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var result = modelToSqlExpressionHelper.Visit(_cachedExpression);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var switcher = new BenchmarkSwitcher(new[]
|
||||
{
|
||||
typeof(BulkInsertBenchmarks),
|
||||
typeof(ModelToSqlExpressionHelperBenchmarks),
|
||||
typeof(XmlBenchmarks),
|
||||
typeof(LinqCastBenchmarks),
|
||||
//typeof(DeepCloneBenchmarks),
|
||||
typeof(XmlPublishedContentInitBenchmarks),
|
||||
|
||||
});
|
||||
switcher.Run(args);
|
||||
new BenchmarkSwitcher(typeof(Program).Assembly).Run(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class StringReplaceManyBenchmarks
|
||||
{
|
||||
/*
|
||||
|
||||
short text, short replacement:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |---------:|----------:|----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 236.0 ns | 40.92 ns | 2.312 ns | 1.00 | 0.00 | 0.0461 | 200 B |
|
||||
'String.ReplaceMany w/chars - For Loop' | 166.7 ns | 70.51 ns | 3.984 ns | 0.71 | 0.01 | 0.0420 | 180 B |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 606.5 ns | 342.94 ns | 19.377 ns | 2.57 | 0.07 | 0.0473 | 212 B |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 571.8 ns | 232.33 ns | 13.127 ns | 2.42 | 0.05 | 0.0458 | 212 B |
|
||||
|
||||
long text, short replacement:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |----------:|----------:|----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 5.771 us | 9.963 us | 0.5630 us | 1.00 | 0.00 | 1.6798 | 6.94 KB |
|
||||
'String.ReplaceMany w/chars - For Loop' | 4.962 us | 2.121 us | 0.1199 us | 0.87 | 0.08 | 1.6840 | 6.92 KB |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 14.514 us | 8.189 us | 0.4627 us | 2.53 | 0.22 | 1.6447 | 6.96 KB |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 15.445 us | 24.745 us | 1.3981 us | 2.69 | 0.30 | 1.5696 | 6.96 KB |
|
||||
|
||||
short text, long replacements dictionary:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 257.0 ns | 200.0 ns | 11.30 ns | 1.00 | 0.00 | 0.0452 | 200 B |
|
||||
'String.ReplaceMany w/chars - For Loop' | 182.4 ns | 221.0 ns | 12.49 ns | 0.71 | 0.05 | 0.0425 | 180 B |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 7,273.8 ns | 2,747.1 ns | 155.22 ns | 28.34 | 1.12 | 0.0714 | 464 B |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 6,981.0 ns | 5,500.7 ns | 310.80 ns | 27.20 | 1.38 | 0.0775 | 464 B |
|
||||
|
||||
long text, long replacements dictionary:
|
||||
|
||||
Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
|
||||
--------------------------------------------- |-----------:|-----------:|-----------:|-------:|---------:|-------:|----------:|
|
||||
'String.ReplaceMany w/chars - Aggregate' | 4.868 us | 3.420 us | 0.1932 us | 1.00 | 0.00 | 1.6816 | 6.94 KB |
|
||||
'String.ReplaceMany w/chars - For Loop' | 4.958 us | 2.633 us | 0.1487 us | 1.02 | 0.04 | 1.6791 | 6.92 KB |
|
||||
'String.ReplaceMany w/dictionary - Aggregate' | 181.309 us | 210.177 us | 11.8754 us | 37.29 | 2.32 | 5.3571 | 24.28 KB |
|
||||
'String.ReplaceMany w/dictionary - For Each' | 174.567 us | 113.733 us | 6.4262 us | 35.90 | 1.57 | 5.8594 | 24.28 KB |
|
||||
|
||||
*/
|
||||
|
||||
// don't use constants
|
||||
// ReSharper disable ConvertToConstant.Local
|
||||
|
||||
// input text for ReplaceMany
|
||||
private static readonly string Text;
|
||||
|
||||
// replaced chars for ReplaceMany with chars
|
||||
private static readonly char[] ReplacedChars = { ',', '.', ':', '&', '#' };
|
||||
|
||||
// replacement char for ReplaceMany with chars
|
||||
private static readonly char ReplacementChar = '*';
|
||||
|
||||
// replacements for ReplaceMany with dictionary
|
||||
private static readonly IDictionary<string, string> Replacements;
|
||||
|
||||
// ReSharper restore ConvertToConstant.Local
|
||||
|
||||
static StringReplaceManyBenchmarks()
|
||||
{
|
||||
// pick what you want to benchmark
|
||||
|
||||
// short
|
||||
Text = "1,2.3:4&5#6";
|
||||
|
||||
// long
|
||||
//Text = "Sed ut perspiciatis unde omnis iste natus &error sit voluptatem accusantium doloremque l:audantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et &quasi architecto beatae vitae ::dicta sunt explicabo. Nemo enim ipsam volupta:tem quia voluptas sit aspernatur aut o&dit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciun&t. Neque porro quisquam est, qui dolorem: ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut e:nim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi co&&nsequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse: quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?";
|
||||
|
||||
// short
|
||||
Replacements = new Dictionary<string, string>
|
||||
{
|
||||
{ ",", "*" },
|
||||
{ ".", "*" },
|
||||
{ ":", "*" },
|
||||
{ "&", "*" },
|
||||
{ "#", "*" },
|
||||
};
|
||||
|
||||
// long
|
||||
//Replacements = new Dictionary<string, string>();
|
||||
//for (var i = 2; i < 100; i++)
|
||||
// Replacements[Convert.ToChar(i).ToString()] = "*";
|
||||
}
|
||||
|
||||
// this is what v7 originally did
|
||||
[Benchmark(Description = "String.ReplaceMany w/chars - Aggregate", Baseline = true)]
|
||||
public string ReplaceManyAggregate()
|
||||
{
|
||||
var result = Text;
|
||||
return ReplacedChars.Aggregate(result, (current, c) => current.Replace(c, ReplacementChar));
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String.ReplaceMany w/chars - For Loop")]
|
||||
public string ReplaceManyForLoop()
|
||||
{
|
||||
var result = Text;
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
// ReSharper disable once ForCanBeConvertedToForeach
|
||||
for (var i = 0; i < ReplacedChars.Length; i++)
|
||||
{
|
||||
result = result.Replace(ReplacedChars[i], ReplacementChar);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// this is what v7 originally did
|
||||
[Benchmark(Description = "String.ReplaceMany w/dictionary - Aggregate")]
|
||||
public string ReplaceManyDictionaryAggregate()
|
||||
{
|
||||
return Replacements.Aggregate(Text, (current, kvp) => current.Replace(kvp.Key, kvp.Value));
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String.ReplaceMany w/dictionary - For Each")]
|
||||
public string ReplaceManyDictionaryForEach()
|
||||
{
|
||||
var result = Text;
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var item in Replacements)
|
||||
{
|
||||
result = result.Replace(item.Key, item.Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
public class TryConvertToBenchmarks
|
||||
{
|
||||
private static readonly List<string> List = new List<string>() { "hello", "world", "awesome" };
|
||||
private static readonly string Date = "Saturday 10, November 2012";
|
||||
|
||||
[Benchmark(Description = "List<string> to IEnumerable<string>")]
|
||||
public IEnumerable<string> TryConvertToEnumerable()
|
||||
{
|
||||
return List.TryConvertTo<IEnumerable<string>>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "Int to Double")]
|
||||
public double TryConvertToDouble()
|
||||
{
|
||||
return 1.TryConvertTo<double>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "Float to Decimal")]
|
||||
public decimal TryConvertToDecimal()
|
||||
{
|
||||
return 1F.TryConvertTo<decimal>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String to Boolean")]
|
||||
public bool TryConvertToBoolean()
|
||||
{
|
||||
return "1".TryConvertTo<bool>().Result;
|
||||
}
|
||||
|
||||
[Benchmark(Description = "String to DateTime")]
|
||||
public DateTime TryConvertToDateTime()
|
||||
{
|
||||
return Date.TryConvertTo<DateTime>().Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,12 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Umbraco.Tests.Benchmarks</RootNamespace>
|
||||
<AssemblyName>Umbraco.Tests.Benchmarks</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -38,38 +39,55 @@
|
||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BenchmarkDotNet, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.0.9.9\lib\net45\BenchmarkDotNet.dll</HintPath>
|
||||
<Reference Include="BenchmarkDotNet, Version=0.10.12.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.0.10.12\lib\net46\BenchmarkDotNet.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Core, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Core.0.9.9\lib\net45\BenchmarkDotNet.Core.dll</HintPath>
|
||||
<Reference Include="BenchmarkDotNet.Core, Version=0.10.12.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Core.0.10.12\lib\net46\BenchmarkDotNet.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Diagnostics.Windows, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Diagnostics.Windows.0.9.9\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Toolchains.Roslyn, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
|
||||
<Reference Include="BenchmarkDotNet.Toolchains.Roslyn, Version=0.10.12.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.10.12\lib\net46\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
|
||||
<Reference Include="Microsoft.CodeAnalysis, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.2.4.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=1.0.41.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.DotNet.InternalAbstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.DotNet.InternalAbstractions.1.0.0\lib\net451\Microsoft.DotNet.InternalAbstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.DotNet.PlatformAbstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.DotNet.PlatformAbstractions.1.1.1\lib\net451\Microsoft.DotNet.PlatformAbstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Win32.Registry, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Win32.Registry.4.3.0\lib\net46\Microsoft.Win32.Registry.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.1.1309.919, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
|
||||
<Reference Include="System.AppContext, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
@@ -77,13 +95,52 @@
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Diagnostics.FileVersionInfo, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Diagnostics.StackTrace, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
|
||||
<Reference Include="System.Reflection.Metadata, Version=1.4.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.4.2\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net46\System.Security.Cryptography.Algorithms.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net46\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Encoding.CodePages, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.3.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Thread, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
@@ -91,20 +148,38 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XmlDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XPath, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XPath.XDocument, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ConcurrentDictionaryBenchmarks.cs" />
|
||||
<Compile Include="Config\QuickRunConfigAttribute.cs" />
|
||||
<Compile Include="Config\QuickRunWithMemoryDiagnoserConfigAttribute.cs" />
|
||||
<Compile Include="LinqCastBenchmarks.cs" />
|
||||
<Compile Include="ModelToSqlExpressionHelperBenchmarks.cs" />
|
||||
<Compile Include="BulkInsertBenchmarks.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="StringReplaceManyBenchmarks.cs" />
|
||||
<Compile Include="TryConvertToBenchmarks.cs" />
|
||||
<Compile Include="XmlBenchmarks.cs" />
|
||||
<Compile Include="XmlPublishedContentInitBenchmarks.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="_TraceEventProgrammersGuide.docx" />
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
@@ -120,10 +195,6 @@
|
||||
<Name>Umbraco.Web</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="TraceEvent.ReadMe.txt" />
|
||||
<Content Include="TraceEvent.ReleaseNotes.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
|
||||
@@ -1,42 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class XmlBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
//Add(ExecutionValidator.FailOnError);
|
||||
|
||||
//The 'quick and dirty' settings, so it runs a little quicker
|
||||
// see benchmarkdotnet FAQ
|
||||
Add(Job.Default
|
||||
.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(100) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
}
|
||||
|
||||
[Setup]
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
var templateId = 0;
|
||||
var xmlText = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<!DOCTYPE root[
|
||||
<!DOCTYPE root[
|
||||
<!ELEMENT Home ANY>
|
||||
<!ATTLIST Home id ID #REQUIRED>
|
||||
<!ELEMENT CustomDocument ANY>
|
||||
@@ -49,7 +26,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
<umbracoNaviHide>1</umbracoNaviHide>
|
||||
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
|
||||
<content><![CDATA[<div>This is some content</div>]]></content>
|
||||
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
|
||||
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
|
||||
<Home id=""1174"" parentID=""1173"" level=""3"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""2"" createDate=""2012-07-20T18:07:54"" updateDate=""2012-07-20T19:10:27"" nodeName=""Sub2"" urlName=""sub2"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173,1174"" isDoc="""">
|
||||
<content><![CDATA[]]></content>
|
||||
<umbracoUrlAlias><![CDATA[only/one/alias]]></umbracoUrlAlias>
|
||||
@@ -70,7 +47,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
_xml.LoadXml(xmlText);
|
||||
}
|
||||
|
||||
[Cleanup]
|
||||
[GlobalCleanup]
|
||||
public void Cleanup()
|
||||
{
|
||||
_xml = null;
|
||||
@@ -90,7 +67,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
public void XmlWithNavigation()
|
||||
{
|
||||
var elt = _xml.DocumentElement;
|
||||
var id = NavigateElementRoute(elt, new[] {"home", "sub1", "sub2"});
|
||||
var id = NavigateElementRoute(elt, new[] { "home", "sub1", "sub2" });
|
||||
if (id <= 0) Console.WriteLine("ERR");
|
||||
}
|
||||
|
||||
@@ -120,4 +97,4 @@ namespace Umbraco.Tests.Benchmarks
|
||||
return found ? int.Parse(elt.GetAttribute("id")) : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,37 +3,17 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnostics.Windows;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Tests.Benchmarks.Config;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
|
||||
namespace Umbraco.Tests.Benchmarks
|
||||
{
|
||||
[Config(typeof(Config))]
|
||||
[QuickRunWithMemoryDiagnoserConfig]
|
||||
public class XmlPublishedContentInitBenchmarks
|
||||
{
|
||||
private class Config : ManualConfig
|
||||
{
|
||||
public Config()
|
||||
{
|
||||
Add(new MemoryDiagnoser());
|
||||
|
||||
//The 'quick and dirty' settings, so it runs a little quicker
|
||||
// see benchmarkdotnet FAQ
|
||||
Add(Job.Default
|
||||
.WithLaunchCount(1) // benchmark process will be launched only once
|
||||
.WithIterationTime(100) // 100ms per iteration
|
||||
.WithWarmupCount(3) // 3 warmup iteration
|
||||
.WithTargetCount(3)); // 3 target iteration
|
||||
}
|
||||
}
|
||||
|
||||
public XmlPublishedContentInitBenchmarks()
|
||||
{
|
||||
_xml10 = Build(10);
|
||||
@@ -281,7 +261,7 @@ namespace Umbraco.Tests.Benchmarks
|
||||
var nodes = xmlNode.SelectNodes(dataXPath);
|
||||
|
||||
contentType = GetPublishedContentType(PublishedItemType.Content, docTypeAlias);
|
||||
|
||||
|
||||
var propertyNodes = new Dictionary<string, XmlNode>();
|
||||
if (nodes != null)
|
||||
foreach (XmlNode n in nodes)
|
||||
@@ -307,8 +287,8 @@ namespace Umbraco.Tests.Benchmarks
|
||||
|
||||
private static PublishedContentType GetPublishedContentType(PublishedItemType type, string alias)
|
||||
{
|
||||
return new PublishedContentType(alias, new string[] {},
|
||||
new List<PublishedPropertyType>(Enumerable.Range(0, 10).Select(x => new PublishedPropertyType("prop" + x, 0, "test", initConverters:false))));
|
||||
return new PublishedContentType(alias, new string[] { },
|
||||
new List<PublishedPropertyType>(Enumerable.Range(0, 10).Select(x => new PublishedPropertyType("prop" + x, 0, "test", initConverters: false))));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Data.SqlServerCe" publicKeyToken="89845dcd8080cc91" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
|
||||
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" />
|
||||
</dependentAssembly>
|
||||
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
@@ -27,6 +30,10 @@
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
@@ -36,45 +43,25 @@
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
<assemblyIdentity name="BenchmarkDotNet.Core" publicKeyToken="aa0ca2f9092cefc4" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-0.10.12.0" newVersion="0.10.12.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
<assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
<assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.2.0.0" newVersion="1.2.0.0" />
|
||||
<assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0" />
|
||||
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
</configuration>
|
||||
@@ -1,40 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="BenchmarkDotNet" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet.Core" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet" version="0.10.12" targetFramework="net46" />
|
||||
<package id="BenchmarkDotNet.Core" version="0.10.12" targetFramework="net46" />
|
||||
<package id="BenchmarkDotNet.Diagnostics.Windows" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet.Toolchains.Roslyn" version="0.9.9" targetFramework="net45" />
|
||||
<package id="BenchmarkDotNet.Toolchains.Roslyn" version="0.10.12" targetFramework="net46" />
|
||||
<package id="Castle.Core" version="4.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.Common" version="1.3.2" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.CSharp" version="1.3.2" targetFramework="net45" />
|
||||
<package id="Microsoft.CodeAnalysis.Common" version="2.4.0" targetFramework="net46" />
|
||||
<package id="Microsoft.CodeAnalysis.CSharp" version="2.4.0" targetFramework="net46" />
|
||||
<package id="Microsoft.Diagnostics.Tracing.TraceEvent" version="1.0.41" targetFramework="net45" />
|
||||
<package id="Microsoft.DotNet.InternalAbstractions" version="1.0.0" targetFramework="net46" />
|
||||
<package id="Microsoft.DotNet.PlatformAbstractions" version="1.1.1" targetFramework="net46" />
|
||||
<package id="Microsoft.SqlServer.Compact" version="4.0.8854.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Win32.Registry" version="4.3.0" targetFramework="net46" />
|
||||
<package id="Moq" version="4.1.1309.0919" targetFramework="net45" />
|
||||
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
|
||||
<package id="System.Collections" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Collections.Concurrent" version="4.0.12" targetFramework="net45" />
|
||||
<package id="System.Collections.Immutable" version="1.2.0" targetFramework="net45" />
|
||||
<package id="System.Diagnostics.Debug" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Diagnostics.Tools" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Dynamic.Runtime" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Globalization" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Linq" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Linq.Expressions" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Reflection" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Reflection.Metadata" version="1.3.0" targetFramework="net45" />
|
||||
<package id="System.AppContext" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Collections" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Collections.Immutable" version="1.3.1" targetFramework="net46" />
|
||||
<package id="System.Console" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Globalization" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Linq" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Reflection" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Reflection.Metadata" version="1.4.2" targetFramework="net46" />
|
||||
<package id="System.Reflection.Primitives" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Resources.ResourceManager" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Runtime" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Runtime.Extensions" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Runtime.InteropServices" version="4.1.0" targetFramework="net45" />
|
||||
<package id="System.Runtime.Numerics" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Text.Encoding" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Threading" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Threading.Tasks" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.0.0" targetFramework="net45" />
|
||||
<package id="System.Threading.Tasks.Parallel" version="4.0.1" targetFramework="net45" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="net45" />
|
||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Threading.Thread" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.ValueTuple" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XmlSerializer" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XPath" version="4.3.0" targetFramework="net46" />
|
||||
<package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net46" />
|
||||
</packages>
|
||||
@@ -6,6 +6,10 @@ using System.Threading;
|
||||
using System.Web.UI.WebControls;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests
|
||||
{
|
||||
@@ -155,16 +159,151 @@ namespace Umbraco.Tests
|
||||
Assert.AreEqual("Hello world", result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Test]
|
||||
public virtual void CanConvertObjectToSameObject()
|
||||
{
|
||||
var obj = new MyTestObject();
|
||||
var result = obj.TryConvertTo<object>();
|
||||
|
||||
Assert.AreEqual(obj, result.Result);
|
||||
Assert.AreEqual(obj, result.Result);
|
||||
}
|
||||
|
||||
private CultureInfo savedCulture;
|
||||
|
||||
[Test]
|
||||
public void ConvertToIntegerTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = "100.001".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = 100.001m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDecimalTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.001".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.001m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToNullableDecimalTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.001".TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.001m.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100.TryConvertTo<decimal?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDateTimeTest()
|
||||
{
|
||||
var conv = "2016-06-07".TryConvertTo<DateTime?>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToNullableDateTimeTest()
|
||||
{
|
||||
var conv = "2016-06-07".TryConvertTo<DateTime>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Value_Editor_Can_Convert_Decimal_To_Decimal_Clr_Type()
|
||||
{
|
||||
var valueEditor = new PropertyValueEditor
|
||||
{
|
||||
ValueType = PropertyEditorValueTypes.Decimal
|
||||
};
|
||||
|
||||
var result = valueEditor.TryConvertValueToCrlType(12.34d);
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(12.34d, result.Result);
|
||||
}
|
||||
|
||||
private CultureInfo _savedCulture;
|
||||
|
||||
/// <summary>
|
||||
/// Run once before each test in derived test fixtures.
|
||||
@@ -172,10 +311,13 @@ namespace Umbraco.Tests
|
||||
[SetUp]
|
||||
public void TestSetup()
|
||||
{
|
||||
savedCulture = Thread.CurrentThread.CurrentCulture;
|
||||
_savedCulture = Thread.CurrentThread.CurrentCulture;
|
||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); // make sure the dates parse correctly
|
||||
return;
|
||||
}
|
||||
|
||||
var settings = SettingsForTests.GetDefault();
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig());
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run once after each test in derived test fixtures.
|
||||
@@ -183,9 +325,9 @@ namespace Umbraco.Tests
|
||||
[TearDown]
|
||||
public void TestTearDown()
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = savedCulture;
|
||||
return;
|
||||
}
|
||||
Thread.CurrentThread.CurrentCulture = _savedCulture;
|
||||
ShortStringHelperResolver.Reset();
|
||||
}
|
||||
|
||||
private class MyTestObject
|
||||
{
|
||||
@@ -195,4 +337,4 @@ namespace Umbraco.Tests
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,6 +332,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var contentType = (IContentType)MockedContentTypes.CreateSimpleContentType2("test", "Test", propertyGroupName: "testGroup");
|
||||
|
||||
Assert.AreEqual(4, contentType.PropertyTypes.Count());
|
||||
|
||||
// remove all templates - since they are not saved, they would break the (wtf) mapping code
|
||||
contentType.AllowedTemplates = new ITemplate[0];
|
||||
|
||||
// there is NO mapping from display to contentType, but only from save
|
||||
// to contentType, so if we want to test, let's to it properly!
|
||||
|
||||
@@ -24,7 +24,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
[TestCase("Alpha (10)", "Alpha (2)", +1)] // this is the real stuff
|
||||
[TestCase("Kilo", "Golf (2)", +1)]
|
||||
[TestCase("Kilo (1)", "Golf (2)", +1)]
|
||||
public void ComparerTest(string name1, string name2, int expected)
|
||||
[TestCase("", "", 0)]
|
||||
[TestCase(null, null, 0)]
|
||||
public void ComparerTest(string name1, string name2, int expected)
|
||||
{
|
||||
var comparer = new SimilarNodeName.Comparer();
|
||||
|
||||
@@ -76,7 +78,9 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
[TestCase(0, "Alpha", "Alpha (3)")]
|
||||
[TestCase(0, "Kilo (1)", "Kilo (1) (1)")] // though... we might consider "Kilo (2)"
|
||||
[TestCase(6, "Kilo (1)", "Kilo (1)")] // because of the id
|
||||
public void Test(int nodeId, string nodeName, string expected)
|
||||
[TestCase(0, "", " (1)")]
|
||||
[TestCase(0, null, " (1)")]
|
||||
public void Test(int nodeId, string nodeName, string expected)
|
||||
{
|
||||
var names = new[]
|
||||
{
|
||||
|
||||
@@ -286,7 +286,7 @@ AnotherContentFinder
|
||||
{
|
||||
var trees = _manager.ResolveAttributedTrees();
|
||||
// commit 6c5e35ec2cbfa31be6790d1228e0c2faf5f55bc8 brings the count down to 14
|
||||
Assert.AreEqual(8, trees.Count());
|
||||
Assert.AreEqual(6, trees.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropData_Properties_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
var index = 0;
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropFocalPoint_Properties_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
Assert.AreEqual(sourceObj.FocalPoint.Left, d.FocalPoint.Left);
|
||||
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropDataSet_Properties_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
Assert.AreEqual(sourceObj.Src, d.Src);
|
||||
@@ -91,7 +91,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void ImageCropDataSet_Methods_As_Dynamic()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
dynamic d = sourceObj;
|
||||
|
||||
Assert.AreEqual(sourceObj.HasCrop("thumb"), d.HasCrop("thumb"));
|
||||
@@ -108,7 +108,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
public void CanConvertImageCropperDataSetSrcToString()
|
||||
{
|
||||
//cropperJson3 - has not crops
|
||||
var sourceObj = cropperJson3.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson3.DeserializeToCropDataSet();
|
||||
var destObj = sourceObj.TryConvertTo<string>();
|
||||
Assert.IsTrue(destObj.Success);
|
||||
Assert.AreEqual(destObj.Result, "/media/1005/img_0672.jpg");
|
||||
@@ -118,7 +118,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
public void CanConvertImageCropperDataSetJObject()
|
||||
{
|
||||
//cropperJson3 - has not crops
|
||||
var sourceObj = cropperJson3.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson3.DeserializeToCropDataSet();
|
||||
var destObj = sourceObj.TryConvertTo<JObject>();
|
||||
Assert.IsTrue(destObj.Success);
|
||||
Assert.AreEqual(sourceObj, destObj.Result.ToObject<ImageCropDataSet>());
|
||||
@@ -127,7 +127,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void CanConvertImageCropperDataSetJsonToString()
|
||||
{
|
||||
var sourceObj = cropperJson1.SerializeToCropDataSet();
|
||||
var sourceObj = cropperJson1.DeserializeToCropDataSet();
|
||||
var destObj = sourceObj.TryConvertTo<string>();
|
||||
Assert.IsTrue(destObj.Success);
|
||||
Assert.IsTrue(destObj.Result.DetectIsJson());
|
||||
@@ -150,7 +150,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
var converter = new Umbraco.Web.PropertyEditors.ValueConverters.ImageCropperValueConverter(dataTypeService.Object);
|
||||
var result = converter.ConvertDataToSource(new PublishedPropertyType("test", 0, "test"), val1, false); // does not use type for conversion
|
||||
|
||||
var resultShouldMatch = val2.SerializeToCropDataSet();
|
||||
var resultShouldMatch = val2.DeserializeToCropDataSet();
|
||||
if (expected)
|
||||
{
|
||||
Assert.AreEqual(resultShouldMatch, result);
|
||||
@@ -220,7 +220,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
[Test]
|
||||
public void GetBaseCropUrlFromModelTest()
|
||||
{
|
||||
var cropDataSet = cropperJson1.SerializeToCropDataSet();
|
||||
var cropDataSet = cropperJson1.DeserializeToCropDataSet();
|
||||
var urlString = cropDataSet.GetCropUrl("thumb");
|
||||
Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
|
||||
}
|
||||
|
||||
@@ -548,7 +548,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
runner.Shutdown(false, true);
|
||||
|
||||
// check that task has been disposed (timer has been killed, etc)
|
||||
Assert.IsTrue(task.IsDisposed);
|
||||
Assert.IsTrue(task.Disposed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -533,6 +533,16 @@ namespace Umbraco.Tests.Services
|
||||
Assert.AreEqual(mediaObjectType, UmbracoObjectTypes.MediaType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Key_For_Id_With_Unknown_Type()
|
||||
{
|
||||
var service = ServiceContext.EntityService;
|
||||
var result = service.GetKeyForId(1060, UmbracoObjectTypes.Unknown);
|
||||
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Key_For_Id()
|
||||
{
|
||||
@@ -554,6 +564,16 @@ namespace Umbraco.Tests.Services
|
||||
Assert.IsFalse(result2.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Id_For_Key_With_Unknown_Type()
|
||||
{
|
||||
var service = ServiceContext.EntityService;
|
||||
var result = service.GetIdForKey(Guid.Parse("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522"), UmbracoObjectTypes.Unknown);
|
||||
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual(1060, result.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EntityService_Can_Get_Id_For_Key()
|
||||
{
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TryConvertToTests
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
var settings = SettingsForTests.GetDefault();
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(settings).WithDefaultConfig());
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
ShortStringHelperResolver.Reset();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToIntegerTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = "100.001".TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
|
||||
// oops
|
||||
conv = 100.001m.TryConvertTo<int>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDecimalTest()
|
||||
{
|
||||
var conv = "100".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100,000".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = "100.001".TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.000m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
|
||||
conv = 100.001m.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100.001m, conv.Result);
|
||||
|
||||
conv = 100.TryConvertTo<decimal>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(100m, conv.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToDateTimeTest()
|
||||
{
|
||||
var conv = "2016-06-07".TryConvertTo<DateTime>();
|
||||
Assert.IsTrue(conv);
|
||||
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +232,6 @@
|
||||
<Compile Include="Services\CachedDataTypeServiceTests.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedPropertyTypes.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedUserGroup.cs" />
|
||||
<Compile Include="TryConvertToTests.cs" />
|
||||
<Compile Include="UdiTests.cs" />
|
||||
<Compile Include="UmbracoExamine\RandomIdRAMDirectory.cs" />
|
||||
<Compile Include="UmbracoExamine\UmbracoContentIndexerTests.cs" />
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
"moment": "~2.10.3",
|
||||
"ace-builds": "^1.2.3",
|
||||
"clipboard": "1.7.1",
|
||||
"font-awesome": "~4.2",
|
||||
"angular-moment": "^1.0.1"
|
||||
"font-awesome": "~4.2"
|
||||
},
|
||||
"install": {
|
||||
"path": "lib-bower",
|
||||
@@ -60,9 +59,6 @@
|
||||
"bower_components/angular-local-storage/dist/angular-local-storage.min.js",
|
||||
"bower_components/angular-local-storage/dist/angular-local-storage.min.js.map"
|
||||
],
|
||||
"angular-moment": [
|
||||
"bower_components/angular-moment/angular-moment.min.js"
|
||||
],
|
||||
"tinymce": [
|
||||
"bower_components/tinymce/tinymce.min.js"
|
||||
],
|
||||
@@ -73,8 +69,5 @@
|
||||
"jquery-migrate": "bower_components/jquery-migrate/jquery-migrate.min.js",
|
||||
"clipboard": "bower_components/clipboard/dist/clipboard.min.js"
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"moment": ">=2.19.3 <3.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,27 +84,21 @@
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.trimStart) {
|
||||
|
||||
/** trims the start of the string*/
|
||||
String.prototype.trimStart = function (str) {
|
||||
if (this.startsWith(str)) {
|
||||
return this.substring(str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.trimEnd) {
|
||||
/** trims the start of the string*/
|
||||
String.prototype.trimStart = function (str) {
|
||||
if (this.startsWith(str)) {
|
||||
return this.substring(str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/** trims the end of the string*/
|
||||
String.prototype.trimEnd = function (str) {
|
||||
if (this.endsWith(str)) {
|
||||
return this.substring(0, this.length - str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
/** trims the end of the string*/
|
||||
String.prototype.trimEnd = function (str) {
|
||||
if (this.endsWith(str)) {
|
||||
return this.substring(0, this.length - str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
if (!String.prototype.utf8Encode) {
|
||||
|
||||
@@ -332,4 +326,4 @@
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -11,8 +11,7 @@ var app = angular.module('umbraco', [
|
||||
'ngMobile',
|
||||
'tmh.dynamicLocale',
|
||||
'ngFileUpload',
|
||||
'LocalStorageModule',
|
||||
'angularMoment'
|
||||
'LocalStorageModule'
|
||||
]);
|
||||
|
||||
var packages = angular.module("umbraco.packages", []);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 440 KiB After Width: | Height: | Size: 386 KiB |
+185
@@ -1,3 +1,188 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTour
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco 7.8</b>. The tour component is a global component and is already added to the umbraco markup.
|
||||
In the Umbraco UI the tours live in the "Help drawer" which opens when you click the Help-icon in the bottom left corner of Umbraco.
|
||||
You can easily add you own tours to the Help-drawer or show and start tours from
|
||||
anywhere in the Umbraco backoffice. To see a real world example of a custom tour implementation, install <a href="https://our.umbraco.org/projects/starter-kits/the-starter-kit/">The Starter Kit</a> in Umbraco 7.8
|
||||
|
||||
<h1><b>Extending the help drawer with custom tours</b></h1>
|
||||
The easiet way to add new tours to Umbraco is through the Help-drawer. All it requires is a my-tour.json file.
|
||||
Place the file in <i>App_Plugins/{MyPackage}/backoffice/tours/{my-tour}.json</i> and it will automatically be
|
||||
picked up by Umbraco and shown in the Help-drawer.
|
||||
|
||||
<h3><b>The tour object</b></h3>
|
||||
The tour object consist of two parts - The overall tour configuration and a list of tour steps. We have split up the tour object for a better overview.
|
||||
<pre>
|
||||
// The tour config object
|
||||
{
|
||||
"name": "My Custom Tour", // (required)
|
||||
"alias": "myCustomTour", // A unique tour alias (required)
|
||||
"group": "My Custom Group" // Used to group tours in the help drawer
|
||||
"groupOrder": 200 // Control the order of tour groups
|
||||
"allowDisable": // Adds a "Don't" show this tour again"-button to the intro step
|
||||
"requiredSections":["content", "media", "mySection"] // Sections that the tour will access while running, if the user does not have access to the required tour sections, the tour will not load.
|
||||
"steps": [] // tour steps - see next example
|
||||
}
|
||||
</pre>
|
||||
<pre>
|
||||
// A tour step object
|
||||
{
|
||||
"title": "Title",
|
||||
"content": "<p>Step content</p>",
|
||||
"type": "intro" // makes the step an introduction step,
|
||||
"element": "[data-element='my-table-row']", // the highlighted element
|
||||
"event": "click" // forces the user to click the UI to go to next step
|
||||
"eventElement": "[data-element='my-table-row'] [data-element='my-tour-button']" // specify an element to click inside a highlighted element
|
||||
"elementPreventClick": false // prevents user interaction in the highlighted element
|
||||
"backdropOpacity": 0.4 // the backdrop opacity
|
||||
"view": "" // add a custom view
|
||||
"customProperties" : {} // add any custom properties needed for the custom view
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h1><b>Adding tours to other parts of the Umbraco backoffice</b></h1>
|
||||
It is also possible to add a list of custom tours to other parts of the Umbraco backoffice,
|
||||
as an example on a Dashboard in a Custom section. You can then use the {@link umbraco.services.tourService tourService} to start and stop tours but you don't have to register them as part of the tour service.
|
||||
|
||||
<h1><b>Using the tour service</b></h1>
|
||||
<h3>Markup example - show custom tour</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.TourController as vm">
|
||||
|
||||
<div>{{vm.tour.name}}</div>
|
||||
<button type="button" ng-click="vm.startTour()">Start tour</button>
|
||||
|
||||
<!-- This button will be clicked in the tour -->
|
||||
<button data-element="my-tour-button" type="button">Click me</button>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example - show custom tour</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function TourController(tourService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.tour = {
|
||||
"name": "My Custom Tour",
|
||||
"alias": "myCustomTour",
|
||||
"steps": [
|
||||
{
|
||||
"title": "Welcome to My Custom Tour",
|
||||
"content": "",
|
||||
"type": "intro"
|
||||
},
|
||||
{
|
||||
"element": "[data-element='my-tour-button']",
|
||||
"title": "Click the button",
|
||||
"content": "Click the button",
|
||||
"event": "click"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
vm.startTour = startTour;
|
||||
|
||||
function startTour() {
|
||||
tourService.startTour(vm.tour);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("My.TourController", TourController);
|
||||
|
||||
})();
|
||||
</pre>
|
||||
|
||||
<h1><b>Custom step views</b></h1>
|
||||
In some cases you will need a custom view for one of your tour steps.
|
||||
This could be for validation or for running any other custom logic for that step.
|
||||
We have added a couple of helper components to make it easier to get the step scaffolding to look like a regular tour step.
|
||||
In the following example you see how to run some custom logic before a step goes to the next step.
|
||||
|
||||
<h3>Markup example - custom step view</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.TourStep as vm">
|
||||
|
||||
<umb-tour-step on-close="model.endTour()">
|
||||
|
||||
<umb-tour-step-header
|
||||
title="model.currentStep.title">
|
||||
</umb-tour-step-header>
|
||||
|
||||
<umb-tour-step-content
|
||||
content="model.currentStep.content">
|
||||
|
||||
<!-- Add any custom content here -->
|
||||
|
||||
</umb-tour-step-content>
|
||||
|
||||
<umb-tour-step-footer class="flex justify-between items-center">
|
||||
|
||||
<umb-tour-step-counter
|
||||
current-step="model.currentStepIndex + 1"
|
||||
total-steps="model.steps.length">
|
||||
</umb-tour-step-counter>
|
||||
|
||||
<div>
|
||||
<umb-button
|
||||
size="xs"
|
||||
button-style="success"
|
||||
type="button"
|
||||
action="vm.initNextStep()"
|
||||
label="Next">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
</umb-tour-step-footer>
|
||||
|
||||
</umb-tour-step>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example - custom step view</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function StepController() {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.initNextStep = initNextStep;
|
||||
|
||||
function initNextStep() {
|
||||
// run logic here before going to the next step
|
||||
$scope.model.nextStep();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("My.TourStep", StepController);
|
||||
|
||||
})();
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Related services</h3>
|
||||
<ul>
|
||||
<li>{@link umbraco.services.tourService tourService}</li>
|
||||
</ul>
|
||||
|
||||
@param {string} model (<code>binding</code>): Tour object
|
||||
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
}
|
||||
|
||||
function createButtons(content) {
|
||||
$scope.page.buttonGroupState = "init";
|
||||
var buttons = contentEditingHelper.configureContentEditorButtons({
|
||||
create: $scope.page.isNew,
|
||||
content: content,
|
||||
@@ -214,6 +215,8 @@
|
||||
|
||||
$scope.page.buttonGroupState = "success";
|
||||
|
||||
}, function(err) {
|
||||
$scope.page.buttonGroupState = 'error';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+35
-24
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService) {
|
||||
function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService, dateHelper) {
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
// get current backoffice user and format dates
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
angular.forEach(data.items, function(item) {
|
||||
item.timestampFormatted = getLocalDate(item.timestamp, currentUser.locale, 'LLL');
|
||||
item.timestampFormatted = dateHelper.getLocalDate(item.timestamp, currentUser.locale, 'LLL');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -149,8 +149,17 @@
|
||||
|
||||
function setPublishDate(date) {
|
||||
|
||||
if (!date) {
|
||||
return;
|
||||
}
|
||||
|
||||
//The date being passed in here is the user's local date/time that they have selected
|
||||
//we need to convert this date back to the server date on the model.
|
||||
|
||||
var serverTime = dateHelper.convertToServerStringTime(moment(date), Umbraco.Sys.ServerVariables.application.serverTimeOffset);
|
||||
|
||||
// update publish value
|
||||
scope.node.releaseDate = date;
|
||||
scope.node.releaseDate = serverTime;
|
||||
|
||||
// make sure dates are formatted to the user's locale
|
||||
formatDatesToLocal();
|
||||
@@ -174,8 +183,17 @@
|
||||
|
||||
function setUnpublishDate(date) {
|
||||
|
||||
if (!date) {
|
||||
return;
|
||||
}
|
||||
|
||||
//The date being passed in here is the user's local date/time that they have selected
|
||||
//we need to convert this date back to the server date on the model.
|
||||
|
||||
var serverTime = dateHelper.convertToServerStringTime(moment(date), Umbraco.Sys.ServerVariables.application.serverTimeOffset);
|
||||
|
||||
// update publish value
|
||||
scope.node.removeDate = date;
|
||||
scope.node.removeDate = serverTime;
|
||||
|
||||
// make sure dates are formatted to the user's locale
|
||||
formatDatesToLocal();
|
||||
@@ -199,31 +217,24 @@
|
||||
|
||||
function ucfirst(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
function getLocalDate(date, culture, format) {
|
||||
if (date) {
|
||||
var dateVal;
|
||||
var serverOffset = Umbraco.Sys.ServerVariables.application.serverTimeOffset;
|
||||
var localOffset = new Date().getTimezoneOffset();
|
||||
var serverTimeNeedsOffsetting = -serverOffset !== localOffset;
|
||||
if (serverTimeNeedsOffsetting) {
|
||||
dateVal = dateHelper.convertToLocalMomentTime(date, serverOffset);
|
||||
} else {
|
||||
dateVal = moment(date, 'YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
return dateVal.locale(culture).format(format);
|
||||
}
|
||||
}
|
||||
|
||||
function formatDatesToLocal() {
|
||||
// get current backoffice user and format dates
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
scope.node.createDateFormatted = getLocalDate(scope.node.createDate, currentUser.locale, 'LLL');
|
||||
scope.node.releaseDateMonth = scope.node.releaseDate ? ucfirst(getLocalDate(scope.node.releaseDate, currentUser.locale, 'MMMM')) : null;
|
||||
scope.node.releaseDateDay = scope.node.releaseDate ? ucfirst(getLocalDate(scope.node.releaseDate, currentUser.locale, 'dddd')) : null;
|
||||
scope.node.removeDateMonth = scope.node.removeDate ? ucfirst(getLocalDate(scope.node.removeDate, currentUser.locale, 'MMMM')) : null;
|
||||
scope.node.removeDateDay = scope.node.removeDate ? ucfirst(getLocalDate(scope.node.removeDate, currentUser.locale, 'dddd')) : null;
|
||||
scope.node.createDateFormatted = dateHelper.getLocalDate(scope.node.createDate, currentUser.locale, 'LLL');
|
||||
|
||||
scope.node.releaseDateYear = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'YYYY')) : null;
|
||||
scope.node.releaseDateMonth = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'MMMM')) : null;
|
||||
scope.node.releaseDateDayNumber = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'DD')) : null;
|
||||
scope.node.releaseDateDay = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'dddd')) : null;
|
||||
scope.node.releaseDateTime = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'HH:mm')) : null;
|
||||
|
||||
scope.node.removeDateYear = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'YYYY')) : null;
|
||||
scope.node.removeDateMonth = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'MMMM')) : null;
|
||||
scope.node.removeDateDayNumber = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'DD')) : null;
|
||||
scope.node.removeDateDay = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'dddd')) : null;
|
||||
scope.node.removeDateTime = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'HH:mm')) : null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+26
-4
@@ -1,20 +1,28 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MediaNodeInfoDirective($timeout, $location) {
|
||||
function MediaNodeInfoDirective($timeout, $location, eventsService, userService, dateHelper) {
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
var evts = [];
|
||||
|
||||
function onInit() {
|
||||
|
||||
scope.allowOpenMediaType = true;
|
||||
|
||||
// get document type details
|
||||
scope.mediaType = scope.node.contentType;
|
||||
|
||||
// get node url
|
||||
scope.nodeUrl = scope.node.mediaLink;
|
||||
// make sure dates are formatted to the user's locale
|
||||
formatDatesToLocal();
|
||||
}
|
||||
|
||||
function formatDatesToLocal() {
|
||||
// get current backoffice user and format dates
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
scope.node.createDateFormatted = dateHelper.getLocalDate(scope.node.createDate, currentUser.locale, 'LLL');
|
||||
scope.node.updateDateFormatted = dateHelper.getLocalDate(scope.node.updateDate, currentUser.locale, 'LLL');
|
||||
});
|
||||
}
|
||||
|
||||
scope.openMediaType = function (mediaType) {
|
||||
@@ -22,6 +30,20 @@
|
||||
var url = "/settings/mediaTypes/edit/" + mediaType.id;
|
||||
$location.path(url);
|
||||
};
|
||||
|
||||
// watch for content updates - reload content when node is saved, published etc.
|
||||
scope.$watch('node.updateDate', function(newValue, oldValue){
|
||||
if(!newValue) { return; }
|
||||
if(newValue === oldValue) { return; }
|
||||
formatDatesToLocal();
|
||||
});
|
||||
|
||||
//ensure to unregister from all events!
|
||||
scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
onInit();
|
||||
|
||||
|
||||
+6
-1
@@ -9,9 +9,14 @@ function noDirtyCheck() {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
|
||||
elm.focus(function () {
|
||||
ctrl.$pristine = false;
|
||||
scope.$watch(function() {
|
||||
ctrl.$pristine = false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* Registers all tours from the server and returns a promise
|
||||
*/
|
||||
function registerAllTours() {
|
||||
tours = [];
|
||||
return tourResource.getTours().then(function(tourFiles) {
|
||||
angular.forEach(tourFiles, function (tourFile) {
|
||||
angular.forEach(tourFile.tours, function(newTour) {
|
||||
@@ -29,80 +30,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.tourService#registerTour
|
||||
* @methodOf umbraco.services.tourService
|
||||
*
|
||||
* @description
|
||||
* Registers a tour in the service
|
||||
* @param {Object} tour The tour you want to register in the service
|
||||
* @param {String} tour.name The tour name
|
||||
* @param {String} tour.alias The tour alias
|
||||
* @param {Array} tour.steps Array of tour steps
|
||||
* @param {String} tour.step.title Step title
|
||||
* @param {DomElement} tour.step.content Step content (pass in any HTML markup)
|
||||
* @param {DomElement} tour.step.element Highlight a DOM-element
|
||||
* @param {Boolean} tour.step.elementPreventClick Adds invisible layer on top of highligted element to prevent all clicks and interaction with it
|
||||
* @param {Number} tour.step.backdropOpacity Sets the backdrop opacity (default 0.4)
|
||||
*/
|
||||
function registerTour(newTour) {
|
||||
validateTour(newTour);
|
||||
validateTourRegistration(newTour);
|
||||
tours.push(newTour);
|
||||
eventsService.emit("appState.tour.updatedTours", tours);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.tourService#registerTours
|
||||
* @methodOf umbraco.services.tourService
|
||||
*
|
||||
* @description
|
||||
* Registers an array of tours in the service
|
||||
* @param {Array} tours The tours to register in the service
|
||||
*/
|
||||
function registerTours(newTours) {
|
||||
angular.forEach(newTours, function(newTour){
|
||||
validateTour(newTour);
|
||||
validateTourRegistration(newTour);
|
||||
tours.push(newTour);
|
||||
});
|
||||
eventsService.emit("appState.tour.updatedTours", tours);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.tourService#unregisterTour
|
||||
* @methodOf umbraco.services.tourService
|
||||
*
|
||||
* @description
|
||||
* Unregisters a tour in the service
|
||||
* @param {String} tourAlias The tour alias of the tour you want to unregister
|
||||
*/
|
||||
function unregisterTour(tourAlias) {
|
||||
tours = tours.filter(function( obj ) {
|
||||
return obj.alias !== tourAlias;
|
||||
});
|
||||
eventsService.emit("appState.tour.updatedTours", tours);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.tourService#unregisterTourGroup
|
||||
* @methodOf umbraco.services.tourService
|
||||
*
|
||||
* @description
|
||||
* Unregisters a tour in the service
|
||||
* @param {String} tourGroupName The name of the tour group you want to unregister
|
||||
*/
|
||||
function unregisterTourGroup(tourGroup) {
|
||||
tours = tours.filter(function( obj ) {
|
||||
return obj.group !== tourGroup;
|
||||
});
|
||||
eventsService.emit("appState.tour.updatedTours", tours);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to return all of the tours as a new instance
|
||||
*/
|
||||
@@ -117,8 +44,8 @@
|
||||
*
|
||||
* @description
|
||||
* Raises an event to start a tour
|
||||
* @param {Object} tour The tour which should be started
|
||||
*/
|
||||
* @param {Object} tour The tour which should be started
|
||||
*/
|
||||
function startTour(tour) {
|
||||
validateTour(tour);
|
||||
eventsService.emit("appState.tour.start", tour);
|
||||
@@ -132,7 +59,7 @@
|
||||
*
|
||||
* @description
|
||||
* Raises an event to end the current tour
|
||||
*/
|
||||
*/
|
||||
function endTour(tour) {
|
||||
eventsService.emit("appState.tour.end", tour);
|
||||
currentTour = null;
|
||||
@@ -163,7 +90,7 @@
|
||||
* @description
|
||||
* Completes a tour for the user, raises an event and returns a promise
|
||||
* @param {Object} tour The tour which should be completed
|
||||
*/
|
||||
*/
|
||||
function completeTour(tour) {
|
||||
var deferred = $q.defer();
|
||||
tour.completed = true;
|
||||
@@ -185,26 +112,12 @@
|
||||
* @description
|
||||
* Returns the current tour
|
||||
* @returns {Object} Returns the current tour
|
||||
*/
|
||||
*/
|
||||
function getCurrentTour() {
|
||||
//TODO: This should be reset if a new user logs in
|
||||
return currentTour;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.tourService#getAllTours
|
||||
* @methodOf umbraco.services.tourService
|
||||
*
|
||||
* @description
|
||||
* Returns a promise of all tours with the current user statuses
|
||||
* @returns {Array} All registered tours
|
||||
*/
|
||||
function getAllTours() {
|
||||
var tours = getTours();
|
||||
return setTourStatuses(tours);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.tourService#getGroupedTours
|
||||
@@ -213,12 +126,43 @@
|
||||
* @description
|
||||
* Returns a promise of grouped tours with the current user statuses
|
||||
* @returns {Array} All registered tours grouped by tour group
|
||||
*/
|
||||
*/
|
||||
function getGroupedTours() {
|
||||
var deferred = $q.defer();
|
||||
var tours = getTours();
|
||||
setTourStatuses(tours).then(function() {
|
||||
var groupedTours = _.groupBy(tours, "group");
|
||||
var groupedTours = [];
|
||||
tours.forEach(function (item) {
|
||||
|
||||
var groupExists = false;
|
||||
var newGroup = {
|
||||
"group": "",
|
||||
"tours": []
|
||||
};
|
||||
|
||||
groupedTours.forEach(function(group){
|
||||
// extend existing group if it is already added
|
||||
if(group.group === item.group) {
|
||||
if(item.groupOrder) {
|
||||
group.groupOrder = item.groupOrder
|
||||
}
|
||||
groupExists = true;
|
||||
group.tours.push(item)
|
||||
}
|
||||
});
|
||||
|
||||
// push new group to array if it doesn't exist
|
||||
if(!groupExists) {
|
||||
newGroup.group = item.group;
|
||||
if(item.groupOrder) {
|
||||
newGroup.groupOrder = item.groupOrder
|
||||
}
|
||||
newGroup.tours.push(item);
|
||||
groupedTours.push(newGroup);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
deferred.resolve(groupedTours);
|
||||
});
|
||||
return deferred.promise;
|
||||
@@ -233,7 +177,7 @@
|
||||
* Returns a promise of the tour found by alias with the current user statuses
|
||||
* @param {Object} tourAlias The tour alias of the tour which should be returned
|
||||
* @returns {Object} Tour object
|
||||
*/
|
||||
*/
|
||||
function getTourByAlias(tourAlias) {
|
||||
var deferred = $q.defer();
|
||||
var tours = getTours();
|
||||
@@ -244,38 +188,6 @@
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.tourService#getCompletedTours
|
||||
* @methodOf umbraco.services.tourService
|
||||
*
|
||||
* @description
|
||||
* Returns a promise of completed tours for the user
|
||||
* @returns {Array} Array of completed tour aliases
|
||||
*/
|
||||
function getCompletedTours() {
|
||||
var deferred = $q.defer();
|
||||
currentUserResource.getTours().then(function (storedTours) {
|
||||
var completedTours = _.where(storedTours, { completed: true });
|
||||
var aliases = _.pluck(completedTours, "alias");
|
||||
deferred.resolve(aliases);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise of disabled tours for the user
|
||||
*/
|
||||
function getDisabledTours() {
|
||||
var deferred = $q.defer();
|
||||
currentUserResource.getTours().then(function (storedTours) {
|
||||
var disabledTours = _.where(storedTours, { disabled: true });
|
||||
var aliases = _.pluck(disabledTours, "alias");
|
||||
deferred.resolve(aliases);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
///////////
|
||||
|
||||
/**
|
||||
@@ -300,6 +212,9 @@
|
||||
throw "Tour " + tour.alias + " is missing tour steps";
|
||||
}
|
||||
|
||||
if (tour.requiredSections.length === 0) {
|
||||
throw "Tour " + tour.alias + " is missing the required sections";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,59 +261,15 @@
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function saveInLocalStorage(tour) {
|
||||
var storedTours = [];
|
||||
var tourFound = false;
|
||||
|
||||
// check if something exists in local storage
|
||||
if (localStorageService.get(localStorageKey)) {
|
||||
storedTours = localStorageService.get(localStorageKey);
|
||||
}
|
||||
|
||||
// update existing tour in localstorage if it's already there
|
||||
if (storedTours.length > 0) {
|
||||
angular.forEach(storedTours, function (storedTour) {
|
||||
if (storedTour.alias === tour.alias) {
|
||||
storedTour.completed = storedTour.completed ? storedTour.completed : tour.completed;
|
||||
storedTour.disabled = storedTour.disabled ? storedTour.disabled : tour.disabled;
|
||||
tourFound = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// create new entry in local storage
|
||||
if (!tourFound) {
|
||||
var storageObject = {
|
||||
"alias": tour.alias,
|
||||
"completed": tour.completed,
|
||||
"disabled": tour.disabled
|
||||
};
|
||||
storedTours.push(storageObject);
|
||||
}
|
||||
|
||||
localStorageService.set(localStorageKey, storedTours);
|
||||
|
||||
}
|
||||
|
||||
var service = {
|
||||
registerAllTours: registerAllTours,
|
||||
registerTour: registerTour,
|
||||
registerTours: registerTours,
|
||||
unregisterTour: unregisterTour,
|
||||
unregisterTourGroup: unregisterTourGroup,
|
||||
startTour: startTour,
|
||||
endTour: endTour,
|
||||
disableTour: disableTour,
|
||||
completeTour: completeTour,
|
||||
getCurrentTour: getCurrentTour,
|
||||
//TODO: Not used
|
||||
getAllTours: getAllTours,
|
||||
getGroupedTours: getGroupedTours,
|
||||
getTourByAlias: getTourByAlias,
|
||||
//TODO: Not used
|
||||
getCompletedTours: getCompletedTours,
|
||||
//TODO: Not used
|
||||
getDisabledTours: getDisabledTours,
|
||||
getTourByAlias: getTourByAlias
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,6 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
$scope.isSearching = false;
|
||||
$scope.selectedResult = -1;
|
||||
|
||||
|
||||
$scope.navigateResults = function (ev) {
|
||||
//38: up 40: down, 13: enter
|
||||
|
||||
@@ -34,24 +33,37 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var group = undefined;
|
||||
var groupNames = [];
|
||||
var groupIndex = -1;
|
||||
var itemIndex = -1;
|
||||
$scope.selectedItem = undefined;
|
||||
|
||||
|
||||
$scope.clearSearch = function () {
|
||||
$scope.searchTerm = null;
|
||||
};
|
||||
function iterateResults(up) {
|
||||
//default group
|
||||
if (!group) {
|
||||
group = $scope.groups[0];
|
||||
|
||||
for (var g in $scope.groups) {
|
||||
if ($scope.groups.hasOwnProperty(g)) {
|
||||
groupNames.push(g);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//Sorting to match the groups order
|
||||
groupNames.sort();
|
||||
|
||||
group = $scope.groups[groupNames[0]];
|
||||
groupIndex = 0;
|
||||
}
|
||||
|
||||
if (up) {
|
||||
if (itemIndex === 0) {
|
||||
if (groupIndex === 0) {
|
||||
gotoGroup($scope.groups.length - 1, true);
|
||||
gotoGroup(Object.keys($scope.groups).length - 1, true);
|
||||
} else {
|
||||
gotoGroup(groupIndex - 1, true);
|
||||
}
|
||||
@@ -62,7 +74,7 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
if (itemIndex < group.results.length - 1) {
|
||||
gotoItem(itemIndex + 1);
|
||||
} else {
|
||||
if (groupIndex === $scope.groups.length - 1) {
|
||||
if (groupIndex === Object.keys($scope.groups).length - 1) {
|
||||
gotoGroup(0);
|
||||
} else {
|
||||
gotoGroup(groupIndex + 1);
|
||||
@@ -73,7 +85,7 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
|
||||
function gotoGroup(index, up) {
|
||||
groupIndex = index;
|
||||
group = $scope.groups[groupIndex];
|
||||
group = $scope.groups[groupNames[groupIndex]];
|
||||
|
||||
if (up) {
|
||||
gotoItem(group.results.length - 1);
|
||||
@@ -95,6 +107,13 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
$scope.hasResults = false;
|
||||
if ($scope.searchTerm) {
|
||||
if (newVal !== null && newVal !== undefined && newVal !== oldVal) {
|
||||
|
||||
//Resetting for brand new search
|
||||
group = undefined;
|
||||
groupNames = [];
|
||||
groupIndex = -1;
|
||||
itemIndex = -1;
|
||||
|
||||
$scope.isSearching = true;
|
||||
navigationService.showSearch();
|
||||
$scope.selectedItem = undefined;
|
||||
@@ -114,7 +133,7 @@ function SearchController($scope, searchService, $log, $location, navigationServ
|
||||
var filtered = {};
|
||||
_.each(result, function (value, key) {
|
||||
if (value.results.length > 0) {
|
||||
filtered[key] = value;
|
||||
filtered[key] = value;
|
||||
}
|
||||
});
|
||||
$scope.groups = filtered;
|
||||
|
||||
@@ -20,8 +20,17 @@ app.run(['userService', '$log', '$rootScope', '$location', 'queryStrings', 'navi
|
||||
assetsService._loadInitAssets().then(function() {
|
||||
|
||||
//Register all of the tours on the server
|
||||
tourService.registerAllTours().then(function (dashboards) {
|
||||
tourService.registerAllTours().then(function () {
|
||||
appReady(data);
|
||||
|
||||
// Auto start intro tour
|
||||
tourService.getTourByAlias("umbIntroIntroduction").then(function (introTour) {
|
||||
// start intro tour if it hasn't been completed or disabled
|
||||
if (introTour && introTour.disabled !== true && introTour.completed !== true) {
|
||||
tourService.startTour(introTour);
|
||||
}
|
||||
});
|
||||
|
||||
}, function(){
|
||||
appReady(data);
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="email">Email</label>
|
||||
<div class="controls">
|
||||
<input type="email" id="email" name="email" placeholder="you@example.com" required ng-model="installer.current.model.email" val-email />
|
||||
<input type="email" id="email" name="email" placeholder="you@example.com" val-email required ng-model="installer.current.model.email" />
|
||||
<small class="inline-help">Your email will be used as your login</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -240,6 +240,7 @@
|
||||
.umb-tree .umb-tree-node-checked i:before {
|
||||
/*check box*/
|
||||
content: "\e165" !important;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
a.umb-options {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="umb-panel" ng-controller="Umbraco.Dialogs.IconPickerController">
|
||||
<div class="umb-panel-header">
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="form-search">
|
||||
<div class="umb-panel-header">
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
style="width: 100%"
|
||||
@@ -9,50 +9,49 @@
|
||||
class="umb-search-field search-query input-block-level"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
no-dirty-check>
|
||||
no-dirty-check />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body with-footer">
|
||||
<div class="umb-panel-body with-footer">
|
||||
|
||||
<div class="umb-control-group">
|
||||
<select ng-model="color" class="input-block-level">
|
||||
<option value=""><localize key="colors_black">Black</localize></option>
|
||||
<option value="color-green"><localize key="colors_green">Green</localize></option>
|
||||
<option value="color-yellow"><localize key="colors_yellow">Yellow</localize></option>
|
||||
<option value="color-orange"><localize key="colors_orange">Orange</localize></option>
|
||||
<option value="color-blue"><localize key="colors_blue">Blue</localize></option>
|
||||
<option value="color-red"><localize key="colors_red">Red</localize></option>
|
||||
</select>
|
||||
<select ng-model="color" class="input-block-level">
|
||||
<option value=""><localize key="colors_black">Black</localize></option>
|
||||
<option value="color-green"><localize key="colors_green">Green</localize></option>
|
||||
<option value="color-yellow"><localize key="colors_yellow">Yellow</localize></option>
|
||||
<option value="color-orange"><localize key="colors_orange">Orange</localize></option>
|
||||
<option value="color-blue"><localize key="colors_blue">Blue</localize></option>
|
||||
<option value="color-red"><localize key="colors_red">Red</localize></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<umb-load-indicator ng-if="loading"></umb-load-indicator>
|
||||
|
||||
<div class="umb-control-group" ng-show="!loading">
|
||||
<ul class="umb-iconpicker" ng-class="color" ng-show="icons">
|
||||
<li class="umb-iconpicker-item" ng-repeat="icon in filtered = (icons | filter: searchTerm) track by $id(icon)">
|
||||
<a href="#" title="{{icon}}" ng-click="submitClass(icon)" prevent-default>
|
||||
<i class="{{icon}} large"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul class="umb-iconpicker" ng-class="color" ng-show="icons">
|
||||
<li class="umb-iconpicker-item" ng-repeat="icon in filtered = (icons | filter: searchTerm) track by $id(icon)">
|
||||
<a href="#" title="{{icon}}" ng-click="submitClass(icon)" prevent-default>
|
||||
<i class="{{icon}} large"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="filtered.length === 0"
|
||||
position="center">
|
||||
<localize key="defaultdialogs_noIconsFound">No icons were found.</localize>
|
||||
</umb-empty-state>
|
||||
</div>
|
||||
<umb-empty-state ng-if="filtered.length === 0"
|
||||
position="center">
|
||||
<localize key="defaultdialogs_noIconsFound">No icons were found.</localize>
|
||||
</umb-empty-state>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-footer" >
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-panel-footer">
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<form novalidate name="insertMacroForm" ng-submit="submitForm()" ng-controller="Umbraco.Dialogs.InsertMacroController" val-form-manager>
|
||||
<form novalidate name="insertMacroForm" ng-controller="Umbraco.Dialogs.InsertMacroController" val-form-manager>
|
||||
<div class="umb-panel">
|
||||
|
||||
<div class="umb-panel-footer">
|
||||
@@ -6,8 +6,8 @@
|
||||
<a href class="btn btn-link" ng-click="close()">
|
||||
<localize key="cancel" />
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<localize key="buttons_select"/>
|
||||
<button type="button" ng-click="submitForm()" class="btn btn-primary">
|
||||
<localize key="buttons_select" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,22 +61,23 @@
|
||||
|
||||
|
||||
<div class="umb-panel umb-dialogs-mediapicker browser"
|
||||
on-drag-leave="dragLeave()"
|
||||
on-drag-end="dragLeave()"
|
||||
on-drag-enter="dragEnter()"
|
||||
ng-hide="target">
|
||||
on-drag-leave="dragLeave()"
|
||||
on-drag-end="dragLeave()"
|
||||
on-drag-enter="dragEnter()"
|
||||
ng-hide="target">
|
||||
|
||||
|
||||
|
||||
<div class="umb-panel-header">
|
||||
|
||||
<div class="umb-el-wrap umb-panel-buttons umb-mediapicker-upload">
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter">
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
no-dirty-check />
|
||||
</div>
|
||||
|
||||
<div class="upload-button">
|
||||
@@ -97,7 +98,7 @@
|
||||
<li ng-repeat="item in path">
|
||||
<a href ng-click="gotoFolder(item)" prevent-default>{{item.name}}</a> /
|
||||
</li>
|
||||
|
||||
|
||||
<li>
|
||||
<a href ng-hide="showFolderInput" ng-click="showFolderInput = true">
|
||||
<i class="icon icon-add small"></i>
|
||||
@@ -114,28 +115,26 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="umb-panel-body with-footer">
|
||||
|
||||
<umb-file-dropzone
|
||||
ng-if="acceptedMediatypes.length > 0"
|
||||
accepted-mediatypes="acceptedMediatypes"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0}}"
|
||||
parent-id="{{currentFolder.id}}"
|
||||
files-uploaded="onUploadComplete"
|
||||
files-queued="onFilesQueue">
|
||||
|
||||
<umb-file-dropzone ng-if="acceptedMediatypes.length > 0"
|
||||
accepted-mediatypes="acceptedMediatypes"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0}}"
|
||||
parent-id="{{currentFolder.id}}"
|
||||
files-uploaded="onUploadComplete"
|
||||
files-queued="onFilesQueue">
|
||||
</umb-file-dropzone>
|
||||
|
||||
<umb-photo-folder
|
||||
min-height="105"
|
||||
min-width="150"
|
||||
max-height="250"
|
||||
ideal-items-per-row="3"
|
||||
on-click="clickHandler"
|
||||
ng-model="images"
|
||||
images-only="{{onlyImages}}"
|
||||
filter-by="searchTerm" />
|
||||
<umb-photo-folder min-height="105"
|
||||
min-width="150"
|
||||
max-height="250"
|
||||
ideal-items-per-row="3"
|
||||
on-click="clickHandler"
|
||||
ng-model="images"
|
||||
images-only="{{onlyImages}}"
|
||||
filter-by="searchTerm" />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="umb-panel" ng-controller="Umbraco.Dialogs.MemberGroupPickerController">
|
||||
|
||||
|
||||
<div class="umb-panel-body with-footer no-header">
|
||||
|
||||
|
||||
<div>
|
||||
<umb-tree section="member"
|
||||
treealias="memberGroups"
|
||||
@@ -14,21 +14,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-footer" >
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<div class="umb-panel-footer">
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
|
||||
<button class="btn btn-primary"
|
||||
ng-click="submit(dialogData.selection)">
|
||||
<localize key="buttons_select">Select</localize>
|
||||
({{dialogData.selection.length}})
|
||||
</button>
|
||||
<button class="btn btn-primary"
|
||||
ng-click="submit(dialogData.selection)">
|
||||
<localize key="buttons_select">Select</localize>
|
||||
({{dialogData.selection.length}})
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,7 +124,7 @@
|
||||
|
||||
function showTourButton(index, tourGroup) {
|
||||
if(index !== 0) {
|
||||
var prevTour = tourGroup[index - 1];
|
||||
var prevTour = tourGroup.tours[index - 1];
|
||||
if(prevTour.completed) {
|
||||
return true;
|
||||
}
|
||||
@@ -147,12 +147,12 @@
|
||||
// Finding out, how many tours are completed for the progress circle
|
||||
angular.forEach(vm.tours, function(group){
|
||||
var completedTours = 0;
|
||||
angular.forEach(group, function(tour){
|
||||
angular.forEach(group.tours, function(tour){
|
||||
if(tour.completed) {
|
||||
completedTours++;
|
||||
}
|
||||
});
|
||||
group.completedPercentage = Math.round((completedTours/group.length)*100);
|
||||
group.completedPercentage = Math.round((completedTours/group.tours.length)*100);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -12,23 +12,23 @@
|
||||
|
||||
<h5 style="margin-bottom: 10px; margin-top: 0;">Tours</h5>
|
||||
|
||||
<div ng-repeat="(key,value) in vm.tours" style="margin-bottom: 5px;">
|
||||
<div ng-repeat="tourGroup in vm.tours | orderBy:'groupOrder'" style="margin-bottom: 5px;">
|
||||
|
||||
<div class="umb-help-list">
|
||||
|
||||
<a href="" class="umb-help-list-item umb-help-list-item__content flex items-center justify-between" style="text-decoration: none;" ng-click="value.open = !value.open">
|
||||
<h5 class="umb-help-list-item__group-title"><i style="margin-right: 2px;text-decoration: none;" ng-class="{'icon-navigation-right': !value.open, 'icon-navigation-down': value.open}"></i>
|
||||
<span ng-if="key !== 'undefined'">{{key}}</span>
|
||||
<span ng-if="key === 'undefined'">Other</span>
|
||||
<a href="" class="umb-help-list-item umb-help-list-item__content flex items-center justify-between" style="text-decoration: none;" ng-click="tourGroup.open = !tourGroup.open">
|
||||
<h5 class="umb-help-list-item__group-title"><i style="margin-right: 2px;text-decoration: none;" ng-class="{'icon-navigation-right': !tourGroup.open, 'icon-navigation-down': tourGroup.open}"></i>
|
||||
<span ng-if="tourGroup.group !== 'undefined'">{{tourGroup.group}}</span>
|
||||
<span ng-if="tourGroup.group === 'undefined'">Other</span>
|
||||
</h5>
|
||||
<umb-progress-circle
|
||||
percentage="{{value.completedPercentage}}"
|
||||
percentage="{{tourGroup.completedPercentage}}"
|
||||
size="40">
|
||||
</umb-progress-circle>
|
||||
</a>
|
||||
|
||||
<div ng-if="value.open">
|
||||
<div data-element="tour-{{tour.alias}}" class="umb-help-list-item" ng-repeat="tour in value">
|
||||
<div ng-if="tourGroup.open">
|
||||
<div data-element="tour-{{tour.alias}}" class="umb-help-list-item" ng-repeat="tour in tourGroup.tours">
|
||||
<div class="umb-help-list-item__content justify-between">
|
||||
<div class="flex items-center">
|
||||
<div ng-if="!tour.completed" class="umb-number-badge umb-number-badge--xs umb-help-list-item__icon">{{ $index + 1 }}</div>
|
||||
@@ -36,7 +36,7 @@
|
||||
<span ng-class="{'strike': tour.completed}" class="umb-help-list-item__title">{{ tour.name }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<umb-button ng-if="!tour.completed && vm.showTourButton($index, value)" button-style="primary" size="xxs" type="button" label="Start" action="vm.startTour(tour)"></umb-button>
|
||||
<umb-button ng-if="!tour.completed && vm.showTourButton($index, tourGroup)" button-style="primary" size="xxs" type="button" label="Start" action="vm.startTour(tour)"></umb-button>
|
||||
<umb-button ng-if="tour.completed" size="xxs" type="button" label="Rerun" action="vm.startTour(tour)"></umb-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+11
-13
@@ -7,9 +7,10 @@
|
||||
style="width: 100%"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query input-block-level"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus>
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus
|
||||
no-dirty-check />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,20 +18,17 @@
|
||||
<localize key="contentTypeEditor_compositionsDescription"></localize>
|
||||
</div>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes <= 1"
|
||||
position="center">
|
||||
<localize key="contentTypeEditor_noAvailableCompositions"></localize>
|
||||
<umb-empty-state ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes <= 1"
|
||||
position="center">
|
||||
<localize key="contentTypeEditor_noAvailableCompositions"></localize>
|
||||
</umb-empty-state>
|
||||
<umb-empty-state
|
||||
ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes > 1"
|
||||
position="center">
|
||||
<localize key="contentTypeEditor_compositionInUse"></localize>
|
||||
<umb-empty-state ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes > 1"
|
||||
position="center">
|
||||
<localize key="contentTypeEditor_compositionInUse"></localize>
|
||||
</umb-empty-state>
|
||||
|
||||
<ul class="umb-checkbox-list">
|
||||
<li class="umb-checkbox-list__item"
|
||||
|
||||
ng-repeat="compositeContentType in model.availableCompositeContentTypes | filter:searchTerm"
|
||||
ng-class="{'-disabled': compositeContentType.allowed===false || compositeContentType.inherited, '-selected': vm.isSelected(compositeContentType.contentType.alias)}">
|
||||
|
||||
@@ -41,7 +39,7 @@
|
||||
checklist-model="model.compositeContentTypes"
|
||||
checklist-value="compositeContentType.contentType.alias"
|
||||
ng-change="model.selectCompositeContentType(compositeContentType.contentType)"
|
||||
ng-disabled="compositeContentType.allowed===false || compositeContentType.inherited"/>
|
||||
ng-disabled="compositeContentType.allowed===false || compositeContentType.inherited" />
|
||||
</div>
|
||||
|
||||
<label for="umb-overlay-comp-{{compositeContentType.contentType.key}}" class="umb-checkbox-list__item-text" ng-class="{'-faded': compositeContentType.allowed===false}">
|
||||
|
||||
+98
-115
@@ -1,120 +1,103 @@
|
||||
<div class="umb-overlay-body" ng-controller="Umbraco.Overlays.EditorPickerOverlay as vm">
|
||||
|
||||
<!-- FILTER -->
|
||||
<div class="umb-control-group -no-border">
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
style="width: 100%"
|
||||
ng-change="vm.filterItems()"
|
||||
ng-model="vm.searchTerm"
|
||||
class="umb-search-field search-query search-input input-block-level"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
|
||||
|
||||
<!-- TABS -->
|
||||
<div ng-if="vm.showTabs">
|
||||
|
||||
<umb-tabs-nav model="vm.tabs"></umb-tabs-nav>
|
||||
|
||||
<umb-tabs-content>
|
||||
|
||||
<umb-tab id="tab{{tab.id}}" ng-repeat="tab in vm.tabs" rel="{{tab.id}}">
|
||||
|
||||
<div ng-if="tab.alias==='Default'">
|
||||
<div ng-repeat="(key,value) in tab.typesAndEditors">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="systemDataType in value | orderBy:'name'"
|
||||
<!-- FILTER -->
|
||||
<div class="umb-control-group -no-border">
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
style="width: 100%"
|
||||
ng-change="vm.filterItems()"
|
||||
ng-model="vm.searchTerm"
|
||||
class="umb-search-field search-query search-input input-block-level"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus
|
||||
no-dirty-check />
|
||||
</div>
|
||||
</div>
|
||||
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
|
||||
<!-- TABS -->
|
||||
<div ng-if="vm.showTabs">
|
||||
<umb-tabs-nav model="vm.tabs"></umb-tabs-nav>
|
||||
<umb-tabs-content>
|
||||
<umb-tab id="tab{{tab.id}}" ng-repeat="tab in vm.tabs" rel="{{tab.id}}">
|
||||
<div ng-if="tab.alias==='Default'">
|
||||
<div ng-repeat="(key,value) in tab.typesAndEditors">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="systemDataType in value | orderBy:'name'"
|
||||
data-element="editor-{{systemDataType.name}}"
|
||||
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
|
||||
ng-click="vm.pickEditor(systemDataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
|
||||
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
|
||||
{{ systemDataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="tab.alias==='Reuse'">
|
||||
<div ng-repeat="(key,value) in tab.userConfigured">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="dataType in value | orderBy:'name'"
|
||||
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
|
||||
ng-click="vm.pickEditor(systemDataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
|
||||
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
|
||||
{{ systemDataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="tab.alias==='Reuse'">
|
||||
<div ng-repeat="(key,value) in tab.userConfigured">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="dataType in value | orderBy:'name'"
|
||||
data-element="editor-{{dataType.name}}"
|
||||
ng-mouseover="vm.showDetailsOverlay(dataType)"
|
||||
ng-click="vm.pickDataType(dataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
|
||||
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
|
||||
{{ dataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</umb-tab>
|
||||
|
||||
</umb-tabs-content>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- FILTER RESULTS -->
|
||||
<div ng-if="vm.showFilterResult">
|
||||
|
||||
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_reuse"></localize></h5>
|
||||
<div ng-repeat="(key,value) in vm.userConfigured">
|
||||
<div ng-if="(value | filter:vm.searchTerm).length > 0">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="dataType in value | orderBy:'name' | filter: vm.searchTerm"
|
||||
ng-mouseover="vm.showDetailsOverlay(dataType)"
|
||||
ng-click="vm.pickDataType(dataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
|
||||
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
|
||||
{{ dataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_availableEditors"></localize></h5>
|
||||
<div ng-repeat="(key,value) in vm.typesAndEditors">
|
||||
<div ng-if="(value | filter:vm.searchTerm).length > 0">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="systemDataType in value | orderBy:'name' | filter: vm.searchTerm"
|
||||
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
|
||||
ng-click="vm.pickEditor(systemDataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
|
||||
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
|
||||
{{ systemDataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<umb-overlay
|
||||
ng-mouseover="vm.showDetailsOverlay(dataType)"
|
||||
ng-click="vm.pickDataType(dataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
|
||||
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
|
||||
{{ dataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</umb-tab>
|
||||
</umb-tabs-content>
|
||||
</div>
|
||||
<!-- FILTER RESULTS -->
|
||||
<div ng-if="vm.showFilterResult">
|
||||
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_reuse"></localize></h5>
|
||||
<div ng-repeat="(key,value) in vm.userConfigured">
|
||||
<div ng-if="(value | filter:vm.searchTerm).length > 0">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="dataType in value | orderBy:'name' | filter: vm.searchTerm"
|
||||
ng-mouseover="vm.showDetailsOverlay(dataType)"
|
||||
ng-click="vm.pickDataType(dataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
|
||||
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
|
||||
{{ dataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_availableEditors"></localize></h5>
|
||||
<div ng-repeat="(key,value) in vm.typesAndEditors">
|
||||
<div ng-if="(value | filter:vm.searchTerm).length > 0">
|
||||
<h5>{{key}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="systemDataType in value | orderBy:'name' | filter: vm.searchTerm"
|
||||
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
|
||||
ng-click="vm.pickEditor(systemDataType)"
|
||||
class="-four-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
|
||||
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
|
||||
{{ systemDataType.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<umb-overlay ng-if="vm.editorSettingsOverlay.show"
|
||||
data-element="overlay-editor-settings"
|
||||
ng-if="vm.editorSettingsOverlay.show"
|
||||
model="vm.editorSettingsOverlay"
|
||||
position="right"
|
||||
view="vm.editorSettingsOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
model="vm.editorSettingsOverlay"
|
||||
position="right"
|
||||
view="vm.editorSettingsOverlay.view">
|
||||
</umb-overlay>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus
|
||||
no-dirty-check>
|
||||
no-dirty-check />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
<div ng-controller="Umbraco.Overlays.ItemPickerOverlay">
|
||||
|
||||
<div class="form-search" ng-hide="model.filter === false" style="margin-bottom: 15px;">
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query input-block-level -full-width-input"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus />
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query input-block-level -full-width-input"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus
|
||||
no-dirty-check />
|
||||
</div>
|
||||
|
||||
<ul class="umb-card-grid">
|
||||
<li
|
||||
ng-repeat="availableItem in model.availableItems | compareArrays:model.selectedItems:'alias' | orderBy:'name' | filter:searchTerm"
|
||||
ng-click="selectItem(availableItem)"
|
||||
class="-three-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ availableItem.name }}">
|
||||
<i class="{{ availableItem.icon }}"></i>
|
||||
{{ availableItem.name }}
|
||||
</a>
|
||||
</li>
|
||||
<li ng-repeat="availableItem in model.availableItems | compareArrays:model.selectedItems:'alias' | orderBy:'name' | filter:searchTerm"
|
||||
ng-click="selectItem(availableItem)"
|
||||
class="-three-in-row">
|
||||
<a class="umb-card-grid-item" href="" title="{{ availableItem.name }}">
|
||||
<i class="{{ availableItem.icon }}"></i>
|
||||
{{ availableItem.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
class="umb-search-field search-query input-block-level"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus />
|
||||
umb-auto-focus
|
||||
no-dirty-check />
|
||||
</div>
|
||||
|
||||
<ul class="umb-card-grid">
|
||||
@@ -27,9 +28,8 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="nomacros"
|
||||
position="center">
|
||||
<umb-empty-state ng-if="nomacros"
|
||||
position="center">
|
||||
<localize key="defaultdialogs_noMacros">
|
||||
There are no macros available to insert
|
||||
</localize>
|
||||
@@ -52,9 +52,8 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="noMacroParams"
|
||||
position="center">
|
||||
<umb-empty-state ng-if="noMacroParams"
|
||||
position="center">
|
||||
<localize key="defaultdialogs_noMacroParams">There are no parameters for this macro</localize>
|
||||
</umb-empty-state>
|
||||
|
||||
|
||||
+111
-123
@@ -3,159 +3,147 @@
|
||||
enctype="multipart/form-data"
|
||||
umb-image-upload="options">
|
||||
|
||||
<div
|
||||
on-drag-leave="dragLeave()"
|
||||
on-drag-end="dragLeave()"
|
||||
on-drag-enter="dragEnter()">
|
||||
<div on-drag-leave="dragLeave()"
|
||||
on-drag-end="dragLeave()"
|
||||
on-drag-enter="dragEnter()">
|
||||
|
||||
<div class="umb-control-group umb-mediapicker-upload">
|
||||
<div class="umb-control-group umb-mediapicker-upload">
|
||||
|
||||
<umb-load-indicator
|
||||
ng-if="loading">
|
||||
</umb-load-indicator>
|
||||
<umb-load-indicator ng-if="loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input
|
||||
class="umb-search-field search-query -full-width-input"
|
||||
ng-model="searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="changeSearch()"
|
||||
type="text">
|
||||
</div>
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input class="umb-search-field search-query -full-width-input"
|
||||
ng-model="searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="changeSearch()"
|
||||
type="text"
|
||||
no-dirty-check />
|
||||
</div>
|
||||
|
||||
<div class="upload-button">
|
||||
<umb-button
|
||||
type="button"
|
||||
label-key="general_upload"
|
||||
action="upload()"
|
||||
disabled="lockedFolder">
|
||||
</umb-button>
|
||||
</div>
|
||||
<div class="upload-button">
|
||||
<umb-button type="button"
|
||||
label-key="general_upload"
|
||||
action="upload()"
|
||||
disabled="lockedFolder">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row umb-control-group" ng-show="!searchOptions.filter">
|
||||
<ul class="umb-breadcrumbs">
|
||||
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
|
||||
<a href ng-click="gotoFolder()" prevent-default>Media</a>
|
||||
<span class="umb-breadcrumbs__seperator">/</span>
|
||||
</li>
|
||||
<div class="row umb-control-group" ng-show="!searchOptions.filter">
|
||||
<ul class="umb-breadcrumbs">
|
||||
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
|
||||
<a href ng-click="gotoFolder()" prevent-default>Media</a>
|
||||
<span class="umb-breadcrumbs__seperator">/</span>
|
||||
</li>
|
||||
|
||||
<li ng-repeat="item in path" class="umb-breadcrumbs__ancestor">
|
||||
<a href ng-click="gotoFolder(item)" prevent-default>{{item.name}}</a>
|
||||
<span class="umb-breadcrumbs__seperator">/</span>
|
||||
</li>
|
||||
<li ng-repeat="item in path" class="umb-breadcrumbs__ancestor">
|
||||
<a href ng-click="gotoFolder(item)" prevent-default>{{item.name}}</a>
|
||||
<span class="umb-breadcrumbs__seperator">/</span>
|
||||
</li>
|
||||
|
||||
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
|
||||
<a href ng-hide="showFolderInput" ng-click="showFolderInput = true">
|
||||
<i class="icon icon-add small"></i>
|
||||
</a>
|
||||
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
|
||||
<a href ng-hide="showFolderInput" ng-click="showFolderInput = true">
|
||||
<i class="icon icon-add small"></i>
|
||||
</a>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
class="umb-breadcrumbs__add-ancestor"
|
||||
ng-show="showFolderInput"
|
||||
ng-model="newFolderName"
|
||||
ng-keydown="enterSubmitFolder($event)"
|
||||
on-blur="submitFolder()"
|
||||
focus-when="{{showFolderInput}}" />
|
||||
</li>
|
||||
</ul>
|
||||
<div class="umb-loader" ng-if="creatingFolder"></div>
|
||||
</div>
|
||||
<input type="text"
|
||||
class="umb-breadcrumbs__add-ancestor"
|
||||
ng-show="showFolderInput"
|
||||
ng-model="newFolderName"
|
||||
ng-keydown="enterSubmitFolder($event)"
|
||||
on-blur="submitFolder()"
|
||||
focus-when="{{showFolderInput}}" />
|
||||
</li>
|
||||
</ul>
|
||||
<div class="umb-loader" ng-if="creatingFolder"></div>
|
||||
</div>
|
||||
|
||||
<umb-file-dropzone
|
||||
ng-if="acceptedMediatypes.length > 0 && !loading && !lockedFolder"
|
||||
accepted-mediatypes="acceptedMediatypes"
|
||||
parent-id="{{currentFolder.id}}"
|
||||
files-uploaded="onUploadComplete"
|
||||
files-queued="onFilesQueue"
|
||||
accept="{{acceptedFileTypes}}"
|
||||
max-file-size="{{maxFileSize}}"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0 || searchOptions.filter }}"
|
||||
compact="{{ images.length > 0 }}">
|
||||
</umb-file-dropzone>
|
||||
<umb-file-dropzone ng-if="acceptedMediatypes.length > 0 && !loading && !lockedFolder"
|
||||
accepted-mediatypes="acceptedMediatypes"
|
||||
parent-id="{{currentFolder.id}}"
|
||||
files-uploaded="onUploadComplete"
|
||||
files-queued="onFilesQueue"
|
||||
accept="{{acceptedFileTypes}}"
|
||||
max-file-size="{{maxFileSize}}"
|
||||
hide-dropzone="{{!activeDrag && images.length > 0 || searchOptions.filter }}"
|
||||
compact="{{ images.length > 0 }}">
|
||||
</umb-file-dropzone>
|
||||
|
||||
<umb-media-grid
|
||||
ng-if="!loading"
|
||||
items="images"
|
||||
on-click="clickHandler"
|
||||
on-click-name="clickItemName"
|
||||
item-max-width="150"
|
||||
item-max-height="150"
|
||||
item-min-width="100"
|
||||
item-min-height="100"
|
||||
only-images={{onlyImages}}>
|
||||
</umb-media-grid>
|
||||
<umb-media-grid ng-if="!loading"
|
||||
items="images"
|
||||
on-click="clickHandler"
|
||||
on-click-name="clickItemName"
|
||||
item-max-width="150"
|
||||
item-max-height="150"
|
||||
item-min-width="100"
|
||||
item-min-height="100"
|
||||
only-images={{onlyImages}}>
|
||||
</umb-media-grid>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<umb-pagination
|
||||
ng-if="searchOptions.totalPages > 0 && !loading"
|
||||
page-number="searchOptions.pageNumber"
|
||||
total-pages="searchOptions.totalPages"
|
||||
on-change="changePagination(pageNumber)">
|
||||
<umb-pagination ng-if="searchOptions.totalPages > 0 && !loading"
|
||||
page-number="searchOptions.pageNumber"
|
||||
total-pages="searchOptions.totalPages"
|
||||
on-change="changePagination(pageNumber)">
|
||||
</umb-pagination>
|
||||
</div>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="searchOptions.filter && images.length === 0 && !loading"
|
||||
position="center">
|
||||
<umb-empty-state ng-if="searchOptions.filter && images.length === 0 && !loading"
|
||||
position="center">
|
||||
<localize key="general_searchNoResult"></localize>
|
||||
</umb-empty-state>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="mediaPickerDetailsOverlay.show"
|
||||
model="mediaPickerDetailsOverlay"
|
||||
position="right">
|
||||
<umb-overlay ng-if="mediaPickerDetailsOverlay.show"
|
||||
model="mediaPickerDetailsOverlay"
|
||||
position="right">
|
||||
|
||||
<div class="umb-control-group">
|
||||
<div class="umb-control-group">
|
||||
|
||||
<div ng-if="target.url">
|
||||
<umb-image-gravity
|
||||
src="target.url"
|
||||
center="target.focalPoint">
|
||||
</umb-image-gravity>
|
||||
</div>
|
||||
<div ng-if="target.url">
|
||||
<umb-image-gravity src="target.url"
|
||||
center="target.focalPoint">
|
||||
</umb-image-gravity>
|
||||
</div>
|
||||
|
||||
<div ng-if="cropSize">
|
||||
<div ng-if="cropSize">
|
||||
|
||||
<h5>
|
||||
<localize key="general_preview">Preview</localize>
|
||||
</h5>
|
||||
<h5>
|
||||
<localize key="general_preview">Preview</localize>
|
||||
</h5>
|
||||
|
||||
<umb-image-thumbnail
|
||||
center="target.focalPoint"
|
||||
src="target.url"
|
||||
height="{{cropSize.height}}"
|
||||
width="{{cropSize.width}}"
|
||||
max-size="400">
|
||||
</umb-image-thumbnail>
|
||||
<umb-image-thumbnail center="target.focalPoint"
|
||||
src="target.url"
|
||||
height="{{cropSize.height}}"
|
||||
width="{{cropSize.width}}"
|
||||
max-size="400">
|
||||
</umb-image-thumbnail>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-control-group">
|
||||
<label><localize key="@general_url"></localize></label>
|
||||
<input
|
||||
type="text"
|
||||
localize="placeholder"
|
||||
placeholder="@general_url"
|
||||
class="umb-editor umb-textstring"
|
||||
ng-model="target.url"
|
||||
ng-disabled="target.id" />
|
||||
</div>
|
||||
<div class="umb-control-group">
|
||||
<label><localize key="@general_url"></localize></label>
|
||||
<input type="text"
|
||||
localize="placeholder"
|
||||
placeholder="@general_url"
|
||||
class="umb-editor umb-textstring"
|
||||
ng-model="target.url"
|
||||
ng-disabled="target.id" />
|
||||
</div>
|
||||
|
||||
<div class="umb-control-group">
|
||||
<label><localize key="@content_altTextOptional"></localize></label>
|
||||
<input type="text" class="umb-editor umb-textstring" ng-model="target.altText" />
|
||||
</div>
|
||||
<div class="umb-control-group">
|
||||
<label><localize key="@content_altTextOptional"></localize></label>
|
||||
<input type="text" class="umb-editor umb-textstring" ng-model="target.altText" />
|
||||
</div>
|
||||
|
||||
|
||||
</umb-overlay>
|
||||
</umb-overlay>
|
||||
|
||||
</form>
|
||||
|
||||
+12
-13
@@ -1,7 +1,6 @@
|
||||
<div ng-controller="Umbraco.Overlays.UserGroupPickerController as vm">
|
||||
|
||||
<umb-load-indicator
|
||||
ng-if="vm.loading">
|
||||
<umb-load-indicator ng-if="vm.loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<div ng-if="!vm.loading">
|
||||
@@ -9,17 +8,18 @@
|
||||
<div class="form-search" style="margin-bottom: 15px;">
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query input-block-level -full-width-input"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus />
|
||||
ng-model="searchTerm"
|
||||
class="umb-search-field search-query input-block-level -full-width-input"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_filter"
|
||||
umb-auto-focus
|
||||
no-dirty-check />
|
||||
</div>
|
||||
|
||||
|
||||
<div class="umb-user-group-picker-list">
|
||||
|
||||
<a href="" class="umb-user-group-picker-list-item" ng-repeat="userGroup in vm.userGroups | filter:searchTerm" ng-click="vm.selectUserGroup(userGroup)">
|
||||
|
||||
|
||||
<div class="umb-user-group-picker-list-item__icon">
|
||||
<i ng-if="!userGroup.selected" class="{{userGroup.icon}}"></i>
|
||||
<umb-checkmark ng-if="userGroup.selected" checked="userGroup.selected" size="xs"></umb-checkmark>
|
||||
@@ -42,7 +42,7 @@
|
||||
<span ng-if="userGroup.contentStartNode">{{ userGroup.contentStartNode.name }}</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="umb-user-group-picker-list-item__permission">
|
||||
<span>
|
||||
<span class="bold"><localize key="user_mediastartnode">Media start node</localize>:</span>
|
||||
@@ -55,9 +55,8 @@
|
||||
|
||||
</div>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="vm.userGroups.length === 0"
|
||||
position="center">
|
||||
<umb-empty-state ng-if="vm.userGroups.length === 0"
|
||||
position="center">
|
||||
No user groups have been added
|
||||
</umb-empty-state>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user