Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f100d82e2c | |||
| 60ce993c09 | |||
| c07021d2a0 | |||
| 744ee39904 | |||
| d669bf64c0 | |||
| ff277cd99c | |||
| 30cd303a13 | |||
| 60ce987507 | |||
| a231899052 | |||
| 7ddcccb0c5 | |||
| db824d8daf | |||
| a1a30240f6 | |||
| 7c4a189aa3 | |||
| 4ec66bc868 | |||
| fa8fe8ec66 | |||
| a76ba9a0a7 | |||
| b804ff6107 | |||
| 72046a6ab9 | |||
| ea2303c327 | |||
| 4c4117a052 | |||
| 521b8076d2 | |||
| 1def88d764 | |||
| 910c349f7c | |||
| 6cfb5bc678 | |||
| a3b5996372 | |||
| 31b4560daa | |||
| 2f2dd9c9b6 | |||
| 02599e1254 | |||
| ac7ff31a67 | |||
| 009f071f48 | |||
| e0ecb3291d | |||
| dbaf7c0190 | |||
| 16e06b6d4d | |||
| 444a028e30 | |||
| 0e5a469577 | |||
| 9d8f33e98e | |||
| 2abb3177af | |||
| 43f99e11a5 | |||
| d1d9878ab6 | |||
| e9753c72a7 | |||
| 3b791c75f6 | |||
| 35cb4d5690 | |||
| adde7c2f50 | |||
| 62943d391f | |||
| 0942eb839d | |||
| 21a4dfe33e | |||
| 8121fc42e5 | |||
| c356ed1df8 | |||
| 92f56ccedd | |||
| 7cbe2410e4 | |||
| 1dda3ce45d | |||
| 1e29a4a8ca | |||
| 01de0bd6a1 | |||
| 4d0d29c004 | |||
| 741c2bb085 | |||
| 2c809857af | |||
| 236d6ee302 | |||
| 3094dea5d4 | |||
| f829b0b16c | |||
| a42526b890 | |||
| 3a36513307 | |||
| 0548a32405 | |||
| 433950dd59 | |||
| ad8926668e | |||
| 4ebc0fe4cf | |||
| 1b1455067e | |||
| 795de94a5f | |||
| d6699ab3b3 | |||
| d94b334375 | |||
| a4a49b1466 | |||
| 2c92cd9ca9 | |||
| c34605937c | |||
| 2a9d3df822 | |||
| 3b849987bf | |||
| 8443513b2b | |||
| fec9d066f0 | |||
| a69c7dd1fc | |||
| 4e6a3458d0 | |||
| a5bb8ba8ee | |||
| d4f3dbcfc0 | |||
| 6a0656fbb0 | |||
| 9dc0999ebd | |||
| 813f1a1f2d | |||
| e45b0a53b8 | |||
| 685635c568 | |||
| a3e37de1ad | |||
| 692a8f807e | |||
| f4bdcae411 | |||
| 3a726348d2 | |||
| d8b029eba6 | |||
| 7c01670caf | |||
| 3ce5ff882e | |||
| 6e7aa19073 | |||
| 1cac4ed075 | |||
| e358390211 | |||
| 2e6c643dde | |||
| d84b8aa675 | |||
| 41a0c1f491 | |||
| e8d4777d74 | |||
| e03ef76fcd | |||
| 781ca34e34 | |||
| d01e963365 | |||
| 821daa82c4 | |||
| a51dd93ffe | |||
| 8299243129 | |||
| 4144590189 | |||
| 2f4ff6aaae | |||
| ab0e549c70 | |||
| be065b2fa3 | |||
| f0dfd0dce2 | |||
| da579c91e1 | |||
| 550d690a31 | |||
| 40b75b7cf5 | |||
| 0b28a68678 | |||
| 5f27355247 | |||
| 356ea6824f | |||
| dc3e144493 | |||
| f20fed3ce8 | |||
| df5c5e78ff | |||
| 5579823b2d | |||
| 824212f6c9 | |||
| 7091cb6012 | |||
| a721f6836f | |||
| 83840ba6dd | |||
| b8097219fb | |||
| e5ec935128 | |||
| 3ea16e66d4 | |||
| 562367e9a2 | |||
| ee386d06da |
+1
-2
@@ -49,12 +49,11 @@ ECHO Setting node_modules folder to hidden to prevent VS13 from crashing on it w
|
||||
attrib +h ..\src\Umbraco.Web.UI.Client\node_modules
|
||||
|
||||
ECHO Adding Web.config transform files to the NuGet package
|
||||
REN .\_BuildOutput\WebApp\MacroScripts\Web.config Web.config.transform
|
||||
REN .\_BuildOutput\WebApp\Views\Web.config Web.config.transform
|
||||
REN .\_BuildOutput\WebApp\Xslt\Web.config Web.config.transform
|
||||
|
||||
ECHO Packing the NuGet release files
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version% -Symbols
|
||||
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.nuspec -Version %version%
|
||||
|
||||
IF ERRORLEVEL 1 GOTO :showerror
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@
|
||||
DestinationFiles="@(WebPiFiles->'$(WebPiFolder)%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
|
||||
<!-- Zip the files -->
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
|
||||
</Target>
|
||||
|
||||
<Target Name="ZipWebApp" DependsOnTargets="CreateSystemFolders" >
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms.Core.AllBinaries</id>
|
||||
<version>6.1.2</version>
|
||||
<title>Umbraco Cms Core All Binaries</title>
|
||||
<authors>Morten Christensen</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
|
||||
<summary>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\bin\AutoMapper.dll" target="lib\AutoMapper.dll" />
|
||||
<file src="..\_BuildOutput\bin\AutoMapper.Net4.dll" target="lib\AutoMapper.Net4.dll" />
|
||||
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\bin\ClientDependency.Core.dll" target="lib\ClientDependency.Core.dll" />
|
||||
<file src="..\_BuildOutput\bin\ClientDependency.Core.Mvc.dll" target="lib\ClientDependency.Core.Mvc.dll" />
|
||||
<file src="..\_BuildOutput\bin\cms.dll" target="lib\cms.dll" />
|
||||
<file src="..\_BuildOutput\bin\controls.dll" target="lib\controls.dll" />
|
||||
<file src="..\_BuildOutput\bin\CookComputing.XmlRpcV2.dll" target="lib\CookComputing.XmlRpcV2.dll" />
|
||||
<file src="..\_BuildOutput\bin\Examine.dll" target="lib\Examine.dll" />
|
||||
<file src="..\_BuildOutput\bin\HtmlAgilityPack.dll" target="lib\HtmlAgilityPack.dll" />
|
||||
<file src="..\_BuildOutput\bin\ICSharpCode.SharpZipLib.dll" target="lib\ICSharpCode.SharpZipLib.dll" />
|
||||
<file src="..\_BuildOutput\bin\ImageProcessor.dll" target="lib\ImageProcessor.dll" />
|
||||
<file src="..\_BuildOutput\bin\ImageProcessor.Web.dll" target="lib\ImageProcessor.Web.dll" />
|
||||
<file src="..\_BuildOutput\bin\interfaces.dll" target="lib\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\bin\log4net.dll" target="lib\log4net.dll" />
|
||||
<file src="..\_BuildOutput\bin\Lucene.Net.dll" target="lib\Lucene.Net.dll" />
|
||||
<file src="..\_BuildOutput\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.dll" target="lib\Microsoft.Threading.Tasks.dll" />
|
||||
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.Extensions.dll" target="lib\Microsoft.Threading.Tasks.Extensions.dll" />
|
||||
<file src="..\_BuildOutput\bin\Microsoft.Web.Infrastructure.dll" target="lib\Microsoft.Web.Infrastructure.dll" />
|
||||
<file src="..\_BuildOutput\bin\Microsoft.Web.Mvc.FixedDisplayModes.dll" target="lib\Microsoft.Web.Mvc.FixedDisplayModes.dll" />
|
||||
<file src="..\_BuildOutput\bin\MiniProfiler.dll" target="lib\MiniProfiler.dll" />
|
||||
<file src="..\_BuildOutput\bin\MySql.Data.dll" target="lib\MySql.Data.dll" />
|
||||
<file src="..\_BuildOutput\bin\Newtonsoft.Json.dll" target="lib\Newtonsoft.Json.dll" />
|
||||
<file src="..\_BuildOutput\bin\NuGet.Core.dll" target="lib\NuGet.Core.dll" />
|
||||
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Net.Http.dll" target="lib\System.Net.Http.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Net.Http.Extensions.dll" target="lib\System.Net.Http.Extensions.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Net.Http.Formatting.dll" target="lib\System.Net.Http.Formatting.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Net.Http.Primitives.dll" target="lib\System.Net.Http.Primitives.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Net.Http.WebRequest.dll" target="lib\System.Net.Http.WebRequest.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.Helpers.dll" target="lib\System.Web.Helpers.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.Http.dll" target="lib\System.Web.Http.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.Http.WebHost.dll" target="lib\System.Web.Http.WebHost.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.Mvc.dll" target="lib\System.Web.Mvc.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.Razor.dll" target="lib\System.Web.Razor.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.WebPages.Administration.dll" target="lib\System.Web.WebPages.Administration.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.WebPages.Deployment.dll" target="lib\System.Web.WebPages.Deployment.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.WebPages.dll" target="lib\System.Web.WebPages.dll" />
|
||||
<file src="..\_BuildOutput\bin\System.Web.WebPages.Razor.dll" target="lib\System.Web.WebPages.Razor.dll" />
|
||||
<file src="..\_BuildOutput\bin\TidyNet.dll" target="lib\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.dll" target="lib\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>UmbracoCms.Core</id>
|
||||
<version>7.0.0</version>
|
||||
<title>Umbraco Cms Core Binaries</title>
|
||||
<authors>Umbraco HQ</authors>
|
||||
<owners>Umbraco HQ</owners>
|
||||
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
|
||||
<projectUrl>http://umbraco.com/</projectUrl>
|
||||
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
|
||||
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.dll" target="lib" />
|
||||
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.pdb" target="lib" />
|
||||
<file src="..\..\src\SQLCE4Umbraco\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\SQLCE4Umbraco" />
|
||||
|
||||
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.businesslogic\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.businesslogic" />
|
||||
|
||||
<file src="..\..\src\umbraco.cms\obj\Debug\cms.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.cms\obj\Debug\cms.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.cms\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.cms" />
|
||||
|
||||
<file src="..\..\src\umbraco.controls\obj\Debug\controls.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.controls\obj\Debug\controls.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.controls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.controls" />
|
||||
|
||||
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.interfaces\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.interfaces" />
|
||||
|
||||
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.dll" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Core\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
|
||||
|
||||
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.datalayer\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.datalayer" />
|
||||
|
||||
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.editorControls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.editorControls" />
|
||||
|
||||
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.MacroEngines\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.MacroEngines" />
|
||||
|
||||
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.dll" target="lib" />
|
||||
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.providers\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.providers" />
|
||||
|
||||
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.dll" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Web\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
|
||||
|
||||
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.dll" target="lib" />
|
||||
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Web.UI\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
|
||||
|
||||
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.dll" target="lib" />
|
||||
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.pdb" target="lib" />
|
||||
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -26,13 +26,13 @@
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.6.5]" />
|
||||
<dependency id="MySql.Data" version="[6.9.6, 7.0.0)" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.8.3.1, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.62, 1.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.63, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
|
||||
</dependencies>
|
||||
@@ -49,6 +49,7 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\SQLCE4Umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
|
||||
@@ -65,8 +66,38 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\UmbracoExamine.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
|
||||
<file src="tools\install.core.ps1" target="tools\install.ps1" />
|
||||
|
||||
<!-- Added to be able to produce a symbols package -->
|
||||
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.pdb" target="lib" />
|
||||
<file src="..\..\src\SQLCE4Umbraco\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\SQLCE4Umbraco" />
|
||||
<file src="..\_BuildOutput\bin\businesslogic.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.businesslogic\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.businesslogic" />
|
||||
<file src="..\_BuildOutput\bin\cms.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.cms\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.cms" />
|
||||
<file src="..\_BuildOutput\bin\controls.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.controls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.controls" />
|
||||
<file src="..\_BuildOutput\bin\interfaces.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.interfaces\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.interfaces" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Core\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.DataLayer.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.datalayer\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.datalayer" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.editorControls.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.editorControls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.editorControls" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.MacroEngines\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.MacroEngines" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.providers.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.providers\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.providers" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Web\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Web.UI\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
|
||||
<file src="..\_BuildOutput\bin\UmbracoExamine.pdb" target="lib" />
|
||||
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -37,8 +37,10 @@
|
||||
<DbProviderFactories xdt:Transform="InsertIfMissing">
|
||||
<remove invariant="System.Data.SqlServerCe.4.0" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(invariant,description,type)" />
|
||||
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(invariant,description,type)" />
|
||||
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="Remove" />
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add invariant="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(type)" />
|
||||
</DbProviderFactories>
|
||||
</system.data>
|
||||
<clientDependency xdt:Transform="RemoveAttributes(version)" />
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.2.5
|
||||
RC
|
||||
7.2.6
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.2.5")]
|
||||
[assembly: AssemblyInformationalVersion("7.2.5-RC")]
|
||||
[assembly: AssemblyFileVersion("7.2.6")]
|
||||
[assembly: AssemblyInformationalVersion("7.2.6")]
|
||||
@@ -165,6 +165,8 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
internal string OriginalRequestUrl { get; set; }
|
||||
|
||||
private bool _versionsDifferenceReported;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the version configured matches the assembly version
|
||||
/// </summary>
|
||||
@@ -174,17 +176,19 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
string configStatus = ConfigurationStatus;
|
||||
string currentVersion = UmbracoVersion.Current.ToString(3);
|
||||
var configStatus = ConfigurationStatus;
|
||||
var currentVersion = UmbracoVersion.Current.ToString(3);
|
||||
var ok = configStatus == currentVersion;
|
||||
|
||||
|
||||
if (currentVersion != configStatus)
|
||||
if (ok == false && _versionsDifferenceReported == false)
|
||||
{
|
||||
LogHelper.Info<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
|
||||
// remember it's been reported so we don't flood the log
|
||||
// no thread-safety so there may be a few log entries, doesn't matter
|
||||
_versionsDifferenceReported = true;
|
||||
LogHelper.Info<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
|
||||
}
|
||||
|
||||
|
||||
return (configStatus == currentVersion);
|
||||
return ok;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -11,6 +11,15 @@ namespace Umbraco.Core
|
||||
// - this is NOT a reader/writer lock
|
||||
// - this is NOT a recursive lock
|
||||
//
|
||||
// using a named Semaphore here and not a Mutex because mutexes have thread
|
||||
// affinity which does not work with async situations
|
||||
//
|
||||
// it is important that managed code properly release the Semaphore before
|
||||
// going down else it will maintain the lock - however note that when the
|
||||
// whole process (w3wp.exe) goes down and all handles to the Semaphore have
|
||||
// been closed, the Semaphore system object is destroyed - so in any case
|
||||
// an iisreset should clean up everything
|
||||
//
|
||||
internal class AsyncLock
|
||||
{
|
||||
private readonly SemaphoreSlim _semaphore;
|
||||
|
||||
@@ -54,5 +54,8 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
public const string DataTypePreValuesCacheKey = "UmbracoPreVal";
|
||||
|
||||
public const string IdToKeyCacheKey = "UI2K";
|
||||
public const string KeyToIdCacheKey = "UK2I";
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Cache
|
||||
protected const string CacheItemPrefix = "umbrtmche";
|
||||
|
||||
// an object that represent a value that has not been created yet
|
||||
protected readonly object ValueNotCreated = new object();
|
||||
protected internal static readonly object ValueNotCreated = new object();
|
||||
|
||||
// manupulate the underlying cache entries
|
||||
// these *must* be called from within the appropriate locks
|
||||
@@ -30,21 +30,58 @@ namespace Umbraco.Core.Cache
|
||||
return string.Format("{0}-{1}", CacheItemPrefix, key);
|
||||
}
|
||||
|
||||
protected object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
|
||||
protected internal static Lazy<object> GetSafeLazy(Func<object> getCacheItem)
|
||||
{
|
||||
// try to generate the value and if it fails,
|
||||
// wrap in an ExceptionHolder - would be much simpler
|
||||
// to just use lazy.IsValueFaulted alas that field is
|
||||
// internal
|
||||
return new Lazy<object>(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new ExceptionHolder(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected internal static object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
|
||||
{
|
||||
// if onlyIfValueIsCreated, do not trigger value creation
|
||||
// must return something, though, to differenciate from null values
|
||||
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
|
||||
|
||||
// if execution has thrown then lazy.IsValueCreated is false
|
||||
// and lazy.IsValueFaulted is true (but internal) so we use our
|
||||
// own exception holder (see Lazy<T> source code) to return null
|
||||
if (lazy.Value is ExceptionHolder) return null;
|
||||
|
||||
// we have a value and execution has not thrown so returning
|
||||
// here does not throw - unless we're re-entering, take care of it
|
||||
try
|
||||
{
|
||||
// if onlyIfValueIsCreated, do not trigger value creation
|
||||
// must return something, though, to differenciate from null values
|
||||
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
|
||||
return lazy.Value;
|
||||
}
|
||||
catch
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
return null;
|
||||
throw new InvalidOperationException("The method that computes a value for the cache has tried to read that value from the cache.", e);
|
||||
}
|
||||
}
|
||||
|
||||
internal class ExceptionHolder
|
||||
{
|
||||
public ExceptionHolder(Exception e)
|
||||
{
|
||||
Exception = e;
|
||||
}
|
||||
|
||||
public Exception Exception { get; private set; }
|
||||
}
|
||||
|
||||
#region Clear
|
||||
|
||||
public virtual void ClearAllCache()
|
||||
|
||||
@@ -105,15 +105,22 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
{
|
||||
result = new Lazy<object>(getCacheItem);
|
||||
result = GetSafeLazy(getCacheItem);
|
||||
ContextItems[cacheKey] = result;
|
||||
}
|
||||
}
|
||||
|
||||
// this may throw if getCacheItem throws, but this is the only place where
|
||||
// it would throw as everywhere else we use GetLazySaveValue() to hide exceptions
|
||||
// and pretend exceptions were never inserted into cache to begin with.
|
||||
return result.Value;
|
||||
// using GetSafeLazy and GetSafeLazyValue ensures that we don't cache
|
||||
// exceptions (but try again and again) and silently eat them - however at
|
||||
// some point we have to report them - so need to re-throw here
|
||||
|
||||
// this does not throw anymore
|
||||
//return result.Value;
|
||||
|
||||
var value = result.Value; // will not throw (safe lazy)
|
||||
var eh = value as ExceptionHolder;
|
||||
if (eh != null) throw eh.Exception; // throw once!
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
{
|
||||
result = new Lazy<object>(getCacheItem);
|
||||
result = GetSafeLazy(getCacheItem);
|
||||
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
|
||||
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
|
||||
|
||||
@@ -138,10 +138,17 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
}
|
||||
|
||||
// this may throw if getCacheItem throws, but this is the only place where
|
||||
// it would throw as everywhere else we use GetLazySaveValue() to hide exceptions
|
||||
// and pretend exceptions were never inserted into cache to begin with.
|
||||
return result.Value;
|
||||
// using GetSafeLazy and GetSafeLazyValue ensures that we don't cache
|
||||
// exceptions (but try again and again) and silently eat them - however at
|
||||
// some point we have to report them - so need to re-throw here
|
||||
|
||||
// this does not throw anymore
|
||||
//return result.Value;
|
||||
|
||||
value = result.Value; // will not throw (safe lazy)
|
||||
var eh = value as ExceptionHolder;
|
||||
if (eh != null) throw eh.Exception; // throw once!
|
||||
return value;
|
||||
}
|
||||
|
||||
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
|
||||
@@ -173,7 +180,7 @@ namespace Umbraco.Core.Cache
|
||||
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
|
||||
// and make sure we don't store a null value.
|
||||
|
||||
var result = new Lazy<object>(getCacheItem);
|
||||
var result = GetSafeLazy(getCacheItem);
|
||||
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
|
||||
if (value == null) return; // do not store null values (backward compat)
|
||||
|
||||
|
||||
@@ -19,29 +19,11 @@ namespace Umbraco.Core.Cache
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
internal ObjectCache MemoryCache;
|
||||
|
||||
// an object that represent a value that has not been created yet
|
||||
protected readonly object ValueNotCreated = new object();
|
||||
|
||||
public ObjectCacheRuntimeCacheProvider()
|
||||
{
|
||||
MemoryCache = new MemoryCache("in-memory");
|
||||
}
|
||||
|
||||
protected object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
// if onlyIfValueIsCreated, do not trigger value creation
|
||||
// must return something, though, to differenciate from null values
|
||||
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
|
||||
return lazy.Value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#region Clear
|
||||
|
||||
public virtual void ClearAllCache()
|
||||
@@ -72,7 +54,7 @@ namespace Umbraco.Core.Cache
|
||||
// x.Value is Lazy<object> and not null, its value may be null
|
||||
// remove null values as well, does not hurt
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
return value == null || value.GetType().ToString().InvariantEquals(typeName);
|
||||
})
|
||||
.Select(x => x.Key)
|
||||
@@ -92,7 +74,7 @@ namespace Umbraco.Core.Cache
|
||||
// x.Value is Lazy<object> and not null, its value may be null
|
||||
// remove null values as well, does not hurt
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
return value == null || value.GetType() == typeOfT;
|
||||
})
|
||||
.Select(x => x.Key)
|
||||
@@ -112,7 +94,7 @@ namespace Umbraco.Core.Cache
|
||||
// x.Value is Lazy<object> and not null, its value may be null
|
||||
// remove null values as well, does not hurt
|
||||
// get non-created as NonCreatedValue & exceptions as null
|
||||
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
|
||||
if (value == null) return true;
|
||||
return value.GetType() == typeOfT
|
||||
&& predicate(x.Key, (T) value);
|
||||
@@ -161,7 +143,7 @@ namespace Umbraco.Core.Cache
|
||||
.ToArray(); // evaluate while locked
|
||||
}
|
||||
return entries
|
||||
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
|
||||
.Select(x => DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
|
||||
.Where(x => x != null) // backward compat, don't store null values in the cache
|
||||
.ToList();
|
||||
}
|
||||
@@ -176,7 +158,7 @@ namespace Umbraco.Core.Cache
|
||||
.ToArray(); // evaluate while locked
|
||||
}
|
||||
return entries
|
||||
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
|
||||
.Select(x => DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
|
||||
.Where(x => x != null) // backward compat, don't store null values in the cache
|
||||
.ToList();
|
||||
}
|
||||
@@ -188,7 +170,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
result = MemoryCache.Get(cacheKey) as Lazy<object>; // null if key not found
|
||||
}
|
||||
return result == null ? null : GetSafeLazyValue(result); // return exceptions as null
|
||||
return result == null ? null : DictionaryCacheProviderBase.GetSafeLazyValue(result); // return exceptions as null
|
||||
}
|
||||
|
||||
public object GetCacheItem(string cacheKey, Func<object> getCacheItem)
|
||||
@@ -205,9 +187,9 @@ namespace Umbraco.Core.Cache
|
||||
using (var lck = new UpgradeableReadLock(_locker))
|
||||
{
|
||||
result = MemoryCache.Get(cacheKey) as Lazy<object>;
|
||||
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
if (result == null || DictionaryCacheProviderBase.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
|
||||
{
|
||||
result = new Lazy<object>(getCacheItem);
|
||||
result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem);
|
||||
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
|
||||
|
||||
lck.UpgradeToWriteLock();
|
||||
@@ -215,7 +197,12 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
}
|
||||
|
||||
return result.Value;
|
||||
//return result.Value;
|
||||
|
||||
var value = result.Value; // will not throw (safe lazy)
|
||||
var eh = value as DictionaryCacheProviderBase.ExceptionHolder;
|
||||
if (eh != null) throw eh.Exception; // throw once!
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -227,7 +214,7 @@ namespace Umbraco.Core.Cache
|
||||
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
|
||||
// and make sure we don't store a null value.
|
||||
|
||||
var result = new Lazy<object>(getCacheItem);
|
||||
var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem);
|
||||
var value = result.Value; // force evaluation now
|
||||
if (value == null) return; // do not store null values (backward compat)
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
var converted = ObjectExtensions.TryConvertTo<T>(RawValue);
|
||||
var converted = RawValue.TryConvertTo<T>();
|
||||
if (converted.Success == false)
|
||||
throw new InvalidCastException("Could not convert value " + RawValue + " to type " + typeof(T));
|
||||
return converted.Result;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using System.Xml.Linq;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class ContentErrorPageElement : InnerTextConfigurationElement<int>, IContentErrorPage
|
||||
internal class ContentErrorPageElement : InnerTextConfigurationElement<string>, IContentErrorPage
|
||||
{
|
||||
public ContentErrorPageElement(XElement rawXml)
|
||||
: base(rawXml)
|
||||
@@ -14,7 +15,43 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
}
|
||||
|
||||
public bool HasContentId
|
||||
{
|
||||
get { return ContentId != int.MinValue; }
|
||||
}
|
||||
|
||||
public bool HasContentKey
|
||||
{
|
||||
get { return ContentKey != Guid.Empty; }
|
||||
}
|
||||
|
||||
public int ContentId
|
||||
{
|
||||
get
|
||||
{
|
||||
int parsed;
|
||||
if (int.TryParse(Value, out parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
return int.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
public Guid ContentKey
|
||||
{
|
||||
get
|
||||
{
|
||||
Guid parsed;
|
||||
if (Guid.TryParse(Value, out parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
return Guid.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public string ContentXPath
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
public interface IContentErrorPage
|
||||
{
|
||||
int ContentId { get; }
|
||||
Guid ContentKey { get; }
|
||||
string ContentXPath { get; }
|
||||
bool HasContentId { get; }
|
||||
bool HasContentKey { get; }
|
||||
string Culture { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.2.5");
|
||||
private static readonly Version Version = new Version("7.2.6");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "RC"; } }
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace Umbraco.Core
|
||||
|
||||
InitializeProfilerResolver();
|
||||
|
||||
_timer = DisposableTimer.DebugDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
|
||||
_timer = DisposableTimer.TraceDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
|
||||
|
||||
CreateApplicationCache();
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static class HttpContextExtensions
|
||||
{
|
||||
public static string GetCurrentRequestIpAddress(this HttpContextBase httpContext)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
return "Unknown, httpContext is null";
|
||||
}
|
||||
if (httpContext.Request == null)
|
||||
{
|
||||
return "Unknown, httpContext.Request is null";
|
||||
}
|
||||
if (httpContext.Request.ServerVariables == null)
|
||||
{
|
||||
return "Unknown, httpContext.Request.ServerVariables is null";
|
||||
}
|
||||
|
||||
// From: http://stackoverflow.com/a/740431/5018
|
||||
|
||||
try
|
||||
{
|
||||
var ipAddress = httpContext.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
|
||||
|
||||
if (string.IsNullOrEmpty(ipAddress))
|
||||
return httpContext.Request.ServerVariables["REMOTE_ADDR"];
|
||||
|
||||
var addresses = ipAddress.Split(',');
|
||||
if (addresses.Length != 0)
|
||||
return addresses[0];
|
||||
|
||||
return httpContext.Request.ServerVariables["REMOTE_ADDR"];
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
//This try catch is to just always ensure that no matter what we're not getting any exceptions caused since
|
||||
// that would cause people to not be able to login
|
||||
return string.Format("Unknown, exception occurred trying to resolve IP {0}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,8 @@ namespace Umbraco.Core.Logging
|
||||
/// <returns></returns>
|
||||
private static string PrefixThreadId(string generateMessageFormat)
|
||||
{
|
||||
return "[Thread " + Thread.CurrentThread.ManagedThreadId + "] " + generateMessageFormat;
|
||||
}
|
||||
return "[T" + Thread.CurrentThread.ManagedThreadId + "/D" + AppDomain.CurrentDomain.Id + "] " + generateMessageFormat;
|
||||
}
|
||||
|
||||
#region Error
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Macros
|
||||
internal class MacroTagParser
|
||||
{
|
||||
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO (?:.+)?macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// This formats the persisted string to something useful for the rte so that the macro renders properly since we
|
||||
|
||||
@@ -337,74 +337,7 @@ namespace Umbraco.Core.Models
|
||||
ChangePublishedState(PublishedState.Unpublished);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current <see cref="IContent"/> entity is dirty.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>True if Property is dirty, otherwise False</returns>
|
||||
public override bool IsPropertyDirty(string propertyName)
|
||||
{
|
||||
bool existsInEntity = base.IsPropertyDirty(propertyName);
|
||||
if (existsInEntity)
|
||||
return true;
|
||||
|
||||
return Properties.Any(x => x.IsPropertyDirty(propertyName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <returns>True if entity is dirty, otherwise False</returns>
|
||||
public override bool IsDirty()
|
||||
{
|
||||
return IsEntityDirty() || IsAnyUserPropertyDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if only the entity properties are direty
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsEntityDirty()
|
||||
{
|
||||
return base.IsDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any of the properties are dirty
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsAnyUserPropertyDirty()
|
||||
{
|
||||
return Properties.Any(x => x.IsDirty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all dirty user defined properties
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<string> GetDirtyUserProperties()
|
||||
{
|
||||
return Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
public override void ResetDirtyProperties()
|
||||
{
|
||||
base.ResetDirtyProperties();
|
||||
|
||||
foreach (var property in Properties)
|
||||
{
|
||||
property.ResetDirtyProperties();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being saved
|
||||
/// </summary>
|
||||
|
||||
@@ -466,6 +466,8 @@ namespace Umbraco.Core.Models
|
||||
|
||||
public abstract void ChangeTrashedState(bool isTrashed, int parentId = -20);
|
||||
|
||||
#region Dirty property handling
|
||||
|
||||
/// <summary>
|
||||
/// We will override this method to ensure that when we reset the dirty properties that we
|
||||
/// also reset the dirty changes made to the content's Properties (user defined)
|
||||
@@ -480,6 +482,89 @@ namespace Umbraco.Core.Models
|
||||
prop.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <returns>True if entity is dirty, otherwise False</returns>
|
||||
public override bool IsDirty()
|
||||
{
|
||||
return IsEntityDirty() || this.IsAnyUserPropertyDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity was dirty.
|
||||
/// </summary>
|
||||
/// <returns>True if entity was dirty, otherwise False</returns>
|
||||
public override bool WasDirty()
|
||||
{
|
||||
return WasEntityDirty() || this.WasAnyUserPropertyDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if only the entity properties are dirty
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsEntityDirty()
|
||||
{
|
||||
return base.IsDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if only the entity properties were dirty
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool WasEntityDirty()
|
||||
{
|
||||
return base.WasDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current <see cref="IContent"/> entity is dirty.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>
|
||||
/// True if any of the class properties are dirty or
|
||||
/// True if any of the user defined PropertyType properties are dirty based on their alias,
|
||||
/// otherwise False
|
||||
/// </returns>
|
||||
public override bool IsPropertyDirty(string propertyName)
|
||||
{
|
||||
bool existsInEntity = base.IsPropertyDirty(propertyName);
|
||||
if (existsInEntity)
|
||||
return true;
|
||||
|
||||
if (Properties.Contains(propertyName))
|
||||
{
|
||||
return Properties[propertyName].IsDirty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current entity was changed and the changes were committed
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>
|
||||
/// True if any of the class properties are dirty or
|
||||
/// True if any of the user defined PropertyType properties are dirty based on their alias,
|
||||
/// otherwise False
|
||||
/// </returns>
|
||||
public override bool WasPropertyDirty(string propertyName)
|
||||
{
|
||||
bool existsInEntity = base.WasPropertyDirty(propertyName);
|
||||
if (existsInEntity)
|
||||
return true;
|
||||
|
||||
if (Properties.Contains(propertyName))
|
||||
{
|
||||
return Properties[propertyName].WasDirty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -77,10 +77,9 @@ namespace Umbraco.Core.Models
|
||||
/// </remarks>
|
||||
internal static bool RequiresSaving(this IContent entity, PublishedState publishedState)
|
||||
{
|
||||
var dirtyEntity = (ICanBeDirty)entity;
|
||||
var publishedChanged = dirtyEntity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
|
||||
var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
|
||||
//check if any user prop has changed
|
||||
var propertyValueChanged = ((Content)entity).IsAnyUserPropertyDirty();
|
||||
var propertyValueChanged = entity.IsAnyUserPropertyDirty();
|
||||
|
||||
//We need to know if any other property apart from Published was changed here
|
||||
//don't create a new version if the published state has changed to 'Save' but no data has actually been changed
|
||||
@@ -114,6 +113,25 @@ namespace Umbraco.Core.Models
|
||||
return ShouldCreateNewVersion(entity, publishedState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all dirty user defined properties
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> GetDirtyUserProperties(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
|
||||
}
|
||||
|
||||
public static bool IsAnyUserPropertyDirty(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Any(x => x.IsDirty());
|
||||
}
|
||||
|
||||
public static bool WasAnyUserPropertyDirty(this IContentBase entity)
|
||||
{
|
||||
return entity.Properties.Any(x => x.WasDirty());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a new version should be created
|
||||
/// </summary>
|
||||
@@ -128,15 +146,13 @@ namespace Umbraco.Core.Models
|
||||
/// </remarks>
|
||||
internal static bool ShouldCreateNewVersion(this IContent entity, PublishedState publishedState)
|
||||
{
|
||||
var dirtyEntity = (ICanBeDirty)entity;
|
||||
|
||||
//check if the published state has changed or the language
|
||||
var publishedChanged = dirtyEntity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
|
||||
var langChanged = dirtyEntity.IsPropertyDirty("Language");
|
||||
var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
|
||||
var langChanged = entity.IsPropertyDirty("Language");
|
||||
var contentChanged = publishedChanged || langChanged;
|
||||
|
||||
//check if any user prop has changed
|
||||
var propertyValueChanged = ((Content)entity).IsAnyUserPropertyDirty();
|
||||
var propertyValueChanged = entity.IsAnyUserPropertyDirty();
|
||||
|
||||
//return true if published or language has changed
|
||||
if (contentChanged)
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// Indicates that the entity had been changed and the changes were committed
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool WasDirty()
|
||||
public virtual bool WasDirty()
|
||||
{
|
||||
return _lastPropertyChangedInfo != null && _lastPropertyChangedInfo.Any();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Configuration.Provider;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Hosting;
|
||||
using System.Web.Security;
|
||||
@@ -893,5 +894,15 @@ namespace Umbraco.Core.Security
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current request IP address for logging if there is one
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string GetCurrentRequestIpAddress()
|
||||
{
|
||||
var httpContext = HttpContext.Current == null ? (HttpContextBase) null : new HttpContextWrapper(HttpContext.Current);
|
||||
return httpContext.GetCurrentRequestIpAddress();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -19,12 +20,13 @@ namespace Umbraco.Core.Services
|
||||
private readonly IMediaService _mediaService;
|
||||
private readonly IMemberService _memberService;
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
private readonly Dictionary<string, Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>> _supportedObjectTypes;
|
||||
|
||||
public EntityService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory,
|
||||
IContentService contentService, IContentTypeService contentTypeService, IMediaService mediaService, IDataTypeService dataTypeService,
|
||||
IMemberService memberService, IMemberTypeService memberTypeService)
|
||||
IMemberService memberService, IMemberTypeService memberTypeService, IRuntimeCacheProvider runtimeCache)
|
||||
{
|
||||
_uowProvider = provider;
|
||||
_repositoryFactory = repositoryFactory;
|
||||
@@ -34,6 +36,7 @@ namespace Umbraco.Core.Services
|
||||
_dataTypeService = dataTypeService;
|
||||
_memberService = memberService;
|
||||
_memberTypeService = memberTypeService;
|
||||
_runtimeCache = runtimeCache;
|
||||
|
||||
_supportedObjectTypes = new Dictionary<string, Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>>
|
||||
{
|
||||
@@ -45,6 +48,83 @@ namespace Umbraco.Core.Services
|
||||
{typeof (IMember).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.Member, _memberService.GetById)},
|
||||
{typeof (IMemberType).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.MemberType, _memberTypeService.Get)}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the integer id for a given GUID
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <returns></returns>
|
||||
public Attempt<int> GetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
var result = _runtimeCache.GetCacheItem<int?>(CacheKeys.IdToKeyCacheKey + key, () =>
|
||||
{
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
switch (umbracoObjectType)
|
||||
{
|
||||
case UmbracoObjectTypes.Document:
|
||||
case UmbracoObjectTypes.MemberType:
|
||||
case UmbracoObjectTypes.Media:
|
||||
case UmbracoObjectTypes.Template:
|
||||
case UmbracoObjectTypes.MediaType:
|
||||
case UmbracoObjectTypes.DocumentType:
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
return uow.Database.ExecuteScalar<int?>(new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.UniqueId == key));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
case UmbracoObjectTypes.MemberGroup:
|
||||
case UmbracoObjectTypes.ContentItem:
|
||||
case UmbracoObjectTypes.ContentItemType:
|
||||
case UmbracoObjectTypes.ROOT:
|
||||
case UmbracoObjectTypes.Unknown:
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
});
|
||||
return result.HasValue ? Attempt.Succeed(result.Value) : Attempt<int>.Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the GUID for a given integer id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <returns></returns>
|
||||
public Attempt<Guid> GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
var result = _runtimeCache.GetCacheItem<Guid?>(CacheKeys.KeyToIdCacheKey + id, () =>
|
||||
{
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
switch (umbracoObjectType)
|
||||
{
|
||||
case UmbracoObjectTypes.Document:
|
||||
case UmbracoObjectTypes.MemberType:
|
||||
case UmbracoObjectTypes.Media:
|
||||
case UmbracoObjectTypes.Template:
|
||||
case UmbracoObjectTypes.MediaType:
|
||||
case UmbracoObjectTypes.DocumentType:
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
return uow.Database.ExecuteScalar<Guid?>(new Sql().Select("uniqueID").From<NodeDto>().Where<NodeDto>(dto => dto.NodeId == id));
|
||||
case UmbracoObjectTypes.RecycleBin:
|
||||
case UmbracoObjectTypes.Stylesheet:
|
||||
case UmbracoObjectTypes.MemberGroup:
|
||||
case UmbracoObjectTypes.ContentItem:
|
||||
case UmbracoObjectTypes.ContentItemType:
|
||||
case UmbracoObjectTypes.ROOT:
|
||||
case UmbracoObjectTypes.Unknown:
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
});
|
||||
return result.HasValue ? Attempt.Succeed(result.Value) : Attempt<Guid>.Fail();
|
||||
}
|
||||
|
||||
public IUmbracoEntity GetByKey(Guid key, bool loadBaseType = true)
|
||||
|
||||
@@ -7,6 +7,21 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
public interface IEntityService
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the integer id for a given GUID
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <returns></returns>
|
||||
Attempt<int> GetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the GUID for a given integer id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="umbracoObjectType"></param>
|
||||
/// <returns></returns>
|
||||
Attempt<Guid> GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an UmbracoEntity by its Id, and optionally loads the complete object graph.
|
||||
|
||||
@@ -85,14 +85,14 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
//get the lazy value from cache
|
||||
result.Add(culture, new Lazy<XDocument>(() => _cache.GetCacheItem<XDocument>(
|
||||
string.Format("{0}-{1}", typeof(LocalizedTextServiceFileSources).Name, culture.Name), () =>
|
||||
result[culture] = new Lazy<XDocument>(() => _cache.GetCacheItem<XDocument>(
|
||||
string.Format("{0}-{1}", typeof (LocalizedTextServiceFileSources).Name, culture.Name), () =>
|
||||
{
|
||||
using (var fs = localCopy.OpenRead())
|
||||
{
|
||||
return XDocument.Load(fs);
|
||||
}
|
||||
}, isSliding: true, timeout: TimeSpan.FromMinutes(10), dependentFiles: new[] { localCopy.FullName })));
|
||||
}, isSliding: true, timeout: TimeSpan.FromMinutes(10), dependentFiles: new[] {localCopy.FullName}));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
@@ -167,7 +167,8 @@ namespace Umbraco.Core.Services
|
||||
if (_entityService == null)
|
||||
_entityService = new Lazy<IEntityService>(() => new EntityService(
|
||||
provider, repositoryFactory.Value,
|
||||
_contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _memberService.Value, _memberTypeService.Value));
|
||||
_contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _memberService.Value, _memberTypeService.Value,
|
||||
cache.RuntimeCache));
|
||||
|
||||
if (_relationService == null)
|
||||
_relationService = new Lazy<IRelationService>(() => new RelationService(provider, repositoryFactory.Value, _entityService.Value));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
@@ -207,6 +208,9 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Remove this in 7.3, we need to track this in a db column!
|
||||
private readonly ConcurrentDictionary<int, int> _failedLoginAttempts = new ConcurrentDictionary<int, int>();
|
||||
|
||||
/// <summary>
|
||||
/// Get an <see cref="IUser"/> by username
|
||||
/// </summary>
|
||||
@@ -217,7 +221,18 @@ namespace Umbraco.Core.Services
|
||||
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IUser>.Builder.Where(x => x.Username.Equals(username));
|
||||
return repository.GetByQuery(query).FirstOrDefault();
|
||||
var user = repository.GetByQuery(query).FirstOrDefault();
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
//check if they have any failed logins and merge
|
||||
int failedAttempts;
|
||||
if (_failedLoginAttempts.TryGetValue(user.Id, out failedAttempts))
|
||||
{
|
||||
user.FailedPasswordAttempts = failedAttempts;
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,6 +299,9 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
else
|
||||
{
|
||||
int failedAttempts;
|
||||
_failedLoginAttempts.TryRemove(user.Id, out failedAttempts);
|
||||
|
||||
if (DeletingUser.IsRaisedEventCancelled(new DeleteEventArgs<IUser>(user), this))
|
||||
return;
|
||||
|
||||
@@ -317,6 +335,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
repository.AddOrUpdate(entity);
|
||||
uow.Commit();
|
||||
|
||||
_failedLoginAttempts.AddOrUpdate(entity.Id, i => entity.FailedPasswordAttempts, (i, i1) => entity.FailedPasswordAttempts);
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
@@ -342,10 +362,15 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
foreach (var member in entities)
|
||||
{
|
||||
repository.AddOrUpdate(member);
|
||||
repository.AddOrUpdate(member);
|
||||
}
|
||||
//commit the whole lot in one go
|
||||
uow.Commit();
|
||||
foreach (var member in entities)
|
||||
{
|
||||
_failedLoginAttempts.AddOrUpdate(member.Id, i => member.FailedPasswordAttempts, (i, i1) => member.FailedPasswordAttempts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</Reference>
|
||||
<Reference Include="MySql.Data">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll</HintPath>
|
||||
<HintPath>..\packages\MySql.Data.6.9.6\lib\net45\MySql.Data.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -313,6 +313,7 @@
|
||||
<Compile Include="Events\SendToPublishEventArgs.cs" />
|
||||
<Compile Include="Exceptions\InvalidCompositionException.cs" />
|
||||
<Compile Include="HideFromTypeFinderAttribute.cs" />
|
||||
<Compile Include="HttpContextExtensions.cs" />
|
||||
<Compile Include="IApplicationEventHandler.cs" />
|
||||
<Compile Include="IDisposeOnRequestEnd.cs" />
|
||||
<Compile Include="Manifest\GridEditorConverter.cs" />
|
||||
@@ -1216,6 +1217,7 @@
|
||||
<Compile Include="WriteLock.cs" />
|
||||
<Compile Include="XmlExtensions.cs" />
|
||||
<Compile Include="XmlHelper.cs" />
|
||||
<Compile Include="Xml\UmbracoXPathPathSyntaxParser.cs" />
|
||||
<Compile Include="Xml\XPath\MacroNavigator.cs" />
|
||||
<Compile Include="Xml\XPath\INavigableContentType.cs" />
|
||||
<Compile Include="Xml\XPath\NavigableNavigator.cs" />
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used to parse our customize Umbraco XPath expressions (i.e. that include special tokens like $site) into
|
||||
/// a real XPath statement
|
||||
/// </summary>
|
||||
internal class UmbracoXPathPathSyntaxParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parses custom umbraco xpath expression
|
||||
/// </summary>
|
||||
/// <param name="xpathExpression">The Xpath expression</param>
|
||||
/// <param name="nodeContextId">
|
||||
/// The current node id context of executing the query - null if there is no current node, in which case
|
||||
/// some of the parameters like $current, $parent, $site will be disabled
|
||||
/// </param>
|
||||
/// <param name="getPath">The callback to create the nodeId path, given a node Id</param>
|
||||
/// <param name="publishedContentExists">The callback to return whether a published node exists based on Id</param>
|
||||
/// <returns></returns>
|
||||
public static string ParseXPathQuery(
|
||||
string xpathExpression,
|
||||
int? nodeContextId,
|
||||
Func<int, IEnumerable<string>> getPath,
|
||||
Func<int, bool> publishedContentExists)
|
||||
{
|
||||
|
||||
//TODO: This should probably support some of the old syntax and token replacements, currently
|
||||
// it does not, there is a ticket raised here about it: http://issues.umbraco.org/issue/U4-6364
|
||||
// previous tokens were: "$currentPage", "$ancestorOrSelf", "$parentPage" and I beleive they were
|
||||
// allowed 'inline', not just at the beginning... whether or not we want to support that is up
|
||||
// for discussion.
|
||||
|
||||
Mandate.ParameterNotNullOrEmpty(xpathExpression, "xpathExpression");
|
||||
Mandate.ParameterNotNull(getPath, "getPath");
|
||||
Mandate.ParameterNotNull(publishedContentExists, "publishedContentExists");
|
||||
|
||||
//no need to parse it
|
||||
if (xpathExpression.StartsWith("$") == false)
|
||||
return xpathExpression;
|
||||
|
||||
//get nearest published item
|
||||
Func<IEnumerable<string>, int> getClosestPublishedAncestor = (path =>
|
||||
{
|
||||
foreach (var i in path)
|
||||
{
|
||||
int idAsInt;
|
||||
if (int.TryParse(i, out idAsInt))
|
||||
{
|
||||
var exists = publishedContentExists(int.Parse(i));
|
||||
if (exists)
|
||||
return idAsInt;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
|
||||
const string rootXpath = "descendant::*[@id={0}]";
|
||||
|
||||
//parseable items:
|
||||
var vars = new Dictionary<string, Func<string, string>>();
|
||||
|
||||
//These parameters must have a node id context
|
||||
if (nodeContextId.HasValue)
|
||||
{
|
||||
vars.Add("$current", q =>
|
||||
{
|
||||
var closestPublishedAncestorId = getClosestPublishedAncestor(getPath(nodeContextId.Value));
|
||||
return q.Replace("$current", string.Format(rootXpath, closestPublishedAncestorId));
|
||||
});
|
||||
|
||||
vars.Add("$parent", q =>
|
||||
{
|
||||
//remove the first item in the array if its the current node
|
||||
//this happens when current is published, but we are looking for its parent specifically
|
||||
var path = getPath(nodeContextId.Value).ToArray();
|
||||
if (path[0] == nodeContextId.ToString())
|
||||
{
|
||||
path = path.Skip(1).ToArray();
|
||||
}
|
||||
|
||||
var closestPublishedAncestorId = getClosestPublishedAncestor(path);
|
||||
return q.Replace("$parent", string.Format(rootXpath, closestPublishedAncestorId));
|
||||
});
|
||||
|
||||
|
||||
vars.Add("$site", q =>
|
||||
{
|
||||
var closestPublishedAncestorId = getClosestPublishedAncestor(getPath(nodeContextId.Value));
|
||||
return q.Replace("$site", string.Format(rootXpath, closestPublishedAncestorId) + "/ancestor-or-self::*[@level = 1]");
|
||||
});
|
||||
}
|
||||
|
||||
//TODO: This used to just replace $root with string.Empty BUT, that would never work
|
||||
// the root is always "/root . Need to confirm with Per why this was string.Empty before!
|
||||
vars.Add("$root", q => q.Replace("$root", "/root"));
|
||||
|
||||
|
||||
foreach (var varible in vars)
|
||||
{
|
||||
if (xpathExpression.StartsWith(varible.Key))
|
||||
{
|
||||
xpathExpression = varible.Value(xpathExpression);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return xpathExpression;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.6" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
|
||||
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net40" />
|
||||
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.30506.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net40" />
|
||||
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
|
||||
<package id="MiniProfiler" version="2.1.0" targetFramework="net45" />
|
||||
<package id="MySql.Data" version="6.6.5" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
|
||||
<package id="SharpZipLib" version="0.86.0" targetFramework="net40" />
|
||||
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net40" />
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" userInstalled="true" />
|
||||
<package id="HtmlAgilityPack" version="1.4.6" targetFramework="net45" userInstalled="true" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" userInstalled="true" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net4" userInstalled="true" />
|
||||
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net4" userInstalled="true" />
|
||||
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.30506.0" targetFramework="net45" userInstalled="true" />
|
||||
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net4" userInstalled="true" />
|
||||
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" userInstalled="true" />
|
||||
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" userInstalled="true" />
|
||||
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net45" userInstalled="true" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net4" userInstalled="true" />
|
||||
<package id="MiniProfiler" version="2.1.0" targetFramework="net45" userInstalled="true" />
|
||||
<package id="MySql.Data" version="6.9.6" targetFramework="net45" userInstalled="true" />
|
||||
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" userInstalled="true" />
|
||||
<package id="SharpZipLib" version="0.86.0" targetFramework="net4" userInstalled="true" />
|
||||
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net4" userInstalled="true" />
|
||||
</packages>
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.UI;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
@@ -21,6 +22,83 @@ namespace Umbraco.Tests.Cache
|
||||
public virtual void TearDown()
|
||||
{
|
||||
Provider.ClearAllCache();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Throws_On_Reentry()
|
||||
{
|
||||
// don't run for StaticCacheProvider - not making sense
|
||||
if (GetType() == typeof (StaticCacheProviderTests))
|
||||
Assert.Ignore("Do not run for StaticCacheProvider.");
|
||||
|
||||
Exception exception = null;
|
||||
var result = Provider.GetCacheItem("blah", () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var result2 = Provider.GetCacheItem("blah");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = e;
|
||||
}
|
||||
return "value";
|
||||
});
|
||||
Assert.IsNotNull(exception);
|
||||
Assert.IsAssignableFrom<InvalidOperationException>(exception);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Does_Not_Cache_Exceptions()
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
object result;
|
||||
try
|
||||
{
|
||||
result = Provider.GetCacheItem("Blah", () =>
|
||||
{
|
||||
counter++;
|
||||
throw new Exception("Do not cache this");
|
||||
});
|
||||
}
|
||||
catch (Exception){}
|
||||
|
||||
try
|
||||
{
|
||||
result = Provider.GetCacheItem("Blah", () =>
|
||||
{
|
||||
counter++;
|
||||
throw new Exception("Do not cache this");
|
||||
});
|
||||
}
|
||||
catch (Exception){}
|
||||
|
||||
Assert.Greater(counter, 1);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ensures_Delegate_Result_Is_Cached_Once()
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
object result;
|
||||
|
||||
result = Provider.GetCacheItem("Blah", () =>
|
||||
{
|
||||
counter++;
|
||||
return "";
|
||||
});
|
||||
|
||||
result = Provider.GetCacheItem("Blah", () =>
|
||||
{
|
||||
counter++;
|
||||
return "";
|
||||
});
|
||||
|
||||
Assert.AreEqual(counter, 1);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Web;
|
||||
using System;
|
||||
using System.Web;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
|
||||
@@ -29,5 +30,29 @@ namespace Umbraco.Tests.Cache
|
||||
{
|
||||
get { return _provider; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DoesNotCacheExceptions()
|
||||
{
|
||||
string value;
|
||||
Assert.Throws<Exception>(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(1)); });
|
||||
Assert.Throws<Exception>(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(2)); });
|
||||
|
||||
// does not throw
|
||||
value = (string)_provider.GetCacheItem("key", () => GetValue(3));
|
||||
Assert.AreEqual("succ3", value);
|
||||
|
||||
// cache
|
||||
value = (string)_provider.GetCacheItem("key", () => GetValue(4));
|
||||
Assert.AreEqual("succ3", value);
|
||||
}
|
||||
|
||||
private static string GetValue(int i)
|
||||
{
|
||||
Console.WriteLine("get" + i);
|
||||
if (i < 3)
|
||||
throw new Exception("fail");
|
||||
return "succ" + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,10 +28,16 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.Count() == 3);
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).Culture == "default");
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).ContentId == 1047);
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentId);
|
||||
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentKey);
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).Culture == "en-US");
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).ContentId == 1048);
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).ContentXPath == "$site/error [@name = 'error']");
|
||||
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentId);
|
||||
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentKey);
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).Culture == "en-UK");
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).ContentId == 1049);
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).ContentKey == new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC"));
|
||||
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentKey);
|
||||
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
</error404>-->
|
||||
<error404>
|
||||
<errorPage culture="default">1047</errorPage>
|
||||
<errorPage culture="en-US">1048</errorPage>
|
||||
<errorPage culture="en-UK">1049</errorPage>
|
||||
<errorPage culture="en-US">$site/error [@name = 'error']</errorPage>
|
||||
<errorPage culture="en-UK">8560867F-B88F-4C74-A9A4-679D8E5B3BFC</errorPage>
|
||||
</error404>
|
||||
<!--<error404>1</error404>-->
|
||||
</errors>
|
||||
|
||||
@@ -109,6 +109,29 @@ namespace Umbraco.Tests.Macros
|
||||
<p>asdfasdf</p>".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_RTE_Data_For_Editor_With_Params_When_MacroAlias_Not_First()
|
||||
{
|
||||
var content = @"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<?UMBRACO_MACRO test1=""value1"" test2=""value2"" macroAlias=""Map"" />
|
||||
<p>asdfasdf</p>";
|
||||
var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary<string, string>() { { "test1", "value1" }, { "test2", "value2" } });
|
||||
|
||||
// Assert.AreEqual(@"<p>asdfasdf</p>
|
||||
//<p>asdfsadf</p>
|
||||
//<div class=""umb-macro-holder Map mceNonEditable"" test1=""value1"" test2=""value2"">
|
||||
//<!-- <?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" /> -->
|
||||
//<ins>Macro alias: <strong>Map</strong></ins></div>
|
||||
//<p>asdfasdf</p>".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty));
|
||||
Assert.AreEqual(@"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<div class=""umb-macro-holder mceNonEditable"" test1=""value1"" test2=""value2"">
|
||||
<!-- <?UMBRACO_MACRO test1=""value1"" test2=""value2"" macroAlias=""Map"" /> -->
|
||||
<ins>Macro alias: <strong>Map</strong></ins></div>
|
||||
<p>asdfasdf</p>".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Format_RTE_Data_For_Editor_With_Params_Closing_Tag()
|
||||
{
|
||||
|
||||
@@ -701,6 +701,37 @@ namespace Umbraco.Tests.Models
|
||||
Assert.That(contentType.WasPropertyDirty("Alias"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void After_Committing_Changes_Was_Dirty_Is_True_On_Changed_Property()
|
||||
{
|
||||
// Arrange
|
||||
var contentType = MockedContentTypes.CreateTextpageContentType();
|
||||
contentType.ResetDirtyProperties(); //reset
|
||||
var content = MockedContent.CreateTextpageContent(contentType, "test", -1);
|
||||
content.ResetDirtyProperties();
|
||||
|
||||
// Act
|
||||
content.SetPropertyValue("title", "new title");
|
||||
Assert.That(content.IsEntityDirty(), Is.False);
|
||||
Assert.That(content.IsDirty(), Is.True);
|
||||
Assert.That(content.IsPropertyDirty("title"), Is.True);
|
||||
Assert.That(content.IsAnyUserPropertyDirty(), Is.True);
|
||||
Assert.That(content.GetDirtyUserProperties().Count(), Is.EqualTo(1));
|
||||
Assert.That(content.Properties[0].IsDirty(), Is.True);
|
||||
Assert.That(content.Properties["title"].IsDirty(), Is.True);
|
||||
|
||||
content.ResetDirtyProperties(); //this would be like committing the entity
|
||||
|
||||
// Assert
|
||||
Assert.That(content.WasDirty(), Is.True);
|
||||
Assert.That(content.Properties[0].WasDirty(), Is.True);
|
||||
|
||||
|
||||
Assert.That(content.WasPropertyDirty("title"), Is.True);
|
||||
Assert.That(content.Properties["title"].IsDirty(), Is.False);
|
||||
Assert.That(content.Properties["title"].WasDirty(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void If_Not_Committed_Was_Dirty_Is_False()
|
||||
{
|
||||
|
||||
@@ -21,17 +21,29 @@ namespace Umbraco.Tests.Scheduling
|
||||
TestHelper.SetupLog4NetForTests();
|
||||
}
|
||||
|
||||
/*
|
||||
[Test]
|
||||
public async void ShutdownWaitWhenRunning()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }))
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions
|
||||
{
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
Thread.Sleep(800); // for long
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
AutoStart = true,
|
||||
KeepAlive = true
|
||||
}))
|
||||
{
|
||||
var stopped = false;
|
||||
runner.Stopped += (sender, args) => { stopped = true; };
|
||||
|
||||
Assert.IsTrue(runner.IsRunning); // because AutoStart is true
|
||||
Thread.Sleep(500); // and because KeepAlive is true...
|
||||
Assert.IsTrue(runner.IsRunning); // ...it keeps running
|
||||
|
||||
runner.Shutdown(false, true); // -force +wait
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
Assert.IsTrue(runner.IsCompleted);
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
Assert.IsFalse(runner.IsRunning); // no more running tasks
|
||||
Assert.IsTrue(stopped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,38 +56,121 @@ namespace Umbraco.Tests.Scheduling
|
||||
|
||||
runner.TaskStarting += (sender, args) => Console.WriteLine("starting {0}", DateTime.Now);
|
||||
runner.TaskCompleted += (sender, args) => Console.WriteLine("completed {0}", DateTime.Now);
|
||||
runner.Stopped += (sender, args) => Console.WriteLine("stopped {0}", DateTime.Now);
|
||||
|
||||
Assert.IsFalse(runner.IsRunning);
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
|
||||
Console.WriteLine("Adding task {0}", DateTime.Now);
|
||||
runner.Add(new MyTask(5000));
|
||||
Thread.Sleep(500);
|
||||
Assert.IsTrue(runner.IsRunning); // is running the task
|
||||
|
||||
Console.WriteLine("Shutting down {0}", DateTime.Now);
|
||||
runner.Shutdown(false, false); // -force -wait
|
||||
Assert.IsTrue(runner.IsCompleted);
|
||||
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
Assert.IsTrue(runner.IsRunning); // still running that task
|
||||
Thread.Sleep(3000); // wait slightly less than the task takes to complete
|
||||
Assert.IsTrue(runner.IsRunning); // still running that task
|
||||
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
|
||||
Console.WriteLine("End {0}", DateTime.Now);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[Test]
|
||||
public async void ShutdownWhenRunningWithWait()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
var stopped = false;
|
||||
runner.Stopped += (sender, args) => { stopped = true; };
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
runner.Add(new MyTask(5000));
|
||||
Assert.IsTrue(runner.IsRunning); // is running the task
|
||||
|
||||
runner.Shutdown(false, true); // -force +wait
|
||||
|
||||
// all this before we await because +wait
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
Assert.IsFalse(runner.IsRunning); // no more running tasks
|
||||
Assert.IsTrue(stopped);
|
||||
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async void ShutdownWhenRunningWithoutWait()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
var stopped = false;
|
||||
runner.Stopped += (sender, args) => { stopped = true; };
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
runner.Add(new MyTask(5000));
|
||||
Assert.IsTrue(runner.IsRunning); // is running the task
|
||||
|
||||
runner.Shutdown(false, false); // -force +wait
|
||||
|
||||
// all this before we await because -wait
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
Assert.IsTrue(runner.IsRunning); // still running the task
|
||||
Assert.IsFalse(stopped);
|
||||
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
|
||||
// and then...
|
||||
Assert.IsFalse(runner.IsRunning); // no more running tasks
|
||||
Assert.IsTrue(stopped);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async void ShutdownCompletesTheRunner()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
|
||||
// shutdown -force => run all queued tasks
|
||||
runner.Shutdown(false, false); // -force -wait
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // still not running anything
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
|
||||
// cannot add tasks to it anymore
|
||||
Assert.IsFalse(runner.TryAdd(new MyTask()));
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
runner.Add(new MyTask());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async void ShutdownFlushesTheQueue()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
Assert.IsFalse(runner.IsRunning);
|
||||
MyTask t;
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
runner.Add(new MyTask(5000));
|
||||
runner.Add(new MyTask());
|
||||
var t = new MyTask();
|
||||
runner.Add(t);
|
||||
Assert.IsTrue(runner.IsRunning); // is running the first task
|
||||
runner.Add(t = new MyTask());
|
||||
Assert.IsTrue(runner.IsRunning); // is running tasks
|
||||
|
||||
// shutdown -force => run all queued tasks
|
||||
runner.Shutdown(false, false); // -force -wait
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
Assert.IsTrue(runner.IsRunning); // is running tasks
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
|
||||
Assert.AreNotEqual(DateTime.MinValue, t.Ended); // t has run
|
||||
}
|
||||
}
|
||||
@@ -85,15 +180,20 @@ namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
Assert.IsFalse(runner.IsRunning);
|
||||
MyTask t;
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
runner.Add(new MyTask(5000));
|
||||
runner.Add(new MyTask());
|
||||
var t = new MyTask();
|
||||
runner.Add(t);
|
||||
Assert.IsTrue(runner.IsRunning); // is running the first task
|
||||
runner.Add(t = new MyTask());
|
||||
Assert.IsTrue(runner.IsRunning); // is running tasks
|
||||
|
||||
// shutdown +force => tries to cancel the current task, ignores queued tasks
|
||||
runner.Shutdown(true, false); // +force -wait
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
Assert.AreEqual(DateTime.MinValue, t.Ended); // t has not run
|
||||
Assert.IsTrue(runner.IsRunning); // is running that long task it cannot cancel
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
|
||||
Assert.AreEqual(DateTime.MinValue, t.Ended); // t has *not* run
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,23 +202,106 @@ namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
Assert.IsFalse(runner.IsRunning);
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
runner.Add(new MyTask(5000));
|
||||
runner.Add(new MyTask());
|
||||
runner.Add(new MyTask());
|
||||
Assert.IsTrue(runner.IsRunning); // is running the task
|
||||
Assert.IsTrue(runner.IsRunning); // is running tasks
|
||||
|
||||
// shutdown -force => run all queued tasks
|
||||
runner.Shutdown(false, false); // -force -wait
|
||||
Assert.IsTrue(runner.IsCompleted);
|
||||
Assert.IsTrue(runner.IsRunning); // still running that task
|
||||
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
Assert.IsTrue(runner.IsRunning); // still running a task
|
||||
Thread.Sleep(3000);
|
||||
Assert.IsTrue(runner.IsRunning); // still running that task
|
||||
Assert.IsTrue(runner.IsRunning); // still running a task
|
||||
|
||||
// shutdown +force => tries to cancel the current task, ignores queued tasks
|
||||
runner.Shutdown(true, false); // +force -wait
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async void HostingStopNonImmediate()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
MyTask t;
|
||||
|
||||
var stopped = false;
|
||||
runner.Stopped += (sender, args) => { stopped = true; };
|
||||
var terminating = false;
|
||||
runner.Terminating += (sender, args) => { terminating = true; };
|
||||
var terminated = false;
|
||||
runner.Terminated += (sender, args) => { terminated = true; };
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
runner.Add(new MyTask(5000));
|
||||
runner.Add(new MyTask());
|
||||
runner.Add(t = new MyTask());
|
||||
Assert.IsTrue(runner.IsRunning); // is running the task
|
||||
|
||||
runner.Stop(false); // -immediate = -force, -wait
|
||||
Assert.IsTrue(terminating); // has raised that event
|
||||
Assert.IsFalse(terminated); // but not terminated yet
|
||||
|
||||
// all this before we await because -wait
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
Assert.IsTrue(runner.IsRunning); // still running the task
|
||||
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
Assert.IsFalse(runner.IsRunning);
|
||||
Assert.IsTrue(stopped);
|
||||
|
||||
await runner.TerminatedAwaitable; // runner terminates, within test's timeout
|
||||
Assert.IsTrue(terminated); // has raised that event
|
||||
|
||||
Assert.AreNotEqual(DateTime.MinValue, t.Ended); // t has run
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Create_IsRunning()
|
||||
public async void HostingStopImmediate()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
MyTask t;
|
||||
|
||||
var stopped = false;
|
||||
runner.Stopped += (sender, args) => { stopped = true; };
|
||||
var terminating = false;
|
||||
runner.Terminating += (sender, args) => { terminating = true; };
|
||||
var terminated = false;
|
||||
runner.Terminated += (sender, args) => { terminated = true; };
|
||||
|
||||
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
|
||||
runner.Add(new MyTask(5000));
|
||||
runner.Add(new MyTask());
|
||||
runner.Add(t = new MyTask());
|
||||
Assert.IsTrue(runner.IsRunning); // is running the task
|
||||
|
||||
runner.Stop(true); // +immediate = +force, +wait
|
||||
Assert.IsTrue(terminating); // has raised that event
|
||||
Assert.IsTrue(terminated); // and that event
|
||||
Assert.IsTrue(stopped); // and that one
|
||||
|
||||
// and all this before we await because +wait
|
||||
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
|
||||
Assert.IsFalse(runner.IsRunning); // done running
|
||||
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
await runner.TerminatedAwaitable; // runner terminates, within test's timeout
|
||||
|
||||
Assert.AreEqual(DateTime.MinValue, t.Ended); // t has *not* run
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Create_IsNotRunning()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
@@ -126,14 +309,17 @@ namespace Umbraco.Tests.Scheduling
|
||||
}
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
|
||||
[Test]
|
||||
public async void Create_AutoStart_IsRunning()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { AutoStart = true }))
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions
|
||||
{
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
AutoStart = true
|
||||
}))
|
||||
{
|
||||
Assert.IsTrue(runner.IsRunning); // because AutoStart is true
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +328,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }))
|
||||
{
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
Assert.IsTrue(runner.IsRunning); // because AutoStart is true
|
||||
Thread.Sleep(800); // for long
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
// dispose will stop it
|
||||
@@ -159,8 +345,13 @@ namespace Umbraco.Tests.Scheduling
|
||||
// dispose will stop it
|
||||
}
|
||||
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // runner stops, within test's timeout
|
||||
//await runner.TerminatedAwaitable; // NO! see note below
|
||||
Assert.Throws<InvalidOperationException>(() => runner.Add(new MyTask()));
|
||||
|
||||
// but do NOT await on TerminatedAwaitable - disposing just shuts the runner down
|
||||
// so that we don't have a runaway task in tests, etc - but it does NOT terminate
|
||||
// the runner - it really is NOT a nice way to end a runner - it's there for tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -188,7 +379,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
runner.Add(new MyTask());
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
waitHandle.WaitOne();
|
||||
await runner; //since we are not being kept alive, it will quit
|
||||
await runner.StoppedAwaitable; //since we are not being kept alive, it will quit
|
||||
Assert.IsFalse(runner.IsRunning);
|
||||
}
|
||||
}
|
||||
@@ -221,11 +412,11 @@ namespace Umbraco.Tests.Scheduling
|
||||
runner.Add(task);
|
||||
await runner.CurrentThreadingTask; // wait for the Task operation to complete
|
||||
Assert.IsTrue(task.Ended != default(DateTime)); // task is done
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
}
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
|
||||
[Test]
|
||||
public async void WaitOnRunner_Tasks()
|
||||
{
|
||||
@@ -237,7 +428,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
tasks.ForEach(runner.Add);
|
||||
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
|
||||
// check that tasks are done
|
||||
Assert.IsTrue(tasks.All(x => x.Ended != default(DateTime)));
|
||||
@@ -260,7 +451,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
runner.Add(task);
|
||||
waitHandle.WaitOne(); // wait 'til task is done
|
||||
Assert.IsTrue(task.Ended != default(DateTime)); // task is done
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +471,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
WaitHandle.WaitAll(tasks.Values.Select(x => (WaitHandle)x).ToArray());
|
||||
Assert.IsTrue(tasks.All(x => x.Key.Ended != default(DateTime)));
|
||||
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,7 +573,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
}
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
|
||||
[Test]
|
||||
public void RecurringTaskTest()
|
||||
{
|
||||
@@ -422,7 +613,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
var task = new MyDelayedTask(200);
|
||||
var task = new MyDelayedTask(200, false);
|
||||
runner.Add(task);
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
Thread.Sleep(5000);
|
||||
@@ -431,7 +622,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
task.Release();
|
||||
await runner.CurrentThreadingTask; //wait for current task to complete
|
||||
Assert.IsTrue(task.HasRun);
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,19 +631,19 @@ namespace Umbraco.Tests.Scheduling
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
var task = new MyDelayedTask(200);
|
||||
var task = new MyDelayedTask(200, true);
|
||||
runner.Add(task);
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
Thread.Sleep(5000);
|
||||
Assert.IsTrue(runner.IsRunning); // still waiting for the task to release
|
||||
Assert.IsFalse(task.HasRun);
|
||||
runner.Shutdown(false, false);
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
Assert.IsTrue(task.HasRun);
|
||||
}
|
||||
}
|
||||
|
||||
[Ignore]
|
||||
|
||||
[Test]
|
||||
public void DelayedRecurring()
|
||||
{
|
||||
@@ -478,6 +669,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
|
||||
waitHandle.WaitOne();
|
||||
Assert.GreaterOrEqual(runCount, 4);
|
||||
Assert.IsTrue(task.HasRun);
|
||||
|
||||
// stops recurring
|
||||
runner.Shutdown(false, false);
|
||||
@@ -492,10 +684,27 @@ namespace Umbraco.Tests.Scheduling
|
||||
var exceptions = new ConcurrentQueue<Exception>();
|
||||
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
|
||||
|
||||
var task = new MyFailingTask(false); // -async
|
||||
var task = new MyFailingTask(false, true, false); // -async, +running, -disposing
|
||||
runner.Add(task);
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
|
||||
Assert.AreEqual(1, exceptions.Count); // traced and reported
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async void FailingTaskDisposing()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
var exceptions = new ConcurrentQueue<Exception>();
|
||||
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
|
||||
|
||||
var task = new MyFailingTask(false, false, true); // -async, -running, +disposing
|
||||
runner.Add(task);
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
|
||||
Assert.AreEqual(1, exceptions.Count); // traced and reported
|
||||
}
|
||||
@@ -509,10 +718,27 @@ namespace Umbraco.Tests.Scheduling
|
||||
var exceptions = new ConcurrentQueue<Exception>();
|
||||
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
|
||||
|
||||
var task = new MyFailingTask(true); // +async
|
||||
var task = new MyFailingTask(true, true, false); // +async, +running, -disposing
|
||||
runner.Add(task);
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
await runner; // wait for the entire runner operation to complete
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
|
||||
Assert.AreEqual(1, exceptions.Count); // traced and reported
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async void FailingTaskDisposingAsync()
|
||||
{
|
||||
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
|
||||
{
|
||||
var exceptions = new ConcurrentQueue<Exception>();
|
||||
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
|
||||
|
||||
var task = new MyFailingTask(false, false, true); // -async, -running, +disposing
|
||||
runner.Add(task);
|
||||
Assert.IsTrue(runner.IsRunning);
|
||||
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
|
||||
|
||||
Assert.AreEqual(1, exceptions.Count); // traced and reported
|
||||
}
|
||||
@@ -521,22 +747,28 @@ namespace Umbraco.Tests.Scheduling
|
||||
private class MyFailingTask : IBackgroundTask
|
||||
{
|
||||
private readonly bool _isAsync;
|
||||
private readonly bool _running;
|
||||
private readonly bool _disposing;
|
||||
|
||||
public MyFailingTask(bool isAsync)
|
||||
public MyFailingTask(bool isAsync, bool running, bool disposing)
|
||||
{
|
||||
_isAsync = isAsync;
|
||||
_running = running;
|
||||
_disposing = disposing;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
throw new Exception("Task has thrown.");
|
||||
if (_running)
|
||||
throw new Exception("Task has thrown.");
|
||||
}
|
||||
|
||||
public async Task RunAsync(CancellationToken token)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
throw new Exception("Task has thrown.");
|
||||
if (_running)
|
||||
throw new Exception("Task has thrown.");
|
||||
}
|
||||
|
||||
public bool IsAsync
|
||||
@@ -544,13 +776,17 @@ namespace Umbraco.Tests.Scheduling
|
||||
get { return _isAsync; }
|
||||
}
|
||||
|
||||
// fixme - must also test what happens if we throw on dispose!
|
||||
public void Dispose()
|
||||
{ }
|
||||
{
|
||||
if (_disposing)
|
||||
throw new Exception("Task has thrown.");
|
||||
}
|
||||
}
|
||||
|
||||
private class MyDelayedRecurringTask : DelayedRecurringTaskBase<MyDelayedRecurringTask>
|
||||
{
|
||||
public bool HasRun { get; private set; }
|
||||
|
||||
public MyDelayedRecurringTask(IBackgroundTaskRunner<MyDelayedRecurringTask> runner, int delayMilliseconds, int periodMilliseconds)
|
||||
: base(runner, delayMilliseconds, periodMilliseconds)
|
||||
{ }
|
||||
@@ -566,7 +802,7 @@ namespace Umbraco.Tests.Scheduling
|
||||
|
||||
public override void PerformRun()
|
||||
{
|
||||
// nothing to do at the moment
|
||||
HasRun = true;
|
||||
}
|
||||
|
||||
public override Task PerformRunAsync()
|
||||
@@ -583,30 +819,28 @@ namespace Umbraco.Tests.Scheduling
|
||||
private class MyDelayedTask : ILatchedBackgroundTask
|
||||
{
|
||||
private readonly int _runMilliseconds;
|
||||
private readonly ManualResetEvent _gate;
|
||||
private readonly ManualResetEventSlim _gate;
|
||||
|
||||
public bool HasRun { get; private set; }
|
||||
|
||||
public MyDelayedTask(int runMilliseconds)
|
||||
public MyDelayedTask(int runMilliseconds, bool runsOnShutdown)
|
||||
{
|
||||
_runMilliseconds = runMilliseconds;
|
||||
_gate = new ManualResetEvent(false);
|
||||
_gate = new ManualResetEventSlim(false);
|
||||
RunsOnShutdown = runsOnShutdown;
|
||||
}
|
||||
|
||||
public WaitHandle Latch
|
||||
{
|
||||
get { return _gate; }
|
||||
get { return _gate.WaitHandle; }
|
||||
}
|
||||
|
||||
public bool IsLatched
|
||||
{
|
||||
get { return true; }
|
||||
get { return _gate.IsSet == false; }
|
||||
}
|
||||
|
||||
public bool RunsOnShutdown
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
public bool RunsOnShutdown { get; private set; }
|
||||
|
||||
public void Run()
|
||||
{
|
||||
|
||||
@@ -58,9 +58,9 @@
|
||||
<Reference Include="AutoMapper.Net4">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.62.2941, Culture=neutral, processorArchitecture=MSIL">
|
||||
<Reference Include="Examine, Version=0.1.63.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Examine.0.1.62.2941\lib\Examine.dll</HintPath>
|
||||
<HintPath>..\packages\Examine.0.1.63.0\lib\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.62.2941" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.63.0" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
|
||||
|
||||
@@ -229,7 +229,7 @@ textarea {
|
||||
.radio input[type="radio"],
|
||||
.checkbox input[type="checkbox"] {
|
||||
float: left;
|
||||
margin-left: -20px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
// Move the options list down to align with labels
|
||||
|
||||
@@ -9,7 +9,7 @@ LazyLoad.js([
|
||||
'/Umbraco/js/umbraco.security.js',
|
||||
'/Umbraco/ServerVariables',
|
||||
'/Umbraco/lib/spectrum/spectrum.js',
|
||||
'http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js',
|
||||
'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js',
|
||||
'/umbraco/js/canvasdesigner.panel.js',
|
||||
], function () {
|
||||
jQuery(document).ready(function () {
|
||||
|
||||
@@ -180,7 +180,7 @@ var app = angular.module("Umbraco.canvasdesigner", ['colorpicker', 'ui.slider',
|
||||
// TODO: special init for font family picker
|
||||
if (item.type == "googlefontpicker" && item.values.fontFamily) {
|
||||
var variant = item.values.fontWeight != "" || item.values.fontStyle != "" ? ":" + item.values.fontWeight + item.values.fontStyle : "";
|
||||
var gimport = "@import url('http://fonts.googleapis.com/css?family=" + item.values.fontFamily + variant + "');";
|
||||
var gimport = "@import url('https://fonts.googleapis.com/css?family=" + item.values.fontFamily + variant + "');";
|
||||
if ($.inArray(gimport, parameters) < 0) {
|
||||
parameters.splice(0, 0, gimport);
|
||||
}
|
||||
@@ -412,7 +412,7 @@ var app = angular.module("Umbraco.canvasdesigner", ['colorpicker', 'ui.slider',
|
||||
var webFontScriptLoaded = false;
|
||||
var loadGoogleFont = function (font) {
|
||||
if (!webFontScriptLoaded) {
|
||||
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
$.getScript('https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
.done(function () {
|
||||
webFontScriptLoaded = true;
|
||||
// Recursively call once webfont script is available.
|
||||
|
||||
@@ -19,7 +19,7 @@ var refreshLayout = function (parameters) {
|
||||
var webFontScriptLoaded = false;
|
||||
var getFont = function (font) {
|
||||
if (!webFontScriptLoaded) {
|
||||
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
$.getScript('https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
.done(function () {
|
||||
webFontScriptLoaded = true;
|
||||
// Recursively call once webfont script is available.
|
||||
|
||||
@@ -22,6 +22,9 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
|
||||
if (scope.showTray) {
|
||||
return 'slide';
|
||||
}
|
||||
else if (scope.showTray === false) {
|
||||
return 'slide';
|
||||
}
|
||||
else {
|
||||
return '';
|
||||
}
|
||||
@@ -49,26 +52,35 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Listen for global state changes
|
||||
eventsService.on("appState.globalState.changed", function (e, args) {
|
||||
if (args.key === "showTray") {
|
||||
scope.showTray = args.value;
|
||||
}
|
||||
if (args.key === "stickyNavigation") {
|
||||
scope.stickyNavigation = args.value;
|
||||
}
|
||||
});
|
||||
|
||||
eventsService.on("appState.sectionState.changed", function (e, args) {
|
||||
if (args.key === "currentSection") {
|
||||
scope.currentSection = args.value;
|
||||
}
|
||||
});
|
||||
|
||||
eventsService.on("app.reInitialize", function (e, args) {
|
||||
var evts = [];
|
||||
|
||||
//Listen for global state changes
|
||||
evts.push(eventsService.on("appState.globalState.changed", function(e, args) {
|
||||
if (args.key === "showTray") {
|
||||
scope.showTray = args.value;
|
||||
}
|
||||
if (args.key === "stickyNavigation") {
|
||||
scope.stickyNavigation = args.value;
|
||||
}
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("appState.sectionState.changed", function(e, args) {
|
||||
if (args.key === "currentSection") {
|
||||
scope.currentSection = args.value;
|
||||
}
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("app.reInitialize", function(e, args) {
|
||||
//re-load the sections if we're re-initializing (i.e. package installed)
|
||||
loadSections();
|
||||
loadSections();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
//on page resize
|
||||
@@ -83,6 +95,13 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
|
||||
};
|
||||
|
||||
scope.sectionClick = function (section) {
|
||||
if (navigationService.userDialog) {
|
||||
navigationService.userDialog.close();
|
||||
}
|
||||
if (navigationService.helpDialog) {
|
||||
navigationService.helpDialog.close();
|
||||
}
|
||||
|
||||
navigationService.hideSearch();
|
||||
navigationService.showTree(section.alias);
|
||||
$location.path("/" + section.alias);
|
||||
@@ -92,8 +111,20 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
|
||||
navigationService.reloadSection(section.alias);
|
||||
};
|
||||
|
||||
scope.trayClick = function(){
|
||||
navigationService.showTray();
|
||||
scope.trayClick = function () {
|
||||
// close dialogs
|
||||
if (navigationService.userDialog) {
|
||||
navigationService.userDialog.close();
|
||||
}
|
||||
if (navigationService.helpDialog) {
|
||||
navigationService.helpDialog.close();
|
||||
}
|
||||
|
||||
if (appState.getGlobalState("showTray") === true) {
|
||||
navigationService.hideTray();
|
||||
} else {
|
||||
navigationService.showTray();
|
||||
}
|
||||
};
|
||||
|
||||
loadSections();
|
||||
|
||||
+10
-6
@@ -48,23 +48,25 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
|
||||
element.addClass(className);
|
||||
}
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the forms saving event
|
||||
scope.$on(savingEventName, function (ev, args) {
|
||||
unsubscribe.push(scope.$on(savingEventName, function(ev, args) {
|
||||
element.addClass(className);
|
||||
|
||||
//set the flag so we can check to see if we should display the error.
|
||||
isSavingNewItem = $routeParams.create;
|
||||
});
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
scope.$on(savedEvent, function (ev, args) {
|
||||
unsubscribe.push(scope.$on(savedEvent, function(ev, args) {
|
||||
//remove validation class
|
||||
element.removeClass(className);
|
||||
|
||||
//clear form state as at this point we retrieve new data from the server
|
||||
//and all validation will have cleared at this point
|
||||
formCtrl.$setPristine();
|
||||
});
|
||||
}));
|
||||
|
||||
//This handles the 'unsaved changes' dialog which is triggered when a route is attempting to be changed but
|
||||
// the form has pending changes
|
||||
@@ -92,10 +94,12 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
|
||||
}
|
||||
|
||||
});
|
||||
unsubscribe.push(locationEvent);
|
||||
|
||||
//Ensure to remove the event handler when this instance is destroyted
|
||||
scope.$on('$destroy', function() {
|
||||
if(locationEvent){
|
||||
locationEvent();
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+17
-6
@@ -96,8 +96,10 @@ function valPropertyMsg(serverValidationManager) {
|
||||
//create properties on our custom scope so we can use it in our template
|
||||
scope.errorMsg = "";
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for form error changes
|
||||
scope.$on("valStatusChanged", function (evt, args) {
|
||||
unsubscribe.push(scope.$on("valStatusChanged", function(evt, args) {
|
||||
if (args.form.$invalid) {
|
||||
|
||||
//first we need to check if the valPropertyMsg validity is invalid
|
||||
@@ -123,10 +125,10 @@ function valPropertyMsg(serverValidationManager) {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}, true);
|
||||
}, true));
|
||||
|
||||
//listen for the forms saving event
|
||||
scope.$on("formSubmitting", function (ev, args) {
|
||||
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (hasError && scope.errorMsg === "") {
|
||||
scope.errorMsg = getErrorMsg();
|
||||
@@ -135,15 +137,15 @@ function valPropertyMsg(serverValidationManager) {
|
||||
scope.errorMsg = "";
|
||||
stopWatch();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
scope.$on("formSubmitted", function (ev, args) {
|
||||
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
|
||||
showValidation = false;
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
stopWatch();
|
||||
});
|
||||
}));
|
||||
|
||||
//listen for server validation changes
|
||||
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
|
||||
@@ -179,7 +181,16 @@ function valPropertyMsg(serverValidationManager) {
|
||||
serverValidationManager.unsubscribe(scope.property.alias, "");
|
||||
});
|
||||
}
|
||||
|
||||
//when the scope is disposed we need to unsubscribe
|
||||
scope.$on('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valPropertyMsg", valPropertyMsg);
|
||||
+9
-6
@@ -43,8 +43,10 @@ function valToggleMsg(serverValidationManager) {
|
||||
}
|
||||
});
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the saving event (the result is a callback method which is called to unsubscribe)
|
||||
var unsubscribeSaving = scope.$on("formSubmitting", function (ev, args) {
|
||||
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
|
||||
element.show();
|
||||
@@ -56,20 +58,21 @@ function valToggleMsg(serverValidationManager) {
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//listen for the saved event (the result is a callback method which is called to unsubscribe)
|
||||
var unsubscribeSaved = scope.$on("formSubmitted", function (ev, args) {
|
||||
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
|
||||
showValidation = false;
|
||||
element.hide();
|
||||
});
|
||||
}));
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise if this directive is part of a modal, the listener still exists because the dom
|
||||
// element might still be there even after the modal has been hidden.
|
||||
element.bind('$destroy', function () {
|
||||
unsubscribeSaving();
|
||||
unsubscribeSaved();
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -537,6 +537,13 @@ angular.module('umbraco.services')
|
||||
template: 'views/common/dialogs/ysod.html',
|
||||
show: true
|
||||
});
|
||||
},
|
||||
|
||||
confirmDialog: function (ysodError) {
|
||||
|
||||
options.template = 'views/common/dialogs/confirm.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -15,7 +15,7 @@ function macroService() {
|
||||
|
||||
//This regex will match an alias of anything except characters that are quotes or new lines (for legacy reasons, when new macros are created
|
||||
// their aliases are cleaned an invalid chars are stripped)
|
||||
var expression = /(<\?UMBRACO_MACRO macroAlias=["']([^\"\'\n\r]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i;
|
||||
var expression = /(<\?UMBRACO_MACRO (?:.+)?macroAlias=["']([^\"\'\n\r]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i;
|
||||
var match = expression.exec(syntax);
|
||||
if (!match || match.length < 3) {
|
||||
return null;
|
||||
|
||||
@@ -513,23 +513,26 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
* Opens the user dialog, next to the sections navigation
|
||||
* template is located in views/common/dialogs/user.html
|
||||
*/
|
||||
showUserDialog: function() {
|
||||
showUserDialog: function () {
|
||||
// hide tray and close help dialog
|
||||
if (service.helpDialog) {
|
||||
service.helpDialog.close();
|
||||
}
|
||||
service.hideTray();
|
||||
|
||||
if(userDialog){
|
||||
userDialog.close();
|
||||
userDialog = null;
|
||||
if (service.userDialog) {
|
||||
service.userDialog.close();
|
||||
service.userDialog = undefined;
|
||||
}
|
||||
|
||||
userDialog = dialogService.open(
|
||||
{
|
||||
template: "views/common/dialogs/user.html",
|
||||
modalClass: "umb-modal-left",
|
||||
show: true
|
||||
});
|
||||
|
||||
|
||||
service.userDialog = dialogService.open(
|
||||
{
|
||||
template: "views/common/dialogs/user.html",
|
||||
modalClass: "umb-modal-left",
|
||||
show: true
|
||||
});
|
||||
|
||||
return userDialog;
|
||||
return service.userDialog;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -541,7 +544,13 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
|
||||
* Opens the user dialog, next to the sections navigation
|
||||
* template is located in views/common/dialogs/user.html
|
||||
*/
|
||||
showHelpDialog: function() {
|
||||
showHelpDialog: function () {
|
||||
// hide tray and close user dialog
|
||||
service.hideTray();
|
||||
if (service.userDialog) {
|
||||
service.userDialog.close();
|
||||
}
|
||||
|
||||
if(service.helpDialog){
|
||||
service.helpDialog.close();
|
||||
service.helpDialog = undefined;
|
||||
|
||||
@@ -206,7 +206,7 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
|
||||
},
|
||||
|
||||
/** builds an image grid row */
|
||||
buildRow: function(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin) {
|
||||
buildRow: function(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin, totalRemaining) {
|
||||
var currRowWidth = 0;
|
||||
var row = { images: [] };
|
||||
|
||||
@@ -253,8 +253,8 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
|
||||
this.setImageStyle(row.images[j], sizes[j].width, sizes[j].height, margin, bottomMargin);
|
||||
}
|
||||
|
||||
if (row.images.length === 1) {
|
||||
//if there's only one image on the row, set the container to max width
|
||||
if (row.images.length === 1 && totalRemaining > 1) {
|
||||
//if there's only one image on the row and there are more images remaining, set the container to max width
|
||||
row.images[0].style.width = maxRowWidth + "px";
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
|
||||
buildGrid: function(images, maxRowWidth, maxRowHeight, startingIndex, minDisplayHeight, idealImgPerRow, margin,imagesOnly) {
|
||||
|
||||
var rows = [];
|
||||
var imagesProcessed = 0;
|
||||
var imagesProcessed = 0;
|
||||
|
||||
//first fill in all of the original image sizes and URLs
|
||||
for (var i = startingIndex; i < images.length; i++) {
|
||||
@@ -298,7 +298,8 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
|
||||
var currImgs = images.slice(imagesProcessed);
|
||||
|
||||
//build the row
|
||||
var row = this.buildRow(currImgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
|
||||
var remaining = images.length - imagesProcessed;
|
||||
var row = this.buildRow(currImgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin, remaining);
|
||||
if (row.images.length > 0) {
|
||||
rows.push(row);
|
||||
imagesProcessed += row.images.length;
|
||||
|
||||
@@ -48,14 +48,16 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
|
||||
eventsService.emit("app.closeDialogs", event);
|
||||
};
|
||||
|
||||
var evts = [];
|
||||
|
||||
//when a user logs out or timesout
|
||||
eventsService.on("app.notAuthenticated", function() {
|
||||
evts.push(eventsService.on("app.notAuthenticated", function() {
|
||||
$scope.authenticated = null;
|
||||
$scope.user = null;
|
||||
});
|
||||
}));
|
||||
|
||||
//when the app is read/user is logged in, setup the data
|
||||
eventsService.on("app.ready", function (evt, data) {
|
||||
evts.push(eventsService.on("app.ready", function (evt, data) {
|
||||
|
||||
$scope.authenticated = data.authenticated;
|
||||
$scope.user = data.user;
|
||||
@@ -73,7 +75,7 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
|
||||
notificationsService.add(notification);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
//if the user has changed we need to redirect to the root so they don't try to continue editing the
|
||||
//last item in the URL (NOTE: the user id can equal zero, so we cannot just do !data.lastUserId since that will resolve to true)
|
||||
@@ -104,6 +106,13 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -47,15 +47,17 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
|
||||
|
||||
$scope.selectedId = navigationService.currentId;
|
||||
|
||||
var evts = [];
|
||||
|
||||
//Listen for global state changes
|
||||
eventsService.on("appState.globalState.changed", function (e, args) {
|
||||
evts.push(eventsService.on("appState.globalState.changed", function(e, args) {
|
||||
if (args.key === "showNavigation") {
|
||||
$scope.showNavigation = args.value;
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//Listen for menu state changes
|
||||
eventsService.on("appState.menuState.changed", function (e, args) {
|
||||
evts.push(eventsService.on("appState.menuState.changed", function(e, args) {
|
||||
if (args.key === "showMenuDialog") {
|
||||
$scope.showContextMenuDialog = args.value;
|
||||
}
|
||||
@@ -71,20 +73,21 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
|
||||
if (args.key === "currentNode") {
|
||||
$scope.menuNode = args.value;
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//Listen for section state changes
|
||||
eventsService.on("appState.treeState.changed", function (e, args) {
|
||||
evts.push(eventsService.on("appState.treeState.changed", function(e, args) {
|
||||
var f = args;
|
||||
if (args.value.root && args.value.root.metaData.containsTrees === false) {
|
||||
$rootScope.emptySection = true;
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
$rootScope.emptySection = false;
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//Listen for section state changes
|
||||
eventsService.on("appState.sectionState.changed", function (e, args) {
|
||||
evts.push(eventsService.on("appState.sectionState.changed", function(e, args) {
|
||||
//section changed
|
||||
if (args.key === "currentSection") {
|
||||
$scope.currentSection = args.value;
|
||||
@@ -93,26 +96,26 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
|
||||
if (args.key === "showSearchResults") {
|
||||
$scope.showSearchResults = args.value;
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//This reacts to clicks passed to the body element which emits a global call to close all dialogs
|
||||
eventsService.on("app.closeDialogs", function (event) {
|
||||
evts.push(eventsService.on("app.closeDialogs", function(event) {
|
||||
if (appState.getGlobalState("stickyNavigation")) {
|
||||
navigationService.hideNavigation();
|
||||
//TODO: don't know why we need this? - we are inside of an angular event listener.
|
||||
angularHelper.safeApply($scope);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//when a user logs out or timesout
|
||||
eventsService.on("app.notAuthenticated", function () {
|
||||
evts.push(eventsService.on("app.notAuthenticated", function() {
|
||||
$scope.authenticated = false;
|
||||
});
|
||||
}));
|
||||
|
||||
//when the application is ready and the user is authorized setup the data
|
||||
eventsService.on("app.ready", function (evt, data) {
|
||||
evts.push(eventsService.on("app.ready", function(evt, data) {
|
||||
$scope.authenticated = true;
|
||||
});
|
||||
}));
|
||||
|
||||
//this reacts to the options item in the tree
|
||||
//todo, migrate to nav service
|
||||
@@ -151,6 +154,13 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//register it
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache',
|
||||
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache) {
|
||||
|
||||
|
||||
//This sets the default jquery ajax headers to include our csrf token, we
|
||||
// need to user the beforeSend method because our token changes per user/login so
|
||||
// it cannot be static
|
||||
@@ -16,8 +15,10 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
|
||||
eventsService.on("app.authenticated", function(evt, data) {
|
||||
assetsService._loadInitAssets().then(function() {
|
||||
appState.setGlobalState("isReady", true);
|
||||
//send the ready event
|
||||
|
||||
//send the ready event with the included returnToPath,returnToSearch data
|
||||
eventsService.emit("app.ready", data);
|
||||
returnToPath = null, returnToSearch = null;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,7 +45,18 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
|
||||
wiring up it's controller, etc... and then redirect to the rejected URL. */
|
||||
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
|
||||
event.preventDefault();
|
||||
$location.path(rejection.path).search(rejection.search);
|
||||
|
||||
var returnPath = null;
|
||||
if (rejection.path == "/login" || rejection.path.startsWith("/login/")) {
|
||||
//Set the current path before redirecting so we know where to redirect back to
|
||||
returnPath = encodeURIComponent($location.url());
|
||||
}
|
||||
|
||||
$location.path(rejection.path)
|
||||
if (returnPath) {
|
||||
$location.search("returnPath", returnPath);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -305,7 +305,8 @@ textarea {
|
||||
.radio input[type="radio"],
|
||||
.checkbox input[type="checkbox"] {
|
||||
float: left;
|
||||
margin-left: -20px;
|
||||
margin-left: 0px;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
// Move the options list down to align with labels
|
||||
@@ -793,3 +794,17 @@ legend + .control-group {
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
// Labels on own row
|
||||
.form-horizontal .control-label {
|
||||
width: 100%;
|
||||
}
|
||||
.form-horizontal .controls {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,9 +22,10 @@
|
||||
}
|
||||
|
||||
.login-overlay .form {
|
||||
position:fixed;
|
||||
display: block;
|
||||
padding-top: 100px;
|
||||
padding-left: 165px;
|
||||
top: 100px;
|
||||
left: 165px;
|
||||
width: 370px;
|
||||
text-align: right
|
||||
}
|
||||
@@ -44,4 +45,12 @@
|
||||
padding-left: 6px;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 565px) {
|
||||
// Remove padding on login-form on smaller devices
|
||||
.login-overlay .form {
|
||||
left: inherit;
|
||||
right:25px;
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ h5{
|
||||
|
||||
.controls-row {
|
||||
padding-top: 5px;
|
||||
margin-left: 240px !important;
|
||||
margin-left: 240px;
|
||||
}
|
||||
.controls-row label {
|
||||
display: inline-block
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
|
||||
.umb-modal-left .umb-panel-header .umb-headline, .umb-modal-left .umb-panel-header h1 {
|
||||
width: auto;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* umb.dialog is used for the dialogs on the conent tree*/
|
||||
|
||||
@@ -37,17 +37,13 @@
|
||||
bottom: 31px !important;
|
||||
}
|
||||
|
||||
/*
|
||||
.umb-tab-buttons.umb-bottom-bar {
|
||||
bottom: 50px !important;
|
||||
}*/
|
||||
|
||||
.umb-panel-header .umb-headline, .umb-panel-header h1 {
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
background: none;
|
||||
margin: 15px 0 0 20px;
|
||||
padding: 3px 5px;
|
||||
line-height: 1.4;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
border: 1px solid @grayLighter;
|
||||
@@ -91,7 +87,7 @@
|
||||
margin: -6px 0 0 0;
|
||||
padding: 0 0 2px 0;
|
||||
border-radius: 0;
|
||||
line-height: 1em;
|
||||
line-height: normal;
|
||||
border: 1px solid transparent;
|
||||
color: @black;
|
||||
letter-spacing: -0.01em
|
||||
@@ -152,27 +148,27 @@
|
||||
/* tab buttons */
|
||||
.umb-bottom-bar{
|
||||
background: white;
|
||||
|
||||
-webkit-box-shadow: 0px -18px 20px rgba(255, 255, 255, 1);
|
||||
-moz-box-shadow: 0px -18px 20px rgba(255, 255, 255, 1);
|
||||
box-shadow: 0px -18px 20px rgba(255, 255, 255, 1);
|
||||
|
||||
border-top: 1px solid @grayLighter;
|
||||
|
||||
padding: 10px 0 10px 0;
|
||||
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 100px;
|
||||
right: 20px;
|
||||
z-index: 6010;
|
||||
};
|
||||
|
||||
@media (min-width: 1101px) {
|
||||
.umb-bottom-bar {left: 460px;}
|
||||
}
|
||||
|
||||
.umb-tab-buttons{padding-left: 240px;}
|
||||
.umb-tab-buttons{
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
@media (min-width: 1101px) {
|
||||
.umb-bottom-bar {
|
||||
left: 460px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-tab-pane{padding-bottom: 90px}
|
||||
|
||||
.tab-content{overflow: visible; }
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
}
|
||||
|
||||
.umb-codeeditor{
|
||||
width: 99%;
|
||||
width: 99%;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -68,7 +68,7 @@ div.umb-codeeditor .umb-btn-toolbar {
|
||||
.mce-ico{font-size: 12px !important; color: @blackLight !important;}
|
||||
/* Special case to support helviticons for the tiny mce button controls */
|
||||
.mce-ico.mce-i-custom[class^="icon-"],
|
||||
.mce-ico.mce-i-custom[class*=" icon-"] {
|
||||
.mce-ico.mce-i-custom[class*=" icon-"] {
|
||||
font-family: icomoon;
|
||||
font-size:16px !important;
|
||||
}
|
||||
@@ -100,8 +100,8 @@ ul.color-picker li a {
|
||||
/* pre-value editor */
|
||||
|
||||
.control-group.color-picker-preval pre {
|
||||
display: inline;
|
||||
margin-right: 20px;
|
||||
display: inline;
|
||||
margin-right: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@@ -116,8 +116,8 @@ ul.color-picker li a {
|
||||
// --------------------------------------------------
|
||||
.umb-mediapicker .add-link{
|
||||
display: inline-block;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
color: @grayLight;
|
||||
border: 2px @grayLight dashed !important;
|
||||
@@ -187,7 +187,7 @@ ul.color-picker li a {
|
||||
|
||||
.umb-sortable-thumbnails li img
|
||||
{
|
||||
max-width:100%;
|
||||
max-width:100%;
|
||||
max-height:100%;
|
||||
margin:auto;
|
||||
display:block;
|
||||
@@ -206,12 +206,12 @@ ul.color-picker li a {
|
||||
.umb-sortable-thumbnails .icon-holder *
|
||||
{
|
||||
color: @grayLight;
|
||||
display: block
|
||||
display: block
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Cropper
|
||||
// Cropper
|
||||
// -------------------------------------------------
|
||||
|
||||
.umb-cropper{
|
||||
@@ -237,7 +237,7 @@ ul.color-picker li a {
|
||||
position: relative;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
.umb-cropper-gravity .viewport{
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
@@ -301,17 +301,13 @@ ul.color-picker li a {
|
||||
// --------------------------------------------------
|
||||
.umb-folderbrowser .add-link{
|
||||
display: inline-block;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
border: 1px @grayLight dashed;
|
||||
line-height: 120px
|
||||
}
|
||||
|
||||
.umb-folderbrowser .selector-overlay{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.umb-upload-drop-zone{
|
||||
margin-bottom:5px;
|
||||
}
|
||||
@@ -368,8 +364,8 @@ ul.color-picker li a {
|
||||
|
||||
|
||||
|
||||
.umb-photo-folder .picrow div a:first-child {
|
||||
width:100%;
|
||||
.umb-photo-folder .picrow div a:first-child {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
@@ -382,15 +378,19 @@ ul.color-picker li a {
|
||||
.umb-photo-folder a:hover{text-decoration: none}
|
||||
.umb-photo-folder .umb-non-thumbnail{
|
||||
text-align: center;
|
||||
vertical-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
background: @grayLighter;
|
||||
color: @black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-photo-folder .selector-overlay{
|
||||
display: none;
|
||||
}
|
||||
|
||||
//this is a temp hack, to provide selectors in the dialog:
|
||||
.umb-photo-folder .pic:hover .selector-overlay{
|
||||
.umb-photo-folder .pic:hover .selector-overlay {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
@@ -402,6 +402,11 @@ ul.color-picker li a {
|
||||
text-align: center;
|
||||
color: white;
|
||||
opacity: 0.4;
|
||||
text-decoration:none;
|
||||
|
||||
overflow: hidden;
|
||||
text-overlow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.umb-photo-folder .umb-non-thumbnail i{
|
||||
@@ -410,7 +415,18 @@ ul.color-picker li a {
|
||||
line-height: 60px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
padding-top: 20px;
|
||||
/*vertically aligns */
|
||||
position: relative;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.umb-photo-folder .umb-non-thumbnail span{
|
||||
position: absolute;
|
||||
display: block;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.umb-photo-folder .selected{
|
||||
@@ -505,4 +521,4 @@ ul.color-picker li a {
|
||||
// --------------------------------------------------
|
||||
.bootstrap-datetimepicker-widget .btn{padding: 0;}
|
||||
.bootstrap-datetimepicker-widget .picker-switch .btn{ background: none; border: none;}
|
||||
.umb-datepicker .input-append .add-on{cursor: pointer;}
|
||||
.umb-datepicker .input-append .add-on{cursor: pointer;}
|
||||
|
||||
@@ -7,6 +7,7 @@ ul.sections {
|
||||
background: @blackLight;
|
||||
height: 100%;
|
||||
width: 80px;
|
||||
border-right: 1px solid @grayDark;
|
||||
}
|
||||
|
||||
ul.sections li {
|
||||
@@ -42,6 +43,7 @@ ul.sections li a {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 0 0 -4px;
|
||||
cursor: pointer; // make sure IE10 displays pointer cursor for expand and help sections.
|
||||
}
|
||||
|
||||
ul.sections a span {
|
||||
@@ -63,7 +65,7 @@ ul.sections:hover a span {
|
||||
// -------------------------
|
||||
|
||||
ul.sections li.avatar {
|
||||
height: 69px;
|
||||
height: 67px;
|
||||
padding: 30px 0 2px 0;
|
||||
text-align: center;
|
||||
margin: 0 0 0 -4px;
|
||||
@@ -116,7 +118,38 @@ ul.sections li.help a {
|
||||
// -------------------------
|
||||
li.expand a, li.expand{border: none !Important;}
|
||||
|
||||
ul.sections-tray {
|
||||
padding-top: 102px;
|
||||
width: 80px;
|
||||
li.expand {
|
||||
|
||||
&.open > a > i.icon {
|
||||
-webkit-transition: all 1s !important;
|
||||
-o-transition: all 1s !important;
|
||||
-moz-transition: all 1s !important;
|
||||
transition: all 1s !important;
|
||||
|
||||
&:before {
|
||||
-ms-transform: rotate(180deg) !important; /* IE 9 */
|
||||
-webkit-transform: rotate(180deg) !important; /* Chrome, Safari, Opera */
|
||||
-o-transform: rotate(180deg) !important;
|
||||
-moz-transform: rotate(180deg) !important;
|
||||
transform: rotate(180deg) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul.sections-tray {
|
||||
padding-top: 99px;
|
||||
width: 80px;
|
||||
|
||||
& > li:first-child > a {
|
||||
border-top: 1px solid #343434;
|
||||
}
|
||||
|
||||
& > li {
|
||||
// 5px (instead of 4px) because of vertical border
|
||||
border-left-width: 5px;
|
||||
|
||||
&.current, &:hover {
|
||||
border-left-width: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ angular.module("umbraco")
|
||||
});
|
||||
|
||||
helpService.findVideos(rq).then(function(videos){
|
||||
$scope.videos = videos;
|
||||
$scope.videos = videos;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<li class="span2" ng-repeat="video in videos">
|
||||
<div class="thumbnail" style="margin-right: 20px">
|
||||
<a target="_blank" href="{{video.link}}?utm_source=core&utm_medium=help&utm_content=link&utm_campaign=tv" title="{{video.title}}">
|
||||
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
|
||||
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -73,7 +73,7 @@ function InsertMacroController($scope, entityResource, macroResource, umbPropEdi
|
||||
|
||||
var val = item.value;
|
||||
|
||||
if (!_.isString(item.value)) {
|
||||
if (item.value != null && item.value != undefined && !_.isString(item.value)) {
|
||||
try {
|
||||
val = angular.toJson(val);
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ angular.module("umbraco")
|
||||
$scope.history = historyService.getCurrent();
|
||||
$scope.version = Umbraco.Sys.ServerVariables.application.version + " assembly: " + Umbraco.Sys.ServerVariables.application.assemblyVersion;
|
||||
|
||||
var evtHandlers = [];
|
||||
evtHandlers.push(eventsService.on("historyService.add", function (e, args) {
|
||||
var evts = [];
|
||||
evts.push(eventsService.on("historyService.add", function (e, args) {
|
||||
$scope.history = args.all;
|
||||
}));
|
||||
evtHandlers.push(eventsService.on("historyService.remove", function (e, args) {
|
||||
evts.push(eventsService.on("historyService.remove", function (e, args) {
|
||||
$scope.history = args.all;
|
||||
}));
|
||||
evtHandlers.push(eventsService.on("historyService.removeAll", function (e, args) {
|
||||
evts.push(eventsService.on("historyService.removeAll", function (e, args) {
|
||||
$scope.history = [];
|
||||
}));
|
||||
|
||||
@@ -62,8 +62,8 @@ angular.module("umbraco")
|
||||
|
||||
//remove all event handlers
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var i = 0; i < evtHandlers.length; i++) {
|
||||
evtHandlers[i]();
|
||||
for (var e = 0; e < evts.length; e++) {
|
||||
evts[e]();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
/** This controller is simply here to launch the login dialog when the route is explicitly changed to /login */
|
||||
angular.module('umbraco').controller("Umbraco.LoginController", function (eventsService, $scope, userService, $location) {
|
||||
angular.module('umbraco').controller("Umbraco.LoginController", function (eventsService, $scope, userService, $location, $rootScope) {
|
||||
|
||||
userService._showLoginDialog();
|
||||
|
||||
eventsService.on("app.ready", function(){
|
||||
$scope.avatar = "assets/img/application/logo.png";
|
||||
$location.path("/").search("");
|
||||
var evtOn = eventsService.on("app.ready", function(evt, data){
|
||||
$scope.avatar = "assets/img/application/logo.png";
|
||||
|
||||
var path = "/";
|
||||
|
||||
//check if there's a returnPath query string, if so redirect to it
|
||||
var locationObj = $location.search();
|
||||
if (locationObj.returnPath) {
|
||||
path = decodeURIComponent(locationObj.returnPath);
|
||||
}
|
||||
|
||||
$location.url(path);
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
eventsService.unsubscribe(evtOn);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -11,15 +11,17 @@
|
||||
|
||||
<div ng-style="img.style" class="umb-non-thumbnail" ng-if="!img.thumbnail">
|
||||
<i class="icon large {{img.icon}}"></i>
|
||||
{{img.name}}
|
||||
<span>{{img.name}}</span>
|
||||
</div>
|
||||
|
||||
<div ng-if="img.thumbnail" class="umb-photo" ng-style="img.thumbStyle" alt="{{img.name}}">
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-if="img.thumbnail" class="umb-photo" ng-style="img.thumbStyle" alt="{{img.name}}"></div>
|
||||
</a>
|
||||
|
||||
<a href ng-click="clickHandler(img, $event, true)"
|
||||
ng-if="img.isFolder" class="selector-overlay">
|
||||
<localize key="buttons_select">Select</localize>
|
||||
<a href ng-click="clickHandler(img, $event, true)" class="selector-overlay">
|
||||
<localize key="buttons_select" ng-if="img.isFolder">Select</localize>
|
||||
<span ng-if="!img.isFolder">{{img.name}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="expand" ng-show="needTray">
|
||||
<li class="expand" ng-class="{ 'open': showTray === true }" ng-show="needTray">
|
||||
<a href ng-click="trayClick()">
|
||||
<i class="icon icon-arrow-right"></i>
|
||||
</a>
|
||||
|
||||
@@ -49,13 +49,18 @@ function mediaPickerController($scope, dialogService, entityResource, $log, icon
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim(currIds.join(), ",");
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
//load media data
|
||||
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
entityResource.getByIds(modelIds, dialogOptions.entityType).then(function (data) {
|
||||
|
||||
@@ -58,10 +58,15 @@ angular.module('umbraco')
|
||||
};
|
||||
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
|
||||
@@ -43,13 +43,18 @@ angular.module('umbraco')
|
||||
|
||||
|
||||
//we always need to ensure we dont submit anything broken
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
if($scope.model.value.type === "member"){
|
||||
$scope.model.value.id = -1;
|
||||
$scope.model.value.query = "";
|
||||
}
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
function populate(item){
|
||||
$scope.clear();
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
|
||||
+14
-5
@@ -91,15 +91,17 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.ChangePasswordCont
|
||||
//set model to null
|
||||
$scope.model.value = null;
|
||||
};
|
||||
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the saved event, when that occurs we'll
|
||||
//change to changing = false;
|
||||
$scope.$on("formSubmitted", function () {
|
||||
unsubscribe.push($scope.$on("formSubmitted", function() {
|
||||
if ($scope.model.config.disableToggle === false) {
|
||||
$scope.changing = false;
|
||||
}
|
||||
});
|
||||
$scope.$on("formSubmitting", function() {
|
||||
}
|
||||
}));
|
||||
unsubscribe.push($scope.$on("formSubmitting", function() {
|
||||
//if there was a previously generated password displaying, clear it
|
||||
if ($scope.changing && $scope.model.value) {
|
||||
$scope.model.value.generatedPassword = null;
|
||||
@@ -108,6 +110,13 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.ChangePasswordCont
|
||||
//we are not changing, so the model needs to be null
|
||||
$scope.model.value = null;
|
||||
}
|
||||
}));
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.showReset = function() {
|
||||
|
||||
+11
-8
@@ -20,29 +20,32 @@
|
||||
|
||||
<!-- we need to show the old pass field when the provider cannot retrieve the password -->
|
||||
<umb-control-group alias="oldPassword" label="Old password" ng-show="$parent.showOldPass()">
|
||||
<input type="text" name="oldPassword" ng-model="$parent.model.value.oldPassword"
|
||||
<input type="password" name="oldPassword" ng-model="$parent.model.value.oldPassword"
|
||||
class="input-large umb-textstring textstring"
|
||||
ng-required="$parent.showOldPass()"
|
||||
val-server="oldPassword" no-dirty-check/>
|
||||
val-server="oldPassword" no-dirty-check
|
||||
autocomplete="off"/>
|
||||
<span class="help-inline" val-msg-for="oldPassword" val-toggle-msg="required">Required</span>
|
||||
<span class="help-inline" val-msg-for="oldPassword" val-toggle-msg="valServer"></span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="password" label="New password" ng-show="$parent.showNewPass()">
|
||||
<input type="text" name="password" ng-model="$parent.model.value.newPassword"
|
||||
class="input-large umb-textstring textstring"
|
||||
<input type="password" name="password" ng-model="$parent.model.value.newPassword"
|
||||
class="input-large umb-textstring textstring"
|
||||
ng-required="!$parent.model.value.reset"
|
||||
val-server="value"
|
||||
ng-minlength="{{$parent.model.config.minPasswordLength}}" no-dirty-check/>
|
||||
val-server="value"
|
||||
ng-minlength="{{$parent.model.config.minPasswordLength}}" no-dirty-check
|
||||
autocomplete="off" />
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="required">Required</span>
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="minlength">Minimum {{$parent.model.config.minPasswordLength}} characters</span>
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="valServer"></span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="confirmpassword" label="Confirm password" ng-show="$parent.showConfirmPass()">
|
||||
<input type="text" name="confirmpassword" ng-model="$parent.model.confirm"
|
||||
<input type="password" name="confirmpassword" ng-model="$parent.model.confirm"
|
||||
class="input-large umb-textstring textstring"
|
||||
val-compare="password" no-dirty-check/>
|
||||
val-compare="password" no-dirty-check
|
||||
autocomplete="off" />
|
||||
|
||||
<span class="help-inline" val-msg-for="confirmpassword" val-toggle-msg="valCompare">Passwords must match</span>
|
||||
</umb-control-group>
|
||||
|
||||
+7
-2
@@ -53,7 +53,7 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
|
||||
startNode: {
|
||||
query: "",
|
||||
type: "content",
|
||||
id: -1
|
||||
id: $scope.model.config.startNodeId ? $scope.model.config.startNodeId : -1 // get start node for simple Content Picker
|
||||
}
|
||||
};
|
||||
|
||||
@@ -158,13 +158,18 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim(currIds.join(), ",");
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
//load current data
|
||||
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
entityResource.getByIds(modelIds, entityType).then(function (data) {
|
||||
|
||||
+18
-3
@@ -18,9 +18,16 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
|
||||
//map the user config
|
||||
$scope.model.config = angular.extend(config, $scope.model.config);
|
||||
|
||||
$scope.datetimePickerValue = $scope.model.value;
|
||||
|
||||
//hide picker if clicking on the document
|
||||
$scope.hidePicker = function () {
|
||||
$element.find("div:first").datetimepicker("hide");
|
||||
//$element.find("div:first").datetimepicker("hide");
|
||||
// Sometimes the statement above fails and generates errors in the browser console. The following statements fix that.
|
||||
var dtp = $element.find("div:first");
|
||||
if (dtp && dtp.datetimepicker) {
|
||||
dtp.datetimepicker("hide");
|
||||
}
|
||||
};
|
||||
$(document).bind("click", $scope.hidePicker);
|
||||
|
||||
@@ -67,8 +74,16 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
|
||||
.datetimepicker($scope.model.config)
|
||||
.on("dp.change", applyDate);
|
||||
|
||||
//manually assign the date to the plugin
|
||||
$element.find("div:first").datetimepicker("setValue", $scope.model.value ? $scope.model.value : null);
|
||||
//manually assign the date to the plugin
|
||||
if (!$scope.model.config.format) {
|
||||
$element.find("div:first").datetimepicker("setValue", $scope.model.value ? $scope.model.value : null);
|
||||
}
|
||||
else {
|
||||
$element.find("div:first").datetimepicker("setValue", $scope.model.value ? new Date($scope.model.value) : null);
|
||||
if ($scope.model.value && $scope.model.config.format) {
|
||||
$scope.datetimePickerValue = moment($scope.model.value).format($scope.model.config.format);
|
||||
}
|
||||
}
|
||||
|
||||
//Ensure to remove the event handler when this instance is destroyted
|
||||
$scope.$on('$destroy', function () {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="umb-editor umb-datepicker" ng-controller="Umbraco.PropertyEditors.DatepickerController">
|
||||
<div class="input-append date datepicker" style="position: relative;" id="datepicker{{model.alias}}">
|
||||
<input name="datepicker" data-format="{{model.config.format}}" type="text"
|
||||
ng-model="model.value"
|
||||
ng-model="datetimePickerValue"
|
||||
ng-required="model.validation.mandatory"
|
||||
val-server="value" />
|
||||
<span class="add-on">
|
||||
|
||||
+85
-67
@@ -1,79 +1,97 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController",
|
||||
function ($scope) {
|
||||
function RowConfigController($scope) {
|
||||
|
||||
$scope.currentRow = angular.copy($scope.dialogOptions.currentRow);
|
||||
$scope.editors = $scope.dialogOptions.editors;
|
||||
$scope.columns = $scope.dialogOptions.columns;
|
||||
|
||||
$scope.currentRow = $scope.dialogOptions.currentRow;
|
||||
$scope.editors = $scope.dialogOptions.editors;
|
||||
$scope.columns = $scope.dialogOptions.columns;
|
||||
$scope.scaleUp = function(section, max, overflow) {
|
||||
var add = 1;
|
||||
if (overflow !== true) {
|
||||
add = (max > 1) ? 1 : max;
|
||||
}
|
||||
//var add = (max > 1) ? 1 : max;
|
||||
section.grid = section.grid + add;
|
||||
};
|
||||
|
||||
$scope.scaleUp = function(section, max, overflow){
|
||||
var add = 1;
|
||||
if(overflow !== true){
|
||||
add = (max > 1) ? 1 : max;
|
||||
}
|
||||
//var add = (max > 1) ? 1 : max;
|
||||
section.grid = section.grid+add;
|
||||
};
|
||||
$scope.scaleDown = function(section) {
|
||||
var remove = (section.grid > 1) ? 1 : section.grid;
|
||||
section.grid = section.grid - remove;
|
||||
};
|
||||
|
||||
$scope.scaleDown = function(section){
|
||||
var remove = (section.grid > 1) ? 1 : section.grid;
|
||||
section.grid = section.grid-remove;
|
||||
};
|
||||
$scope.percentage = function(spans) {
|
||||
return ((spans / $scope.columns) * 100).toFixed(1);
|
||||
};
|
||||
|
||||
$scope.percentage = function(spans){
|
||||
return ((spans / $scope.columns) * 100).toFixed(1);
|
||||
};
|
||||
|
||||
$scope.toggleCollection = function(collection, toggle){
|
||||
if(toggle){
|
||||
collection = [];
|
||||
}else{
|
||||
delete collection;
|
||||
}
|
||||
};
|
||||
$scope.toggleCollection = function(collection, toggle) {
|
||||
if (toggle) {
|
||||
collection = [];
|
||||
}
|
||||
else {
|
||||
delete collection;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/****************
|
||||
area
|
||||
*****************/
|
||||
$scope.configureCell = function(cell, row){
|
||||
if($scope.currentCell && $scope.currentCell=== cell){
|
||||
delete $scope.currentCell;
|
||||
}else{
|
||||
if(cell === undefined){
|
||||
var available = $scope.availableRowSpace;
|
||||
var space = 4;
|
||||
/****************
|
||||
area
|
||||
*****************/
|
||||
$scope.configureCell = function(cell, row) {
|
||||
if ($scope.currentCell && $scope.currentCell === cell) {
|
||||
delete $scope.currentCell;
|
||||
}
|
||||
else {
|
||||
if (cell === undefined) {
|
||||
var available = $scope.availableRowSpace;
|
||||
var space = 4;
|
||||
|
||||
if(available < 4 && available > 0){
|
||||
space = available;
|
||||
}
|
||||
|
||||
cell = {
|
||||
grid: space
|
||||
};
|
||||
|
||||
row.areas.push(cell);
|
||||
}
|
||||
$scope.currentCell = cell;
|
||||
if (available < 4 && available > 0) {
|
||||
space = available;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.deleteArea = function(index){
|
||||
$scope.currentRow.areas.splice(index, 1);
|
||||
};
|
||||
$scope.closeArea = function(){
|
||||
$scope.currentCell = undefined;
|
||||
};
|
||||
cell = {
|
||||
grid: space
|
||||
};
|
||||
|
||||
row.areas.push(cell);
|
||||
}
|
||||
$scope.currentCell = cell;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$watch("currentRow", function(row){
|
||||
if(row){
|
||||
var total = 0;
|
||||
_.forEach(row.areas, function(area){
|
||||
total = (total + area.grid);
|
||||
});
|
||||
$scope.deleteArea = function(index) {
|
||||
$scope.currentRow.areas.splice(index, 1);
|
||||
};
|
||||
$scope.closeArea = function() {
|
||||
$scope.currentCell = undefined;
|
||||
};
|
||||
|
||||
$scope.availableRowSpace = $scope.columns - total;
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
$scope.nameChanged = false;
|
||||
var originalName = $scope.currentRow.name;
|
||||
$scope.$watch("currentRow", function(row) {
|
||||
if (row) {
|
||||
|
||||
var total = 0;
|
||||
_.forEach(row.areas, function(area) {
|
||||
total = (total + area.grid);
|
||||
});
|
||||
|
||||
$scope.availableRowSpace = $scope.columns - total;
|
||||
|
||||
if (originalName) {
|
||||
if (originalName != row.name) {
|
||||
$scope.nameChanged = true;
|
||||
}
|
||||
else {
|
||||
$scope.nameChanged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
$scope.complete = function () {
|
||||
angular.extend($scope.dialogOptions.currentRow, $scope.currentRow);
|
||||
$scope.close();
|
||||
}
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController", RowConfigController);
|
||||
@@ -1,11 +1,17 @@
|
||||
<div class="umb-panel usky-grid usky-grid-configuration"
|
||||
ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController">
|
||||
<div class="umb-panel-body no-header with-footer">
|
||||
|
||||
<div class="umb-forms-settings">
|
||||
|
||||
<h5><localize key="grid_addRowConfiguration" /></h5>
|
||||
<p><localize key="grid_addRowConfigurationDetail" /></p>
|
||||
|
||||
<div class="alert alert-warn ng-scope" ng-show="nameChanged">
|
||||
Modifying a row configuration name will result in loss of
|
||||
data for any existing content that is based on this configuration.
|
||||
</div>
|
||||
|
||||
<umb-control-group label="@general_name">
|
||||
<input type="text" ng-model="currentRow.name" />
|
||||
</umb-control-group>
|
||||
@@ -83,7 +89,11 @@ ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController">
|
||||
<div class="umb-panel-footer">
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<a href="" ng-click="close()" class="btn btn-primary">
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
|
||||
<a href ng-click="complete()" class="btn btn-primary">
|
||||
<localize key="general_ok" class="ng-isolate-scope ng-scope">Done</localize>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<div>
|
||||
<div class="umb-panel-body no-header with-footer compact">
|
||||
|
||||
<umb-pane>
|
||||
<h3 class="alert alert-warn ng-scope">Warning!</h3>
|
||||
|
||||
<p>
|
||||
You are deleting the row configuration '<strong>{{dialogData.rowName}}</strong>'
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Modifying a row configuration name will result in loss of
|
||||
data for any existing content that is based on this configuration.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<localize key="general_areyousure">Are you sure?</localize>
|
||||
</p>
|
||||
</umb-pane>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-footer">
|
||||
<umb-confirm on-confirm="submit" on-cancel="close">
|
||||
</umb-confirm>
|
||||
</div>
|
||||
</div>
|
||||
@@ -14,6 +14,8 @@ angular.module("umbraco")
|
||||
// Sortable options
|
||||
// *********************************************
|
||||
|
||||
var draggedRteSettings;
|
||||
|
||||
$scope.sortableOptions = {
|
||||
distance: 10,
|
||||
cursor: "move",
|
||||
@@ -40,15 +42,22 @@ angular.module("umbraco")
|
||||
},
|
||||
|
||||
start: function (e, ui) {
|
||||
draggedRteSettings = {};
|
||||
ui.item.find('.mceNoEditor').each(function () {
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
|
||||
// remove all RTEs in the dragged row and save their settings
|
||||
var id = $(this).attr('id');
|
||||
draggedRteSettings[id] = _.findWhere(tinyMCE.editors, { id: id }).settings;
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, id);
|
||||
});
|
||||
},
|
||||
|
||||
stop: function (e, ui) {
|
||||
// reset all RTEs affected by the dragging
|
||||
ui.item.parents(".usky-column").find('.mceNoEditor').each(function () {
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
|
||||
tinyMCE.execCommand('mceAddEditor', false, $(this).attr('id'));
|
||||
var id = $(this).attr('id');
|
||||
draggedRteSettings[id] = draggedRteSettings[id] || _.findWhere(tinyMCE.editors, { id: id }).settings;
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, id);
|
||||
tinyMCE.init(draggedRteSettings[id]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -98,6 +107,7 @@ angular.module("umbraco")
|
||||
},
|
||||
|
||||
update: function (event, ui) {
|
||||
// add all RTEs which are affected by the dragging
|
||||
if (!ui.sender) {
|
||||
if (cancelMove) {
|
||||
ui.item.sortable.cancel();
|
||||
@@ -121,6 +131,11 @@ angular.module("umbraco")
|
||||
start: function (e, ui) {
|
||||
ui.item.find('.mceNoEditor').each(function () {
|
||||
notIncludedRte = [];
|
||||
|
||||
// save the dragged RTE settings
|
||||
draggedRteSettings = _.findWhere(tinyMCE.editors, { id: $(this).attr('id') }).settings;
|
||||
|
||||
// remove the dragged RTE
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
|
||||
});
|
||||
},
|
||||
@@ -128,14 +143,21 @@ angular.module("umbraco")
|
||||
stop: function (e, ui) {
|
||||
ui.item.parents(".usky-cell").find('.mceNoEditor').each(function () {
|
||||
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
|
||||
// add all dragged's neighbouring RTEs in the new cell
|
||||
notIncludedRte.splice(0, 0, $(this).attr('id'));
|
||||
}
|
||||
});
|
||||
$timeout(function () {
|
||||
// reconstruct the dragged RTE
|
||||
tinyMCE.init(draggedRteSettings);
|
||||
|
||||
_.forEach(notIncludedRte, function (id) {
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, id);
|
||||
tinyMCE.execCommand('mceAddEditor', false, id);
|
||||
console.info("stop " + id);
|
||||
// reset all the other RTEs
|
||||
if (id != draggedRteSettings.id) {
|
||||
var rteSettings = _.findWhere(tinyMCE.editors, { id: id }).settings;
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, id);
|
||||
tinyMCE.init(rteSettings);
|
||||
}
|
||||
});
|
||||
}, 500, false);
|
||||
}
|
||||
|
||||
+23
-3
@@ -127,9 +127,24 @@ angular.module("umbraco")
|
||||
);
|
||||
};
|
||||
|
||||
//var rowDeletesPending = false;
|
||||
$scope.deleteLayout = function (index) {
|
||||
//rowDeletesPending = true;
|
||||
|
||||
$scope.deleteLayout = function(index){
|
||||
$scope.model.value.layouts.splice(index, 1);
|
||||
//show ok/cancel dialog
|
||||
var confirmDialog = dialogService.open(
|
||||
{
|
||||
template: "views/propertyEditors/grid/dialogs/rowdeleteconfirm.html",
|
||||
show: true,
|
||||
callback: function() {
|
||||
$scope.model.value.layouts.splice(index, 1);
|
||||
},
|
||||
dialogData: {
|
||||
rowName: $scope.model.value.layouts[index].name
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -216,7 +231,7 @@ angular.module("umbraco")
|
||||
/****************
|
||||
Clean up
|
||||
*****************/
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var ts = $scope.model.value.templates;
|
||||
var ls = $scope.model.value.layouts;
|
||||
|
||||
@@ -237,4 +252,9 @@ angular.module("umbraco")
|
||||
});
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="umb-editor">
|
||||
<input name="integerField" type="number" class="umb-editor umb-number"
|
||||
<input name="integerField" type="number" class="umb-editor umb-number "
|
||||
ng-model="model.value"
|
||||
val-server="value"
|
||||
fix-number />
|
||||
fix-number min="{{model.config.min}}" max="{{model.config.max}}" step="{{model.config.step}}" />
|
||||
|
||||
<span class="help-inline" val-msg-for="integerField" val-toggle-msg="number">Not a number</span>
|
||||
<span class="help-inline" val-msg-for="integerField" val-toggle-msg="valServer">{{propertyForm.requiredField.errorMsg}}</span>
|
||||
|
||||
@@ -50,14 +50,14 @@
|
||||
<td>
|
||||
<a href="#" ng-click="sort('Name', true)" prevent-default class="sortable">
|
||||
<localize key="general_name">Name</localize>
|
||||
<i class="icon" ng-class="{'icon-navigation-down': isSortDirection('Name', 'asc'), 'icon-navigation-up': isSortDirection('Name', 'desc')}"></i>
|
||||
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection('Name', 'asc'), 'icon-navigation-down': isSortDirection('Name', 'desc')}"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td ng-repeat="column in options.includeProperties">
|
||||
<a href="#" ng-click="sort(column.alias, column.allowSorting)" ng-class="{'sortable':column.allowSorting}" prevent-default>
|
||||
<span ng-bind="column.header"></span>
|
||||
<i class="icon" ng-class="{'icon-navigation-down': isSortDirection(column.alias, 'asc'), 'icon-navigation-up': isSortDirection(column.alias, 'desc')}"></i>
|
||||
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection(column.alias, 'asc'), 'icon-navigation-down': isSortDirection(column.alias, 'desc')}"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
|
||||
+6
-1
@@ -85,7 +85,7 @@ angular.module('umbraco')
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var syntax = [];
|
||||
angular.forEach($scope.renderModel, function(value, key){
|
||||
syntax.push(value.syntax);
|
||||
@@ -94,6 +94,11 @@ angular.module('umbraco')
|
||||
$scope.model.value = syntax.join("");
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
|
||||
|
||||
+31
-28
@@ -1,7 +1,5 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.MarkdownEditorController",
|
||||
//inject umbracos assetsServce and dialog service
|
||||
function ($scope, assetsService, dialogService, $timeout) {
|
||||
function MarkdownEditorController($scope, assetsService, dialogService, $timeout) {
|
||||
|
||||
//tell the assets service to load the markdown.editor libs from the markdown editors
|
||||
//plugin folder
|
||||
@@ -11,36 +9,41 @@ function ($scope, assetsService, dialogService, $timeout) {
|
||||
}
|
||||
|
||||
assetsService
|
||||
.load([
|
||||
"lib/markdown/markdown.converter.js",
|
||||
.load([
|
||||
"lib/markdown/markdown.converter.js",
|
||||
"lib/markdown/markdown.sanitizer.js",
|
||||
"lib/markdown/markdown.editor.js"
|
||||
])
|
||||
.then(function () {
|
||||
|
||||
//this function will execute when all dependencies have loaded
|
||||
// but in the case that they've been previously loaded, we can only
|
||||
// init the md editor after this digest because the DOM needs to be ready first
|
||||
// so run the init on a timeout
|
||||
$timeout(function() {
|
||||
var converter2 = new Markdown.Converter();
|
||||
var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias);
|
||||
editor2.run();
|
||||
.then(function () {
|
||||
|
||||
//subscribe to the image dialog clicks
|
||||
editor2.hooks.set("insertImageDialog", function (callback) {
|
||||
// we need a short delay to wait for the textbox to appear.
|
||||
setTimeout(function () {
|
||||
//this function will execute when all dependencies have loaded
|
||||
// but in the case that they've been previously loaded, we can only
|
||||
// init the md editor after this digest because the DOM needs to be ready first
|
||||
// so run the init on a timeout
|
||||
$timeout(function () {
|
||||
var converter2 = new Markdown.Converter();
|
||||
var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias);
|
||||
editor2.run();
|
||||
|
||||
dialogService.mediaPicker({
|
||||
callback: function (data) {
|
||||
callback(data.image);
|
||||
}
|
||||
//subscribe to the image dialog clicks
|
||||
editor2.hooks.set("insertImageDialog", function (callback) {
|
||||
|
||||
dialogService.mediaPicker({
|
||||
callback: function (data) {
|
||||
callback(data.image);
|
||||
}
|
||||
});
|
||||
|
||||
return true; // tell the editor that we'll take care of getting the image url
|
||||
});
|
||||
|
||||
return true; // tell the editor that we'll take care of getting the image url
|
||||
});
|
||||
}, 200);
|
||||
});
|
||||
});
|
||||
|
||||
//load the seperat css for the editor to avoid it blocking our js loading TEMP HACK
|
||||
assetsService.loadCss("lib/markdown/markdown.css");
|
||||
});
|
||||
//load the seperat css for the editor to avoid it blocking our js loading TEMP HACK
|
||||
assetsService.loadCss("lib/markdown/markdown.css");
|
||||
})
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.MarkdownEditorController", MarkdownEditorController);
|
||||
+6
-1
@@ -65,13 +65,18 @@ function memberGroupPicker($scope, dialogService){
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim(currIds.join(), ",");
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.MemberGroupPickerController", memberGroupPicker);
|
||||
+6
-1
@@ -60,13 +60,18 @@ function memberPickerController($scope, dialogService, entityResource, $log, ico
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim(currIds.join(), ",");
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
//load member data
|
||||
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
entityResource.getByIds(modelIds, "Member").then(function (data) {
|
||||
|
||||
+8
@@ -1,5 +1,13 @@
|
||||
function MultipleTextBoxController($scope) {
|
||||
|
||||
$scope.sortableOptions = {
|
||||
axis: 'y',
|
||||
containment: 'parent',
|
||||
cursor: 'move',
|
||||
items: '> div.control-group',
|
||||
tolerance: 'pointer'
|
||||
};
|
||||
|
||||
if (!$scope.model.value) {
|
||||
$scope.model.value = [];
|
||||
}
|
||||
|
||||
+14
-11
@@ -1,17 +1,20 @@
|
||||
<div class="umb-editor umb-multiple-textbox" ng-controller="Umbraco.PropertyEditors.MultipleTextBoxController">
|
||||
|
||||
<div class="control-group" ng-repeat="item in model.value">
|
||||
<input type="text" name="item_{{$index}}" ng-model="item.value" class="umb-editor" />
|
||||
<a prevent-default href="" title="Remove this text box"
|
||||
ng-show="model.value.length > model.config.min"
|
||||
ng-click="remove($index)">
|
||||
<i class="icon icon-remove"></i>
|
||||
</a>
|
||||
<div ui-sortable="sortableOptions" ng-model="model.value">
|
||||
<div class="control-group" ng-repeat="item in model.value">
|
||||
<i class="icon icon-navigation handle"></i>
|
||||
<input type="text" name="item_{{$index}}" ng-model="item.value" class="umb-editor" />
|
||||
<a prevent-default href="" title="Remove this text box"
|
||||
ng-show="model.value.length > model.config.min"
|
||||
ng-click="remove($index)">
|
||||
<i class="icon icon-remove"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<a prevent-default href="" title="Add another text box"
|
||||
ng-show="model.config.max <= 0 || model.value.length < model.config.max"
|
||||
ng-click="add()">
|
||||
ng-show="model.config.max <= 0 || model.value.length < model.config.max"
|
||||
ng-click="add()">
|
||||
<i class="icon icon-add"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -58,12 +58,16 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
|
||||
var commands = _.where($scope.tinyMceConfig.commands, {selected: true});
|
||||
$scope.model.value.toolbar = _.pluck(commands, "frontEndCommand");
|
||||
|
||||
|
||||
});
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -40,6 +40,18 @@ describe('macro service tests', function () {
|
||||
expect(result.macroParamsDictionary.test2).toBe("hello");
|
||||
});
|
||||
|
||||
it('can parse syntax for macros when macroAlias is not the first parameter', function () {
|
||||
|
||||
var result = macroService.parseMacroSyntax("<?UMBRACO_MACRO test=\"asdf\" test2='hello' macroAlias='Map.Test' />");
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.macroAlias).toBe("Map.Test");
|
||||
expect(result.macroParamsDictionary.test).not.toBeUndefined();
|
||||
expect(result.macroParamsDictionary.test).toBe("asdf");
|
||||
expect(result.macroParamsDictionary.test2).not.toBeUndefined();
|
||||
expect(result.macroParamsDictionary.test2).toBe("hello");
|
||||
});
|
||||
|
||||
it('can parse syntax for macros with aliases containing whitespace and other chars', function () {
|
||||
|
||||
var result = macroService.parseMacroSyntax("<?UMBRACO_MACRO macroAlias='Map Test [Hello\\World]' test=\"asdf\" test2='hello' />");
|
||||
|
||||
@@ -84,9 +84,8 @@
|
||||
<ConfigurationOverrideFile>
|
||||
</ConfigurationOverrideFile>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DocumentationFile>bin\Umbraco.Web.UI.XML</DocumentationFile>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<FileAlignment>4096</FileAlignment>
|
||||
<NoStdLib>false</NoStdLib>
|
||||
<NoWarn>
|
||||
@@ -96,7 +95,7 @@
|
||||
<RemoveIntegerChecks>false</RemoveIntegerChecks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
@@ -127,9 +126,9 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.62.2941, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Examine.0.1.62.2941\lib\Examine.dll</HintPath>
|
||||
<Reference Include="Examine">
|
||||
<HintPath>..\packages\Examine.0.1.63.0\lib\Examine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -152,12 +151,6 @@
|
||||
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Threading.Tasks">
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Threading.Tasks.Extensions">
|
||||
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
@@ -172,7 +165,7 @@
|
||||
</Reference>
|
||||
<Reference Include="MySql.Data">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll</HintPath>
|
||||
<HintPath>..\packages\MySql.Data.6.9.6\lib\net45\MySql.Data.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -2070,6 +2063,7 @@
|
||||
<Content Include="Umbraco\PartialViewMacros\Templates\Navigation.cshtml" />
|
||||
<Content Include="Umbraco\PartialViewMacros\Templates\SiteMap.cshtml" />
|
||||
<Content Include="Umbraco\Views\AuthorizeUpgrade.cshtml" />
|
||||
<Content Include="Umbraco\Translation\translationTasks.dtd" />
|
||||
<None Include="Umbraco_client\CodeMirror\js\mode\coffeescript\LICENSE" />
|
||||
<None Include="Umbraco_client\CodeMirror\js\mode\pascal\LICENSE" />
|
||||
<None Include="Umbraco_client\CodeMirror\js\mode\perl\LICENSE" />
|
||||
@@ -2546,9 +2540,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7250</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7260</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7250</IISUrl>
|
||||
<IISUrl>http://localhost:7260</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
|
||||
<errors>
|
||||
<error404>1</error404>
|
||||
<!--
|
||||
The value for error pages can be:
|
||||
* A content item's integer ID (example: 1234)
|
||||
* A content item's GUID ID (example: 26C1D84F-C900-4D53-B167-E25CC489DAC8)
|
||||
* An XPath statement (example: //errorPages[@nodeName='My cool error']
|
||||
-->
|
||||
<!--
|
||||
<error404>
|
||||
<errorPage culture="default">1</errorPage>
|
||||
|
||||
@@ -118,33 +118,10 @@
|
||||
<useDomainPrefixes>false</useDomainPrefixes>
|
||||
<!-- this will add a trailing slash (/) to urls when in directory url mode -->
|
||||
<addTrailingSlash>true</addTrailingSlash>
|
||||
<urlReplacing removeDoubleDashes="true">
|
||||
<urlReplacing removeDoubleDashes="true" toAscii="true">
|
||||
<char org=" ">-</char>
|
||||
<char org="""></char>
|
||||
<char org="'"></char>
|
||||
<char org="%"></char>
|
||||
<char org="."></char>
|
||||
<char org=";"></char>
|
||||
<char org="/"></char>
|
||||
<char org="\"></char>
|
||||
<char org=":"></char>
|
||||
<char org="#"></char>
|
||||
<char org="+">plus</char>
|
||||
<char org="*">star</char>
|
||||
<char org="&"></char>
|
||||
<char org="?"></char>
|
||||
<char org="æ">ae</char>
|
||||
<char org="ø">oe</char>
|
||||
<char org="å">aa</char>
|
||||
<char org="ä">ae</char>
|
||||
<char org="ö">oe</char>
|
||||
<char org="ü">ue</char>
|
||||
<char org="ß">ss</char>
|
||||
<char org="Ä">ae</char>
|
||||
<char org="Ö">oe</char>
|
||||
<char org="|">-</char>
|
||||
<char org="<"></char>
|
||||
<char org=">"></char>
|
||||
<char org="ö">oxxx</char>
|
||||
<!--<char org="ü">ue</char>-->
|
||||
</urlReplacing>
|
||||
</requestHandler>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user