Compare commits
389 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a54cdb583 | |||
| d580153c9a | |||
| 1090d54763 | |||
| a43359e440 | |||
| 8fce680430 | |||
| 1815112ae7 | |||
| 66d12ddab2 | |||
| 2a592bfe8c | |||
| 3bf5160895 | |||
| 041fdc40e7 | |||
| 9c599868cc | |||
| ac52960938 | |||
| 3995c7c521 | |||
| b952156027 | |||
| 4c23d7fec9 | |||
| 3d80d511a4 | |||
| fc0f996500 | |||
| 16b88ca2ff | |||
| 6cf82669fb | |||
| 6baea68a7d | |||
| e906808a9b | |||
| c4dbb90d10 | |||
| ef24c2e2f2 | |||
| 4b55f99493 | |||
| 3332e93d4c | |||
| ed88ce8ae2 | |||
| 96cd42b316 | |||
| 2e7aa11211 | |||
| 4c1129e944 | |||
| 74cbff5ee5 | |||
| bfdeb6c987 | |||
| 07f4295810 | |||
| 74be040298 | |||
| c03a4d978b | |||
| 64eff0ba0f | |||
| f81fd8f35f | |||
| 0222f929df | |||
| f34b2edb08 | |||
| e5839a89cd | |||
| 503d6d0265 | |||
| 6adec17b26 | |||
| 3a5538730b | |||
| fe3c1bc089 | |||
| 8031562ea2 | |||
| 4881fb76e4 | |||
| e9b06701cc | |||
| 496d5d7791 | |||
| b92fbffd7c | |||
| 29b4da4dca | |||
| 6cd77df1ad | |||
| adf762bdf8 | |||
| 6b17248f64 | |||
| a5684f867a | |||
| e2730f2b66 | |||
| b4368666ca | |||
| b60fe9cc0a | |||
| 3aabe424a8 | |||
| 9c667414bc | |||
| 5d5fa3fac8 | |||
| d23f25beba | |||
| c0ad64d259 | |||
| 6802716cf1 | |||
| 23a27c3519 | |||
| 0e636b4ce1 | |||
| f00a230d12 | |||
| 009e373178 | |||
| 3c6d3280d8 | |||
| 43d84a37a3 | |||
| 264958f097 | |||
| 99dedac375 | |||
| 078a7d5679 | |||
| 1df2cf5935 | |||
| 86c56ae844 | |||
| 16322bed31 | |||
| 044decc0dc | |||
| b9482fc867 | |||
| 4d8e5e1416 | |||
| 958c8b1214 | |||
| d04b967fe6 | |||
| 6bfcc7bb34 | |||
| 6274a08a4f | |||
| 4ebfd8ca37 | |||
| 1370894b38 | |||
| c5f1d2d885 | |||
| 4df63c7f04 | |||
| a822e18719 | |||
| 1605b6f909 | |||
| 5e8d73cd20 | |||
| f05915ef08 | |||
| 5fd423dbb6 | |||
| 1758d0cd1a | |||
| d698aa56d0 | |||
| 0478a37b00 | |||
| 6def4d6248 | |||
| 2835da8e96 | |||
| f895900ec5 | |||
| 21e91ac4e1 | |||
| ecc7a3b96e | |||
| 9598d2c2e6 | |||
| 966bfafe22 | |||
| f2a5e5da87 | |||
| 5eb0f6f92f | |||
| f2e01d8f65 | |||
| d328a53590 | |||
| 27d5b258df | |||
| b271c77d97 | |||
| 906c7a4ccd | |||
| 5942bce7da | |||
| ab2f0c3a1c | |||
| 85905f7a77 | |||
| 85456bbb9b | |||
| 8e925c930b | |||
| 18c7680baf | |||
| 77407a9446 | |||
| 62e72a54b7 | |||
| 5d7aa4bcf5 | |||
| 90912a4b2a | |||
| 01116e21f4 | |||
| a7ebf9bed3 | |||
| a01efcb59f | |||
| 880e86820e | |||
| 7e064cee83 | |||
| cc7bf4cef5 | |||
| 70203512fb | |||
| 48ceb0d41d | |||
| 173df80e3d | |||
| 9b62269bde | |||
| 4d3154c7fa | |||
| e139fa6719 | |||
| 09617d9b50 | |||
| 00e33fb156 | |||
| dc27bd148a | |||
| 6dc343f9d8 | |||
| 2470a2737f | |||
| 1753ddbfc4 | |||
| 4230ad27f3 | |||
| 9bca5e0347 | |||
| f82dff597b | |||
| 56d7755487 | |||
| 82f966ca24 | |||
| 2179e85638 | |||
| defbb8e821 | |||
| f7dce756a7 | |||
| 30385789c8 | |||
| 8bac388f73 | |||
| 53c7df36b0 | |||
| 5f5b21b43e | |||
| 64f7cc1c29 | |||
| c80187938b | |||
| bb4be11a0b | |||
| 103c92bc69 | |||
| 950849a4c6 | |||
| da125405ea | |||
| d05e188d00 | |||
| 4cf55a8837 | |||
| 5436478dfb | |||
| 9333426985 | |||
| c21b740c71 | |||
| 9e03103cbb | |||
| e889ec1fa9 | |||
| dc66807d13 | |||
| fe57ef329b | |||
| 5ce226104b | |||
| 43586e6bb7 | |||
| fecf561279 | |||
| 61cc22dccf | |||
| e7f4f61f93 | |||
| a6d8b48ab4 | |||
| 7cc9747b2f | |||
| 72d588287f | |||
| 700fe9b787 | |||
| d5858fe1be | |||
| 6dba751167 | |||
| b367ae6c80 | |||
| 07684bb1d6 | |||
| 7eadcf66ed | |||
| 977bf91409 | |||
| fab025bf66 | |||
| 8d382fb9b7 | |||
| c19be0c64e | |||
| 67e046e477 | |||
| aba409600b | |||
| fdfcb75a71 | |||
| ac44f800a6 | |||
| 7eddc22bba | |||
| 9280c74062 | |||
| 90cbdbf2cd | |||
| fdc9adfe83 | |||
| e6f6c498a5 | |||
| 5472297245 | |||
| 71bea2bc25 | |||
| d9653026de | |||
| 3185f7ae97 | |||
| 417b270f59 | |||
| 509b1151a2 | |||
| 0cf857e8bc | |||
| 50f6779c17 | |||
| 5d0010a993 | |||
| f47cfe155a | |||
| 6c08828887 | |||
| 74b4689059 | |||
| 2f1687cd4f | |||
| 9443599382 | |||
| 160d140167 | |||
| db7ae9a7e2 | |||
| 2e6f032222 | |||
| 9fc33d71e4 | |||
| 916cd999d5 | |||
| a75506d60b | |||
| 6631a50a44 | |||
| 9611791f31 | |||
| c35a3fa702 | |||
| 153ac58d2a | |||
| a969ff6e10 | |||
| c7b4d1b206 | |||
| aaf8ba0211 | |||
| 072c014055 | |||
| 655befde42 | |||
| 344b7731ce | |||
| 687cc4630f | |||
| e180bb6722 | |||
| 32104fff41 | |||
| 8b6fbee47e | |||
| 59df7f1399 | |||
| f55e05da79 | |||
| 2a43170915 | |||
| 717f8c9944 | |||
| ff4fe2cd79 | |||
| 233f00e2d4 | |||
| 18a2871419 | |||
| 8c954ef433 | |||
| b232d3c694 | |||
| d2f727a1ba | |||
| 38bb98b099 | |||
| d87464b8e4 | |||
| aba9c89ff4 | |||
| 74f98d51cd | |||
| 1e475bfc6f | |||
| e7f3f8da68 | |||
| a3af3d6d2b | |||
| 29a542a0dd | |||
| 73e4c6022d | |||
| eb10d71bff | |||
| 9cf69d53c2 | |||
| 2a930e5a66 | |||
| 2d32863fc9 | |||
| 2c32fabd36 | |||
| a48d97e631 | |||
| 4107f47588 | |||
| bdac2a4a41 | |||
| 791581f502 | |||
| 1941c0dd1c | |||
| 650ef39780 | |||
| 7db0440b5c | |||
| a2a247b413 | |||
| 0b6a369047 | |||
| 522fdefb8c | |||
| 4d8d10f07a | |||
| 1ad19edfbd | |||
| 637cf6a608 | |||
| a3ee718824 | |||
| d0701ae34e | |||
| 3668b68155 | |||
| e8e29c9390 | |||
| 0787824fba | |||
| 40d2898fb8 | |||
| 6f44e4fd09 | |||
| 27b4329c1e | |||
| 02ddf80014 | |||
| 9f9d24e6b3 | |||
| e4f6794c59 | |||
| 440ac40674 | |||
| dba241ef50 | |||
| 3b22480b5d | |||
| 52bc4b04b3 | |||
| 3f5ccb302d | |||
| 32197f0bd1 | |||
| 6cb55789bd | |||
| 723d9eddd1 | |||
| fa655b812c | |||
| 747a8cba2e | |||
| 7e64f455b2 | |||
| 576c10cd50 | |||
| 0cf609fdce | |||
| 3a26443f58 | |||
| 9953aea156 | |||
| aa75fcfdb3 | |||
| d4ba1298d5 | |||
| 14f9445ffb | |||
| 7f7c9d2796 | |||
| ba4bb843de | |||
| 43fc926f1b | |||
| e06d18330c | |||
| fb3f2101f0 | |||
| f8f28ec46a | |||
| 6323dfcf9c | |||
| 108e3e527f | |||
| ebe4c1b3c3 | |||
| 93f382fc0f | |||
| 8b509656cd | |||
| 179afe7e0d | |||
| a09e612e1f | |||
| 9ad5dad710 | |||
| 7afd01ff5c | |||
| f8af9fd895 | |||
| ac1d462bc5 | |||
| a4e00b62b3 | |||
| ed8ba3ddcf | |||
| 9928b770f7 | |||
| 43759fbef3 | |||
| 94334ff04f | |||
| 1fcce288da | |||
| 5fbd455fd8 | |||
| be7f42c454 | |||
| ff707e8768 | |||
| d2e04614c6 | |||
| e540a4ac23 | |||
| ed4de5b000 | |||
| 699c34263e | |||
| c96cd09dba | |||
| a96bca5fab | |||
| 8e5d33b15e | |||
| 0a66bbb293 | |||
| f246dd7dca | |||
| b29fd4ada3 | |||
| b1674235e9 | |||
| 8441d9017b | |||
| 7e1ee26dee | |||
| 6c8ded6275 | |||
| 968fc40622 | |||
| 9eb1415796 | |||
| 1aec0e1d9c | |||
| 1c9b449c46 | |||
| 2ee8f9dea2 | |||
| c87a9d6bfa | |||
| ae853a178d | |||
| a4d8f0cd55 | |||
| f141025248 | |||
| e38095b727 | |||
| b5796ad237 | |||
| 6e1a40e2ee | |||
| 75bba068a4 | |||
| 2ae639a3ae | |||
| 30da32ee94 | |||
| de8f01a4b2 | |||
| f985c437b5 | |||
| 63fb8f5933 | |||
| 10f22f7848 | |||
| bc821db8eb | |||
| 959402d545 | |||
| df46593ef3 | |||
| 1ff67df9df | |||
| db0a069b02 | |||
| 4e027f7c83 | |||
| d2ff96e7ea | |||
| 17e9487bf0 | |||
| 7f61a6fe9f | |||
| 3d949c9a55 | |||
| eb529783c4 | |||
| a8265db5f0 | |||
| 0997fe6732 | |||
| fb1f2c8af4 | |||
| e6d75f27de | |||
| 9bcd70589c | |||
| 7dcf2b1abb | |||
| 514452ddb9 | |||
| 0676726bfc | |||
| bb43fc310a | |||
| ff9179a15f | |||
| 3524ba83a8 | |||
| a7941b9678 | |||
| 31fd8066a4 | |||
| 5899f08d7f | |||
| 8a16c749e1 | |||
| 011d406301 | |||
| 8bd9ae062d | |||
| d51daa2a8a | |||
| cc9a7ff942 | |||
| 33a91bb9e9 | |||
| 761297a2db | |||
| 0c602567ce | |||
| 28d4f1cc44 | |||
| 4851bb0534 | |||
| b9d1df0844 | |||
| 32a622a6ea | |||
| 7ca6739cee | |||
| 214457fc04 | |||
| 30d46a6204 | |||
| b94b94ea06 |
@@ -161,3 +161,4 @@ build/temp/
|
||||
|
||||
# eof
|
||||
/src/Umbraco.Web.UI.Client/TESTS-*.xml
|
||||
/src/ApiDocs/api/*
|
||||
|
||||
@@ -54,6 +54,5 @@
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -59,8 +59,6 @@
|
||||
|
||||
<!-- symbols -->
|
||||
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
|
||||
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
|
||||
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
|
||||
</files>
|
||||
</package>
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<!-- config transforms -->
|
||||
<!-- beware! config transforms not supported by PackageReference -->
|
||||
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
|
||||
<file src="tools\serilog.config.install.xdt" target="Content\config\serilog.config.install.xdt" />
|
||||
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
|
||||
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
|
||||
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" /> <!-- FIXME: Content\ !! and then... transform?! -->
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">>
|
||||
<appSettings>
|
||||
|
||||
<add key="serilog:using:File" value="Umbraco.Core" xdt:Transform="SetAttributes(value)" xdt:Locator="Match(key)"/>
|
||||
<add key="serilog:write-to:File.shared" xdt:Transform="Remove" xdt:Locator="Match(key)"/>
|
||||
|
||||
</appSettings>
|
||||
</configuration>
|
||||
+55
-3
@@ -11,6 +11,11 @@
|
||||
[Alias("loc")]
|
||||
[switch] $local = $false,
|
||||
|
||||
# enable docfx
|
||||
[Parameter(Mandatory=$false)]
|
||||
[Alias("doc")]
|
||||
[switch] $docfx = $false,
|
||||
|
||||
# keep the build directories, don't clear them
|
||||
[Parameter(Mandatory=$false)]
|
||||
[Alias("c")]
|
||||
@@ -31,7 +36,7 @@
|
||||
$ubuild = &"$PSScriptRoot\build-bootstrap.ps1"
|
||||
if (-not $?) { return }
|
||||
$ubuild.Boot($PSScriptRoot,
|
||||
@{ Local = $local; },
|
||||
@{ Local = $local; WithDocFx = $docfx },
|
||||
@{ Continue = $continue })
|
||||
if ($ubuild.OnError()) { return }
|
||||
|
||||
@@ -387,13 +392,13 @@
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Core.nuspec" `
|
||||
-Properties BuildTmp="$($this.BuildTemp)" `
|
||||
-Version "$($this.Version.Semver.ToString())" `
|
||||
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
|
||||
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
|
||||
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Core." }
|
||||
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Web.nuspec" `
|
||||
-Properties BuildTmp="$($this.BuildTemp)" `
|
||||
-Version "$($this.Version.Semver.ToString())" `
|
||||
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
|
||||
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
|
||||
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Web." }
|
||||
|
||||
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.nuspec" `
|
||||
@@ -424,6 +429,52 @@
|
||||
Write-Host "Prepare Azure Gallery"
|
||||
$this.CopyFile("$($this.SolutionRoot)\build\Azure\azuregalleryrelease.ps1", $this.BuildOutput)
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("BuildCSharpDocs",
|
||||
{
|
||||
Write-Host "Building C# Documentation"
|
||||
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$tmp = $this.BuildTemp
|
||||
$out = $this.BuildOutput
|
||||
$DocFxJson = Join-Path -Path $src "\ApiDocs\docfx.json"
|
||||
$DocFxSiteOutput = Join-Path -Path $tmp "\_site\*.*"
|
||||
|
||||
# run DocFx
|
||||
$DocFx = $this.BuildEnv.DocFx
|
||||
|
||||
& $DocFx metadata $DocFxJson
|
||||
& $DocFx build $DocFxJson
|
||||
|
||||
# zip it
|
||||
& $this.BuildEnv.Zip a -tzip -r "$out\csharp-docs.zip" $DocFxSiteOutput
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("BuildAngularDocs",
|
||||
{
|
||||
Write-Host "Building Angular Documentation"
|
||||
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$out = $this.BuildOutput
|
||||
|
||||
# Check if the solution has been built
|
||||
if (!(Test-Path "$src\Umbraco.Web.UI.Client\node_modules")) {throw "Umbraco needs to be built before generating the Angular Docs"}
|
||||
|
||||
Push-Location "$src\Umbraco.Web.UI.Client"
|
||||
|
||||
"Generating the docs and waiting before executing the next commands"
|
||||
& gulp docs | Out-Null
|
||||
|
||||
Pop-Location
|
||||
|
||||
# change baseUrl
|
||||
$BaseUrl = "https://our.umbraco.com/apidocs/v8/ui/"
|
||||
$IndexPath = "$src\Umbraco.Web.UI.Client\docs\api\index.html"
|
||||
(Get-Content $IndexPath).replace('location.href.replace(rUrl, indexFile)', "`'" + $BaseUrl + "`'") | Set-Content $IndexPath
|
||||
|
||||
# zip it
|
||||
& $this.BuildEnv.Zip a -tzip -r "$out\ui-docs.zip" "$src\Umbraco.Web.UI.Client\docs\api\*.*"
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("Build",
|
||||
{
|
||||
@@ -456,6 +507,7 @@
|
||||
if ($this.OnError()) { return }
|
||||
$this.PostPackageHook()
|
||||
if ($this.OnError()) { return }
|
||||
|
||||
Write-Host "Done"
|
||||
})
|
||||
|
||||
|
||||
+10
-24
@@ -2,21 +2,20 @@
|
||||
"metadata": [
|
||||
{
|
||||
"src": [
|
||||
{
|
||||
{
|
||||
"src": "../",
|
||||
"files": [
|
||||
"Umbraco.Core/Umbraco.Core.csproj",
|
||||
"Umbraco.Web/Umbraco.Web.csproj"
|
||||
],
|
||||
"exclude": [
|
||||
"**/obj/**",
|
||||
"**/bin/**",
|
||||
"_site/**"
|
||||
],
|
||||
"cwd": "../src"
|
||||
"**/bin/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
"dest": "../apidocs/api",
|
||||
"filter": "../apidocs/docfx.filter.yml"
|
||||
"dest": "api",
|
||||
"filter": "docfx.filter.yml"
|
||||
}
|
||||
],
|
||||
"build": {
|
||||
@@ -35,19 +34,7 @@
|
||||
"*.md"
|
||||
],
|
||||
"exclude": [
|
||||
"obj/**",
|
||||
"_site/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
"resource": [
|
||||
{
|
||||
"files": [
|
||||
"images/**"
|
||||
],
|
||||
"exclude": [
|
||||
"obj/**",
|
||||
"_site/**"
|
||||
"obj/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -57,8 +44,7 @@
|
||||
"**.md"
|
||||
],
|
||||
"exclude": [
|
||||
"obj/**",
|
||||
"_site/**"
|
||||
"obj/**"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -67,9 +53,9 @@
|
||||
"_enableSearch": true,
|
||||
"_disableContribution": false
|
||||
},
|
||||
"dest": "_site",
|
||||
"dest": "../../build.tmp/_site",
|
||||
"template": [
|
||||
"default", "umbracotemplate"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,23 @@ namespace Umbraco.Core.Composing
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Type> PrepareComposerTypes()
|
||||
internal IEnumerable<Type> PrepareComposerTypes()
|
||||
{
|
||||
var requirements = GetRequirements();
|
||||
|
||||
// only for debugging, this is verbose
|
||||
//_logger.Debug<Composers>(GetComposersReport(requirements));
|
||||
|
||||
var sortedComposerTypes = SortComposers(requirements);
|
||||
|
||||
// bit verbose but should help for troubleshooting
|
||||
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
|
||||
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
|
||||
|
||||
return sortedComposerTypes;
|
||||
}
|
||||
|
||||
internal Dictionary<Type, List<Type>> GetRequirements(bool throwOnMissing = true)
|
||||
{
|
||||
// create a list, remove those that cannot be enabled due to runtime level
|
||||
var composerTypeList = _composerTypes
|
||||
@@ -89,25 +105,69 @@ namespace Umbraco.Core.Composing
|
||||
// enable or disable composers
|
||||
EnableDisableComposers(composerTypeList);
|
||||
|
||||
// sort the composers according to their dependencies
|
||||
var requirements = new Dictionary<Type, List<Type>>();
|
||||
foreach (var type in composerTypeList) requirements[type] = null;
|
||||
foreach (var type in composerTypeList)
|
||||
void GatherInterfaces<TAttribute>(Type type, Func<TAttribute, Type> getTypeInAttribute, HashSet<Type> iset, List<Type> set2)
|
||||
where TAttribute : Attribute
|
||||
{
|
||||
GatherRequirementsFromRequireAttribute(type, composerTypeList, requirements);
|
||||
GatherRequirementsFromRequiredByAttribute(type, composerTypeList, requirements);
|
||||
foreach (var attribute in type.GetCustomAttributes<TAttribute>())
|
||||
{
|
||||
var typeInAttribute = getTypeInAttribute(attribute);
|
||||
if (typeInAttribute != null && // if the attribute references a type ...
|
||||
typeInAttribute.IsInterface && // ... which is an interface ...
|
||||
typeof(IComposer).IsAssignableFrom(typeInAttribute) && // ... which implements IComposer ...
|
||||
!iset.Contains(typeInAttribute)) // ... which is not already in the list
|
||||
{
|
||||
// add it to the new list
|
||||
iset.Add(typeInAttribute);
|
||||
set2.Add(typeInAttribute);
|
||||
|
||||
// add all its interfaces implementing IComposer
|
||||
foreach (var i in typeInAttribute.GetInterfaces().Where(x => typeof(IComposer).IsAssignableFrom(x)))
|
||||
{
|
||||
iset.Add(i);
|
||||
set2.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only for debugging, this is verbose
|
||||
//_logger.Debug<Composers>(GetComposersReport(requirements));
|
||||
// gather interfaces too
|
||||
var interfaces = new HashSet<Type>(composerTypeList.SelectMany(x => x.GetInterfaces().Where(y => typeof(IComposer).IsAssignableFrom(y))));
|
||||
composerTypeList.AddRange(interfaces);
|
||||
var list1 = composerTypeList;
|
||||
while (list1.Count > 0)
|
||||
{
|
||||
var list2 = new List<Type>();
|
||||
foreach (var t in list1)
|
||||
{
|
||||
GatherInterfaces<ComposeAfterAttribute>(t, a => a.RequiredType, interfaces, list2);
|
||||
GatherInterfaces<ComposeBeforeAttribute>(t, a => a.RequiringType, interfaces, list2);
|
||||
}
|
||||
composerTypeList.AddRange(list2);
|
||||
list1 = list2;
|
||||
}
|
||||
|
||||
// sort the composers according to their dependencies
|
||||
var requirements = new Dictionary<Type, List<Type>>();
|
||||
foreach (var type in composerTypeList)
|
||||
requirements[type] = null;
|
||||
foreach (var type in composerTypeList)
|
||||
{
|
||||
GatherRequirementsFromAfterAttribute(type, composerTypeList, requirements, throwOnMissing);
|
||||
GatherRequirementsFromBeforeAttribute(type, composerTypeList, requirements);
|
||||
}
|
||||
|
||||
return requirements;
|
||||
}
|
||||
|
||||
internal IEnumerable<Type> SortComposers(Dictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
// sort composers
|
||||
var graph = new TopoGraph<Type, KeyValuePair<Type, List<Type>>>(kvp => kvp.Key, kvp => kvp.Value);
|
||||
graph.AddItems(requirements);
|
||||
List<Type> sortedComposerTypes;
|
||||
try
|
||||
{
|
||||
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).ToList();
|
||||
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).Where(x => !x.IsInterface).ToList();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -117,40 +177,37 @@ namespace Umbraco.Core.Composing
|
||||
throw;
|
||||
}
|
||||
|
||||
// bit verbose but should help for troubleshooting
|
||||
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
|
||||
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
|
||||
|
||||
return sortedComposerTypes;
|
||||
}
|
||||
|
||||
private static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
|
||||
internal static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
var text = new StringBuilder();
|
||||
text.AppendLine("Composers & Dependencies:");
|
||||
text.AppendLine(" < compose before");
|
||||
text.AppendLine(" > compose after");
|
||||
text.AppendLine(" : implements");
|
||||
text.AppendLine(" = depends");
|
||||
text.AppendLine();
|
||||
|
||||
bool HasReq(IEnumerable<Type> types, Type type)
|
||||
=> types.Any(x => type.IsAssignableFrom(x) && !x.IsInterface);
|
||||
|
||||
foreach (var kvp in requirements)
|
||||
{
|
||||
var type = kvp.Key;
|
||||
|
||||
text.AppendLine(type.FullName);
|
||||
foreach (var attribute in type.GetCustomAttributes<ComposeAfterAttribute>())
|
||||
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
|
||||
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
|
||||
: ""));
|
||||
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
|
||||
text.AppendLine(" -< " + attribute.RequiringType);
|
||||
foreach (var i in type.GetInterfaces())
|
||||
{
|
||||
text.AppendLine(" : " + i.FullName);
|
||||
foreach (var attribute in i.GetCustomAttributes<ComposeAfterAttribute>())
|
||||
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
|
||||
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
|
||||
: ""));
|
||||
foreach (var attribute in i.GetCustomAttributes<ComposeBeforeAttribute>())
|
||||
text.AppendLine(" -< " + attribute.RequiringType);
|
||||
var weak = !(attribute.RequiredType.IsInterface ? attribute.Weak == false : attribute.Weak != true);
|
||||
text.AppendLine(" > " + attribute.RequiredType +
|
||||
(weak ? " (weak" : " (strong") + (HasReq(requirements.Keys, attribute.RequiredType) ? ", found" : ", missing") + ")");
|
||||
}
|
||||
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
|
||||
text.AppendLine(" < " + attribute.RequiringType);
|
||||
foreach (var i in type.GetInterfaces())
|
||||
text.AppendLine(" : " + i.FullName);
|
||||
if (kvp.Value != null)
|
||||
foreach (var t in kvp.Value)
|
||||
text.AppendLine(" = " + t);
|
||||
@@ -221,16 +278,16 @@ namespace Umbraco.Core.Composing
|
||||
types.Remove(kvp.Key);
|
||||
}
|
||||
|
||||
private static void GatherRequirementsFromRequireAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
|
||||
private static void GatherRequirementsFromAfterAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements, bool throwOnMissing = true)
|
||||
{
|
||||
// get 'require' attributes
|
||||
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
|
||||
var requireAttributes = type
|
||||
var afterAttributes = type
|
||||
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeAfterAttribute>()) // those marking interfaces
|
||||
.Concat(type.GetCustomAttributes<ComposeAfterAttribute>()); // those marking the composer
|
||||
|
||||
// what happens in case of conflicting attributes (different strong/weak for same type) is not specified.
|
||||
foreach (var attr in requireAttributes)
|
||||
foreach (var attr in afterAttributes)
|
||||
{
|
||||
if (attr.RequiredType == type) continue; // ignore self-requirements (+ exclude in implems, below)
|
||||
|
||||
@@ -238,13 +295,13 @@ namespace Umbraco.Core.Composing
|
||||
// unless strong, and then require at least one enabled composer implementing that interface
|
||||
if (attr.RequiredType.IsInterface)
|
||||
{
|
||||
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x)).ToList();
|
||||
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x) && !x.IsInterface).ToList();
|
||||
if (implems.Count > 0)
|
||||
{
|
||||
if (requirements[type] == null) requirements[type] = new List<Type>();
|
||||
requirements[type].AddRange(implems);
|
||||
}
|
||||
else if (attr.Weak == false) // if explicitly set to !weak, is strong, else is weak
|
||||
else if (attr.Weak == false && throwOnMissing) // if explicitly set to !weak, is strong, else is weak
|
||||
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
|
||||
}
|
||||
// requiring a class = require that the composer is enabled
|
||||
@@ -256,28 +313,28 @@ namespace Umbraco.Core.Composing
|
||||
if (requirements[type] == null) requirements[type] = new List<Type>();
|
||||
requirements[type].Add(attr.RequiredType);
|
||||
}
|
||||
else if (attr.Weak != true) // if not explicitly set to weak, is strong
|
||||
else if (attr.Weak != true && throwOnMissing) // if not explicitly set to weak, is strong
|
||||
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void GatherRequirementsFromRequiredByAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
|
||||
private static void GatherRequirementsFromBeforeAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
|
||||
{
|
||||
// get 'required' attributes
|
||||
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
|
||||
var requiredAttributes = type
|
||||
var beforeAttributes = type
|
||||
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeBeforeAttribute>()) // those marking interfaces
|
||||
.Concat(type.GetCustomAttributes<ComposeBeforeAttribute>()); // those marking the composer
|
||||
|
||||
foreach (var attr in requiredAttributes)
|
||||
foreach (var attr in beforeAttributes)
|
||||
{
|
||||
if (attr.RequiringType == type) continue; // ignore self-requirements (+ exclude in implems, below)
|
||||
|
||||
// required by an interface = by any enabled composer implementing this that interface
|
||||
if (attr.RequiringType.IsInterface)
|
||||
{
|
||||
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x)).ToList();
|
||||
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x) && !x.IsInterface).ToList();
|
||||
foreach (var implem in implems)
|
||||
{
|
||||
if (requirements[implem] == null) requirements[implem] = new List<Type>();
|
||||
|
||||
@@ -6,30 +6,50 @@ namespace Umbraco.Core.Composing
|
||||
/// <summary>
|
||||
/// Provides a base class for collections of types.
|
||||
/// </summary>
|
||||
public abstract class TypeCollectionBuilderBase<TCollection, TConstraint> : ICollectionBuilder<TCollection, Type>
|
||||
public abstract class TypeCollectionBuilderBase<TBuilder, TCollection, TConstraint> : ICollectionBuilder<TCollection, Type>
|
||||
where TBuilder : TypeCollectionBuilderBase<TBuilder, TCollection, TConstraint>
|
||||
where TCollection : class, IBuilderCollection<Type>
|
||||
{
|
||||
private readonly HashSet<Type> _types = new HashSet<Type>();
|
||||
|
||||
private Type Validate(Type type, string action)
|
||||
protected abstract TBuilder This { get; }
|
||||
|
||||
private static Type Validate(Type type, string action)
|
||||
{
|
||||
if (!typeof(TConstraint).IsAssignableFrom(type))
|
||||
throw new InvalidOperationException($"Cannot {action} type {type.FullName} as it does not inherit from/implement {typeof(TConstraint).FullName}.");
|
||||
return type;
|
||||
}
|
||||
|
||||
public void Add(Type type) => _types.Add(Validate(type, "add"));
|
||||
|
||||
public void Add<T>() => Add(typeof(T));
|
||||
|
||||
public void Add(IEnumerable<Type> types)
|
||||
public TBuilder Add(Type type)
|
||||
{
|
||||
foreach (var type in types) Add(type);
|
||||
_types.Add(Validate(type, "add"));
|
||||
return This;
|
||||
}
|
||||
|
||||
public void Remove(Type type) => _types.Remove(Validate(type, "remove"));
|
||||
public TBuilder Add<T>()
|
||||
{
|
||||
Add(typeof(T));
|
||||
return This;
|
||||
}
|
||||
|
||||
public void Remove<T>() => Remove(typeof(T));
|
||||
public TBuilder Add(IEnumerable<Type> types)
|
||||
{
|
||||
foreach (var type in types) Add(type);
|
||||
return This;
|
||||
}
|
||||
|
||||
public TBuilder Remove(Type type)
|
||||
{
|
||||
_types.Remove(Validate(type, "remove"));
|
||||
return This;
|
||||
}
|
||||
|
||||
public TBuilder Remove<T>()
|
||||
{
|
||||
Remove(typeof(T));
|
||||
return This;
|
||||
}
|
||||
|
||||
public TCollection CreateCollection(IFactory factory)
|
||||
{
|
||||
|
||||
@@ -315,7 +315,7 @@ namespace Umbraco.Core.Configuration
|
||||
var hash = hashString.GenerateHash();
|
||||
var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash);
|
||||
|
||||
return _localTempPath = System.IO.Path.Combine(siteTemp, "umbraco.config");
|
||||
return _localTempPath = siteTemp;
|
||||
|
||||
//case LocalTempStorage.Default:
|
||||
//case LocalTempStorage.Unknown:
|
||||
|
||||
@@ -10,6 +10,18 @@ namespace Umbraco.Core
|
||||
///</summary>
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
internal static bool HasDuplicates<T>(this IEnumerable<T> items, bool includeNull)
|
||||
{
|
||||
var hs = new HashSet<T>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if ((item != null || includeNull) && !hs.Add(item))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Wraps this object instance into an IEnumerable{T} consisting of a single item.
|
||||
/// </summary>
|
||||
@@ -100,7 +112,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if all items in the other collection exist in this collection
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Serilog;
|
||||
using Serilog.Configuration;
|
||||
using Serilog.Core;
|
||||
using Serilog.Events;
|
||||
using Serilog.Formatting;
|
||||
using Serilog.Formatting.Compact;
|
||||
using Umbraco.Core.Logging.Serilog.Enrichers;
|
||||
|
||||
@@ -9,6 +13,7 @@ namespace Umbraco.Core.Logging.Serilog
|
||||
{
|
||||
public static class LoggerConfigExtensions
|
||||
{
|
||||
private const string AppDomainId = "AppDomainId";
|
||||
/// <summary>
|
||||
/// This configures Serilog with some defaults
|
||||
/// Such as adding ProcessID, Thread, AppDomain etc
|
||||
@@ -28,14 +33,14 @@ namespace Umbraco.Core.Logging.Serilog
|
||||
.Enrich.WithProcessId()
|
||||
.Enrich.WithProcessName()
|
||||
.Enrich.WithThreadId()
|
||||
.Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
|
||||
.Enrich.WithProperty(AppDomainId, AppDomain.CurrentDomain.Id)
|
||||
.Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
|
||||
.Enrich.WithProperty("MachineName", Environment.MachineName)
|
||||
.Enrich.With<Log4NetLevelMapperEnricher>()
|
||||
.Enrich.With<HttpSessionIdEnricher>()
|
||||
.Enrich.With<HttpRequestNumberEnricher>()
|
||||
.Enrich.With<HttpRequestIdEnricher>();
|
||||
|
||||
|
||||
return logConfig;
|
||||
}
|
||||
|
||||
@@ -50,15 +55,51 @@ namespace Umbraco.Core.Logging.Serilog
|
||||
//Main .txt logfile - in similar format to older Log4Net output
|
||||
//Ends with ..txt as Date is inserted before file extension substring
|
||||
logConfig.WriteTo.File($@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
|
||||
shared: true,
|
||||
rollingInterval: RollingInterval.Day,
|
||||
restrictedToMinimumLevel: minimumLevel,
|
||||
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}");
|
||||
shared: true,
|
||||
rollingInterval: RollingInterval.Day,
|
||||
restrictedToMinimumLevel: minimumLevel,
|
||||
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
|
||||
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}");
|
||||
|
||||
return logConfig;
|
||||
}
|
||||
|
||||
|
||||
/// <remarks>
|
||||
/// Used in config - If renamed or moved to other assembly the config file also has be updated.
|
||||
/// </remarks>
|
||||
public static LoggerConfiguration File(this LoggerSinkConfiguration configuration, ITextFormatter formatter,
|
||||
string path,
|
||||
LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose,
|
||||
LoggingLevelSwitch levelSwitch = null,
|
||||
long? fileSizeLimitBytes = 1073741824,
|
||||
TimeSpan? flushToDiskInterval = null,
|
||||
RollingInterval rollingInterval = RollingInterval.Infinite,
|
||||
bool rollOnFileSizeLimit = false,
|
||||
int? retainedFileCountLimit = 31,
|
||||
Encoding encoding = null
|
||||
)
|
||||
{
|
||||
return configuration.Async(
|
||||
asyncConfiguration => asyncConfiguration.Map(AppDomainId, (_,mapConfiguration) =>
|
||||
mapConfiguration.File(
|
||||
formatter,
|
||||
path,
|
||||
restrictedToMinimumLevel,
|
||||
fileSizeLimitBytes,
|
||||
levelSwitch,
|
||||
buffered:true,
|
||||
shared:false,
|
||||
flushToDiskInterval,
|
||||
rollingInterval,
|
||||
rollOnFileSizeLimit,
|
||||
retainedFileCountLimit,
|
||||
encoding),
|
||||
sinkMapCountLimit:0)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Outputs a CLEF format JSON log at /App_Data/Logs/
|
||||
/// </summary>
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Logging.Serilog
|
||||
///<summary>
|
||||
/// Implements <see cref="ILogger"/> on top of Serilog.
|
||||
///</summary>
|
||||
public class SerilogLogger : ILogger
|
||||
public class SerilogLogger : ILogger, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="SerilogLogger"/> class with a configuration file.
|
||||
@@ -271,5 +271,10 @@ namespace Umbraco.Core.Logging.Serilog
|
||||
{
|
||||
LoggerFor(reporting).Verbose(messageTemplate, propertyValues);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
|
||||
{
|
||||
//Filename ending to search for (As could be multiple)
|
||||
var filesToFind = $"*{day:yyyyMMdd}.json";
|
||||
var filesToFind = GetSearchPattern(day);
|
||||
|
||||
var filesForCurrentDay = Directory.GetFiles(logDirectory, filesToFind);
|
||||
|
||||
@@ -52,6 +52,11 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
return logSizeAsMegabytes <= FileSizeCap;
|
||||
}
|
||||
|
||||
private string GetSearchPattern(DateTime day)
|
||||
{
|
||||
return $"*{day:yyyyMMdd}*.json";
|
||||
}
|
||||
|
||||
protected override IReadOnlyList<LogEvent> GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take)
|
||||
{
|
||||
var logs = new List<LogEvent>();
|
||||
@@ -66,7 +71,7 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
|
||||
{
|
||||
//Filename ending to search for (As could be multiple)
|
||||
var filesToFind = $"*{day:yyyyMMdd}.json";
|
||||
var filesToFind = GetSearchPattern(day);
|
||||
|
||||
var filesForCurrentDay = Directory.GetFiles(logDirectory, filesToFind);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Mapping
|
||||
{
|
||||
@@ -112,6 +113,18 @@ namespace Umbraco.Core.Mapping
|
||||
}
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Maps an enumerable of source objects to a new list of target objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
|
||||
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
|
||||
/// <param name="source">The source objects.</param>
|
||||
/// <returns>A list containing the target objects.</returns>
|
||||
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source)
|
||||
{
|
||||
return source.Select(Map<TSourceElement, TTargetElement>).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -29,11 +30,16 @@ namespace Umbraco.Core.Mapping
|
||||
/// </remarks>
|
||||
public class UmbracoMapper
|
||||
{
|
||||
private readonly Dictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors
|
||||
= new Dictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>>();
|
||||
// note
|
||||
//
|
||||
// the outer dictionary *can* be modified, see GetCtor and GetMap, hence have to be ConcurrentDictionary
|
||||
// the inner dictionaries are never modified and therefore can be simple Dictionary
|
||||
|
||||
private readonly Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>> _maps
|
||||
= new Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>>();
|
||||
private readonly ConcurrentDictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors
|
||||
= new ConcurrentDictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>>();
|
||||
|
||||
private readonly ConcurrentDictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>> _maps
|
||||
= new ConcurrentDictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UmbracoMapper"/> class.
|
||||
@@ -101,16 +107,12 @@ namespace Umbraco.Core.Mapping
|
||||
|
||||
private Dictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType)
|
||||
{
|
||||
if (!_ctors.TryGetValue(sourceType, out var sourceCtor))
|
||||
sourceCtor = _ctors[sourceType] = new Dictionary<Type, Func<object, MapperContext, object>>();
|
||||
return sourceCtor;
|
||||
return _ctors.GetOrAdd(sourceType, _ => new Dictionary<Type, Func<object, MapperContext, object>>());
|
||||
}
|
||||
|
||||
private Dictionary<Type, Action<object, object, MapperContext>> DefineMaps(Type sourceType)
|
||||
{
|
||||
if (!_maps.TryGetValue(sourceType, out var sourceMap))
|
||||
sourceMap = _maps[sourceType] = new Dictionary<Type, Action<object, object, MapperContext>>();
|
||||
return sourceMap;
|
||||
return _maps.GetOrAdd(sourceType, _ => new Dictionary<Type, Action<object, object, MapperContext>>());
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -229,7 +231,7 @@ namespace Umbraco.Core.Mapping
|
||||
if (ctor != null && map != null)
|
||||
{
|
||||
// register (for next time) and do it now (for this time)
|
||||
object NCtor(object s, MapperContext c) => MapEnumerable<TTarget>((IEnumerable) s, targetGenericArg, ctor, map, c);
|
||||
object NCtor(object s, MapperContext c) => MapEnumerableInternal<TTarget>((IEnumerable) s, targetGenericArg, ctor, map, c);
|
||||
DefineCtors(sourceType)[targetType] = NCtor;
|
||||
DefineMaps(sourceType)[targetType] = Identity;
|
||||
return (TTarget) NCtor(source, context);
|
||||
@@ -241,7 +243,7 @@ namespace Umbraco.Core.Mapping
|
||||
throw new InvalidOperationException($"Don't know how to map {sourceType.FullName} to {targetType.FullName}.");
|
||||
}
|
||||
|
||||
private TTarget MapEnumerable<TTarget>(IEnumerable source, Type targetGenericArg, Func<object, MapperContext, object> ctor, Action<object, object, MapperContext> map, MapperContext context)
|
||||
private TTarget MapEnumerableInternal<TTarget>(IEnumerable source, Type targetGenericArg, Func<object, MapperContext, object> ctor, Action<object, object, MapperContext> map, MapperContext context)
|
||||
{
|
||||
var targetList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(targetGenericArg));
|
||||
|
||||
@@ -326,6 +328,8 @@ namespace Umbraco.Core.Mapping
|
||||
if (_ctors.TryGetValue(sourceType, out var sourceCtor) && sourceCtor.TryGetValue(targetType, out var ctor))
|
||||
return ctor;
|
||||
|
||||
// we *may* run this more than once but it does not matter
|
||||
|
||||
ctor = null;
|
||||
foreach (var (stype, sctors) in _ctors)
|
||||
{
|
||||
@@ -347,6 +351,8 @@ namespace Umbraco.Core.Mapping
|
||||
if (_maps.TryGetValue(sourceType, out var sourceMap) && sourceMap.TryGetValue(targetType, out var map))
|
||||
return map;
|
||||
|
||||
// we *may* run this more than once but it does not matter
|
||||
|
||||
map = null;
|
||||
foreach (var (stype, smap) in _maps)
|
||||
{
|
||||
@@ -379,6 +385,46 @@ namespace Umbraco.Core.Mapping
|
||||
throw new Exception("panic");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps an enumerable of source objects to a new list of target objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
|
||||
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
|
||||
/// <param name="source">The source objects.</param>
|
||||
/// <returns>A list containing the target objects.</returns>
|
||||
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source)
|
||||
{
|
||||
return source.Select(Map<TSourceElement, TTargetElement>).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps an enumerable of source objects to a new list of target objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
|
||||
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
|
||||
/// <param name="source">The source objects.</param>
|
||||
/// <param name="f">A mapper context preparation method.</param>
|
||||
/// <returns>A list containing the target objects.</returns>
|
||||
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source, Action<MapperContext> f)
|
||||
{
|
||||
var context = new MapperContext(this);
|
||||
f(context);
|
||||
return source.Select(x => Map<TSourceElement, TTargetElement>(x, context)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps an enumerable of source objects to a new list of target objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
|
||||
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
|
||||
/// <param name="source">The source objects.</param>
|
||||
/// <param name="context">A mapper context.</param>
|
||||
/// <returns>A list containing the target objects.</returns>
|
||||
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source, MapperContext context)
|
||||
{
|
||||
return source.Select(x => Map<TSourceElement, TTargetElement>(x, context)).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,17 +83,25 @@ namespace Umbraco.Core.Migrations.Expressions.Create
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICreateConstraintOnTableBuilder PrimaryKey()
|
||||
public ICreateConstraintOnTableBuilder PrimaryKey() => PrimaryKey(true);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICreateConstraintOnTableBuilder PrimaryKey(bool clustered)
|
||||
{
|
||||
var expression = new CreateConstraintExpression(_context, ConstraintType.PrimaryKey);
|
||||
expression.Constraint.IsPrimaryKeyClustered = clustered;
|
||||
return new CreateConstraintBuilder(expression);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName)
|
||||
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName) => PrimaryKey(primaryKeyName, true);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName, bool clustered)
|
||||
{
|
||||
var expression = new CreateConstraintExpression(_context, ConstraintType.PrimaryKey);
|
||||
expression.Constraint.ConstraintName = primaryKeyName;
|
||||
expression.Constraint.IsPrimaryKeyClustered = clustered;
|
||||
return new CreateConstraintBuilder(expression);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Migrations.Expressions.Create.Expressions
|
||||
var constraintType = (Constraint.IsPrimaryKeyConstraint) ? "PRIMARY KEY" : "UNIQUE";
|
||||
|
||||
if (Constraint.IsPrimaryKeyConstraint && SqlSyntax.SupportsClustered())
|
||||
constraintType += " CLUSTERED";
|
||||
constraintType += Constraint.IsPrimaryKeyClustered ? " CLUSTERED" : " NONCLUSTERED";
|
||||
|
||||
if (Constraint.IsNonUniqueConstraint)
|
||||
constraintType = string.Empty;
|
||||
|
||||
@@ -68,6 +68,16 @@ namespace Umbraco.Core.Migrations.Expressions.Create
|
||||
/// </summary>
|
||||
ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName);
|
||||
|
||||
/// <summary>
|
||||
/// Builds a Create Primary Key expression.
|
||||
/// </summary>
|
||||
ICreateConstraintOnTableBuilder PrimaryKey(bool clustered);
|
||||
|
||||
/// <summary>
|
||||
/// Builds a Create Primary Key expression.
|
||||
/// </summary>
|
||||
ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName, bool clustered);
|
||||
|
||||
/// <summary>
|
||||
/// Builds a Create Unique Constraint expression.
|
||||
/// </summary>
|
||||
|
||||
@@ -226,6 +226,8 @@ namespace Umbraco.Core.Migrations.Install
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
|
||||
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
|
||||
using Umbraco.Core.Migrations.Upgrade.V_8_1_0;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade
|
||||
{
|
||||
@@ -139,6 +140,7 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
|
||||
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
|
||||
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
|
||||
To<ConvertTinyMceAndGridMediaUrlsToLocalLink>("{B69B6E8C-A769-4044-A27E-4A4E18D1645A}");
|
||||
|
||||
//FINAL
|
||||
|
||||
|
||||
@@ -79,7 +79,8 @@ HAVING COUNT(v2.id) <> 1").Any())
|
||||
// transform column versionId from guid to integer (contentVersion.id)
|
||||
if (ColumnType(PreTables.PropertyData, "versionId") == "uniqueidentifier")
|
||||
{
|
||||
Database.Execute($"ALTER TABLE {PreTables.PropertyData} ADD COLUMN versionId2 INT NULL;");
|
||||
Alter.Table(PreTables.PropertyData).AddColumn("versionId2").AsInt32().Nullable().Do();
|
||||
|
||||
// SQLCE does not support UPDATE...FROM
|
||||
var temp = Database.Fetch<dynamic>($"SELECT id, versionId FROM {PreTables.ContentVersion}");
|
||||
foreach (var t in temp)
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Migrations.PostMigrations;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
{
|
||||
public class ConvertTinyMceAndGridMediaUrlsToLocalLink : MigrationBase
|
||||
{
|
||||
private readonly IMediaService _mediaService;
|
||||
|
||||
public ConvertTinyMceAndGridMediaUrlsToLocalLink(IMigrationContext context, IMediaService mediaService) : base(context)
|
||||
{
|
||||
_mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
|
||||
}
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
var mediaLinkPattern = new Regex(
|
||||
@"(<a[^>]*href="")(\/ media[^""\?]*)([^>]*>)",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
|
||||
var sqlPropertyData = Sql()
|
||||
.Select<PropertyDataDto>(x => x.Id, x => x.TextValue)
|
||||
.AndSelect<DataTypeDto>(x => x.EditorAlias)
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
|
||||
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
|
||||
.Where<DataTypeDto>(x =>
|
||||
x.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce ||
|
||||
x.EditorAlias == Constants.PropertyEditors.Aliases.Grid);
|
||||
|
||||
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var value = property.TextValue;
|
||||
if (string.IsNullOrWhiteSpace(value)) continue;
|
||||
|
||||
if (property.PropertyTypeDto.DataTypeDto.EditorAlias == Constants.PropertyEditors.Aliases.Grid)
|
||||
{
|
||||
var obj = JsonConvert.DeserializeObject<JObject>(value);
|
||||
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
|
||||
|
||||
foreach (var control in allControls.SelectMany(c => c))
|
||||
{
|
||||
var controlValue = control["value"];
|
||||
if (controlValue.Type == JTokenType.String)
|
||||
{
|
||||
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
|
||||
}
|
||||
}
|
||||
|
||||
property.TextValue = JsonConvert.SerializeObject(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
property.TextValue = UpdateMediaUrls(mediaLinkPattern, value);
|
||||
}
|
||||
|
||||
Database.Update(property, x => x.TextValue);
|
||||
}
|
||||
|
||||
Context.AddPostMigration<RebuildPublishedSnapshot>();
|
||||
}
|
||||
|
||||
private string UpdateMediaUrls(Regex mediaLinkPattern, string value)
|
||||
{
|
||||
return mediaLinkPattern.Replace(value, match =>
|
||||
{
|
||||
// match groups:
|
||||
// - 1 = from the beginning of the a tag until href attribute value begins
|
||||
// - 2 = the href attribute value excluding the querystring (if present)
|
||||
// - 3 = anything after group 2 until the a tag is closed
|
||||
var href = match.Groups[2].Value;
|
||||
|
||||
var media = _mediaService.GetMediaByPath(href);
|
||||
return media == null
|
||||
? match.Value
|
||||
: $"{match.Groups[1].Value}/{{localLink:{media.GetUdi()}}}{match.Groups[3].Value}";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,21 @@ namespace Umbraco.Core.Models
|
||||
|
||||
protected void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
//enable this to detect duplicate property aliases. We do want this, however making this change in a
|
||||
//patch release might be a little dangerous
|
||||
|
||||
////detect if there are any duplicate aliases - this cannot be allowed
|
||||
//if (e.Action == NotifyCollectionChangedAction.Add
|
||||
// || e.Action == NotifyCollectionChangedAction.Replace)
|
||||
//{
|
||||
// var allAliases = _noGroupPropertyTypes.Concat(PropertyGroups.SelectMany(x => x.PropertyTypes)).Select(x => x.Alias);
|
||||
// if (allAliases.HasDuplicates(false))
|
||||
// {
|
||||
// var newAliases = string.Join(", ", e.NewItems.Cast<PropertyType>().Select(x => x.Alias));
|
||||
// throw new InvalidOperationException($"Other property types already exist with the aliases: {newAliases}");
|
||||
// }
|
||||
//}
|
||||
|
||||
OnPropertyChanged(nameof(PropertyTypes));
|
||||
}
|
||||
|
||||
@@ -388,15 +403,16 @@ namespace Umbraco.Core.Models
|
||||
var group = PropertyGroups[propertyGroupName];
|
||||
if (group == null) return;
|
||||
|
||||
// re-assign the group's properties to no group
|
||||
// first remove the group
|
||||
PropertyGroups.RemoveItem(propertyGroupName);
|
||||
|
||||
// Then re-assign the group's properties to no group
|
||||
foreach (var property in group.PropertyTypes)
|
||||
{
|
||||
property.PropertyGroupId = null;
|
||||
_noGroupPropertyTypes.Add(property);
|
||||
}
|
||||
|
||||
// actually remove the group
|
||||
PropertyGroups.RemoveItem(propertyGroupName);
|
||||
OnPropertyChanged(nameof(PropertyGroups));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models
|
||||
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged, IDeepCloneable
|
||||
{
|
||||
private readonly object _addLocker = new object();
|
||||
internal Action OnAdd;
|
||||
|
||||
internal Func<Property, bool> AdditionValidator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -49,10 +49,12 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
internal void Reset(IEnumerable<Property> properties)
|
||||
{
|
||||
//collection events will be raised in each of these calls
|
||||
Clear();
|
||||
|
||||
//collection events will be raised in each of these calls
|
||||
foreach (var property in properties)
|
||||
Add(property);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,8 +62,9 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
protected override void SetItem(int index, Property property)
|
||||
{
|
||||
var oldItem = index >= 0 ? this[index] : property;
|
||||
base.SetItem(index, property);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property, index));
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, property, oldItem));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -120,10 +123,8 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
//collection events will be raised in InsertItem with Add
|
||||
base.Add(property);
|
||||
|
||||
OnAdd?.Invoke();
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
|
||||
|
||||
// TODO: this doesn't seem to be used anywhere
|
||||
internal Action OnAdd;
|
||||
|
||||
internal PropertyGroupCollection()
|
||||
{ }
|
||||
|
||||
@@ -37,16 +34,19 @@ namespace Umbraco.Core.Models
|
||||
/// <remarks></remarks>
|
||||
internal void Reset(IEnumerable<PropertyGroup> groups)
|
||||
{
|
||||
//collection events will be raised in each of these calls
|
||||
Clear();
|
||||
|
||||
//collection events will be raised in each of these calls
|
||||
foreach (var group in groups)
|
||||
Add(group);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
|
||||
protected override void SetItem(int index, PropertyGroup item)
|
||||
{
|
||||
var oldItem = index >= 0 ? this[index] : item;
|
||||
base.SetItem(index, item);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
|
||||
}
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
@@ -84,6 +84,7 @@ namespace Umbraco.Core.Models
|
||||
if (keyExists)
|
||||
throw new Exception($"Naming conflict: Changing the name of PropertyGroup '{item.Name}' would result in duplicates");
|
||||
|
||||
//collection events will be raised in SetItem
|
||||
SetItem(IndexOfKey(item.Id), item);
|
||||
return;
|
||||
}
|
||||
@@ -96,16 +97,14 @@ namespace Umbraco.Core.Models
|
||||
var exists = Contains(key);
|
||||
if (exists)
|
||||
{
|
||||
//collection events will be raised in SetItem
|
||||
SetItem(IndexOfKey(key), item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//collection events will be raised in InsertItem
|
||||
base.Add(item);
|
||||
OnAdd?.Invoke();
|
||||
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
|
||||
[IgnoreDataMember]
|
||||
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
|
||||
|
||||
// TODO: This doesn't seem to be used
|
||||
[IgnoreDataMember]
|
||||
internal Action OnAdd;
|
||||
|
||||
internal PropertyTypeCollection(bool supportsPublishing)
|
||||
{
|
||||
@@ -43,36 +40,44 @@ namespace Umbraco.Core.Models
|
||||
/// <remarks></remarks>
|
||||
internal void Reset(IEnumerable<PropertyType> properties)
|
||||
{
|
||||
//collection events will be raised in each of these calls
|
||||
Clear();
|
||||
|
||||
//collection events will be raised in each of these calls
|
||||
foreach (var property in properties)
|
||||
Add(property);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
Add(property);
|
||||
}
|
||||
|
||||
protected override void SetItem(int index, PropertyType item)
|
||||
{
|
||||
item.SupportsPublishing = SupportsPublishing;
|
||||
base.SetItem(index, item);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
|
||||
var oldItem = index >= 0 ? this[index] : item;
|
||||
base.SetItem(index, item);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
|
||||
item.PropertyChanged += Item_PropertyChanged;
|
||||
}
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
var removed = this[index];
|
||||
base.RemoveItem(index);
|
||||
removed.PropertyChanged -= Item_PropertyChanged;
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
|
||||
}
|
||||
|
||||
protected override void InsertItem(int index, PropertyType item)
|
||||
{
|
||||
item.SupportsPublishing = SupportsPublishing;
|
||||
base.InsertItem(index, item);
|
||||
base.InsertItem(index, item);
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
|
||||
item.PropertyChanged += Item_PropertyChanged;
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
{
|
||||
base.ClearItems();
|
||||
foreach (var item in this)
|
||||
item.PropertyChanged -= Item_PropertyChanged;
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
|
||||
@@ -91,6 +96,7 @@ namespace Umbraco.Core.Models
|
||||
var exists = Contains(key);
|
||||
if (exists)
|
||||
{
|
||||
//collection events will be raised in SetItem
|
||||
SetItem(IndexOfKey(key), item);
|
||||
return;
|
||||
}
|
||||
@@ -103,10 +109,8 @@ namespace Umbraco.Core.Models
|
||||
item.SortOrder = this.Max(x => x.SortOrder) + 1;
|
||||
}
|
||||
|
||||
//collection events will be raised in InsertItem
|
||||
base.Add(item);
|
||||
OnAdd?.Invoke();
|
||||
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -115,6 +119,17 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a property changes on a PropertyType that exists in this collection
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void Item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
var propType = (PropertyType)sender;
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, propType, propType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this collection contains a <see cref="Property"/> whose alias matches the specified PropertyType.
|
||||
/// </summary>
|
||||
|
||||
@@ -18,5 +18,6 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
public string ConstraintName { get; set; }
|
||||
public string TableName { get; set; }
|
||||
public ICollection<string> Columns = new HashSet<string>();
|
||||
public bool IsPrimaryKeyClustered { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +379,20 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
return "variantName";
|
||||
}
|
||||
|
||||
// content type alias is invariant
|
||||
if(ordering.OrderBy.InvariantEquals("contentTypeAlias"))
|
||||
{
|
||||
var joins = Sql()
|
||||
.InnerJoin<ContentTypeDto>("ctype").On<ContentDto, ContentTypeDto>((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype");
|
||||
|
||||
// see notes in ApplyOrdering: the field MUST be selected + aliased
|
||||
sql = Sql(InsertBefore(sql, "FROM", ", " + SqlSyntax.GetFieldName<ContentTypeDto>(x => x.Alias, "ctype") + " AS ordering "), sql.Arguments);
|
||||
|
||||
sql = InsertJoins(sql, joins);
|
||||
|
||||
return "ordering";
|
||||
}
|
||||
|
||||
// previously, we'd accept anything and just sanitize it - not anymore
|
||||
throw new NotSupportedException($"Ordering by {ordering.OrderBy} not supported.");
|
||||
}
|
||||
|
||||
@@ -240,6 +240,25 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
propertyIx++;
|
||||
}
|
||||
contentType.NoGroupPropertyTypes = noGroupPropertyTypes;
|
||||
|
||||
// ensure builtin properties
|
||||
if (contentType is MemberType memberType)
|
||||
{
|
||||
// ensure that the group exists (ok if it already exists)
|
||||
memberType.AddPropertyGroup(Constants.Conventions.Member.StandardPropertiesGroupName);
|
||||
|
||||
// ensure that property types exist (ok if they already exist)
|
||||
foreach (var (alias, propertyType) in builtinProperties)
|
||||
{
|
||||
var added = memberType.AddPropertyType(propertyType, Constants.Conventions.Member.StandardPropertiesGroupName);
|
||||
|
||||
if (added)
|
||||
{
|
||||
var access = new MemberTypePropertyProfileAccess(false, false, false);
|
||||
memberType.MemberTypePropertyTypes[alias] = access;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +283,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (contentType is MemberType memberType)
|
||||
{
|
||||
var access = new MemberTypePropertyProfileAccess(dto.ViewOnProfile, dto.CanEdit, dto.IsSensitive);
|
||||
memberType.MemberTypePropertyTypes.Add(dto.Alias, access);
|
||||
memberType.MemberTypePropertyTypes[dto.Alias] = access;
|
||||
}
|
||||
|
||||
return new PropertyType(dto.DataTypeDto.EditorAlias, storageType, readonlyStorageType, dto.Alias)
|
||||
|
||||
@@ -13,12 +13,15 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
public class ConfigurationEditor : IConfigurationEditor
|
||||
{
|
||||
private IDictionary<string, object> _defaultConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfigurationEditor"/> class.
|
||||
/// </summary>
|
||||
public ConfigurationEditor()
|
||||
{
|
||||
Fields = new List<ConfigurationField>();
|
||||
_defaultConfiguration = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -61,7 +64,10 @@ namespace Umbraco.Core.PropertyEditors
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonProperty("defaultConfig")]
|
||||
public virtual IDictionary<string, object> DefaultConfiguration => new Dictionary<string, object>();
|
||||
public virtual IDictionary<string, object> DefaultConfiguration {
|
||||
get => _defaultConfiguration;
|
||||
internal set => _defaultConfiguration = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual object DefaultConfigurationObject => DefaultConfiguration;
|
||||
|
||||
@@ -173,7 +173,13 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
protected virtual IConfigurationEditor CreateConfigurationEditor()
|
||||
{
|
||||
return new ConfigurationEditor();
|
||||
var editor = new ConfigurationEditor();
|
||||
// pass the default configuration if this is not a property value editor
|
||||
if((Type & EditorType.PropertyValue) == 0)
|
||||
{
|
||||
editor.DefaultConfiguration = _defaultConfiguration;
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
internal class DropDownFlexibleConfiguration : ValueListConfiguration
|
||||
public class DropDownFlexibleConfiguration : ValueListConfiguration
|
||||
{
|
||||
[ConfigurationField("multiple", "Enable multiple choice", "boolean", Description = "When checked, the dropdown will be a select multiple / combo box style dropdown.")]
|
||||
public bool Multiple { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
public bool EnableRange { get; set; }
|
||||
|
||||
[ConfigurationField("initVal1", "Initial value", "number")]
|
||||
public int InitialValue { get; set; }
|
||||
public decimal InitialValue { get; set; }
|
||||
|
||||
[ConfigurationField("initVal2", "Initial value 2", "number", Description = "Used when range is enabled")]
|
||||
public int InitialValue2 { get; set; }
|
||||
public decimal InitialValue2 { get; set; }
|
||||
|
||||
[ConfigurationField("minVal", "Minimum value", "number")]
|
||||
public int MinimumValue { get; set; }
|
||||
public decimal MinimumValue { get; set; }
|
||||
|
||||
[ConfigurationField("maxVal", "Maximum value", "number")]
|
||||
public int MaximumValue { get; set; }
|
||||
public decimal MaximumValue { get; set; }
|
||||
|
||||
[ConfigurationField("step", "Step increments", "number")]
|
||||
public int StepIncrements { get; set; }
|
||||
public decimal StepIncrements { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
@@ -315,8 +316,16 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Empties the recycle bin.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
|
||||
OperationResult EmptyRecycleBin();
|
||||
|
||||
/// <summary>
|
||||
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
|
||||
/// </summary>
|
||||
/// <param name="userId">Optional Id of the User emptying the Recycle Bin</param>
|
||||
OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Sorts documents.
|
||||
/// </summary>
|
||||
|
||||
@@ -162,8 +162,16 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
|
||||
OperationResult EmptyRecycleBin();
|
||||
|
||||
/// <summary>
|
||||
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
|
||||
/// </summary>
|
||||
/// <param name="userId">Optional Id of the User emptying the Recycle Bin</param>
|
||||
OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes all media of specified type. All children of deleted media is moved to Recycle Bin.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
@@ -1888,9 +1889,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
content.ParentId = parentId;
|
||||
|
||||
// get the level delta (old pos to new pos)
|
||||
var levelDelta = parent == null
|
||||
? 1 - content.Level + (parentId == Constants.System.RecycleBinContent ? 1 : 0)
|
||||
: parent.Level + 1 - content.Level;
|
||||
// note that recycle bin (id:-20) level is 0!
|
||||
var levelDelta = 1 - content.Level + (parent?.Level ?? 0);
|
||||
|
||||
var paths = new Dictionary<int, string>();
|
||||
|
||||
@@ -1939,7 +1939,14 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <summary>
|
||||
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
|
||||
/// </summary>
|
||||
public OperationResult EmptyRecycleBin()
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
|
||||
public OperationResult EmptyRecycleBin() => EmptyRecycleBin(Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
|
||||
/// </summary>
|
||||
public OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
var nodeObjectType = Constants.ObjectTypes.Document;
|
||||
var deleted = new List<IContent>();
|
||||
@@ -1974,7 +1981,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
recycleBinEventArgs.RecycleBinEmptiedSuccessfully = true; // oh my?!
|
||||
scope.Events.Dispatch(EmptiedRecycleBin, this, recycleBinEventArgs);
|
||||
scope.Events.Dispatch(TreeChanged, this, deleted.Select(x => new TreeChange<IContent>(x, TreeChangeTypes.Remove)).ToEventArgs());
|
||||
Audit(AuditType.Delete, 0, Constants.System.RecycleBinContent, "Recycle bin emptied");
|
||||
Audit(AuditType.Delete, userId, Constants.System.RecycleBinContent, "Recycle bin emptied");
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
@@ -2878,25 +2885,16 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
foreach (var property in blueprint.Properties)
|
||||
{
|
||||
if (property.PropertyType.VariesByCulture())
|
||||
{
|
||||
content.SetValue(property.Alias, property.GetValue(culture), culture);
|
||||
}
|
||||
else
|
||||
{
|
||||
content.SetValue(property.Alias, property.GetValue());
|
||||
}
|
||||
var propertyCulture = property.PropertyType.VariesByCulture() ? culture : null;
|
||||
content.SetValue(property.Alias, property.GetValue(propertyCulture), propertyCulture);
|
||||
}
|
||||
|
||||
content.Name = blueprint.Name;
|
||||
if (!string.IsNullOrEmpty(culture))
|
||||
{
|
||||
content.SetCultureInfo(culture, blueprint.GetCultureName(culture), now);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
@@ -1034,10 +1034,12 @@ namespace Umbraco.Core.Services.Implement
|
||||
//strip the @inherits if it's there
|
||||
snippetContent = StripPartialViewHeader(snippetContent);
|
||||
|
||||
//Update Model.Content. to be Model. when used as PartialView
|
||||
//Update Model.Content to be Model when used as PartialView
|
||||
if (partialViewType == PartialViewType.PartialView)
|
||||
{
|
||||
snippetContent = snippetContent.Replace("Model.Content.", "Model.");
|
||||
snippetContent = snippetContent
|
||||
.Replace("Model.Content.", "Model.")
|
||||
.Replace("(Model.Content)", "(Model)");
|
||||
}
|
||||
|
||||
var content = $"{partialViewHeader}{Environment.NewLine}{snippetContent}";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -289,7 +290,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
scope.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IMedia>(media, TreeChangeTypes.RefreshNode).ToEventArgs());
|
||||
}
|
||||
|
||||
|
||||
if (withIdentity == false)
|
||||
return;
|
||||
|
||||
@@ -716,7 +717,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
#endregion
|
||||
|
||||
#region Delete
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes an <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
@@ -975,9 +976,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
media.ParentId = parentId;
|
||||
|
||||
// get the level delta (old pos to new pos)
|
||||
var levelDelta = parent == null
|
||||
? 1 - media.Level + (parentId == Constants.System.RecycleBinMedia ? 1 : 0)
|
||||
: parent.Level + 1 - media.Level;
|
||||
// note that recycle bin (id:-20) level is 0!
|
||||
var levelDelta = 1 - media.Level + (parent?.Level ?? 0);
|
||||
|
||||
var paths = new Dictionary<int, string>();
|
||||
|
||||
@@ -1024,7 +1024,15 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <summary>
|
||||
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
|
||||
/// </summary>
|
||||
public OperationResult EmptyRecycleBin()
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
|
||||
public OperationResult EmptyRecycleBin() => EmptyRecycleBin(Constants.Security.SuperUserId);
|
||||
|
||||
/// <summary>
|
||||
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
|
||||
/// </summary>
|
||||
/// <param name="userId">Optional Id of the User emptying the Recycle Bin</param>
|
||||
public OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
var nodeObjectType = Constants.ObjectTypes.Media;
|
||||
var deleted = new List<IMedia>();
|
||||
@@ -1063,7 +1071,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
args.CanCancel = false;
|
||||
scope.Events.Dispatch(EmptiedRecycleBin, this, args);
|
||||
scope.Events.Dispatch(TreeChanged, this, deleted.Select(x => new TreeChange<IMedia>(x, TreeChangeTypes.Remove)).ToEventArgs());
|
||||
Audit(AuditType.Delete, 0, Constants.System.RecycleBinMedia, "Empty Media recycle bin");
|
||||
Audit(AuditType.Delete, userId, Constants.System.RecycleBinMedia, "Empty Media recycle bin");
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,12 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- note: NuGet deals with transitive references now -->
|
||||
<PackageReference Include="Serilog.Sinks.Async">
|
||||
<Version>1.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Map">
|
||||
<Version>1.0.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Umbraco.Code">
|
||||
<Version>1.0.5</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
@@ -219,6 +225,7 @@
|
||||
<Compile Include="Mapping\MapDefinitionCollectionBuilder.cs" />
|
||||
<Compile Include="Mapping\IMapDefinition.cs" />
|
||||
<Compile Include="Mapping\UmbracoMapper.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_1_0\ConvertTinyMceAndGridMediaUrlsToLocalLink.cs" />
|
||||
<Compile Include="Models\CultureImpact.cs" />
|
||||
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
|
||||
|
||||
@@ -159,6 +159,7 @@ namespace Umbraco.Tests.Cache
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
TestObjects.GetGlobalSettings(),
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
// just assert it does not throw
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace Umbraco.Tests.Cache.PublishedCache
|
||||
new WebSecurity(_httpContextFactory.HttpContext, Current.Services.UserService, globalSettings),
|
||||
umbracoSettings,
|
||||
Enumerable.Empty<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
globalSettings,
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Compose;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.IO;
|
||||
@@ -299,11 +300,19 @@ namespace Umbraco.Tests.Components
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
Assert.Throws<Exception>(() => composers.Compose());
|
||||
Console.WriteLine("throws:");
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var requirements = composers.GetRequirements(false);
|
||||
Console.WriteLine(Composers.GetComposersReport(requirements));
|
||||
|
||||
types = new[] { typeof(Composer2) };
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
Assert.Throws<Exception>(() => composers.Compose());
|
||||
Console.WriteLine("throws:");
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
requirements = composers.GetRequirements(false);
|
||||
Console.WriteLine(Composers.GetComposersReport(requirements));
|
||||
|
||||
types = new[] { typeof(Composer12) };
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
@@ -349,6 +358,25 @@ namespace Umbraco.Tests.Components
|
||||
Assert.AreEqual(typeof(Composer27), Composed[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllComposers()
|
||||
{
|
||||
var typeLoader = new TypeLoader(AppCaches.Disabled.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), Mock.Of<IProfilingLogger>());
|
||||
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
var types = typeLoader.GetTypes<IComposer>().Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web"));
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var requirements = composers.GetRequirements();
|
||||
var report = Composers.GetComposersReport(requirements);
|
||||
Console.WriteLine(report);
|
||||
var composerTypes = composers.SortComposers(requirements);
|
||||
|
||||
foreach (var type in composerTypes)
|
||||
Console.WriteLine(type);
|
||||
}
|
||||
|
||||
#region Compothings
|
||||
|
||||
public class TestComposerBase : IComposer
|
||||
|
||||
@@ -27,10 +27,7 @@ namespace Umbraco.Tests.Composing
|
||||
public void Initialize()
|
||||
{
|
||||
// this ensures it's reset
|
||||
_typeLoader = new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
|
||||
foreach (var file in Directory.GetFiles(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache")))
|
||||
File.Delete(file);
|
||||
_typeLoader = new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()), false);
|
||||
|
||||
// for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
|
||||
// TODO: Should probably update this so it only searches this assembly and add custom types to be found
|
||||
|
||||
@@ -381,6 +381,9 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
}
|
||||
}
|
||||
|
||||
public override IPublishedContent GetById(bool preview, Udi nodeId)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override bool HasById(bool preview, int contentId)
|
||||
{
|
||||
return GetXml(preview).CreateNavigator().MoveToId(contentId.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
@@ -97,6 +97,9 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IPublishedContent GetById(bool preview, Udi nodeId)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override bool HasById(bool preview, int contentId)
|
||||
{
|
||||
return GetUmbracoMedia(contentId) != null;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Tests.Mapping
|
||||
{
|
||||
@@ -11,11 +15,11 @@ namespace Umbraco.Tests.Mapping
|
||||
[Test]
|
||||
public void SimpleMap()
|
||||
{
|
||||
var profiles = new MapDefinitionCollection(new IMapDefinition[]
|
||||
var definitions = new MapDefinitionCollection(new IMapDefinition[]
|
||||
{
|
||||
new Profile1(),
|
||||
new MapperDefinition1(),
|
||||
});
|
||||
var mapper = new UmbracoMapper(profiles);
|
||||
var mapper = new UmbracoMapper(definitions);
|
||||
|
||||
var thing1 = new Thing1 { Value = "value" };
|
||||
var thing2 = mapper.Map<Thing1, Thing2>(thing1);
|
||||
@@ -36,11 +40,11 @@ namespace Umbraco.Tests.Mapping
|
||||
[Test]
|
||||
public void EnumerableMap()
|
||||
{
|
||||
var profiles = new MapDefinitionCollection(new IMapDefinition[]
|
||||
var definitions = new MapDefinitionCollection(new IMapDefinition[]
|
||||
{
|
||||
new Profile1(),
|
||||
new MapperDefinition1(),
|
||||
});
|
||||
var mapper = new UmbracoMapper(profiles);
|
||||
var mapper = new UmbracoMapper(definitions);
|
||||
|
||||
var thing1A = new Thing1 { Value = "valueA" };
|
||||
var thing1B = new Thing1 { Value = "valueB" };
|
||||
@@ -58,16 +62,23 @@ namespace Umbraco.Tests.Mapping
|
||||
Assert.AreEqual(2, thing2.Count);
|
||||
Assert.AreEqual("valueA", thing2[0].Value);
|
||||
Assert.AreEqual("valueB", thing2[1].Value);
|
||||
|
||||
thing2 = mapper.MapEnumerable<Thing1, Thing2>(thing1).ToList();
|
||||
|
||||
Assert.IsNotNull(thing2);
|
||||
Assert.AreEqual(2, thing2.Count);
|
||||
Assert.AreEqual("valueA", thing2[0].Value);
|
||||
Assert.AreEqual("valueB", thing2[1].Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InheritedMap()
|
||||
{
|
||||
var profiles = new MapDefinitionCollection(new IMapDefinition[]
|
||||
var definitions = new MapDefinitionCollection(new IMapDefinition[]
|
||||
{
|
||||
new Profile1(),
|
||||
new MapperDefinition1(),
|
||||
});
|
||||
var mapper = new UmbracoMapper(profiles);
|
||||
var mapper = new UmbracoMapper(definitions);
|
||||
|
||||
var thing3 = new Thing3 { Value = "value" };
|
||||
var thing2 = mapper.Map<Thing3, Thing2>(thing3);
|
||||
@@ -85,6 +96,82 @@ namespace Umbraco.Tests.Mapping
|
||||
Assert.AreEqual("value", thing2.Value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CollectionsMap()
|
||||
{
|
||||
var definitions = new MapDefinitionCollection(new IMapDefinition[]
|
||||
{
|
||||
new MapperDefinition2(),
|
||||
});
|
||||
var mapper = new UmbracoMapper(definitions);
|
||||
|
||||
// can map a PropertyCollection
|
||||
var source = new PropertyCollection();
|
||||
var target = mapper.Map<IEnumerable<ContentPropertyDto>>(source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Explicit]
|
||||
public void ConcurrentMap()
|
||||
{
|
||||
var definitions = new MapDefinitionCollection(new IMapDefinition[]
|
||||
{
|
||||
new MapperDefinition1(),
|
||||
new MapperDefinition3(),
|
||||
});
|
||||
var mapper = new UmbracoMapper(definitions);
|
||||
|
||||
// the mapper currently has a map from Thing1 to Thing2
|
||||
// because Thing3 inherits from Thing1, it will map a Thing3 instance,
|
||||
// and register a new map from Thing3 to Thing2,
|
||||
// thus modifying its internal dictionaries
|
||||
|
||||
// if timing is good, and mapper does have non-concurrent dictionaries, it fails
|
||||
// practically, to reproduce, one needs to add a 1s sleep in the mapper's loop
|
||||
// hence, this test is explicit
|
||||
|
||||
var thing3 = new Thing3 { Value = "value" };
|
||||
var thing4 = new Thing4();
|
||||
Exception caught = null;
|
||||
|
||||
void ThreadLoop()
|
||||
{
|
||||
// keep failing at mapping - and looping through the maps
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
mapper.Map<Thing2>(thing4);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
caught = e;
|
||||
Console.WriteLine($"{e.GetType().Name} {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("done");
|
||||
}
|
||||
|
||||
var thread = new Thread(ThreadLoop);
|
||||
thread.Start();
|
||||
Thread.Sleep(1000);
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"{DateTime.Now:O} mapping");
|
||||
var thing2 = mapper.Map<Thing2>(thing3);
|
||||
Console.WriteLine($"{DateTime.Now:O} mapped");
|
||||
|
||||
Assert.IsNotNull(thing2);
|
||||
Assert.AreEqual("value", thing2.Value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
thread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
private class Thing1
|
||||
{
|
||||
public string Value { get; set; }
|
||||
@@ -98,7 +185,10 @@ namespace Umbraco.Tests.Mapping
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
private class Profile1 : IMapDefinition
|
||||
private class Thing4
|
||||
{ }
|
||||
|
||||
private class MapperDefinition1 : IMapDefinition
|
||||
{
|
||||
public void DefineMaps(UmbracoMapper mapper)
|
||||
{
|
||||
@@ -110,5 +200,29 @@ namespace Umbraco.Tests.Mapping
|
||||
target.Value = source.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private class MapperDefinition2 : IMapDefinition
|
||||
{
|
||||
public void DefineMaps(UmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<Property, ContentPropertyDto>((source, context) => new ContentPropertyDto(), Map);
|
||||
}
|
||||
|
||||
private static void Map(Property source, ContentPropertyDto target, MapperContext context)
|
||||
{ }
|
||||
}
|
||||
|
||||
private class MapperDefinition3 : IMapDefinition
|
||||
{
|
||||
public void DefineMaps(UmbracoMapper mapper)
|
||||
{
|
||||
// just some random things so that the mapper contains things
|
||||
mapper.Define<int, object>();
|
||||
mapper.Define<string, object>();
|
||||
mapper.Define<double, object>();
|
||||
mapper.Define<UmbracoMapper, object>();
|
||||
mapper.Define<Property, object>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,47 @@ namespace Umbraco.Tests.Models
|
||||
[TestFixture]
|
||||
public class ContentTypeTests : UmbracoTestBase
|
||||
{
|
||||
[Test]
|
||||
[Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")]
|
||||
public void Cannot_Add_Duplicate_Property_Aliases()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateBasicContentType();
|
||||
|
||||
contentType.PropertyGroups.Add(new PropertyGroup(new PropertyTypeCollection(false, new[]
|
||||
{
|
||||
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar){ Alias = "myPropertyType" }
|
||||
})));
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
contentType.PropertyTypeCollection.Add(
|
||||
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar) { Alias = "myPropertyType" }));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")]
|
||||
public void Cannot_Update_Duplicate_Property_Aliases()
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateBasicContentType();
|
||||
|
||||
contentType.PropertyGroups.Add(new PropertyGroup(new PropertyTypeCollection(false, new[]
|
||||
{
|
||||
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar){ Alias = "myPropertyType" }
|
||||
})));
|
||||
|
||||
contentType.PropertyTypeCollection.Add(new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar) { Alias = "myPropertyType2" });
|
||||
|
||||
var toUpdate = contentType.PropertyTypeCollection["myPropertyType2"];
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => toUpdate.Alias = "myPropertyType");
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Deep_Clone_Content_Type_Sort()
|
||||
{
|
||||
var contentType = new ContentTypeSort(new Lazy<int>(() => 3), 4, "test");
|
||||
var clone = (ContentTypeSort) contentType.DeepClone();
|
||||
var clone = (ContentTypeSort)contentType.DeepClone();
|
||||
Assert.AreNotSame(clone, contentType);
|
||||
Assert.AreEqual(clone, contentType);
|
||||
Assert.AreEqual(clone.Id.Value, contentType.Id.Value);
|
||||
@@ -54,7 +88,7 @@ namespace Umbraco.Tests.Models
|
||||
contentType.Id = 10;
|
||||
contentType.CreateDate = DateTime.Now;
|
||||
contentType.CreatorId = 22;
|
||||
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
|
||||
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
|
||||
{
|
||||
Id = 88
|
||||
});
|
||||
@@ -117,12 +151,12 @@ namespace Umbraco.Tests.Models
|
||||
{
|
||||
group.Id = ++i;
|
||||
}
|
||||
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
|
||||
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
|
||||
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
|
||||
contentType.Id = 10;
|
||||
contentType.CreateDate = DateTime.Now;
|
||||
contentType.CreatorId = 22;
|
||||
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
|
||||
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
|
||||
{
|
||||
Id = 88
|
||||
});
|
||||
@@ -167,12 +201,12 @@ namespace Umbraco.Tests.Models
|
||||
{
|
||||
group.Id = ++i;
|
||||
}
|
||||
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
|
||||
contentType.AllowedContentTypes = new[] {new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2")};
|
||||
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
|
||||
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
|
||||
contentType.Id = 10;
|
||||
contentType.CreateDate = DateTime.Now;
|
||||
contentType.CreatorId = 22;
|
||||
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
|
||||
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
|
||||
{
|
||||
Id = 88
|
||||
});
|
||||
@@ -264,12 +298,12 @@ namespace Umbraco.Tests.Models
|
||||
{
|
||||
propertyType.Id = ++i;
|
||||
}
|
||||
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
|
||||
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
|
||||
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
|
||||
contentType.Id = 10;
|
||||
contentType.CreateDate = DateTime.Now;
|
||||
contentType.CreatorId = 22;
|
||||
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
|
||||
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
|
||||
{
|
||||
Id = 88
|
||||
});
|
||||
|
||||
@@ -171,7 +171,6 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//NOTE: This tests for left join logic (rev 7b14e8eacc65f82d4f184ef46c23340c09569052)
|
||||
[Test]
|
||||
public void Can_Get_All_Members_When_No_Properties_Assigned()
|
||||
@@ -200,7 +199,6 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Member_Type_By_Id()
|
||||
{
|
||||
@@ -233,22 +231,114 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
// See: https://github.com/umbraco/Umbraco-CMS/issues/4963#issuecomment-483516698
|
||||
[Test]
|
||||
public void Bug_Changing_Built_In_Member_Type_Property_Type_Aliases_Results_In_Exception()
|
||||
{
|
||||
var stubs = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider);
|
||||
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType("mtype");
|
||||
|
||||
// created without the stub properties
|
||||
Assert.AreEqual(1, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3, memberType.PropertyTypes.Count());
|
||||
|
||||
// saving *new* member type adds the stub properties
|
||||
repository.Save(memberType);
|
||||
|
||||
// saving has added (and saved) the stub properties
|
||||
Assert.AreEqual(2, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
|
||||
|
||||
foreach (var stub in stubs)
|
||||
{
|
||||
var prop = memberType.PropertyTypes.First(x => x.Alias == stub.Key);
|
||||
prop.Alias = prop.Alias + "__0000";
|
||||
}
|
||||
|
||||
// saving *existing* member type does *not* ensure stub properties
|
||||
repository.Save(memberType);
|
||||
|
||||
// therefore, nothing has changed
|
||||
Assert.AreEqual(2, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
|
||||
|
||||
// fetching ensures that the stub properties are there
|
||||
memberType = repository.Get("mtype");
|
||||
Assert.IsNotNull(memberType);
|
||||
|
||||
Assert.AreEqual(2, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3 + stubs.Count * 2, memberType.PropertyTypes.Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Built_In_Member_Type_Properties_Are_Automatically_Added_When_Creating()
|
||||
{
|
||||
var stubs = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
using (provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider);
|
||||
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
|
||||
// created without the stub properties
|
||||
Assert.AreEqual(1, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3, memberType.PropertyTypes.Count());
|
||||
|
||||
// saving *new* member type adds the stub properties
|
||||
repository.Save(memberType);
|
||||
|
||||
// saving has added (and saved) the stub properties
|
||||
Assert.AreEqual(2, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
|
||||
|
||||
// getting with stub properties
|
||||
memberType = repository.Get(memberType.Id);
|
||||
|
||||
Assert.That(memberType.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count));
|
||||
Assert.That(memberType.PropertyGroups.Count(), Is.EqualTo(2));
|
||||
Assert.AreEqual(2, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Built_In_Member_Type_Properties_Missing_Are_Automatically_Added_When_Creating()
|
||||
{
|
||||
var stubs = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
|
||||
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider);
|
||||
|
||||
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
|
||||
|
||||
// created without the stub properties
|
||||
Assert.AreEqual(1, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3, memberType.PropertyTypes.Count());
|
||||
|
||||
// add one stub property, others are still missing
|
||||
memberType.AddPropertyType(stubs.First().Value, Constants.Conventions.Member.StandardPropertiesGroupName);
|
||||
|
||||
// saving *new* member type adds the (missing) stub properties
|
||||
repository.Save(memberType);
|
||||
|
||||
// saving has added (and saved) the (missing) stub properties
|
||||
Assert.AreEqual(2, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
|
||||
|
||||
// getting with stub properties
|
||||
memberType = repository.Get(memberType.Id);
|
||||
|
||||
Assert.AreEqual(2, memberType.PropertyGroups.Count);
|
||||
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace Umbraco.Tests.PublishedContent
|
||||
new WebSecurity(httpContext, Current.Services.UserService, globalSettings),
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
Enumerable.Empty<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
globalSettings,
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
|
||||
@@ -92,6 +92,9 @@ namespace Umbraco.Tests.PublishedContent
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IPublishedContent GetById(bool preview, Udi nodeId)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override bool HasById(bool preview, int contentId)
|
||||
{
|
||||
return _content.ContainsKey(contentId);
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Tests.PublishedContent;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Stubs;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Routing
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public class MediaUrlProviderTests : BaseWebTest
|
||||
{
|
||||
private DefaultMediaUrlProvider _mediaUrlProvider;
|
||||
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
_mediaUrlProvider = new DefaultMediaUrlProvider();
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
{
|
||||
base.TearDown();
|
||||
|
||||
_mediaUrlProvider = null;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Media_Url_Resolves_Url_From_Upload_Property_Editor()
|
||||
{
|
||||
const string expected = "/media/rfeiw584/test.jpg";
|
||||
|
||||
var umbracoContext = GetUmbracoContext("/", mediaUrlProviders: new[] { _mediaUrlProvider });
|
||||
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.UploadField, expected, null);
|
||||
|
||||
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Auto, null, null);
|
||||
|
||||
Assert.AreEqual(expected, resolvedUrl);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Media_Url_Resolves_Url_From_Image_Cropper_Property_Editor()
|
||||
{
|
||||
const string expected = "/media/rfeiw584/test.jpg";
|
||||
|
||||
var configuration = new ImageCropperConfiguration();
|
||||
var imageCropperValue = JsonConvert.SerializeObject(new ImageCropperValue
|
||||
{
|
||||
Src = expected
|
||||
});
|
||||
|
||||
var umbracoContext = GetUmbracoContext("/", mediaUrlProviders: new[] { _mediaUrlProvider });
|
||||
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.ImageCropper, imageCropperValue, configuration);
|
||||
|
||||
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Auto, null, null);
|
||||
|
||||
Assert.AreEqual(expected, resolvedUrl);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Media_Url_Can_Resolve_Absolute_Url()
|
||||
{
|
||||
const string mediaUrl = "/media/rfeiw584/test.jpg";
|
||||
var expected = $"http://localhost{mediaUrl}";
|
||||
|
||||
var umbracoContext = GetUmbracoContext("http://localhost", mediaUrlProviders: new[] { _mediaUrlProvider });
|
||||
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.UploadField, mediaUrl, null);
|
||||
|
||||
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Absolute, null, null);
|
||||
|
||||
Assert.AreEqual(expected, resolvedUrl);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Media_Url_Returns_Empty_String_When_PropertyType_Is_Not_Supported()
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext("/", mediaUrlProviders: new[] { _mediaUrlProvider });
|
||||
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.Boolean, "0", null);
|
||||
|
||||
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "test", UrlProviderMode.Absolute, null, null);
|
||||
|
||||
Assert.AreEqual(string.Empty, resolvedUrl);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Media_Url_Can_Resolve_Variant_Property_Url()
|
||||
{
|
||||
var umbracoContext = GetUmbracoContext("http://localhost", mediaUrlProviders: new[] { _mediaUrlProvider });
|
||||
|
||||
var umbracoFilePropertyType = CreatePropertyType(Constants.PropertyEditors.Aliases.UploadField, null, ContentVariation.Culture);
|
||||
|
||||
const string enMediaUrl = "/media/rfeiw584/en.jpg";
|
||||
const string daMediaUrl = "/media/uf8ewud2/da.jpg";
|
||||
|
||||
var property = new SolidPublishedPropertyWithLanguageVariants
|
||||
{
|
||||
Alias = "umbracoFile",
|
||||
PropertyType = umbracoFilePropertyType,
|
||||
};
|
||||
|
||||
property.SetValue("en", enMediaUrl, true);
|
||||
property.SetValue("da", daMediaUrl);
|
||||
|
||||
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), new [] { umbracoFilePropertyType }, ContentVariation.Culture);
|
||||
var publishedContent = new SolidPublishedContent(contentType) {Properties = new[] {property}};
|
||||
|
||||
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Auto, "da", null);
|
||||
Assert.AreEqual(daMediaUrl, resolvedUrl);
|
||||
}
|
||||
|
||||
private static TestPublishedContent CreatePublishedContent(string propertyEditorAlias, object propertyValue, object dataTypeConfiguration)
|
||||
{
|
||||
var umbracoFilePropertyType = CreatePropertyType(propertyEditorAlias, dataTypeConfiguration, ContentVariation.Nothing);
|
||||
|
||||
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(),
|
||||
new[] {umbracoFilePropertyType}, ContentVariation.Nothing);
|
||||
|
||||
return new TestPublishedContent(contentType, 1234, Guid.NewGuid(),
|
||||
new Dictionary<string, object> {{"umbracoFile", propertyValue } }, false);
|
||||
}
|
||||
|
||||
private static PublishedPropertyType CreatePropertyType(string propertyEditorAlias, object dataTypeConfiguration, ContentVariation variation)
|
||||
{
|
||||
var uploadDataType = new PublishedDataType(1234, propertyEditorAlias, new Lazy<object>(() => dataTypeConfiguration));
|
||||
|
||||
var propertyValueConverters = new PropertyValueConverterCollection(new IPropertyValueConverter[]
|
||||
{
|
||||
new UploadPropertyConverter(),
|
||||
new ImageCropperValueConverter(),
|
||||
});
|
||||
|
||||
var publishedModelFactory = Mock.Of<IPublishedModelFactory>();
|
||||
var publishedContentTypeFactory = new Mock<IPublishedContentTypeFactory>();
|
||||
publishedContentTypeFactory.Setup(x => x.GetDataType(It.IsAny<int>()))
|
||||
.Returns(uploadDataType);
|
||||
|
||||
return new PublishedPropertyType("umbracoFile", 42, true, variation, propertyValueConverters, publishedModelFactory, publishedContentTypeFactory.Object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,6 +118,7 @@ namespace Umbraco.Tests.Scoping
|
||||
new WebSecurity(httpContext, Current.Services.UserService, globalSettings),
|
||||
umbracoSettings ?? SettingsForTests.GetDefaultUmbracoSettings(),
|
||||
urlProviders ?? Enumerable.Empty<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
globalSettings,
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Microsoft.Owin;
|
||||
using Moq;
|
||||
@@ -33,7 +34,7 @@ namespace Umbraco.Tests.Security
|
||||
Mock.Of<HttpContextBase>(),
|
||||
Mock.Of<IPublishedSnapshotService>(),
|
||||
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, globalSettings),
|
||||
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(),globalSettings,
|
||||
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), Enumerable.Empty<IMediaUrlProvider>(), globalSettings,
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Install);
|
||||
@@ -53,7 +54,7 @@ namespace Umbraco.Tests.Security
|
||||
Mock.Of<HttpContextBase>(),
|
||||
Mock.Of<IPublishedSnapshotService>(),
|
||||
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, globalSettings),
|
||||
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), globalSettings,
|
||||
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), Enumerable.Empty<IMediaUrlProvider>(), globalSettings,
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run);
|
||||
|
||||
@@ -139,6 +139,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
|
||||
webSecurity.Object,
|
||||
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
|
||||
Enumerable.Empty<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
globalSettings,
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
var umbracoSettings = GetUmbracoSettings();
|
||||
var globalSettings = GetGlobalSettings();
|
||||
var urlProviders = new UrlProviderCollection(Enumerable.Empty<IUrlProvider>());
|
||||
var mediaUrlProviders = new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>());
|
||||
|
||||
if (accessor == null) accessor = new TestUmbracoContextAccessor();
|
||||
|
||||
@@ -133,6 +134,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
umbracoSettings,
|
||||
globalSettings,
|
||||
urlProviders,
|
||||
mediaUrlProviders,
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
return umbracoContextFactory.EnsureUmbracoContext(httpContext).UmbracoContext;
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
}
|
||||
}
|
||||
|
||||
protected UmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable<IUrlProvider> urlProviders = null, IGlobalSettings globalSettings = null, IPublishedSnapshotService snapshotService = null)
|
||||
protected UmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable<IUrlProvider> urlProviders = null, IEnumerable<IMediaUrlProvider> mediaUrlProviders = null, IGlobalSettings globalSettings = null, IPublishedSnapshotService snapshotService = null)
|
||||
{
|
||||
// ensure we have a PublishedCachesService
|
||||
var service = snapshotService ?? PublishedSnapshotService as PublishedSnapshotService;
|
||||
@@ -380,6 +380,7 @@ namespace Umbraco.Tests.TestHelpers
|
||||
Factory.GetInstance<IGlobalSettings>()),
|
||||
umbracoSettings ?? Factory.GetInstance<IUmbracoSettingsSection>(),
|
||||
urlProviders ?? Enumerable.Empty<IUrlProvider>(),
|
||||
mediaUrlProviders ?? Enumerable.Empty<IMediaUrlProvider>(),
|
||||
globalSettings ?? Factory.GetInstance<IGlobalSettings>(),
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Umbraco.Tests.Testing.TestingTests
|
||||
.Returns(UrlInfo.Url("/hello/world/1234"));
|
||||
var urlProvider = urlProviderMock.Object;
|
||||
|
||||
var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }, umbracoContext.VariationContextAccessor);
|
||||
var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }, Enumerable.Empty<IMediaUrlProvider>(), umbracoContext.VariationContextAccessor);
|
||||
|
||||
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
|
||||
var publishedContent = Mock.Of<IPublishedContent>();
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
<Compile Include="PublishedContent\PublishedContentSnapshotTestBase.cs" />
|
||||
<Compile Include="PublishedContent\SolidPublishedSnapshot.cs" />
|
||||
<Compile Include="PublishedContent\NuCacheTests.cs" />
|
||||
<Compile Include="Routing\MediaUrlProviderTests.cs" />
|
||||
<Compile Include="Runtimes\StandaloneTests.cs" />
|
||||
<Compile Include="Routing\GetContentUrlsTests.cs" />
|
||||
<Compile Include="Services\AmbiguousEventTests.cs" />
|
||||
|
||||
@@ -72,6 +72,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
@@ -101,6 +102,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
@@ -130,6 +132,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
@@ -159,6 +162,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
@@ -74,6 +75,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
@@ -104,6 +106,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
@@ -141,6 +144,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == webRoutingSettings),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
|
||||
|
||||
@@ -440,6 +440,7 @@ namespace Umbraco.Tests.Web.Mvc
|
||||
new WebSecurity(http, Current.Services.UserService, globalSettings),
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
Enumerable.Empty<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
globalSettings,
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
|
||||
@@ -61,10 +61,12 @@ namespace Umbraco.Tests.Web
|
||||
|
||||
[TestCase("", "")]
|
||||
[TestCase("hello href=\"{localLink:1234}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/media/1001/my-image.jpg\" world ")]
|
||||
//this one has an invalid char so won't match
|
||||
[TestCase("hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"#\" world ")]
|
||||
public void ParseLocalLinks(string input, string result)
|
||||
{
|
||||
var serviceCtxMock = new TestObjects(null).GetServiceContextMock();
|
||||
@@ -77,7 +79,7 @@ namespace Umbraco.Tests.Web
|
||||
// return Attempt.Succeed(1234);
|
||||
// });
|
||||
|
||||
//setup a mock url provider which we'll use fo rtesting
|
||||
//setup a mock url provider which we'll use for testing
|
||||
var testUrlProvider = new Mock<IUrlProvider>();
|
||||
testUrlProvider
|
||||
.Setup(x => x.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlProviderMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
|
||||
@@ -96,6 +98,10 @@ namespace Umbraco.Tests.Web
|
||||
Mock.Get(snapshot).Setup(x => x.Content).Returns(contentCache);
|
||||
var snapshotService = Mock.Of<IPublishedSnapshotService>();
|
||||
Mock.Get(snapshotService).Setup(x => x.CreatePublishedSnapshot(It.IsAny<string>())).Returns(snapshot);
|
||||
var media = Mock.Of<IPublishedContent>();
|
||||
Mock.Get(media).Setup(x => x.Url).Returns("/media/1001/my-image.jpg");
|
||||
var mediaCache = Mock.Of<IPublishedMediaCache>();
|
||||
Mock.Get(mediaCache).Setup(x => x.GetById(It.IsAny<Guid>())).Returns(media);
|
||||
|
||||
var umbracoContextFactory = new UmbracoContextFactory(
|
||||
Umbraco.Web.Composing.Current.UmbracoContextAccessor,
|
||||
@@ -105,11 +111,12 @@ namespace Umbraco.Tests.Web
|
||||
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
|
||||
globalSettings,
|
||||
new UrlProviderCollection(new[] { testUrlProvider.Object }),
|
||||
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
|
||||
Mock.Of<IUserService>());
|
||||
|
||||
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
|
||||
{
|
||||
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider);
|
||||
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider, mediaCache);
|
||||
|
||||
Assert.AreEqual(result, output);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
@@ -31,6 +32,7 @@ namespace Umbraco.Tests.Web
|
||||
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
new List<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
TestObjects.GetGlobalSettings(),
|
||||
new TestVariationContextAccessor());
|
||||
var r1 = new RouteData();
|
||||
@@ -49,6 +51,7 @@ namespace Umbraco.Tests.Web
|
||||
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
new List<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
TestObjects.GetGlobalSettings(),
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
@@ -77,6 +80,7 @@ namespace Umbraco.Tests.Web
|
||||
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
|
||||
TestObjects.GetUmbracoSettings(),
|
||||
new List<IUrlProvider>(),
|
||||
Enumerable.Empty<IMediaUrlProvider>(),
|
||||
TestObjects.GetGlobalSettings(),
|
||||
new TestVariationContextAccessor());
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"]
|
||||
}
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": "last 2 version, not dead, > 0.5%, not ie 11"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,46 +6,6 @@
|
||||
|
||||
This documentation relates to the angular, js, css and less APIs for developing back office components
|
||||
|
||||
##Running the site with mocked data
|
||||
|
||||
This won't require any database or setup, as everything is running through node. All you have to do is install
|
||||
node and grunt on either windows or OSX and the entire setup is ready for you.
|
||||
|
||||
|
||||
###Install node.js
|
||||
We need node to run tests and automated less compiling and other automated tasks. go to http://nodejs.org. Node.js is a powerfull javascript engine, which allows us to run all our tests and tasks written in javascript locally.
|
||||
|
||||
*note:* On windows you might need to restart explorer.exe to register node.
|
||||
|
||||
|
||||
###Install dependencies
|
||||
Next we need to install all the required packages. This is done with the package tool, included with node.js, open /Umbraco.Belle.Client in cmd.exe or osx terminal and run the command:
|
||||
|
||||
npm install
|
||||
|
||||
this will fetch all needed packages to your local machine.
|
||||
|
||||
|
||||
###Install grunt globally
|
||||
Grunt is a task runner for node.js, and we use it for all automated tasks in the build process. For convenience we need to install it globally on your machine, so it can be used directly in cmd.exe or the terminal.
|
||||
|
||||
So run the command:
|
||||
|
||||
npm install grunt-cli -g
|
||||
|
||||
*note:* On windows you might need to restart explorer.exe to register the grunt cmd.
|
||||
|
||||
*note:* On OSX you might need to run:
|
||||
|
||||
sudo npm install grunt-cli -g
|
||||
|
||||
Now that you have node and grunt installed, you can open `/Umbraco.Web.UI.Client` in either `cmd.exe` or terminal and run:
|
||||
|
||||
grunt dev
|
||||
|
||||
This will build the site, merge less files, run tests and create the /Build folder, and finally open the site in your
|
||||
browser.
|
||||
|
||||
##Getting started
|
||||
The current app is built, following conventions from angularJs and bootstrap. To get started with the applicaton you will need to atleast know the basics of these frameworks
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ var babel = require("gulp-babel");
|
||||
var sort = require('gulp-sort');
|
||||
var concat = require('gulp-concat');
|
||||
var wrap = require("gulp-wrap-js");
|
||||
var embedTemplates = require('gulp-angular-embed-templates');
|
||||
|
||||
module.exports = function(files, out) {
|
||||
|
||||
@@ -22,6 +23,7 @@ module.exports = function(files, out) {
|
||||
// sort files in stream by path or any custom sort comparator
|
||||
task = task.pipe(babel())
|
||||
.pipe(sort())
|
||||
.pipe(embedTemplates({ basePath: "./src/" }))
|
||||
.pipe(concat(out))
|
||||
.pipe(wrap('(function(){\n%= body %\n})();'))
|
||||
.pipe(gulp.dest(config.root + config.targets.js));
|
||||
@@ -29,4 +31,4 @@ module.exports = function(files, out) {
|
||||
|
||||
return task;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
+323
-46
@@ -1122,6 +1122,12 @@
|
||||
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
|
||||
"dev": true
|
||||
},
|
||||
"argh": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/argh/-/argh-0.1.4.tgz",
|
||||
"integrity": "sha1-PrTWEpc/xrbcbvM49W91nyrFw6Y=",
|
||||
"dev": true
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
@@ -1216,7 +1222,7 @@
|
||||
"arraybuffer.slice": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
|
||||
"integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=",
|
||||
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
|
||||
"dev": true
|
||||
},
|
||||
"asap": {
|
||||
@@ -1253,6 +1259,15 @@
|
||||
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
|
||||
"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.11"
|
||||
}
|
||||
},
|
||||
"async-each": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
|
||||
@@ -1269,7 +1284,7 @@
|
||||
"async-limiter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
|
||||
"integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=",
|
||||
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
|
||||
"dev": true
|
||||
},
|
||||
"asynckit": {
|
||||
@@ -1520,7 +1535,7 @@
|
||||
},
|
||||
"bl": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
|
||||
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -1536,7 +1551,7 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -1551,7 +1566,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -1725,7 +1740,7 @@
|
||||
"buffer-alloc": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
|
||||
"integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=",
|
||||
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-alloc-unsafe": "^1.1.0",
|
||||
@@ -1735,7 +1750,7 @@
|
||||
"buffer-alloc-unsafe": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
|
||||
"integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=",
|
||||
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
|
||||
"dev": true
|
||||
},
|
||||
"buffer-crc32": {
|
||||
@@ -1920,9 +1935,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30000913",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000913.tgz",
|
||||
"integrity": "sha512-PP7Ypc35XY1mNduHqweGNOp0qfNUCmaQauGOYDByvirlFjrzRyY72pBRx7jnBidOB8zclg00DAzsy2H475BouQ==",
|
||||
"version": "1.0.30000967",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000967.tgz",
|
||||
"integrity": "sha512-rUBIbap+VJfxTzrM4akJ00lkvVb5/n5v3EGXfWzSH5zT8aJmGzjA8HWhJ4U6kCpzxozUSnB+yvAYDRPY6mRpgQ==",
|
||||
"dev": true
|
||||
},
|
||||
"canonical-path": {
|
||||
@@ -2111,6 +2126,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli-color": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz",
|
||||
"integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.1.1",
|
||||
"d": "1",
|
||||
"es5-ext": "^0.10.46",
|
||||
"es6-iterator": "^2.0.3",
|
||||
"memoizee": "^0.4.14",
|
||||
"timers-ext": "^0.1.5"
|
||||
}
|
||||
},
|
||||
"cli-cursor": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
|
||||
@@ -2287,12 +2316,40 @@
|
||||
"integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=",
|
||||
"dev": true
|
||||
},
|
||||
"colornames": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
|
||||
"integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=",
|
||||
"dev": true
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
|
||||
"integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
|
||||
"dev": true
|
||||
},
|
||||
"colorspace": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz",
|
||||
"integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color": "3.0.x",
|
||||
"text-hex": "1.0.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"color": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
|
||||
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.1",
|
||||
"color-string": "^1.5.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"combine-lists": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz",
|
||||
@@ -2459,7 +2516,7 @@
|
||||
"content-type": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
|
||||
"dev": true
|
||||
},
|
||||
"continuable-cache": {
|
||||
@@ -3417,6 +3474,17 @@
|
||||
"integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
|
||||
"dev": true
|
||||
},
|
||||
"diagnostics": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
|
||||
"integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"colorspace": "1.1.x",
|
||||
"enabled": "1.0.x",
|
||||
"kuler": "1.0.x"
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
@@ -3467,6 +3535,15 @@
|
||||
"integrity": "sha512-SQVCLFS2E7G5CRCMdn6K9bIhRj1bS6QBWZfF0TUPh4V/BbqrQ619IdSS3/izn0FZ+9l+uODzaZjb08fjOfablA==",
|
||||
"dev": true
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
|
||||
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
|
||||
@@ -3921,6 +3998,21 @@
|
||||
"integrity": "sha512-EV5FZ68Hu+n9fHVhOc9AcG3Lvf+E1YqR36ulJUpwaQTkf4LwdvBqmGIazaIrt4kt6J8Gw3Kv7r9F+PQjAkjWeA==",
|
||||
"dev": true
|
||||
},
|
||||
"emits": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emits/-/emits-3.0.0.tgz",
|
||||
"integrity": "sha1-MnUrupXhcHshlWI4Srm7ix/WL3A=",
|
||||
"dev": true
|
||||
},
|
||||
"enabled": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
|
||||
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"env-variable": "0.0.x"
|
||||
}
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
@@ -3953,7 +4045,7 @@
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
@@ -3969,7 +4061,7 @@
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
|
||||
"integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -3989,7 +4081,7 @@
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
@@ -4028,6 +4120,12 @@
|
||||
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
|
||||
"dev": true
|
||||
},
|
||||
"env-variable": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
|
||||
"integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==",
|
||||
"dev": true
|
||||
},
|
||||
"errno": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
|
||||
@@ -4119,6 +4217,18 @@
|
||||
"es5-ext": "~0.10.14"
|
||||
}
|
||||
},
|
||||
"es6-weak-map": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
|
||||
"integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"d": "1",
|
||||
"es5-ext": "^0.10.14",
|
||||
"es6-iterator": "^2.0.1",
|
||||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
@@ -4338,6 +4448,16 @@
|
||||
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
|
||||
"dev": true
|
||||
},
|
||||
"event-emitter": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
|
||||
"integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"d": "1",
|
||||
"es5-ext": "~0.10.14"
|
||||
}
|
||||
},
|
||||
"event-stream": {
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz",
|
||||
@@ -4356,13 +4476,13 @@
|
||||
"eventemitter3": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
|
||||
"integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=",
|
||||
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==",
|
||||
"dev": true
|
||||
},
|
||||
"exec-buffer": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz",
|
||||
"integrity": "sha1-sWhtvZBMfPmC5lLB9aebHlVzCCs=",
|
||||
"integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
@@ -5124,7 +5244,7 @@
|
||||
"fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
|
||||
"dev": true
|
||||
},
|
||||
"fs-extra": {
|
||||
@@ -5189,7 +5309,8 @@
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@@ -5210,12 +5331,14 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -5230,17 +5353,20 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -5357,7 +5483,8 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -5369,6 +5496,7 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -5383,6 +5511,7 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -5390,12 +5519,14 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -5414,6 +5545,7 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -5494,7 +5626,8 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -5506,6 +5639,7 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -5591,7 +5725,8 @@
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@@ -5627,6 +5762,7 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@@ -5646,6 +5782,7 @@
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@@ -5689,12 +5826,14 @@
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6185,6 +6324,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"gulp-angular-embed-templates": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/gulp-angular-embed-templates/-/gulp-angular-embed-templates-2.3.0.tgz",
|
||||
"integrity": "sha1-wBDv3VlN7pRRMoNFN9eSOt6EDXk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"gulp-util": "^3.0.6",
|
||||
"htmlparser2": "~3.9.1",
|
||||
"minimize": "^2.0.0",
|
||||
"object-assign": "4.1.0",
|
||||
"through2": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"object-assign": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
|
||||
"integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"gulp-babel": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz",
|
||||
@@ -7415,7 +7575,7 @@
|
||||
"has-binary2": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
|
||||
"integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=",
|
||||
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isarray": "2.0.1"
|
||||
@@ -7537,6 +7697,58 @@
|
||||
"integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
|
||||
"dev": true
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
|
||||
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "^1.3.0",
|
||||
"domhandler": "^2.3.0",
|
||||
"domutils": "^1.5.1",
|
||||
"entities": "^1.1.1",
|
||||
"inherits": "^2.0.1",
|
||||
"readable-stream": "^2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
|
||||
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
|
||||
"dev": true
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||
@@ -7566,7 +7778,7 @@
|
||||
"http-proxy": {
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
|
||||
"integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=",
|
||||
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eventemitter3": "^3.0.0",
|
||||
@@ -8306,9 +8518,9 @@
|
||||
}
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
|
||||
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.0.tgz",
|
||||
"integrity": "sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ=="
|
||||
},
|
||||
"jquery-ui-dist": {
|
||||
"version": "1.12.1",
|
||||
@@ -8560,6 +8772,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"kuler": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz",
|
||||
"integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"colornames": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"lazy-cache": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
|
||||
@@ -9114,7 +9335,7 @@
|
||||
"lowercase-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||
"integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=",
|
||||
"integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
|
||||
"dev": true
|
||||
},
|
||||
"lpad-align": {
|
||||
@@ -9136,10 +9357,19 @@
|
||||
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
|
||||
"dev": true
|
||||
},
|
||||
"lru-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
|
||||
"integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es5-ext": "~0.10.2"
|
||||
}
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
|
||||
"integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=",
|
||||
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pify": "^3.0.0"
|
||||
@@ -9225,6 +9455,22 @@
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
|
||||
"dev": true
|
||||
},
|
||||
"memoizee": {
|
||||
"version": "0.4.14",
|
||||
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz",
|
||||
"integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"d": "1",
|
||||
"es5-ext": "^0.10.45",
|
||||
"es6-weak-map": "^2.0.2",
|
||||
"event-emitter": "^0.3.5",
|
||||
"is-promise": "^2.1",
|
||||
"lru-queue": "0.1",
|
||||
"next-tick": "1",
|
||||
"timers-ext": "^0.1.5"
|
||||
}
|
||||
},
|
||||
"meow": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
@@ -9355,6 +9601,21 @@
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true
|
||||
},
|
||||
"minimize": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimize/-/minimize-2.2.0.tgz",
|
||||
"integrity": "sha512-IxR2XMbw9pXCxApkdD9BTcH2U4XlXhbeySUrv71rmMS9XDA8BVXEsIuFu24LtwCfBgfbL7Fuh8/ZzkO5DaTLlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argh": "^0.1.4",
|
||||
"async": "^2.1.5",
|
||||
"cli-color": "^1.2.0",
|
||||
"diagnostics": "^1.1.0",
|
||||
"emits": "^3.0.0",
|
||||
"htmlparser2": "^3.9.2",
|
||||
"uuid": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"mixin-deep": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
|
||||
@@ -12474,7 +12735,7 @@
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -13355,7 +13616,7 @@
|
||||
"qjobs": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
|
||||
"integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=",
|
||||
"integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
@@ -14514,7 +14775,7 @@
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
|
||||
"integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -14526,7 +14787,7 @@
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
@@ -14659,7 +14920,7 @@
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@@ -15067,7 +15328,7 @@
|
||||
"strip-outer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
|
||||
"integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=",
|
||||
"integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"escape-string-regexp": "^1.0.2"
|
||||
@@ -15227,7 +15488,7 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -15269,6 +15530,12 @@
|
||||
"uuid": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"text-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
|
||||
"dev": true
|
||||
},
|
||||
"text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
@@ -15369,6 +15636,16 @@
|
||||
"integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=",
|
||||
"dev": true
|
||||
},
|
||||
"timers-ext": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
|
||||
"integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es5-ext": "~0.10.46",
|
||||
"next-tick": "1"
|
||||
}
|
||||
},
|
||||
"timsort": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
|
||||
@@ -15454,7 +15731,7 @@
|
||||
"to-buffer": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
|
||||
"integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=",
|
||||
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
|
||||
"dev": true
|
||||
},
|
||||
"to-fast-properties": {
|
||||
@@ -15583,7 +15860,7 @@
|
||||
"type-is": {
|
||||
"version": "1.6.16",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
|
||||
"integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=",
|
||||
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
@@ -15625,7 +15902,7 @@
|
||||
"ultron": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
|
||||
"integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=",
|
||||
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
|
||||
"dev": true
|
||||
},
|
||||
"unc-path-regex": {
|
||||
@@ -16228,7 +16505,7 @@
|
||||
"ws": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
|
||||
"integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=",
|
||||
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"diff": "3.5.0",
|
||||
"flatpickr": "4.5.2",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "3.3.1",
|
||||
"jquery": "^3.4.0",
|
||||
"jquery-ui-dist": "1.12.1",
|
||||
"jquery-ui-touch-punch": "0.2.3",
|
||||
"lazyload-js": "1.0.0",
|
||||
@@ -50,6 +50,7 @@
|
||||
"cssnano": "4.1.7",
|
||||
"fs": "0.0.2",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-angular-embed-templates": "^2.3.0",
|
||||
"gulp-babel": "8.0.0",
|
||||
"gulp-clean-css": "4.0.0",
|
||||
"gulp-cli": "^2.0.1",
|
||||
@@ -76,6 +77,7 @@
|
||||
"lodash": "4.17.11",
|
||||
"marked": "^0.5.2",
|
||||
"merge-stream": "1.0.1",
|
||||
"run-sequence": "2.2.1"
|
||||
"run-sequence": "2.2.1",
|
||||
"caniuse-lite": "^1.0.30000966"
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function AppHeaderDirective(eventsService, appState, userService) {
|
||||
function AppHeaderDirective(eventsService, appState, userService, focusService) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
@@ -54,7 +54,9 @@
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
scope.rememberFocus = focusService.rememberFocus;
|
||||
|
||||
scope.searchClick = function() {
|
||||
var showSearch = appState.getSearchState("show");
|
||||
appState.setSearchState("show", !showSearch);
|
||||
@@ -101,4 +103,4 @@
|
||||
|
||||
angular.module("umbraco.directives").directive("umbAppHeader", AppHeaderDirective);
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
+18
-9
@@ -16,7 +16,6 @@
|
||||
function UmbLoginController($scope, $location, currentUserResource, formHelper, mediaHelper, umbRequestHelper, Upload, localizationService, userService, externalLoginInfo, resetPasswordCodeInfo, $timeout, authResource, $q) {
|
||||
|
||||
const vm = this;
|
||||
let twoFactorloginDialog = null;
|
||||
|
||||
vm.invitedUser = null;
|
||||
|
||||
@@ -69,7 +68,9 @@
|
||||
).then(function (data) {
|
||||
vm.labels.usernameLabel = data[0];
|
||||
vm.labels.usernamePlaceholder = data[1];
|
||||
})
|
||||
});
|
||||
|
||||
vm.twoFactor = {};
|
||||
|
||||
function onInit() {
|
||||
|
||||
@@ -126,6 +127,7 @@
|
||||
function togglePassword() {
|
||||
var elem = $("form[name='vm.loginForm'] input[name='password']");
|
||||
elem.attr("type", (elem.attr("type") === "text" ? "password" : "text"));
|
||||
elem.focus();
|
||||
$(".password-text.show, .password-text.hide").toggle();
|
||||
}
|
||||
|
||||
@@ -186,15 +188,18 @@
|
||||
vm.view = "set-password";
|
||||
}
|
||||
|
||||
function loginSubmit(login, password) {
|
||||
|
||||
function loginSubmit() {
|
||||
|
||||
// make sure that we are returning to the login view.
|
||||
vm.view = "login";
|
||||
|
||||
// TODO: Do validation properly like in the invite password update
|
||||
|
||||
//if the login and password are not empty we need to automatically
|
||||
// validate them - this is because if there are validation errors on the server
|
||||
// then the user has to change both username & password to resubmit which isn't ideal,
|
||||
// so if they're not empty, we'll just make sure to set them to valid.
|
||||
if (login && password && login.length > 0 && password.length > 0) {
|
||||
if (vm.login && vm.password && vm.login.length > 0 && vm.password.length > 0) {
|
||||
vm.loginForm.username.$setValidity('auth', true);
|
||||
vm.loginForm.password.$setValidity('auth', true);
|
||||
}
|
||||
@@ -205,7 +210,7 @@
|
||||
|
||||
vm.loginStates.submitButton = "busy";
|
||||
|
||||
userService.authenticate(login, password)
|
||||
userService.authenticate(vm.login, vm.password)
|
||||
.then(function (data) {
|
||||
vm.loginStates.submitButton = "success";
|
||||
userService._retryRequestQueue(true);
|
||||
@@ -218,7 +223,7 @@
|
||||
//is Two Factor required?
|
||||
if (reason.status === 402) {
|
||||
vm.errorMsg = "Additional authentication required";
|
||||
show2FALoginDialog(reason.data.twoFactorView, submit);
|
||||
show2FALoginDialog(reason.data.twoFactorView);
|
||||
}
|
||||
else {
|
||||
vm.loginStates.submitButton = "error";
|
||||
@@ -402,8 +407,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
function show2FALoginDialog(view, callback) {
|
||||
// TODO: show 2FA window
|
||||
function show2FALoginDialog(viewPath) {
|
||||
vm.twoFactor.submitCallback = function submitCallback() {
|
||||
vm.onLogin();
|
||||
}
|
||||
vm.twoFactor.view = viewPath;
|
||||
vm.view = "2fa-login";
|
||||
}
|
||||
|
||||
function resetInputValidation() {
|
||||
|
||||
+12
-2
@@ -13,7 +13,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
function umbSearchController($timeout, backdropService, searchService) {
|
||||
function umbSearchController($timeout, backdropService, searchService, focusService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
vm.handleKeyUp = handleKeyUp;
|
||||
vm.closeSearch = closeSearch;
|
||||
vm.focusSearch = focusSearch;
|
||||
|
||||
//we need to capture the focus before this element is initialized.
|
||||
vm.focusBeforeOpening = focusService.getLastKnownFocus();
|
||||
|
||||
function onInit() {
|
||||
vm.searchQuery = "";
|
||||
@@ -70,6 +73,10 @@
|
||||
* @param {object} event
|
||||
*/
|
||||
function handleKeyUp(event) {
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
// esc
|
||||
if(event.keyCode === 27) {
|
||||
closeSearch();
|
||||
@@ -80,6 +87,9 @@
|
||||
* Used to proxy a callback
|
||||
*/
|
||||
function closeSearch() {
|
||||
if(vm.focusBeforeOpening) {
|
||||
vm.focusBeforeOpening.focus();
|
||||
}
|
||||
if(vm.onClose) {
|
||||
vm.onClose();
|
||||
}
|
||||
@@ -115,4 +125,4 @@
|
||||
|
||||
angular.module('umbraco.directives').component('umbSearch', umbSearch);
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
+2
@@ -117,6 +117,8 @@ Use this directive to render an umbraco button. The directive can be used to gen
|
||||
vm.innerState = "init";
|
||||
|
||||
vm.buttonLabel = vm.label;
|
||||
// is this a primary button style (i.e. anything but an 'info' button)?
|
||||
vm.isPrimaryButtonStyle = vm.buttonStyle && vm.buttonStyle !== 'info';
|
||||
|
||||
if (vm.buttonStyle) {
|
||||
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbToggleGroup
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
Use this directive to render a group of toggle buttons.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.Controller as vm">
|
||||
|
||||
<umb-toggle-group
|
||||
items="vm.items"
|
||||
on-click="vm.toggle(item)">
|
||||
</umb-toggle-group>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function Controller() {
|
||||
|
||||
var vm = this;
|
||||
vm.toggle = toggle;
|
||||
|
||||
function toggle(item) {
|
||||
if(item.checked) {
|
||||
// do something if item is checked
|
||||
}
|
||||
else {
|
||||
// do something else if item is unchecked
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
vm.items = [{
|
||||
name: "Item 1",
|
||||
description: "Item 1 description",
|
||||
checked: false,
|
||||
disabled: false
|
||||
}, {
|
||||
name: "Item 2",
|
||||
description: "Item 2 description",
|
||||
checked: true,
|
||||
disabled: true
|
||||
}];
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("My.Controller", Controller);
|
||||
|
||||
})();
|
||||
</pre>
|
||||
|
||||
@param {Array} items The items to list in the toggle group
|
||||
@param {callback} onClick The function which should be called when the toggle is clicked for one of the items.
|
||||
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function ToggleGroupDirective() {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
scope.change = function(item) {
|
||||
if (item.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.checked = !item.checked;
|
||||
if(scope.onClick) {
|
||||
scope.onClick({'item': item});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/buttons/umb-toggle-group.html',
|
||||
scope: {
|
||||
items: "=",
|
||||
onClick: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbToggleGroup', ToggleGroupDirective);
|
||||
|
||||
})();
|
||||
+2
-2
@@ -55,9 +55,9 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// if we still dont have a app, lets show the first one:
|
||||
if (isAppPresent === false) {
|
||||
if (isAppPresent === false && content.apps.length) {
|
||||
content.apps[0].active = true;
|
||||
$scope.appChanged(content.apps[0]);
|
||||
}
|
||||
|
||||
+5
-3
@@ -198,9 +198,11 @@
|
||||
return a.alias === "umbContent";
|
||||
});
|
||||
|
||||
//The view model for the content app is simply the index of the variant being edited
|
||||
var variantIndex = vm.content.variants.indexOf(variant);
|
||||
contentApp.viewModel = variantIndex;
|
||||
if (contentApp) {
|
||||
//The view model for the content app is simply the index of the variant being edited
|
||||
var variantIndex = vm.content.variants.indexOf(variant);
|
||||
contentApp.viewModel = variantIndex;
|
||||
}
|
||||
|
||||
// make sure the same app it set to active in the new variant
|
||||
if(activeAppAlias) {
|
||||
|
||||
+3
@@ -47,6 +47,9 @@ The sub header is sticky and will follow along down the page when scrolling.
|
||||
transclude: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
scope: {
|
||||
"appearance": "@?"
|
||||
},
|
||||
templateUrl: 'views/components/editor/subheader/umb-editor-sub-header.html'
|
||||
};
|
||||
|
||||
|
||||
+4
-2
@@ -4,7 +4,7 @@
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.directive('hotkey', function($window, keyboardService, $log) {
|
||||
.directive('hotkey', function($window, keyboardService, $log, focusService) {
|
||||
|
||||
return function(scope, el, attrs) {
|
||||
|
||||
@@ -28,7 +28,9 @@ angular.module("umbraco.directives")
|
||||
}
|
||||
|
||||
keyboardService.bind(keyCombo, function() {
|
||||
|
||||
|
||||
focusService.rememberFocus();
|
||||
|
||||
var element = $(el);
|
||||
var activeElementType = document.activeElement.tagName;
|
||||
var clickableElements = ["A", "BUTTON"];
|
||||
|
||||
+60
-29
@@ -6,7 +6,7 @@
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbImageCrop',
|
||||
function ($timeout, localizationService, cropperHelper, $log) {
|
||||
function ($timeout, cropperHelper) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
@@ -21,6 +21,9 @@ angular.module("umbraco.directives")
|
||||
},
|
||||
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
let sliderRef = null;
|
||||
|
||||
scope.width = 400;
|
||||
scope.height = 320;
|
||||
|
||||
@@ -30,12 +33,56 @@ angular.module("umbraco.directives")
|
||||
viewport:{},
|
||||
margin: 20,
|
||||
scale: {
|
||||
min: 0.3,
|
||||
min: 0,
|
||||
max: 3,
|
||||
current: 1
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
scope.sliderOptions = {
|
||||
"start": scope.dimensions.scale.current,
|
||||
"step": 0.001,
|
||||
"tooltips": [false],
|
||||
"format": {
|
||||
to: function (value) {
|
||||
return parseFloat(parseFloat(value).toFixed(3)); //Math.round(value);
|
||||
},
|
||||
from: function (value) {
|
||||
return parseFloat(parseFloat(value).toFixed(3)); //Math.round(value);
|
||||
}
|
||||
},
|
||||
"range": {
|
||||
"min": scope.dimensions.scale.min,
|
||||
"max": scope.dimensions.scale.max
|
||||
}
|
||||
};
|
||||
|
||||
scope.setup = function (slider) {
|
||||
sliderRef = slider;
|
||||
|
||||
// Set slider handle position
|
||||
sliderRef.noUiSlider.set(scope.dimensions.scale.current);
|
||||
|
||||
// Update slider range min/max
|
||||
sliderRef.noUiSlider.updateOptions({
|
||||
"range": {
|
||||
"min": scope.dimensions.scale.min,
|
||||
"max": scope.dimensions.scale.max
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
scope.slide = function (values) {
|
||||
if (values) {
|
||||
scope.dimensions.scale.current = parseFloat(values);
|
||||
}
|
||||
};
|
||||
|
||||
scope.change = function (values) {
|
||||
if (values) {
|
||||
scope.dimensions.scale.current = parseFloat(values);
|
||||
}
|
||||
};
|
||||
|
||||
//live rendering of viewport and image styles
|
||||
scope.style = function () {
|
||||
@@ -63,7 +110,6 @@ angular.module("umbraco.directives")
|
||||
constraints.top.min = scope.dimensions.margin + scope.dimensions.cropper.height - scope.dimensions.image.height;
|
||||
};
|
||||
|
||||
|
||||
var setDimensions = function(originalImage){
|
||||
originalImage.width("auto");
|
||||
originalImage.height("auto");
|
||||
@@ -131,13 +177,11 @@ angular.module("umbraco.directives")
|
||||
|
||||
scope.dimensions.scale.current = scope.dimensions.image.ratio;
|
||||
|
||||
//min max based on original width/height
|
||||
// Update min and max based on original width/height
|
||||
scope.dimensions.scale.min = ratioCalculation.ratio;
|
||||
scope.dimensions.scale.max = 2;
|
||||
scope.dimensions.scale.max = 2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var validatePosition = function(left, top){
|
||||
if(left > constraints.left.max)
|
||||
{
|
||||
@@ -191,8 +235,6 @@ angular.module("umbraco.directives")
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
var init = function(image){
|
||||
scope.loaded = false;
|
||||
|
||||
@@ -219,10 +261,10 @@ angular.module("umbraco.directives")
|
||||
};
|
||||
|
||||
|
||||
/// WATCHERS ////
|
||||
// Watchers
|
||||
scope.$watchCollection('[width, height]', function(newValues, oldValues){
|
||||
//we have to reinit the whole thing if
|
||||
//one of the external params changes
|
||||
// We have to reinit the whole thing if
|
||||
// one of the external params changes
|
||||
if(newValues !== oldValues){
|
||||
setDimensions($image);
|
||||
setConstraints();
|
||||
@@ -230,29 +272,18 @@ angular.module("umbraco.directives")
|
||||
});
|
||||
|
||||
var throttledResizing = _.throttle(function(){
|
||||
resizeImageToScale(scope.dimensions.scale.current);
|
||||
resizeImageToScale(scope.dimensions.scale.current);
|
||||
calculateCropBox();
|
||||
}, 15);
|
||||
|
||||
|
||||
//happens when we change the scale
|
||||
scope.$watch("dimensions.scale.current", function(){
|
||||
if(scope.loaded){
|
||||
// Happens when we change the scale
|
||||
scope.$watch("dimensions.scale.current", function (newValue, oldValue) {
|
||||
if (scope.loaded) {
|
||||
throttledResizing();
|
||||
}
|
||||
});
|
||||
|
||||
//ie hack
|
||||
if(window.navigator.userAgent.indexOf("MSIE ") >= 0){
|
||||
var ranger = element.find("input");
|
||||
ranger.on("change",function(){
|
||||
scope.$apply(function(){
|
||||
scope.dimensions.scale.current = ranger.val();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//// INIT /////
|
||||
// Init
|
||||
$image.on("load", function(){
|
||||
$timeout(function(){
|
||||
init($image);
|
||||
|
||||
+3
-1
@@ -295,7 +295,8 @@ Opens an overlay to show a custom YSOD. </br>
|
||||
scope.closeOverLay();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
@@ -511,6 +512,7 @@ Opens an overlay to show a custom YSOD. </br>
|
||||
model: "=",
|
||||
view: "=",
|
||||
position: "@",
|
||||
size: "=?",
|
||||
parentScope: "=?"
|
||||
},
|
||||
link: link
|
||||
|
||||
+7
@@ -41,6 +41,7 @@
|
||||
vm.removeTag = removeTag;
|
||||
vm.showPrompt = showPrompt;
|
||||
vm.hidePrompt = hidePrompt;
|
||||
vm.onKeyUpOnTag = onKeyUpOnTag;
|
||||
|
||||
vm.htmlId = "t" + String.CreateGuid();
|
||||
vm.isLoading = true;
|
||||
@@ -272,6 +273,12 @@
|
||||
vm.promptIsVisible = "-1";
|
||||
}
|
||||
|
||||
function onKeyUpOnTag(tag, $event) {
|
||||
if ($event.keyCode === 8 || $event.keyCode === 46) {
|
||||
removeTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
// helper method to remove current tags
|
||||
function removeCurrentTagsFromSuggestions(suggestions) {
|
||||
return $.grep(suggestions, function (suggestion) {
|
||||
|
||||
+7
@@ -12,6 +12,7 @@ function treeSearchBox(localizationService, searchService, $q) {
|
||||
searchFromName: "@",
|
||||
showSearch: "@",
|
||||
section: "@",
|
||||
ignoreUserStartNodes: "@",
|
||||
hideSearchCallback: "=",
|
||||
searchCallback: "="
|
||||
},
|
||||
@@ -34,6 +35,7 @@ function treeSearchBox(localizationService, searchService, $q) {
|
||||
scope.showSearch = "false";
|
||||
}
|
||||
|
||||
|
||||
//used to cancel any request in progress if another one needs to take it's place
|
||||
var canceler = null;
|
||||
|
||||
@@ -60,6 +62,11 @@ function treeSearchBox(localizationService, searchService, $q) {
|
||||
searchArgs["searchFrom"] = scope.searchFromId;
|
||||
}
|
||||
|
||||
//append ignoreUserStartNodes value if there is one
|
||||
if (scope.ignoreUserStartNodes) {
|
||||
searchArgs["ignoreUserStartNodes"] = scope.ignoreUserStartNodes;
|
||||
}
|
||||
|
||||
searcher(searchArgs).then(function (data) {
|
||||
scope.searchCallback(data);
|
||||
//set back to null so it can be re-created
|
||||
|
||||
@@ -60,6 +60,7 @@ function confirmDirective() {
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
scope.showCancel = false;
|
||||
scope.showConfirm = false;
|
||||
scope.confirmButtonState = "init";
|
||||
|
||||
if (scope.onConfirm) {
|
||||
scope.showConfirm = true;
|
||||
@@ -68,6 +69,15 @@ function confirmDirective() {
|
||||
if (scope.onCancel) {
|
||||
scope.showCancel = true;
|
||||
}
|
||||
|
||||
scope.confirm = function () {
|
||||
if (!scope.onConfirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
scope.confirmButtonState = "busy";
|
||||
scope.onConfirm();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+6
-6
@@ -3,7 +3,7 @@
|
||||
function () {
|
||||
|
||||
var link = function ($scope) {
|
||||
|
||||
|
||||
// Clone the model because some property editors
|
||||
// do weird things like updating and config values
|
||||
// so we want to ensure we start from a fresh every
|
||||
@@ -12,10 +12,10 @@
|
||||
$scope.nodeContext = $scope.model;
|
||||
|
||||
// Find the selected tab
|
||||
var selectedTab = $scope.model.tabs[0];
|
||||
var selectedTab = $scope.model.variants[0].tabs[0];
|
||||
|
||||
if ($scope.tabAlias) {
|
||||
angular.forEach($scope.model.tabs, function (tab) {
|
||||
angular.forEach($scope.model.variants[0].tabs, function (tab) {
|
||||
if (tab.alias.toLowerCase() === $scope.tabAlias.toLowerCase()) {
|
||||
selectedTab = tab;
|
||||
return;
|
||||
@@ -31,9 +31,9 @@
|
||||
|
||||
// Tell inner controls we are submitting
|
||||
$scope.$broadcast("formSubmitting", { scope: $scope });
|
||||
|
||||
|
||||
// Sync the values back
|
||||
angular.forEach($scope.ngModel.tabs, function (tab) {
|
||||
angular.forEach($scope.ngModel.variants[0].tabs, function (tab) {
|
||||
if (tab.alias.toLowerCase() === selectedTab.alias.toLowerCase()) {
|
||||
|
||||
var localPropsMap = selectedTab.properties.reduce(function (map, obj) {
|
||||
@@ -94,4 +94,4 @@
|
||||
// },
|
||||
// link: link
|
||||
// }
|
||||
//});
|
||||
//});
|
||||
|
||||
@@ -91,6 +91,10 @@ Use this directive to generate a pagination.
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
function activate() {
|
||||
// page number is sometimes a string - let's make sure it's an int before we do anything with it
|
||||
if (scope.pageNumber) {
|
||||
scope.pageNumber = parseInt(scope.pageNumber);
|
||||
}
|
||||
|
||||
scope.pagination = [];
|
||||
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function PermissionDirective() {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
scope.change = function() {
|
||||
scope.selected = !scope.selected;
|
||||
if(scope.onChange) {
|
||||
scope.onChange({'selected': scope.selected});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/users/umb-permission.html',
|
||||
scope: {
|
||||
name: "=",
|
||||
description: "=?",
|
||||
selected: "=",
|
||||
onChange: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbPermission', PermissionDirective);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @ngdoc filter
|
||||
* @name umbraco.filters.filter:truncate
|
||||
* @namespace truncateFilter
|
||||
*
|
||||
* param {any} wordwise if true, the string will be cut after last fully displayed word.
|
||||
* param {any} max max length of the outputtet string
|
||||
* param {any} tail option tail, defaults to: ' ...'
|
||||
*
|
||||
* @description
|
||||
* Limits the length of a string, if a cut happens only the string will be appended with three dots to indicate that more is available.
|
||||
*/
|
||||
angular.module("umbraco.filters").filter('truncate',
|
||||
function () {
|
||||
return function (value, wordwise, max, tail) {
|
||||
if (!value) return '';
|
||||
max = parseInt(max, 10);
|
||||
if (!max) return value;
|
||||
if (value.length <= max) return value;
|
||||
|
||||
value = value.substr(0, max);
|
||||
if (wordwise) {
|
||||
var lastspace = value.lastIndexOf(' ');
|
||||
if (lastspace != -1) {
|
||||
value = value.substr(0, lastspace);
|
||||
}
|
||||
}
|
||||
return value + (tail || (wordwise ? ' …' : '…'));
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -59,20 +59,27 @@
|
||||
}
|
||||
|
||||
//A 401 means that the user is not logged in
|
||||
if (rejection.status === 401 && !rejection.config.url.endsWith("umbraco/backoffice/UmbracoApi/Authentication/GetCurrentUser")) {
|
||||
if (rejection.status === 401) {
|
||||
//avoid an infinite loop
|
||||
var umbRequestHelper = $injector.get('umbRequestHelper');
|
||||
var getCurrentUserPath = umbRequestHelper.getApiUrl("authenticationApiBaseUrl", "GetCurrentUser");
|
||||
if (!rejection.config.url.endsWith(getCurrentUserPath)) {
|
||||
|
||||
var userService = $injector.get('userService'); // see above
|
||||
var userService = $injector.get('userService'); // see above
|
||||
|
||||
//Associate the user name with the retry to ensure we retry for the right user
|
||||
return userService.getCurrentUser()
|
||||
.then(function (user) {
|
||||
var userName = user ? user.name : null;
|
||||
//The request bounced because it was not authorized - add a new request to the retry queue
|
||||
return requestRetryQueue.pushRetryFn('unauthorized-server', userName, function retryRequest() {
|
||||
// We must use $injector to get the $http service to prevent circular dependency
|
||||
return $injector.get('$http')(rejection.config);
|
||||
//Associate the user name with the retry to ensure we retry for the right user
|
||||
return userService.getCurrentUser()
|
||||
.then(function(user) {
|
||||
var userName = user ? user.name : null;
|
||||
//The request bounced because it was not authorized - add a new request to the retry queue
|
||||
return requestRetryQueue.pushRetryFn('unauthorized-server',
|
||||
userName,
|
||||
function retryRequest() {
|
||||
// We must use $injector to get the $http service to prevent circular dependency
|
||||
return $injector.get('$http')(rejection.config);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (rejection.status === 404) {
|
||||
|
||||
|
||||
@@ -215,14 +215,6 @@ angular.module('umbraco.mocks').
|
||||
"placeholders_nameentity": "Name the %0%...",
|
||||
"placeholders_search": "Type to search...",
|
||||
"placeholders_filter": "Type to filter...",
|
||||
"editcontenttype_allowedchildnodetypes": "Allowed child nodetypes",
|
||||
"editcontenttype_create": "Create",
|
||||
"editcontenttype_deletetab": "Delete tab",
|
||||
"editcontenttype_description": "Description",
|
||||
"editcontenttype_newtab": "New tab",
|
||||
"editcontenttype_tab": "Tab",
|
||||
"editcontenttype_thumbnail": "Thumbnail",
|
||||
"editcontenttype_iscontainercontenttype": "Use as container content type",
|
||||
"editdatatype_addPrevalue": "Add prevalue",
|
||||
"editdatatype_dataBaseDatatype": "Database datatype",
|
||||
"editdatatype_guid": "Property editor GUID",
|
||||
|
||||
@@ -365,17 +365,28 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} id id of content item to return
|
||||
* @param {Int} culture optional culture to retrieve the item in
|
||||
* @param {Bool} options.ignoreUserStartNodes set to true to allow a user to choose nodes that they normally don't have access to
|
||||
* @returns {Promise} resourcePromise object containing the content item.
|
||||
*
|
||||
*/
|
||||
getById: function (id) {
|
||||
getById: function (id, options) {
|
||||
var defaults = {
|
||||
ignoreUserStartNodes: false
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"GetById",
|
||||
{ id: id })),
|
||||
[{ id: id }, { ignoreUserStartNodes: options.ignoreUserStartNodes }])),
|
||||
'Failed to retrieve data for content id ' + id)
|
||||
.then(function (result) {
|
||||
return $q.when(umbDataFormatter.formatContentGetData(result));
|
||||
|
||||
@@ -344,6 +344,12 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca
|
||||
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "Import", { file: file })),
|
||||
"Failed to import document type " + file
|
||||
);
|
||||
},
|
||||
|
||||
createDefaultTemplate: function (id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCreateDefaultTemplate", { id: id })),
|
||||
'Failed to create default template for content type with id ' + id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -284,15 +284,31 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the entity.
|
||||
*
|
||||
*/
|
||||
getAncestors: function (id, type, culture) {
|
||||
getAncestors: function (id, type, culture, options) {
|
||||
var defaults = {
|
||||
ignoreUserStartNodes: false
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
//overwrite the defaults if there are any specified
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
if (culture === undefined) culture = "";
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetAncestors",
|
||||
[{ id: id }, { type: type }, { culture: culture }])),
|
||||
'Failed to retrieve ancestor data for id ' + id);
|
||||
[
|
||||
{ id: id },
|
||||
{ type: type },
|
||||
{ culture: culture },
|
||||
{ ignoreUserStartNodes: options.ignoreUserStartNodes }
|
||||
])),
|
||||
|
||||
'Failed to retrieve ancestor data for id ' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -424,7 +440,8 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
pageNumber: 1,
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder"
|
||||
orderBy: "SortOrder",
|
||||
ignoreUserStartNodes: false
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
@@ -453,7 +470,8 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
pageSize: options.pageSize,
|
||||
orderBy: options.orderBy,
|
||||
orderDirection: options.orderDirection,
|
||||
filter: encodeURIComponent(options.filter)
|
||||
filter: encodeURIComponent(options.filter),
|
||||
ignoreUserStartNodes: options.ignoreUserStartNodes
|
||||
}
|
||||
)),
|
||||
'Failed to retrieve child data for id ' + parentId);
|
||||
@@ -481,12 +499,19 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the entity array.
|
||||
*
|
||||
*/
|
||||
search: function (query, type, searchFrom, canceler) {
|
||||
search: function (query, type, options, canceler) {
|
||||
|
||||
var args = [{ query: query }, { type: type }];
|
||||
if (searchFrom) {
|
||||
args.push({ searchFrom: searchFrom });
|
||||
|
||||
if(options !== undefined) {
|
||||
if (options.searchFrom) {
|
||||
args.push({ searchFrom: options.searchFrom });
|
||||
}
|
||||
if (options.ignoreUserStartNodes) {
|
||||
args.push({ ignoreUserStartNodes: options.ignoreUserStartNodes });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var httpConfig = {};
|
||||
if (canceler) {
|
||||
|
||||
@@ -53,7 +53,7 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
*
|
||||
* @param {Object} options options object
|
||||
* @param {Int} options.id the id of the entity
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 1
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
|
||||
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
|
||||
@@ -122,7 +122,7 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* </pre>
|
||||
*
|
||||
* @param {Object} options options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 1
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
|
||||
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
|
||||
|
||||
@@ -329,7 +329,8 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
filter: '',
|
||||
orderDirection: "Ascending",
|
||||
orderBy: "SortOrder",
|
||||
orderBySystemField: true
|
||||
orderBySystemField: true,
|
||||
ignoreUserStartNodes: false
|
||||
};
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
@@ -367,6 +368,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
"GetChildren",
|
||||
[
|
||||
{ id: parentId },
|
||||
{ ignoreUserStartNodes: options.ignoreUserStartNodes },
|
||||
{ pageNumber: options.pageNumber },
|
||||
{ pageSize: options.pageSize },
|
||||
{ orderBy: options.orderBy },
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.clipboardService
|
||||
*
|
||||
* @requires notificationsService
|
||||
* @requires eventsService
|
||||
*
|
||||
* @description
|
||||
* Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrive.
|
||||
* The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
|
||||
*
|
||||
*/
|
||||
function clipboardService(notificationsService, eventsService, localStorageService) {
|
||||
|
||||
|
||||
var STORAGE_KEY = "umbClipboardService";
|
||||
|
||||
var retriveStorage = function() {
|
||||
if (localStorageService.isSupported === false) {
|
||||
return null;
|
||||
}
|
||||
var dataJSON;
|
||||
var dataString = localStorageService.get(STORAGE_KEY);
|
||||
if (dataString != null) {
|
||||
dataJSON = JSON.parse(dataString);
|
||||
}
|
||||
|
||||
if(dataJSON == null) {
|
||||
dataJSON = new Object();
|
||||
}
|
||||
|
||||
if(dataJSON.entries === undefined) {
|
||||
dataJSON.entries = [];
|
||||
}
|
||||
|
||||
return dataJSON;
|
||||
}
|
||||
|
||||
var saveStorage = function(storage) {
|
||||
var storageString = JSON.stringify(storage);
|
||||
|
||||
try {
|
||||
var storageJSON = JSON.parse(storageString);
|
||||
localStorageService.set(STORAGE_KEY, storageString);
|
||||
|
||||
eventsService.emit("clipboardService.storageUpdate");
|
||||
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.clipboardService#copy
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param type {string} umbraco A string defining the type of data to storing, example: 'elementType', 'contentNode'
|
||||
* @param alias {string} umbraco A string defining the alias of the data to store, example: 'product'
|
||||
* @param data {object} umbraco A object containing the properties to be saved.
|
||||
*
|
||||
* @description
|
||||
* Saves a single JS-object with a type and alias to the clipboard.
|
||||
*/
|
||||
service.copy = function(type, alias, data) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
var shallowCloneData = Object.assign({}, data);// Notice only a shallow copy, since we dont need to deep copy. (that will happen when storing the data)
|
||||
delete shallowCloneData.key;
|
||||
delete shallowCloneData.$$hashKey;
|
||||
|
||||
var key = data.key || data.$$hashKey || console.error("missing unique key for this content");
|
||||
|
||||
// remove previous copies of this entry:
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== key;
|
||||
}
|
||||
);
|
||||
|
||||
var entry = {unique:key, type:type, alias:alias, data:shallowCloneData};
|
||||
storage.entries.push(entry);
|
||||
|
||||
if (saveStorage(storage) === true) {
|
||||
notificationsService.success("Clipboard", "Copied to clipboard.");
|
||||
} else {
|
||||
notificationsService.success("Clipboard", "Couldnt copy this data to clipboard.");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#supported
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @description
|
||||
* Determins wether the current browser is able to performe its actions.
|
||||
*/
|
||||
service.isSupported = function() {
|
||||
return localStorageService.isSupported;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#hasEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param type {string} umbraco A string defining the type of data test for.
|
||||
* @param aliases {string} umbraco A array of strings providing the alias of the data you want to test for.
|
||||
*
|
||||
* @description
|
||||
* Determines whether the current clipboard has entries that match a given type and one of the aliases.
|
||||
*/
|
||||
service.hasEntriesOfType = function(type, aliases) {
|
||||
|
||||
if(service.retriveEntriesOfType(type, aliases).length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param type {string} umbraco A string defining the type of data to recive.
|
||||
* @param aliases {string} umbraco A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveEntriesOfType = function(type, aliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return (entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
|
||||
}
|
||||
);
|
||||
|
||||
return filteretEntries;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param type {string} umbraco A string defining the type of data to recive.
|
||||
* @param aliases {string} umbraco A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of data of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveDataOfType = function(type, aliases) {
|
||||
return service.retriveEntriesOfType(type, aliases).map((x) => x.data);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param type {string} umbraco A string defining the type of data to remove.
|
||||
* @param aliases {string} umbraco A array of strings providing the alias of the data you want to remove.
|
||||
*
|
||||
* @description
|
||||
* Removes entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.clearEntriesOfType = function(type, aliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return !(entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
|
||||
}
|
||||
);
|
||||
|
||||
storage.entries = filteretEntries;
|
||||
|
||||
saveStorage(storage);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
@@ -163,9 +164,22 @@ When building a custom infinite editor view you can use the same components as a
|
||||
"use strict";
|
||||
|
||||
function editorService(eventsService, keyboardService, $timeout) {
|
||||
|
||||
|
||||
|
||||
let editorsKeyboardShorcuts = [];
|
||||
var editors = [];
|
||||
var isEnabled = true;
|
||||
|
||||
|
||||
// events for backdrop
|
||||
eventsService.on("appState.backdrop", function (name, args) {
|
||||
if (args.show === true) {
|
||||
blur();
|
||||
} else {
|
||||
focus();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
@@ -190,7 +204,43 @@ When building a custom infinite editor view you can use the same components as a
|
||||
function getNumberOfEditors() {
|
||||
return editors.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.editorService#blur
|
||||
* @methodOf umbraco.services.editorService
|
||||
*
|
||||
* @description
|
||||
* Method to tell editors that they are begin blurred.
|
||||
*/
|
||||
function blur() {
|
||||
|
||||
/* keyboard shortcuts will be overwritten by the new infinite editor
|
||||
so we need to store the shortcuts for the current editor so they can be rebound
|
||||
when the infinite editor closes
|
||||
*/
|
||||
unbindKeyboardShortcuts();
|
||||
isEnabled = false;
|
||||
}
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.editorService#blur
|
||||
* @methodOf umbraco.services.editorService
|
||||
*
|
||||
* @description
|
||||
* Method to tell editors that they are gaining focus again.
|
||||
*/
|
||||
function focus() {
|
||||
if(isEnabled === false) {
|
||||
/* keyboard shortcuts will be overwritten by the new infinite editor
|
||||
so we need to store the shortcuts for the current editor so they can be rebound
|
||||
when the infinite editor closes
|
||||
*/
|
||||
rebindKeyboardShortcuts();
|
||||
isEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.editorService#open
|
||||
@@ -201,7 +251,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
*
|
||||
* @param {Object} editor rendering options
|
||||
* @param {String} editor.view Path to view
|
||||
* @param {String} editor.size Sets the size of the editor ("Small"). If nothing is set it will use full width.
|
||||
* @param {String} editor.size Sets the size of the editor ("small"). If nothing is set it will use full width.
|
||||
*/
|
||||
function open(editor) {
|
||||
|
||||
@@ -465,6 +515,8 @@ When building a custom infinite editor view you can use the same components as a
|
||||
* @description
|
||||
* Opens an icon picker in infinite editing, the submit callback returns the selected icon
|
||||
* @param {Object} editor rendering options
|
||||
* @param {String} editor.icon The CSS class representing the icon - eg. "icon-autofill".
|
||||
* @param {String} editor.color The CSS class representing the color - eg. "color-red".
|
||||
* @param {Callback} editor.submit Submits the editor
|
||||
* @param {Callback} editor.close Closes the editor
|
||||
* @returns {Object} editor object
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
@ngdoc service
|
||||
* @name umbraco.services.focusService
|
||||
*
|
||||
* @description
|
||||
* <b>Added in Umbraco 8.1</b>. Application-wide service for focus related stuff.
|
||||
*
|
||||
*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function focusService() {
|
||||
|
||||
|
||||
var currentFocus = null;
|
||||
var lastKnownFocus = null;
|
||||
|
||||
|
||||
function focusInApp(e) {
|
||||
currentFocus = e.target;
|
||||
}
|
||||
document.addEventListener('focusin', focusInApp);
|
||||
|
||||
|
||||
var service = {
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.services.focusService#getLastKnownFocus
|
||||
* @methodOf umbraco.services.focusService
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Gives the element that was set to be remembered, the directive using this should store the value of this to make sure that its not changed white using that directive.
|
||||
* This variable is avaiable for directives that are not able to figure out the focused element on init, and there this service will help remembering it untill the directive is initialized.
|
||||
*
|
||||
*/
|
||||
getLastKnownFocus: function() {
|
||||
return lastKnownFocus;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.services.focusService#rememberFocus
|
||||
* @methodOf umbraco.services.focusService
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Call this before a new focus is begin set, to be able to return to the focus before a given scenario.
|
||||
*
|
||||
*/
|
||||
rememberFocus: function() {
|
||||
lastKnownFocus = currentFocus;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.services.focusService#setLastKnownFocus
|
||||
* @methodOf umbraco.services.focusService
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Overwrite the element remembered as the last known element in focus.
|
||||
*
|
||||
*/
|
||||
setLastKnownFocus: function(element) {
|
||||
lastKnownFocus = element;
|
||||
}
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco.services").factory("focusService", focusService);
|
||||
|
||||
})();
|
||||
@@ -45,7 +45,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function listViewHelper(localStorageService) {
|
||||
function listViewHelper($location, localStorageService, urlHelper) {
|
||||
|
||||
var firstSelectedIndex = 0;
|
||||
var localStorageKey = "umblistViewLayout";
|
||||
@@ -559,6 +559,32 @@
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.listViewHelper#editItem
|
||||
* @methodOf umbraco.services.listViewHelper
|
||||
*
|
||||
* @description
|
||||
* Method for opening an item in a list view for editing.
|
||||
*
|
||||
* @param {Object} item The item to edit
|
||||
*/
|
||||
function editItem(item) {
|
||||
if (!item.editPath) {
|
||||
return;
|
||||
}
|
||||
var parts = item.editPath.split("?");
|
||||
var path = parts[0];
|
||||
var params = parts[1]
|
||||
? urlHelper.getQueryStringParams("?" + parts[1])
|
||||
: {};
|
||||
|
||||
$location.path(path);
|
||||
for (var p in params) {
|
||||
$location.search(p, params[p]);
|
||||
}
|
||||
}
|
||||
|
||||
function isMatchingLayout(id, layout) {
|
||||
// legacy format uses "nodeId", be sure to look for both
|
||||
return layout.id === id || layout.nodeId === id;
|
||||
@@ -579,7 +605,8 @@
|
||||
isSelectedAll: isSelectedAll,
|
||||
setSortingDirection: setSortingDirection,
|
||||
setSorting: setSorting,
|
||||
getButtonPermissions: getButtonPermissions
|
||||
getButtonPermissions: getButtonPermissions,
|
||||
editItem: editItem
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
overlay.position = "center";
|
||||
}
|
||||
|
||||
// set the default overlay size to small
|
||||
if(!overlay.size) {
|
||||
overlay.size = "small";
|
||||
}
|
||||
|
||||
// use a default empty view if nothing is set
|
||||
if(!overlay.view) {
|
||||
overlay.view = "views/common/overlays/default/default.html";
|
||||
@@ -72,4 +77,4 @@
|
||||
|
||||
angular.module("umbraco.services").factory("overlayService", overlayService);
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
@@ -42,7 +42,11 @@ angular.module('umbraco.services')
|
||||
throw "args.term is required";
|
||||
}
|
||||
|
||||
return entityResource.search(args.term, "Member", args.searchFrom).then(function (data) {
|
||||
var options = {
|
||||
searchFrom: args.searchFrom
|
||||
}
|
||||
|
||||
return entityResource.search(args.term, "Member", options).then(function (data) {
|
||||
_.each(data, function (item) {
|
||||
searchResultFormatter.configureMemberResult(item);
|
||||
});
|
||||
@@ -67,7 +71,12 @@ angular.module('umbraco.services')
|
||||
throw "args.term is required";
|
||||
}
|
||||
|
||||
return entityResource.search(args.term, "Document", args.searchFrom, args.canceler).then(function (data) {
|
||||
var options = {
|
||||
searchFrom: args.searchFrom,
|
||||
ignoreUserStartNodes: args.ignoreUserStartNodes
|
||||
}
|
||||
|
||||
return entityResource.search(args.term, "Document", options, args.canceler).then(function (data) {
|
||||
_.each(data, function (item) {
|
||||
searchResultFormatter.configureContentResult(item);
|
||||
});
|
||||
@@ -92,7 +101,12 @@ angular.module('umbraco.services')
|
||||
throw "args.term is required";
|
||||
}
|
||||
|
||||
return entityResource.search(args.term, "Media", args.searchFrom).then(function (data) {
|
||||
var options = {
|
||||
searchFrom: args.searchFrom,
|
||||
ignoreUserStartNodes: args.ignoreUserStartNodes
|
||||
}
|
||||
|
||||
return entityResource.search(args.term, "Media", options).then(function (data) {
|
||||
_.each(data, function (item) {
|
||||
searchResultFormatter.configureMediaResult(item);
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user