Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 420746397d | |||
| 142a9963af | |||
| 1dd103caa3 | |||
| 43bfd6e472 | |||
| b07665f4d4 | |||
| 0ebd66d926 | |||
| 8d45898274 | |||
| a99a33477a | |||
| b42d3b226d | |||
| b6925f9f07 | |||
| ffbb1a85ab | |||
| ac9c938e92 | |||
| 762656e964 | |||
| 46a4f9242c | |||
| 8cae2526d5 | |||
| 6b313aba48 | |||
| 7b4c58538d | |||
| e41c99d5bc | |||
| a49dd36461 | |||
| 82a1e85431 | |||
| 1c7d83f589 | |||
| 157428dbc8 | |||
| 0bcaa0da7f | |||
| 922942197f | |||
| b8975de04d | |||
| f00950bfe4 | |||
| 80d012f3ad | |||
| 654efd1128 | |||
| aa2375b8ba | |||
| f6532d2743 | |||
| 8c334a8c95 | |||
| 42cd71ef6c | |||
| 5956394bf1 | |||
| d1e9fb6d9f | |||
| 48dcc373dc | |||
| c9961b5192 | |||
| 03d3503531 | |||
| 9acba1d6d7 | |||
| 659f47c038 | |||
| 78613823ae | |||
| cb7f26c998 | |||
| 16b5c86192 | |||
| c83ab00827 | |||
| 937e840104 | |||
| 8d49c730d5 | |||
| fadb503b97 | |||
| 289bed8fd2 | |||
| eec1048631 | |||
| 313d77eb91 | |||
| b048341da0 | |||
| 03cb54e931 | |||
| 150b67d10f | |||
| ac88da4188 | |||
| cca27e064a | |||
| 4e5019d5af | |||
| f1a312b14a | |||
| da0b935604 | |||
| b91a06ab98 | |||
| d61fb5d94d | |||
| 3b424274ee | |||
| b763c2ab2f |
+10
-1
@@ -1,5 +1,9 @@
|
||||
@ECHO OFF
|
||||
SET release=7.1.2
|
||||
IF NOT EXIST UmbracoVersion.txt (
|
||||
ECHO UmbracoVersion.txt missing!
|
||||
GOTO :showerror
|
||||
)
|
||||
SET /p release=<UmbracoVersion.txt
|
||||
SET comment=
|
||||
SET version=%release%
|
||||
|
||||
@@ -15,6 +19,11 @@ SET nuGetFolder=%CD%\..\src\packages\
|
||||
ECHO Removing the belle build folder to make sure everything is clean as a whistle
|
||||
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
|
||||
|
||||
ECHO Removing existing built files to make sure everything is clean as a whistle
|
||||
DEL /F /Q UmbracoCms.*.zip
|
||||
DEL /F /Q UmbracoCms.*.nupkg
|
||||
DEL /F /Q webpihash.txt
|
||||
|
||||
ECHO Performing MSBuild and producing Umbraco binaries zip files
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment%
|
||||
|
||||
|
||||
+1
-1
@@ -325,7 +325,7 @@
|
||||
Regex="CurrentComment { get { return "([a-zA-Z]+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)""/>
|
||||
|
||||
<XmlPoke XmlInputPath=".\NuSpecs\build\UmbracoCms.targets"
|
||||
<XmlPoke XmlInputPath=".\NuSpecs\build\UmbracoCms.props"
|
||||
Namespaces="<Namespace Prefix='x' Uri='http://schemas.microsoft.com/developer/msbuild/2003' />"
|
||||
Query="//x:UmbracoVersion"
|
||||
Value="$(NewVersion)" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@ECHO OFF
|
||||
SET release=%1
|
||||
ECHO Installing Npm NuGet Package
|
||||
|
||||
SET nuGetFolder=%CD%\..\src\packages\
|
||||
@@ -26,7 +27,7 @@ ECHO Do npm install and the grunt build of Belle
|
||||
call npm install
|
||||
call npm install -g grunt-cli
|
||||
call npm install -g bower
|
||||
call grunt build --buildversion=7.1.2
|
||||
call grunt build --buildversion=%release%
|
||||
|
||||
ECHO Reset path to what it was before
|
||||
path=%oldPath%
|
||||
|
||||
@@ -67,5 +67,6 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.XmlSerializers.dll" target="lib\umbraco.XmlSerializers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
|
||||
<file src="tools\install.core.ps1" target="tools\install.ps1" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -1,12 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<CopyAllFilesToSingleFolderForPackageDependsOn>
|
||||
AddUmbracoFilesToOutput;
|
||||
$(CopyAllFilesToSingleFolderForPackageDependsOn);
|
||||
</CopyAllFilesToSingleFolderForPackageDependsOn>
|
||||
|
||||
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
|
||||
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
|
||||
AddUmbracoFilesToOutput;
|
||||
$(CopyAllFilesToSingleFolderForPackageDependsOn);
|
||||
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<UmbracoVersion>7.1.2</UmbracoVersion>
|
||||
</PropertyGroup>
|
||||
<Target Name="CopyUmbracoFilesToWebRoot" BeforeTargets="AfterBuild">
|
||||
<PropertyGroup>
|
||||
<UmbracoFilesFolder>..\packages\UmbracoCms.$(UmbracoVersion)\UmbracoFiles\</UmbracoFilesFolder>
|
||||
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<UmbracoFiles Include="$(UmbracoFilesFolder)**\*" />
|
||||
@@ -33,6 +30,9 @@
|
||||
<CustomFilesToInclude Include=".\Config\Splashes\**\*">
|
||||
<Dir>Config\Splashes</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\data\**\*">
|
||||
<Dir>data</Dir>
|
||||
</CustomFilesToInclude>
|
||||
<CustomFilesToInclude Include=".\umbraco\**\*">
|
||||
<Dir>umbraco</Dir>
|
||||
</CustomFilesToInclude>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
|
||||
if ($project) {
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
$copyLogsPath = Join-Path $backupPath "CopyLogs"
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
|
||||
# Create backup folder and logs folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
New-Item -ItemType Directory -Force -Path $copyLogsPath
|
||||
|
||||
# After backing up, remove all dlls from bin folder in case dll files are included in the VS project
|
||||
# See: http://issues.umbraco.org/issue/U4-4930
|
||||
$umbracoBinFolder = Join-Path $projectDestinationPath "bin"
|
||||
if(Test-Path $umbracoBinFolder) {
|
||||
$umbracoBinBackupPath = Join-Path $backupPath "bin"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBinBackupPath
|
||||
|
||||
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
|
||||
Remove-Item $umbracoBinFolder\*.dll -Force -Confirm:$false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
7.1.3
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.1.2");
|
||||
private static readonly Version Version = new Version("7.1.3");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -9,6 +9,8 @@ using System.Linq;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
@@ -539,7 +541,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
return ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
}
|
||||
|
||||
|
||||
#region Tag methods
|
||||
|
||||
///// <summary>
|
||||
@@ -567,6 +569,21 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="tagGroup">The group/category to assign the tags, the default value is "default"</param>
|
||||
/// <returns></returns>
|
||||
public static void SetTags(this IContentBase content, string propertyTypeAlias, IEnumerable<string> tags, bool replaceTags, string tagGroup = "default")
|
||||
{
|
||||
content.SetTags(TagCacheStorageType.Csv, propertyTypeAlias, tags, replaceTags, tagGroup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets tags for the property - will add tags to the tags table and set the property value to be the comma delimited value of the tags.
|
||||
/// </summary>
|
||||
/// <param name="content">The content item to assign the tags to</param>
|
||||
/// <param name="storageType">The tag storage type in cache (default is csv)</param>
|
||||
/// <param name="propertyTypeAlias">The property alias to assign the tags to</param>
|
||||
/// <param name="tags">The tags to assign</param>
|
||||
/// <param name="replaceTags">True to replace the tags on the current property with the tags specified or false to merge them with the currently assigned ones</param>
|
||||
/// <param name="tagGroup">The group/category to assign the tags, the default value is "default"</param>
|
||||
/// <returns></returns>
|
||||
public static void SetTags(this IContentBase content, TagCacheStorageType storageType, string propertyTypeAlias, IEnumerable<string> tags, bool replaceTags, string tagGroup = "default")
|
||||
{
|
||||
var property = content.Properties[propertyTypeAlias];
|
||||
if (property == null)
|
||||
@@ -583,15 +600,39 @@ namespace Umbraco.Core.Models
|
||||
//ensure the property value is set to the same thing
|
||||
if (replaceTags)
|
||||
{
|
||||
property.Value = string.Join(",", trimmedTags);
|
||||
switch (storageType)
|
||||
{
|
||||
case TagCacheStorageType.Csv:
|
||||
property.Value = string.Join(",", trimmedTags);
|
||||
break;
|
||||
case TagCacheStorageType.Json:
|
||||
//json array
|
||||
property.Value = JsonConvert.SerializeObject(trimmedTags);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
var currTags = property.Value.ToString().Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
|
||||
switch (storageType)
|
||||
{
|
||||
case TagCacheStorageType.Csv:
|
||||
var currTags = property.Value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x => x.Trim());
|
||||
property.Value = string.Join(",", trimmedTags.Union(currTags));
|
||||
property.Value = string.Join(",", trimmedTags.Union(currTags));
|
||||
break;
|
||||
case TagCacheStorageType.Json:
|
||||
var currJson = JsonConvert.DeserializeObject<JArray>(property.Value.ToString());
|
||||
//need to append the new ones
|
||||
foreach (var tag in trimmedTags)
|
||||
{
|
||||
currJson.Add(tag);
|
||||
}
|
||||
//json array
|
||||
property.Value = JsonConvert.SerializeObject(currJson);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -664,7 +705,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
return ApplicationContext.Current.Services.PackagingService.Export(media, true, raiseEvents: false);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
@@ -687,10 +728,10 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
return ((PackagingService)(ApplicationContext.Current.Services.PackagingService)).Export(member);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -133,29 +133,6 @@ namespace Umbraco.Core.Models
|
||||
Key = Guid.NewGuid();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being updated
|
||||
/// </summary>
|
||||
/// <remarks>Modified Date is set and a new Version guid is set</remarks>
|
||||
internal override void UpdatingEntity()
|
||||
{
|
||||
base.UpdatingEntity();
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (ContentType)base.DeepClone();
|
||||
var propertyGroups = PropertyGroups.Select(x => (PropertyGroup)x.DeepClone()).ToList();
|
||||
clone.PropertyGroups = new PropertyGroupCollection(propertyGroups);
|
||||
//set the property types that are not part of a group
|
||||
clone.PropertyTypes = PropertyTypeCollection
|
||||
.Where(x => x.PropertyGroupId == null)
|
||||
.Select(x => (PropertyType)x.DeepClone()).ToList();
|
||||
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
|
||||
@@ -331,11 +331,6 @@ namespace Umbraco.Core.Models
|
||||
get { return _additionalData; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
public IDictionary<string, object> AdditionalData { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list of integer Ids for allowed ContentTypes
|
||||
/// </summary>
|
||||
@@ -356,7 +351,9 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// List of PropertyGroups available on this ContentType
|
||||
/// </summary>
|
||||
/// <remarks>A PropertyGroup corresponds to a Tab in the UI</remarks>
|
||||
/// <remarks>
|
||||
/// A PropertyGroup corresponds to a Tab in the UI
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public virtual PropertyGroupCollection PropertyGroups
|
||||
{
|
||||
@@ -372,7 +369,13 @@ namespace Umbraco.Core.Models
|
||||
/// List of PropertyTypes available on this ContentType.
|
||||
/// This list aggregates PropertyTypes across the PropertyGroups.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Marked as DoNotClone because the result of this property is not the natural result of the data, it is
|
||||
/// a union of data so when auto-cloning if the setter is used it will be setting the unnatural result of the
|
||||
/// data. We manually clone this instead.
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
[DoNotClone]
|
||||
public virtual IEnumerable<PropertyType> PropertyTypes
|
||||
{
|
||||
get
|
||||
@@ -388,6 +391,14 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the property type collection containing types that are non-groups - used for tests
|
||||
/// </summary>
|
||||
internal IEnumerable<PropertyType> NonGroupedPropertyTypes
|
||||
{
|
||||
get { return _propertyTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A boolean flag indicating if a property type has been removed from this instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
@@ -584,5 +595,19 @@ namespace Umbraco.Core.Models
|
||||
propertyType.ResetDirtyProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (ContentTypeBase)base.DeepClone();
|
||||
|
||||
//need to manually wire up the event handlers for the property type collections - we've ensured
|
||||
// its ignored from the auto-clone process because its return values are unions, not raw and
|
||||
// we end up with duplicates, see: http://issues.umbraco.org/issue/U4-4842
|
||||
|
||||
clone._propertyTypes = (PropertyTypeCollection)_propertyTypes.DeepClone();
|
||||
clone._propertyTypes.CollectionChanged += clone.PropertyTypesChanged;
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,29 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to attribute properties that have a setter and are a reference type
|
||||
/// that should be ignored for cloning when using the DeepCloneHelper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// This attribute must be used:
|
||||
/// * when the property is backed by a field but the result of the property is the un-natural data stored in the field
|
||||
///
|
||||
/// This attribute should not be used:
|
||||
/// * when the property is virtual
|
||||
/// * when the setter performs additional required logic other than just setting the underlying field
|
||||
///
|
||||
/// </remarks>
|
||||
internal class DoNotCloneAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static class DeepCloneHelper
|
||||
{
|
||||
/// <summary>
|
||||
@@ -25,8 +45,10 @@ namespace Umbraco.Core.Models
|
||||
|
||||
var refProperties = inputType.GetProperties()
|
||||
.Where(x =>
|
||||
//is not attributed with the ignore clone attribute
|
||||
x.GetCustomAttribute<DoNotCloneAttribute>() == null
|
||||
//reference type but not string
|
||||
x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
|
||||
&& x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
|
||||
//settable
|
||||
&& x.CanWrite
|
||||
//non-indexed
|
||||
|
||||
@@ -240,52 +240,6 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
DeepCloneHelper.DeepCloneRefProperties(this, clone);
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
|
||||
//Using data contract serializer - has issues
|
||||
|
||||
//var s = Serialize(this);
|
||||
//var d = Deserialize(s, this.GetType());
|
||||
//return d;
|
||||
|
||||
//Using binary serializer - has issues
|
||||
|
||||
//using (var memoryStream = new MemoryStream(10))
|
||||
//{
|
||||
//IFormatter formatter = new BinaryFormatter();
|
||||
//formatter.Serialize(memoryStream, this);
|
||||
//memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
//return formatter.Deserialize(memoryStream);
|
||||
//}
|
||||
}
|
||||
|
||||
// serialize/deserialize with data contracts:
|
||||
|
||||
//public static string Serialize(object obj)
|
||||
//{
|
||||
// using (var memoryStream = new MemoryStream())
|
||||
// using (var reader = new StreamReader(memoryStream))
|
||||
// {
|
||||
// var serializer = new DataContractSerializer(obj.GetType());
|
||||
// serializer.WriteObject(memoryStream, obj);
|
||||
// memoryStream.Position = 0;
|
||||
// return reader.ReadToEnd();
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static object Deserialize(string xml, Type toType)
|
||||
//{
|
||||
// using (Stream stream = new MemoryStream())
|
||||
// {
|
||||
// using (var writer = new StreamWriter(stream, Encoding.UTF8))
|
||||
// {
|
||||
// writer.Write(xml);
|
||||
// //byte[] data = Encoding.UTF8.GetBytes(xml);
|
||||
// //stream.Write(data, 0, data.Length);
|
||||
// stream.Position = 0;
|
||||
// var deserializer = new DataContractSerializer(toType);
|
||||
// return deserializer.ReadObject(stream);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Defines a Property for a Macro
|
||||
/// </summary>
|
||||
public interface IMacroProperty : IValueObject
|
||||
public interface IMacroProperty : IValueObject, IDeepCloneable, IRememberBeingDirty
|
||||
{
|
||||
[DataMember]
|
||||
int Id { get; set; }
|
||||
|
||||
@@ -138,12 +138,11 @@ namespace Umbraco.Core.Models
|
||||
|
||||
var alias = prop.Alias;
|
||||
|
||||
//remove from the removed/added props (since people could add/remove all they want in one request)
|
||||
_removedProperties.RemoveAll(s => s == alias);
|
||||
_addedProperties.RemoveAll(s => s == alias);
|
||||
|
||||
//add to the added props
|
||||
_addedProperties.Add(alias);
|
||||
if (_addedProperties.Contains(alias) == false)
|
||||
{
|
||||
//add to the added props
|
||||
_addedProperties.Add(alias);
|
||||
}
|
||||
}
|
||||
else if (e.Action == NotifyCollectionChangedAction.Remove)
|
||||
{
|
||||
@@ -153,12 +152,10 @@ namespace Umbraco.Core.Models
|
||||
|
||||
var alias = prop.Alias;
|
||||
|
||||
//remove from the removed/added props (since people could add/remove all they want in one request)
|
||||
_removedProperties.RemoveAll(s => s == alias);
|
||||
_addedProperties.RemoveAll(s => s == alias);
|
||||
|
||||
//add to the added props
|
||||
_removedProperties.Add(alias);
|
||||
if (_removedProperties.Contains(alias) == false)
|
||||
{
|
||||
_removedProperties.Add(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +401,8 @@ namespace Umbraco.Core.Models
|
||||
|
||||
clone._addedProperties = new List<string>();
|
||||
clone._removedProperties = new List<string>();
|
||||
clone._properties = new MacroPropertyCollection();
|
||||
clone._properties = (MacroPropertyCollection)Properties.DeepClone();
|
||||
//re-assign the event handler
|
||||
clone._properties.CollectionChanged += clone.PropertiesChanged;
|
||||
|
||||
clone.ResetDirtyProperties(false);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class MacroProperty : TracksChangesEntityBase, IMacroProperty, IRememberBeingDirty
|
||||
public class MacroProperty : TracksChangesEntityBase, IMacroProperty, IRememberBeingDirty, IDeepCloneable
|
||||
{
|
||||
public MacroProperty()
|
||||
{
|
||||
@@ -176,5 +176,37 @@ namespace Umbraco.Core.Models
|
||||
}, _editorAlias, PropertyTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
//Memberwise clone on MacroProperty will work since it doesn't have any deep elements
|
||||
// for any sub class this will work for standard properties as well that aren't complex object's themselves.
|
||||
var clone = (MacroProperty)MemberwiseClone();
|
||||
//Automatically deep clone ref properties that are IDeepCloneable
|
||||
DeepCloneHelper.DeepCloneRefProperties(this, clone);
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected bool Equals(MacroProperty other)
|
||||
{
|
||||
return string.Equals(_alias, other._alias) && _id == other._id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((MacroProperty) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((_alias != null ? _alias.GetHashCode() : 0)*397) ^ _id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,60 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// A macro's property collection
|
||||
/// </summary>
|
||||
public class MacroPropertyCollection : ObservableDictionary<string, IMacroProperty>
|
||||
public class MacroPropertyCollection : ObservableDictionary<string, IMacroProperty>, IDeepCloneable
|
||||
{
|
||||
public MacroPropertyCollection()
|
||||
: base(property => property.Alias)
|
||||
{
|
||||
}
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
var clone = new MacroPropertyCollection();
|
||||
foreach (var item in this)
|
||||
{
|
||||
clone.Add((IMacroProperty)item.DeepClone());
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to update an existing macro property
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="sortOrder"></param>
|
||||
/// <param name="editorAlias"></param>
|
||||
/// <param name="currentAlias">
|
||||
/// The existing property alias
|
||||
/// </param>
|
||||
/// <param name="newAlias"></param>
|
||||
public void UpdateProperty(string currentAlias, string name = null, int? sortOrder = null, string editorAlias = null, string newAlias = null)
|
||||
{
|
||||
var prop = this[currentAlias];
|
||||
if (prop == null)
|
||||
{
|
||||
throw new InvalidOperationException("No property exists with alias " + currentAlias);
|
||||
}
|
||||
|
||||
if (name.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
prop.Name = name;
|
||||
}
|
||||
if (sortOrder.HasValue)
|
||||
{
|
||||
prop.SortOrder = sortOrder.Value;
|
||||
}
|
||||
if (name.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
prop.EditorAlias = editorAlias;
|
||||
}
|
||||
|
||||
if (newAlias.IsNullOrWhiteSpace() == false && currentAlias != newAlias)
|
||||
{
|
||||
prop.Alias = newAlias;
|
||||
ChangeKey(currentAlias, newAlias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// Represents a stored pre-value field value
|
||||
/// </summary>
|
||||
public class PreValue
|
||||
public class PreValue : IDeepCloneable
|
||||
{
|
||||
public PreValue(int id, string value, int sortOrder)
|
||||
{
|
||||
@@ -37,5 +37,12 @@
|
||||
/// The sort order stored for the pre-value field value
|
||||
/// </summary>
|
||||
public int SortOrder { get; private set; }
|
||||
|
||||
public virtual object DeepClone()
|
||||
{
|
||||
//Memberwise clone on PreValue will work since it doesn't have any deep elements
|
||||
var clone = (PreValue)MemberwiseClone();
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Models
|
||||
/// Most legacy property editors won't support the dictionary format but new property editors should always use the dictionary format.
|
||||
/// In order to get overrideable pre-values working we need a dictionary since we'll have to reference a pre-value by a key.
|
||||
/// </remarks>
|
||||
public class PreValueCollection
|
||||
public class PreValueCollection : IDeepCloneable
|
||||
{
|
||||
private IDictionary<string, PreValue> _preValuesAsDictionary;
|
||||
private IEnumerable<PreValue> _preValuesAsArray;
|
||||
@@ -82,5 +82,21 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public object DeepClone()
|
||||
{
|
||||
var clone = (PreValueCollection) MemberwiseClone();
|
||||
if (_preValuesAsArray != null)
|
||||
{
|
||||
clone._preValuesAsArray = _preValuesAsArray.Select(x => (PreValue)x.DeepClone()).ToArray();
|
||||
}
|
||||
if (_preValuesAsDictionary != null)
|
||||
{
|
||||
clone._preValuesAsDictionary = _preValuesAsDictionary.ToDictionary(x => x.Key, x => (PreValue)x.Value.DeepClone());
|
||||
}
|
||||
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal enum PropertyTagBehavior
|
||||
{
|
||||
Replace,
|
||||
Remove,
|
||||
Merge
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,4 @@ namespace Umbraco.Core.Models
|
||||
public IEnumerable<Tuple<string, string>> Tags { get; set; }
|
||||
|
||||
}
|
||||
|
||||
internal enum PropertyTagBehavior
|
||||
{
|
||||
Replace,
|
||||
Remove,
|
||||
Merge
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public enum TagCacheStorageType
|
||||
{
|
||||
Csv,
|
||||
Json
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Initializes a new instance of the <see cref="LazyManyObjectsResolverBase{TResolver, TResolved}"/> class with an initial list
|
||||
/// <remarks>If <paramref name="scope"/> is per HttpRequest then there must be a current HttpContext.</remarks>
|
||||
/// <exception cref="InvalidOperationException"><paramref name="scope"/> is per HttpRequest but the current HttpContext is null.</exception>
|
||||
/// </summary>
|
||||
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> lazyTypeList, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
@@ -108,7 +109,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Gets a value indicating whether the resolver has resolved types to create instances from.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal bool HasResolvedTypes
|
||||
public bool HasResolvedTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -135,6 +135,28 @@ namespace Umbraco.Core
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows us to change the key of an item
|
||||
/// </summary>
|
||||
/// <param name="currentKey"></param>
|
||||
/// <param name="newKey"></param>
|
||||
public virtual void ChangeKey(TKey currentKey, TKey newKey)
|
||||
{
|
||||
if (!Indecies.ContainsKey(currentKey))
|
||||
{
|
||||
throw new InvalidOperationException("No item with the key " + currentKey + "was found in the collection");
|
||||
}
|
||||
if (ContainsKey(newKey))
|
||||
{
|
||||
throw new DuplicateKeyException(newKey.ToString());
|
||||
}
|
||||
|
||||
var currentIndex = Indecies[currentKey];
|
||||
|
||||
Indecies.Remove(currentKey);
|
||||
Indecies.Add(newKey, currentIndex);
|
||||
}
|
||||
|
||||
internal class DuplicateKeyException : Exception
|
||||
{
|
||||
|
||||
|
||||
@@ -128,9 +128,9 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
public void Save(Type type, IEntity entity)
|
||||
{
|
||||
//IMPORTANT: we must clone to store, see: http://issues.umbraco.org/issue/U4-4259
|
||||
entity = (IEntity)entity.DeepClone();
|
||||
var clone = (IEntity)entity.DeepClone();
|
||||
|
||||
var key = GetCompositeId(type, entity.Id);
|
||||
var key = GetCompositeId(type, clone.Id);
|
||||
|
||||
_keyTracker.TryAdd(key);
|
||||
|
||||
@@ -139,11 +139,11 @@ namespace Umbraco.Core.Persistence.Caching
|
||||
|
||||
if (_memoryCache != null)
|
||||
{
|
||||
_memoryCache.Set(key, entity, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) });
|
||||
_memoryCache.Set(key, clone, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMinutes(5) });
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpRuntime.Cache.Insert(key, entity, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(5));
|
||||
HttpRuntime.Cache.Insert(key, clone, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(5));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,8 +295,8 @@ AND umbracoNode.id <> @id",
|
||||
var cached = _cacheHelper.RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(GetPrefixedCacheKey(dataTypeId));
|
||||
if (cached != null && cached.Any())
|
||||
{
|
||||
//return from the cache
|
||||
return cached.First();
|
||||
//return from the cache, ensure it's a cloned result
|
||||
return (PreValueCollection)cached.First().DeepClone();
|
||||
}
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
|
||||
@@ -493,14 +493,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
// Is this the same UmbracoEntity as the current one we're processing
|
||||
if (Current != null && Current.Key == a.uniqueID)
|
||||
{
|
||||
// Add this UmbracoProperty to the current additional data
|
||||
Current.AdditionalData[p.PropertyAlias] = new UmbracoEntity.EntityProperty
|
||||
if (p != null && p.PropertyAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
PropertyEditorAlias = p.PropertyEditorAlias,
|
||||
Value = p.NTextValue.IsNullOrWhiteSpace()
|
||||
? p.NVarcharValue
|
||||
: p.NTextValue.ConvertToJsonIfPossible()
|
||||
};
|
||||
// Add this UmbracoProperty to the current additional data
|
||||
Current.AdditionalData[p.PropertyAlias] = new UmbracoEntity.EntityProperty
|
||||
{
|
||||
PropertyEditorAlias = p.PropertyEditorAlias,
|
||||
Value = p.NTextValue.IsNullOrWhiteSpace()
|
||||
? p.NVarcharValue
|
||||
: p.NTextValue.ConvertToJsonIfPossible()
|
||||
};
|
||||
}
|
||||
|
||||
// Return null to indicate we're not done with this UmbracoEntity yet
|
||||
return null;
|
||||
@@ -516,14 +519,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
Current = _factory.BuildEntityFromDynamic(a);
|
||||
|
||||
//add the property/create the prop list if null
|
||||
Current.AdditionalData[p.PropertyAlias] = new UmbracoEntity.EntityProperty
|
||||
if (p != null && p.PropertyAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
PropertyEditorAlias = p.PropertyEditorAlias,
|
||||
Value = p.NTextValue.IsNullOrWhiteSpace()
|
||||
? p.NVarcharValue
|
||||
: p.NTextValue.ConvertToJsonIfPossible()
|
||||
};
|
||||
//add the property/create the prop list if null
|
||||
Current.AdditionalData[p.PropertyAlias] = new UmbracoEntity.EntityProperty
|
||||
{
|
||||
PropertyEditorAlias = p.PropertyEditorAlias,
|
||||
Value = p.NTextValue.IsNullOrWhiteSpace()
|
||||
? p.NVarcharValue
|
||||
: p.NTextValue.ConvertToJsonIfPossible()
|
||||
};
|
||||
}
|
||||
|
||||
// Return the now populated previous UmbracoEntity (or null if first time through)
|
||||
return prev;
|
||||
|
||||
@@ -165,10 +165,18 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
Database.Update(dto);
|
||||
|
||||
//update the sections if they've changed
|
||||
//update the properties if they've changed
|
||||
var macro = (Macro)entity;
|
||||
if (macro.IsPropertyDirty("Properties"))
|
||||
if (macro.IsPropertyDirty("Properties") || macro.Properties.Any(x => x.IsDirty()))
|
||||
{
|
||||
//now we need to delete any props that have been removed
|
||||
foreach (var propAlias in macro.RemovedProperties)
|
||||
{
|
||||
//delete the property
|
||||
Database.Delete<MacroPropertyDto>("WHERE macro=@macroId AND macroPropertyAlias=@propAlias",
|
||||
new { macroId = macro.Id, propAlias = propAlias });
|
||||
}
|
||||
|
||||
//for any that exist on the object, we need to determine if we need to update or insert
|
||||
foreach (var propDto in dto.MacroPropertyDtos)
|
||||
{
|
||||
@@ -180,17 +188,15 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.Update(propDto);
|
||||
//only update if it's dirty
|
||||
if (macro.Properties[propDto.Alias].IsDirty())
|
||||
{
|
||||
Database.Update(propDto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//now we need to delete any props that have been removed
|
||||
foreach (var propAlias in macro.RemovedProperties)
|
||||
{
|
||||
//delete the property
|
||||
Database.Delete<MacroPropertyDto>("WHERE macro=@macroId AND macroPropertyAlias=@propAlias",
|
||||
new { macroId = macro.Id, propAlias = propAlias });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
((ICanBeDirty)entity).ResetDirtyProperties();
|
||||
|
||||
@@ -285,7 +285,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (group.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
sql = sql.Where<TagDto>(dto => dto.Group == group);
|
||||
}
|
||||
}
|
||||
|
||||
var factory = new TagFactory();
|
||||
|
||||
@@ -329,7 +329,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//NOTE: There's some very clever logic in the umbraco.cms.businesslogic.Tags.Tag to insert tags where they don't exist,
|
||||
// and assign where they don't exist which we've borrowed here. The queries are pretty zany but work, otherwise we'll end up
|
||||
// with quite a few additional queries.
|
||||
|
||||
|
||||
//do all this in one transaction
|
||||
using (var trans = Database.GetTransaction())
|
||||
{
|
||||
@@ -397,7 +397,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public void RemoveTagsFromProperty(int contentId, int propertyTypeId, IEnumerable<ITag> tags)
|
||||
{
|
||||
var tagSetSql = GetTagSet(tags);
|
||||
|
||||
|
||||
var deleteSql = string.Concat("DELETE FROM cmsTagRelationship WHERE nodeId = ",
|
||||
contentId,
|
||||
" AND propertyTypeId = ",
|
||||
@@ -439,7 +439,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <returns></returns>
|
||||
private static string GetTagSet(IEnumerable<ITag> tagsToInsert)
|
||||
{
|
||||
var array = tagsToInsert.Select(tag => string.Format("select '{0}' as Tag, '{1}' as [Group]", tag.Text.Replace("'", "''"), tag.Group)).ToArray();
|
||||
var array = tagsToInsert
|
||||
.Select(tag =>
|
||||
string.Format("select '{0}' as Tag, '{1}' as [Group]",
|
||||
PetaPocoExtensions.EscapeAtSymbols(tag.Text.Replace("'", "''")), tag.Group))
|
||||
.ToArray();
|
||||
return "(" + string.Join(" union ", array).Replace(" ", " ") + ") as TagSet";
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
"DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
|
||||
"UPDATE cmsDocument SET templateId = NULL WHERE nodeId = @Id",
|
||||
"UPDATE cmsDocument SET templateId = NULL WHERE templateId = @Id",
|
||||
"DELETE FROM cmsDocumentType WHERE templateNodeId = @Id",
|
||||
"DELETE FROM cmsTemplate WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoNode WHERE id = @Id"
|
||||
|
||||
@@ -44,9 +44,9 @@ namespace Umbraco.Core
|
||||
/// file is cached temporarily until app startup completes.
|
||||
/// </summary>
|
||||
/// <param name="appContext"></param>
|
||||
/// <param name="detectBinChanges"></param>
|
||||
internal PluginManager(ApplicationContext appContext, bool detectBinChanges = true)
|
||||
: this(detectBinChanges)
|
||||
/// <param name="detectChanges"></param>
|
||||
internal PluginManager(ApplicationContext appContext, bool detectChanges = true)
|
||||
: this(detectChanges)
|
||||
{
|
||||
if (appContext == null) throw new ArgumentNullException("appContext");
|
||||
_appContext = appContext;
|
||||
@@ -55,11 +55,11 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Creates a new PluginManager
|
||||
/// </summary>
|
||||
/// <param name="detectCodeChanges">
|
||||
/// If true will detect changes in the /bin folder and therefor load plugins from the
|
||||
/// <param name="detectChanges">
|
||||
/// If true will detect changes in the /bin folder, app_code, etc... and therefor load plugins from the
|
||||
/// cached plugins file if one is found. If false will never use the cache file for plugins
|
||||
/// </param>
|
||||
internal PluginManager(bool detectCodeChanges = true)
|
||||
internal PluginManager(bool detectChanges = true)
|
||||
{
|
||||
_tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache");
|
||||
//create the folder if it doesn't exist
|
||||
@@ -68,29 +68,41 @@ namespace Umbraco.Core
|
||||
Directory.CreateDirectory(_tempFolder);
|
||||
}
|
||||
|
||||
var pluginListFile = GetPluginListFilePath();
|
||||
|
||||
//this is a check for legacy changes, before we didn't store the TypeResolutionKind in the file which was a mistake,
|
||||
//so we need to detect if the old file is there without this attribute, if it is then we delete it
|
||||
if (DetectLegacyPluginListFile())
|
||||
{
|
||||
var filePath = GetPluginListFilePath();
|
||||
File.Delete(filePath);
|
||||
File.Delete(pluginListFile);
|
||||
}
|
||||
|
||||
if (detectCodeChanges)
|
||||
if (detectChanges)
|
||||
{
|
||||
//first check if the cached hash is 0, if it is then we ne
|
||||
//do the check if they've changed
|
||||
HaveAssembliesChanged = (CachedAssembliesHash != CurrentAssembliesHash) || CachedAssembliesHash == 0;
|
||||
RequiresRescanning = (CachedAssembliesHash != CurrentAssembliesHash) || CachedAssembliesHash == 0;
|
||||
//if they have changed, we need to write the new file
|
||||
if (HaveAssembliesChanged)
|
||||
if (RequiresRescanning)
|
||||
{
|
||||
//if the hash has changed, clear out the persisted list no matter what, this will force
|
||||
// rescanning of all plugin types including lazy ones.
|
||||
// http://issues.umbraco.org/issue/U4-4789
|
||||
File.Delete(pluginListFile);
|
||||
|
||||
WriteCachePluginsHash();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//if the hash has changed, clear out the persisted list no matter what, this will force
|
||||
// rescanning of all plugin types including lazy ones.
|
||||
// http://issues.umbraco.org/issue/U4-4789
|
||||
File.Delete(pluginListFile);
|
||||
|
||||
//always set to true if we're not detecting (generally only for testing)
|
||||
HaveAssembliesChanged = true;
|
||||
RequiresRescanning = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -130,9 +142,9 @@ namespace Umbraco.Core
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a bool if the assemblies in the /bin have changed since they were last hashed.
|
||||
/// Returns a bool if the assemblies in the /bin, app_code, global.asax, etc... have changed since they were last hashed.
|
||||
/// </summary>
|
||||
internal bool HaveAssembliesChanged { get; private set; }
|
||||
internal bool RequiresRescanning { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the currently cached hash value of the scanned assemblies in the /bin folder. Returns 0
|
||||
@@ -328,7 +340,7 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// Generally only used for resetting cache, for example during the install process
|
||||
/// </remarks>
|
||||
internal void ClearPluginCache()
|
||||
public void ClearPluginCache()
|
||||
{
|
||||
var path = GetPluginListFilePath();
|
||||
if (File.Exists(path))
|
||||
@@ -670,7 +682,7 @@ namespace Umbraco.Core
|
||||
|
||||
//we first need to look into our cache file (this has nothing to do with the 'cacheResult' parameter which caches in memory).
|
||||
//if assemblies have not changed and the cache file actually exists, then proceed to try to lookup by the cache file.
|
||||
if (HaveAssembliesChanged == false && File.Exists(GetPluginListFilePath()))
|
||||
if (RequiresRescanning == false && File.Exists(GetPluginListFilePath()))
|
||||
{
|
||||
var fileCacheResult = TryGetCachedPluginsFromFile<T>(resolutionType);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
@@ -30,6 +31,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
Delimiter = ",";
|
||||
ReplaceTags = true;
|
||||
TagGroup = "default";
|
||||
StorageType = TagCacheStorageType.Csv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,6 +39,11 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </summary>
|
||||
public TagValueType ValueType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines how to store the tags in cache (CSV or Json)
|
||||
/// </summary>
|
||||
public TagCacheStorageType StorageType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines a custom delimiter, the default is a comma
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
@@ -30,8 +31,14 @@ namespace Umbraco.Core.PropertyEditors
|
||||
Delimiter = tagsAttribute.Delimiter;
|
||||
ReplaceTags = tagsAttribute.ReplaceTags;
|
||||
TagGroup = tagsAttribute.TagGroup;
|
||||
StorageType = TagCacheStorageType.Csv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines how to store the tags in cache (CSV or Json)
|
||||
/// </summary>
|
||||
public virtual TagCacheStorageType StorageType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines a custom delimiter, the default is a comma
|
||||
/// </summary>
|
||||
|
||||
@@ -86,6 +86,7 @@ namespace Umbraco.Core.Security
|
||||
public static UmbracoBackOfficeIdentity GetCurrentIdentity(this HttpContextBase http, bool authenticateRequestIfNotFound)
|
||||
{
|
||||
if (http == null) throw new ArgumentNullException("http");
|
||||
if (http.User == null) return null; //there's no user at all so no identity
|
||||
var identity = http.User.Identity as UmbracoBackOfficeIdentity;
|
||||
if (identity != null) return identity;
|
||||
if (authenticateRequestIfNotFound == false) return null;
|
||||
|
||||
@@ -124,7 +124,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var collection = repository.GetPreValuesCollectionByDataTypeId(id);
|
||||
//now convert the collection to a string list
|
||||
var list = collection.FormatAsDictionary().Select(x => x.Value.Value).ToList();
|
||||
var list = collection.FormatAsDictionary()
|
||||
.Select(x => x.Value.Value)
|
||||
.ToList();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@ namespace Umbraco.Core
|
||||
//this is from SqlMetal and just makes it a bit of fun to allow pluralisation
|
||||
public static string MakePluralName(this string name)
|
||||
{
|
||||
if ((name.EndsWith("x", StringComparison.OrdinalIgnoreCase) || name.EndsWith("ch", StringComparison.OrdinalIgnoreCase)) || (name.EndsWith("ss", StringComparison.OrdinalIgnoreCase) || name.EndsWith("sh", StringComparison.OrdinalIgnoreCase)))
|
||||
if ((name.EndsWith("x", StringComparison.OrdinalIgnoreCase) || name.EndsWith("ch", StringComparison.OrdinalIgnoreCase)) || (name.EndsWith("s", StringComparison.OrdinalIgnoreCase) || name.EndsWith("sh", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
name = name + "es";
|
||||
return name;
|
||||
|
||||
@@ -349,12 +349,14 @@
|
||||
<Compile Include="Models\MemberGroup.cs" />
|
||||
<Compile Include="Models\MemberTypePropertyProfileAccess.cs" />
|
||||
<Compile Include="Models\Notification.cs" />
|
||||
<Compile Include="Models\PropertyTagBehavior.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedContentExtended.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedPropertyBase.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModelFactoryImpl.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedContentModelFactory.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModel.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModelFactoryResolver.cs" />
|
||||
<Compile Include="Models\TagCacheStorageType.cs" />
|
||||
<Compile Include="Models\TaggableObjectTypes.cs" />
|
||||
<Compile Include="Models\TemplateNode.cs" />
|
||||
<Compile Include="Models\UmbracoEntityExtensions.cs" />
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Umbraco.Tests.Models
|
||||
[TestFixture]
|
||||
public class ContentTypeTests : BaseUmbracoConfigurationTest
|
||||
{
|
||||
|
||||
|
||||
[Test]
|
||||
public void Can_Deep_Clone_Content_Type_Sort()
|
||||
{
|
||||
@@ -150,6 +152,7 @@ namespace Umbraco.Tests.Models
|
||||
}
|
||||
Assert.AreNotSame(clone.PropertyTypes, contentType.PropertyTypes);
|
||||
Assert.AreEqual(clone.PropertyTypes.Count(), contentType.PropertyTypes.Count());
|
||||
Assert.AreEqual(0, ((ContentTypeBase)clone).NonGroupedPropertyTypes.Count());
|
||||
for (var index = 0; index < contentType.PropertyTypes.Count(); index++)
|
||||
{
|
||||
Assert.AreNotSame(clone.PropertyTypes.ElementAt(index), contentType.PropertyTypes.ElementAt(index));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -19,6 +20,7 @@ namespace Umbraco.Tests.Models
|
||||
public void Can_Deep_Clone()
|
||||
{
|
||||
var macro = new Macro(1, true, 3, "test", "Test", "blah", "blah", "xslt", false, true, true, "script");
|
||||
macro.Properties.Add(new MacroProperty(6, "rewq", "REWQ", 1, "asdfasdf"));
|
||||
|
||||
var clone = (Macro)macro.DeepClone();
|
||||
|
||||
@@ -26,6 +28,14 @@ namespace Umbraco.Tests.Models
|
||||
Assert.AreEqual(clone, macro);
|
||||
Assert.AreEqual(clone.Id, macro.Id);
|
||||
|
||||
Assert.AreEqual(clone.Properties.Count, macro.Properties.Count);
|
||||
|
||||
for (int i = 0; i < clone.Properties.Count; i++)
|
||||
{
|
||||
Assert.AreEqual(clone.Properties[i], macro.Properties[i]);
|
||||
Assert.AreNotSame(clone.Properties[i], macro.Properties[i]);
|
||||
}
|
||||
|
||||
Assert.AreNotSame(clone.Properties, macro.Properties);
|
||||
Assert.AreNotSame(clone.AddedProperties, macro.AddedProperties);
|
||||
Assert.AreNotSame(clone.RemovedProperties, macro.RemovedProperties);
|
||||
@@ -44,6 +54,9 @@ namespace Umbraco.Tests.Models
|
||||
Assert.IsFalse(asDirty.IsPropertyDirty("Properties"));
|
||||
clone.Properties.Add(new MacroProperty(3, "asdf", "SDF", 3, "asdfasdf"));
|
||||
Assert.IsTrue(asDirty.IsPropertyDirty("Properties"));
|
||||
Assert.AreEqual(1, clone.AddedProperties.Count());
|
||||
clone.Properties.Remove("rewq");
|
||||
Assert.AreEqual(1, clone.RemovedProperties.Count());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Tests.Models
|
||||
{
|
||||
[TestFixture]
|
||||
public class PreValueCollectionTests
|
||||
{
|
||||
[Test]
|
||||
public void Can_Deep_Clone()
|
||||
{
|
||||
var d = new PreValueCollection(new Dictionary<string, PreValue>
|
||||
{
|
||||
{"blah1", new PreValue(1, "test1", 1)},
|
||||
{"blah2", new PreValue(2, "test1", 3)},
|
||||
{"blah3", new PreValue(3, "test1", 2)}
|
||||
});
|
||||
|
||||
var a = new PreValueCollection(new[]
|
||||
{
|
||||
new PreValue(1, "test1", 1),
|
||||
new PreValue(2, "test1", 3),
|
||||
new PreValue(3, "test1", 2)
|
||||
});
|
||||
|
||||
var clone1 = (PreValueCollection)d.DeepClone();
|
||||
var clone2 = (PreValueCollection)a.DeepClone();
|
||||
|
||||
Action<PreValueCollection, PreValueCollection> assert = (orig, clone) =>
|
||||
{
|
||||
Assert.AreNotSame(orig, clone);
|
||||
var oDic = orig.FormatAsDictionary();
|
||||
var cDic = clone.FormatAsDictionary();
|
||||
Assert.AreEqual(oDic.Keys.Count(), cDic.Keys.Count());
|
||||
foreach (var k in oDic.Keys)
|
||||
{
|
||||
Assert.AreNotSame(oDic[k], cDic[k]);
|
||||
Assert.AreEqual(oDic[k].Id, cDic[k].Id);
|
||||
Assert.AreEqual(oDic[k].SortOrder, cDic[k].SortOrder);
|
||||
Assert.AreEqual(oDic[k].Value, cDic[k].Value);
|
||||
}
|
||||
};
|
||||
|
||||
assert(d, clone1);
|
||||
assert(a, clone2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@ using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Serialization;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.Models
|
||||
{
|
||||
[TestFixture]
|
||||
public class PropertyGroupTests
|
||||
public class PropertyGroupTests : BaseUmbracoConfigurationTest
|
||||
{
|
||||
[Test]
|
||||
public void Can_Deep_Clone()
|
||||
@@ -37,7 +38,7 @@ namespace Umbraco.Tests.Models
|
||||
Alias = "test2",
|
||||
CreateDate = DateTime.Now,
|
||||
DataTypeDefinitionId = 6,
|
||||
DataTypeId = Guid.NewGuid(),
|
||||
PropertyEditorAlias = "propTest",
|
||||
Description = "testing2",
|
||||
Key = Guid.NewGuid(),
|
||||
Mandatory = true,
|
||||
@@ -118,7 +119,7 @@ namespace Umbraco.Tests.Models
|
||||
Alias = "test2",
|
||||
CreateDate = DateTime.Now,
|
||||
DataTypeDefinitionId = 6,
|
||||
DataTypeId = Guid.NewGuid(),
|
||||
PropertyEditorAlias = "propTest",
|
||||
Description = "testing2",
|
||||
Key = Guid.NewGuid(),
|
||||
Mandatory = true,
|
||||
|
||||
@@ -364,7 +364,58 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Update_Property_For_Macro()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = new MacroRepository(unitOfWork, NullCacheProvider.Current))
|
||||
{
|
||||
var macro = repository.Get(1);
|
||||
macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test"));
|
||||
repository.AddOrUpdate(macro);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//Act
|
||||
macro = repository.Get(1);
|
||||
macro.Properties["new1"].Name = "this is a new name";
|
||||
repository.AddOrUpdate(macro);
|
||||
unitOfWork.Commit();
|
||||
|
||||
|
||||
// Assert
|
||||
var result = repository.Get(1);
|
||||
Assert.AreEqual("new1", result.Properties.First().Alias);
|
||||
Assert.AreEqual("this is a new name", result.Properties.First().Name);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Update_Macro_Property_Alias()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
using (var repository = new MacroRepository(unitOfWork, NullCacheProvider.Current))
|
||||
{
|
||||
var macro = repository.Get(1);
|
||||
macro.Properties.Add(new MacroProperty("new1", "New1", 3, "test"));
|
||||
repository.AddOrUpdate(macro);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//Act
|
||||
macro = repository.Get(1);
|
||||
macro.Properties.UpdateProperty("new1", newAlias: "newAlias");
|
||||
repository.AddOrUpdate(macro);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Assert
|
||||
var result = repository.Get(1);
|
||||
Assert.AreEqual("newAlias", result.Properties.First().Alias);
|
||||
}
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public override void TearDown()
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
@@ -10,6 +11,7 @@ using Umbraco.Core.Persistence.Caching;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
@@ -37,10 +39,13 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
|
||||
// Act
|
||||
var repository = RepositoryResolver.Current.ResolveByType<ITemplateRepository>(unitOfWork);
|
||||
using (var repository = RepositoryResolver.Current.ResolveByType<ITemplateRepository>(unitOfWork))
|
||||
{
|
||||
|
||||
// Assert
|
||||
Assert.That(repository, Is.Not.Null);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.That(repository, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -51,10 +56,13 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
|
||||
// Act
|
||||
var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem);
|
||||
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
|
||||
{
|
||||
|
||||
// Assert
|
||||
Assert.That(repository, Is.Not.Null);
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.That(repository, Is.Not.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -63,16 +71,18 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem);
|
||||
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
|
||||
{
|
||||
// Act
|
||||
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
|
||||
//Assert
|
||||
Assert.That(repository.Get("test"), Is.Not.Null);
|
||||
Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.True);
|
||||
//Assert
|
||||
Assert.That(repository.Get("test"), Is.Not.Null);
|
||||
Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.True);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -81,22 +91,25 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem);
|
||||
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
|
||||
{
|
||||
// Act
|
||||
var template = new Template("test-updated-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var template = new Template("test-updated-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
template.Content = @"<%@ Master Language=""VB"" %>";
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
|
||||
template.Content = @"<%@ Master Language=""VB"" %>";
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
var updated = repository.Get("test");
|
||||
|
||||
var updated = repository.Get("test");
|
||||
// Assert
|
||||
Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.True);
|
||||
Assert.That(updated.Content, Is.EqualTo(@"<%@ Master Language=""VB"" %>"));
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.That(_masterPageFileSystem.FileExists("test.master"), Is.True);
|
||||
Assert.That(updated.Content, Is.EqualTo(@"<%@ Master Language=""VB"" %>"));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -105,19 +118,64 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem);
|
||||
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
|
||||
{
|
||||
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
// Act
|
||||
var templates = repository.Get("test");
|
||||
repository.Delete(templates);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var templates = repository.Get("test");
|
||||
repository.Delete(templates);
|
||||
unitOfWork.Commit();
|
||||
// Assert
|
||||
Assert.IsNull(repository.Get("test"));
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.IsNull(repository.Get("test"));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Delete_When_Assigned_To_Doc()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
|
||||
var templateRepository = new TemplateRepository(unitOfWork, NullCacheProvider.Current);
|
||||
var tagRepository = new TagsRepository(unitOfWork, NullCacheProvider.Current);
|
||||
var contentTypeRepository = new ContentTypeRepository(unitOfWork, NullCacheProvider.Current, templateRepository);
|
||||
var contentRepo = new ContentRepository(unitOfWork, NullCacheProvider.Current, contentTypeRepository, templateRepository, tagRepository, CacheHelper.CreateDisabledCacheHelper());
|
||||
|
||||
using (contentRepo)
|
||||
{
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage2", "Textpage");
|
||||
var textpage = MockedContent.CreateSimpleContent(contentType);
|
||||
contentTypeRepository.AddOrUpdate(contentType);
|
||||
contentRepo.AddOrUpdate(textpage);
|
||||
unitOfWork.Commit();
|
||||
|
||||
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
|
||||
{
|
||||
var template = new Template("test-add-masterpage.master", "test", "test") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
repository.AddOrUpdate(template);
|
||||
unitOfWork.Commit();
|
||||
|
||||
textpage.Template = template;
|
||||
contentRepo.AddOrUpdate(textpage);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var templates = repository.Get("test");
|
||||
repository.Delete(templates);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Assert
|
||||
Assert.IsNull(repository.Get("test"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -126,27 +184,30 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem);
|
||||
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
|
||||
{
|
||||
var parent = new Template("test-parent-masterpage.master", "parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var child = new Template("test-child-masterpage.master", "child", "child") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var baby = new Template("test-baby-masterpage.master", "baby", "baby") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
child.MasterTemplateAlias = parent.Alias;
|
||||
child.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
baby.MasterTemplateAlias = child.Alias;
|
||||
baby.MasterTemplateId = new Lazy<int>(() => child.Id);
|
||||
repository.AddOrUpdate(parent);
|
||||
repository.AddOrUpdate(child);
|
||||
repository.AddOrUpdate(baby);
|
||||
unitOfWork.Commit();
|
||||
|
||||
var parent = new Template("test-parent-masterpage.master", "parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var child = new Template("test-child-masterpage.master", "child", "child") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var baby = new Template("test-baby-masterpage.master", "baby", "baby") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
child.MasterTemplateAlias = parent.Alias;
|
||||
child.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
baby.MasterTemplateAlias = child.Alias;
|
||||
baby.MasterTemplateId = new Lazy<int>(() => child.Id);
|
||||
repository.AddOrUpdate(parent);
|
||||
repository.AddOrUpdate(child);
|
||||
repository.AddOrUpdate(baby);
|
||||
unitOfWork.Commit();
|
||||
// Act
|
||||
var templates = repository.Get("parent");
|
||||
repository.Delete(templates);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var templates = repository.Get("parent");
|
||||
repository.Delete(templates);
|
||||
unitOfWork.Commit();
|
||||
// Assert
|
||||
Assert.IsNull(repository.Get("test"));
|
||||
}
|
||||
|
||||
// Assert
|
||||
Assert.IsNull(repository.Get("test"));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -155,66 +216,69 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider();
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem);
|
||||
using (var repository = new TemplateRepository(unitOfWork, NullCacheProvider.Current, _masterPageFileSystem, _viewsFileSystem))
|
||||
{
|
||||
var parent = new Template("test-parent-masterpage.master", "parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
|
||||
var child1 = new Template("test-child1-masterpage.master", "child1", "child1") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler1 = new Template("test-toddler1-masterpage.master", "toddler1", "toddler1") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler2 = new Template("test-toddler2-masterpage.master", "toddler2", "toddler2") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var baby1 = new Template("test-baby1-masterpage.master", "baby1", "baby1") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
|
||||
var child2 = new Template("test-child2-masterpage.master", "child2", "child2") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler3 = new Template("test-toddler3-masterpage.master", "toddler3", "toddler3") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler4 = new Template("test-toddler4-masterpage.master", "toddler4", "toddler4") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var baby2 = new Template("test-baby2-masterpage.master", "baby2", "baby2") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
|
||||
|
||||
child1.MasterTemplateAlias = parent.Alias;
|
||||
child1.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
child2.MasterTemplateAlias = parent.Alias;
|
||||
child2.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
|
||||
toddler1.MasterTemplateAlias = child1.Alias;
|
||||
toddler1.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
toddler2.MasterTemplateAlias = child1.Alias;
|
||||
toddler2.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
|
||||
toddler3.MasterTemplateAlias = child2.Alias;
|
||||
toddler3.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
toddler4.MasterTemplateAlias = child2.Alias;
|
||||
toddler4.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
|
||||
baby1.MasterTemplateAlias = toddler2.Alias;
|
||||
baby1.MasterTemplateId = new Lazy<int>(() => toddler2.Id);
|
||||
|
||||
baby2.MasterTemplateAlias = toddler4.Alias;
|
||||
baby2.MasterTemplateId = new Lazy<int>(() => toddler4.Id);
|
||||
|
||||
repository.AddOrUpdate(parent);
|
||||
repository.AddOrUpdate(child1);
|
||||
repository.AddOrUpdate(child2);
|
||||
repository.AddOrUpdate(toddler1);
|
||||
repository.AddOrUpdate(toddler2);
|
||||
repository.AddOrUpdate(toddler3);
|
||||
repository.AddOrUpdate(toddler4);
|
||||
repository.AddOrUpdate(baby1);
|
||||
repository.AddOrUpdate(baby2);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var rootNode = repository.GetTemplateNode("parent");
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "parent"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "child1"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "child2"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler1"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler2"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler3"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler4"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby1"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby2"));
|
||||
}
|
||||
|
||||
var parent = new Template("test-parent-masterpage.master", "parent", "parent") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
|
||||
var child1 = new Template("test-child1-masterpage.master", "child1", "child1") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler1 = new Template("test-toddler1-masterpage.master", "toddler1", "toddler1") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler2 = new Template("test-toddler2-masterpage.master", "toddler2", "toddler2") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var baby1 = new Template("test-baby1-masterpage.master", "baby1", "baby1") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
|
||||
var child2 = new Template("test-child2-masterpage.master", "child2", "child2") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler3 = new Template("test-toddler3-masterpage.master", "toddler3", "toddler3") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var toddler4 = new Template("test-toddler4-masterpage.master", "toddler4", "toddler4") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
var baby2 = new Template("test-baby2-masterpage.master", "baby2", "baby2") { Content = @"<%@ Master Language=""C#"" %>" };
|
||||
|
||||
|
||||
child1.MasterTemplateAlias = parent.Alias;
|
||||
child1.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
child2.MasterTemplateAlias = parent.Alias;
|
||||
child2.MasterTemplateId = new Lazy<int>(() => parent.Id);
|
||||
|
||||
toddler1.MasterTemplateAlias = child1.Alias;
|
||||
toddler1.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
toddler2.MasterTemplateAlias = child1.Alias;
|
||||
toddler2.MasterTemplateId = new Lazy<int>(() => child1.Id);
|
||||
|
||||
toddler3.MasterTemplateAlias = child2.Alias;
|
||||
toddler3.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
toddler4.MasterTemplateAlias = child2.Alias;
|
||||
toddler4.MasterTemplateId = new Lazy<int>(() => child2.Id);
|
||||
|
||||
baby1.MasterTemplateAlias = toddler2.Alias;
|
||||
baby1.MasterTemplateId = new Lazy<int>(() => toddler2.Id);
|
||||
|
||||
baby2.MasterTemplateAlias = toddler4.Alias;
|
||||
baby2.MasterTemplateId = new Lazy<int>(() => toddler4.Id);
|
||||
|
||||
repository.AddOrUpdate(parent);
|
||||
repository.AddOrUpdate(child1);
|
||||
repository.AddOrUpdate(child2);
|
||||
repository.AddOrUpdate(toddler1);
|
||||
repository.AddOrUpdate(toddler2);
|
||||
repository.AddOrUpdate(toddler3);
|
||||
repository.AddOrUpdate(toddler4);
|
||||
repository.AddOrUpdate(baby1);
|
||||
repository.AddOrUpdate(baby2);
|
||||
unitOfWork.Commit();
|
||||
|
||||
// Act
|
||||
var rootNode = repository.GetTemplateNode("parent");
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "parent"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "child1"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "child2"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler1"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler2"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler3"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "toddler4"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby1"));
|
||||
Assert.IsNotNull(repository.FindTemplateInTree(rootNode, "baby2"));
|
||||
}
|
||||
|
||||
//[Test]
|
||||
|
||||
@@ -150,6 +150,40 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Add_And_Remove_Properties()
|
||||
{
|
||||
var macroService = ServiceContext.MacroService;
|
||||
var macro = new Macro("test", "Test", scriptPath: "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
|
||||
|
||||
//adds some properties
|
||||
macro.Properties.Add(new MacroProperty("blah1", "Blah1", 0, "blah1"));
|
||||
macro.Properties.Add(new MacroProperty("blah2", "Blah2", 0, "blah2"));
|
||||
macro.Properties.Add(new MacroProperty("blah3", "Blah3", 0, "blah3"));
|
||||
macro.Properties.Add(new MacroProperty("blah4", "Blah4", 0, "blah4"));
|
||||
macroService.Save(macro);
|
||||
|
||||
var result1 = macroService.GetById(macro.Id);
|
||||
Assert.AreEqual(4, result1.Properties.Count());
|
||||
|
||||
//simulate clearing the sections
|
||||
foreach (var s in result1.Properties.ToArray())
|
||||
{
|
||||
result1.Properties.Remove(s.Alias);
|
||||
}
|
||||
//now just re-add a couple
|
||||
result1.Properties.Add(new MacroProperty("blah3", "Blah3", 0, "blah3"));
|
||||
result1.Properties.Add(new MacroProperty("blah4", "Blah4", 0, "blah4"));
|
||||
macroService.Save(result1);
|
||||
|
||||
//assert
|
||||
|
||||
//re-get
|
||||
result1 = macroService.GetById(result1.Id);
|
||||
Assert.AreEqual(2, result1.Properties.Count());
|
||||
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//public void Can_Get_Many_By_Alias()
|
||||
//{
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
<Compile Include="Models\LanguageTests.cs" />
|
||||
<Compile Include="Models\MemberGroupTests.cs" />
|
||||
<Compile Include="Models\MemberTests.cs" />
|
||||
<Compile Include="Models\PreValueCollectionTests.cs" />
|
||||
<Compile Include="Models\PropertyGroupTests.cs" />
|
||||
<Compile Include="Models\PropertyTypeTests.cs" />
|
||||
<Compile Include="Models\RelationTests.cs" />
|
||||
|
||||
@@ -55,7 +55,22 @@ function authResource($q, $http, umbRequestHelper, angularHelper) {
|
||||
umbRequestHelper.getApiUrl(
|
||||
"authenticationApiBaseUrl",
|
||||
"IsAuthenticated")),
|
||||
'Server call failed for checking authentication');
|
||||
{
|
||||
success: function (data, status, headers, config) {
|
||||
//if the response is false, they are not logged in so return a rejection
|
||||
if (data === false || data === "false") {
|
||||
return $q.reject('User is not logged in');
|
||||
}
|
||||
return data;
|
||||
},
|
||||
error: function (data, status, headers, config) {
|
||||
return {
|
||||
errorMsg: 'Server call failed for checking authentication',
|
||||
data: data,
|
||||
status: status
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Gets the user's remaining seconds before their login times out */
|
||||
|
||||
@@ -81,7 +81,7 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
umbRequestHelper.getApiUrl(
|
||||
"dataTypeApiBaseUrl",
|
||||
"GetAll")),
|
||||
'Failed to retreive data');
|
||||
'Failed to retrieve data');
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -118,7 +118,7 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
umbRequestHelper.getApiUrl(
|
||||
"dataTypeApiBaseUrl",
|
||||
"GetEmpty")),
|
||||
'Failed to retreive data for empty datatype');
|
||||
'Failed to retrieve data for empty datatype');
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
@@ -146,7 +146,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
"entityApiBaseUrl",
|
||||
"GetByIds",
|
||||
query)),
|
||||
'Failed to retreive entity data for ids ' + ids);
|
||||
'Failed to retrieve entity data for ids ' + ids);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -192,7 +192,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
"entityApiBaseUrl",
|
||||
"GetAll",
|
||||
query)),
|
||||
'Failed to retreive entity data for type ' + type);
|
||||
'Failed to retrieve entity data for type ' + type);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -215,7 +215,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
"entityApiBaseUrl",
|
||||
"GetAncestors",
|
||||
[{id: id}, {type: type}])),
|
||||
'Failed to retreive ancestor data for id ' + id);
|
||||
'Failed to retrieve ancestor data for id ' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -238,7 +238,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
"entityApiBaseUrl",
|
||||
"GetChildren",
|
||||
[{ id: id }, { type: type }])),
|
||||
'Failed to retreive child data for id ' + id);
|
||||
'Failed to retrieve child data for id ' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -271,7 +271,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
"entityApiBaseUrl",
|
||||
"Search",
|
||||
[{ query: query }, {type: type}])),
|
||||
'Failed to retreive entity data for query ' + query);
|
||||
'Failed to retrieve entity data for query ' + query);
|
||||
},
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
"entityApiBaseUrl",
|
||||
"SearchAll",
|
||||
[{ query: query }])),
|
||||
'Failed to retreive entity data for query ' + query);
|
||||
'Failed to retrieve entity data for query ' + query);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -99,7 +99,7 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
"logApiBaseUrl",
|
||||
"GetLog",
|
||||
[{ logtype: type, sinceDate: since }])),
|
||||
'Failed to retreive user data for id ' + id);
|
||||
'Failed to retrieve user data for id ' + id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
umbRequestHelper.getApiUrl(
|
||||
"memberApiBaseUrl",
|
||||
"GetEmpty")),
|
||||
'Failed to retreive data for empty member item type ' + alias);
|
||||
'Failed to retrieve data for empty member item type ' + alias);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
@@ -93,7 +93,7 @@ function stylesheetResource($q, $http, umbRequestHelper) {
|
||||
"stylesheetApiBaseUrl",
|
||||
"GetRulesByName",
|
||||
[{ name: name }])),
|
||||
'Failed to retreive stylesheets ');
|
||||
'Failed to retrieve stylesheets ');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ function treeResource($q, $http, umbRequestHelper) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(getTreeNodesUrl(options.node)),
|
||||
'Failed to retreive data for child nodes ' + options.node.nodeId);
|
||||
'Failed to retrieve data for child nodes ' + options.node.nodeId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -178,9 +178,8 @@ angular.module('umbraco.services')
|
||||
* @methodOf umbraco.services.assetsService
|
||||
*
|
||||
* @description
|
||||
* Injects a collection of files, this can be a mixed collection of css and js files, the loader will determine how to load them
|
||||
* Injects a collection of files, this can be ONLY js files
|
||||
*
|
||||
* **Warning:** if the collection of files contains a .css file, you will in some cases not receive a resolved promise, it is therefore prefered to use the individual loadCss and loadJs methods
|
||||
*
|
||||
* @param {Array} pathArray string array of paths to the files to load
|
||||
* @param {Scope} scope optional scope to pass into the loader
|
||||
|
||||
@@ -114,11 +114,11 @@ function cropperHelper(umbRequestHelper, $http) {
|
||||
crop.x2 = x2_px / image.width;
|
||||
crop.y2 = y2_px / image.height;
|
||||
|
||||
_.forEach(crop, function(coord){
|
||||
if(coord < 0){
|
||||
coord = 0;
|
||||
for(var coord in crop){
|
||||
if(crop[coord] < 0){
|
||||
crop[coord] = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return crop;
|
||||
},
|
||||
|
||||
@@ -31,476 +31,492 @@
|
||||
angular.module('umbraco.services')
|
||||
.factory('dialogService', function ($rootScope, $compile, $http, $timeout, $q, $templateCache, appState, eventsService) {
|
||||
|
||||
var dialogs = [];
|
||||
|
||||
/** Internal method that removes all dialogs */
|
||||
function removeAllDialogs(args) {
|
||||
for (var i = 0; i < dialogs.length; i++) {
|
||||
var dialog = dialogs[i];
|
||||
dialog.close(args);
|
||||
dialogs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
var dialogs = [];
|
||||
|
||||
/** Internal method that handles opening all dialogs */
|
||||
function openDialog(options) {
|
||||
var defaults = {
|
||||
container: $("body"),
|
||||
animation: "fade",
|
||||
modalClass: "umb-modal",
|
||||
width: "100%",
|
||||
inline: false,
|
||||
iframe: false,
|
||||
show: true,
|
||||
template: "views/common/notfound.html",
|
||||
callback: undefined,
|
||||
closeCallback: undefined,
|
||||
element: undefined,
|
||||
//this allows us to pass in data to the dialog if required which can be used to configure the dialog
|
||||
//and re-use it for different purposes. It will set on to the $scope.dialogData if it is defined.
|
||||
dialogData: undefined
|
||||
};
|
||||
|
||||
var dialog = angular.extend(defaults, options);
|
||||
var scope = options.scope || $rootScope.$new();
|
||||
|
||||
//Modal dom obj and unique id
|
||||
dialog.element = $('<div ng-swipe-right="swipeHide($event)" data-backdrop="false"></div>');
|
||||
var id = dialog.template.replace('.html', '').replace('.aspx', '').replace(/[\/|\.|:\&\?\=]/g, "-") + '-' + scope.$id;
|
||||
/** Internal method that removes all dialogs */
|
||||
function removeAllDialogs(args) {
|
||||
for (var i = 0; i < dialogs.length; i++) {
|
||||
var dialog = dialogs[i];
|
||||
dialog.close(args);
|
||||
dialogs.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.inline) {
|
||||
dialog.animation = "";
|
||||
}
|
||||
else {
|
||||
dialog.element.addClass("modal");
|
||||
dialog.element.addClass("hide");
|
||||
}
|
||||
/** Internal method that handles opening all dialogs */
|
||||
function openDialog(options) {
|
||||
var defaults = {
|
||||
container: $("body"),
|
||||
animation: "fade",
|
||||
modalClass: "umb-modal",
|
||||
width: "100%",
|
||||
inline: false,
|
||||
iframe: false,
|
||||
show: true,
|
||||
template: "views/common/notfound.html",
|
||||
callback: undefined,
|
||||
closeCallback: undefined,
|
||||
element: undefined,
|
||||
//this allows us to pass in data to the dialog if required which can be used to configure the dialog
|
||||
//and re-use it for different purposes. It will set on to the $scope.dialogData if it is defined.
|
||||
dialogData: undefined
|
||||
};
|
||||
|
||||
//set the id and add classes
|
||||
dialog.element
|
||||
.attr('id', id)
|
||||
.addClass(dialog.animation)
|
||||
.addClass(dialog.modalClass);
|
||||
var dialog = angular.extend(defaults, options);
|
||||
var scope = options.scope || $rootScope.$new();
|
||||
|
||||
//push the modal into the global modal collection
|
||||
//we halt the .push because a link click will trigger a closeAll right away
|
||||
$timeout(function () {
|
||||
dialogs.push(dialog);
|
||||
}, 500);
|
||||
|
||||
//Modal dom obj and unique id
|
||||
dialog.element = $('<div ng-swipe-right="swipeHide($event)" data-backdrop="false"></div>');
|
||||
var id = dialog.template.replace('.html', '').replace('.aspx', '').replace(/[\/|\.|:\&\?\=]/g, "-") + '-' + scope.$id;
|
||||
|
||||
dialog.close = function(data) {
|
||||
if (dialog.closeCallback) {
|
||||
dialog.closeCallback(data);
|
||||
}
|
||||
if (options.inline) {
|
||||
dialog.animation = "";
|
||||
}
|
||||
else {
|
||||
dialog.element.addClass("modal");
|
||||
dialog.element.addClass("hide");
|
||||
}
|
||||
|
||||
if(dialog.element){
|
||||
dialog.element.modal('hide');
|
||||
//set the id and add classes
|
||||
dialog.element
|
||||
.attr('id', id)
|
||||
.addClass(dialog.animation)
|
||||
.addClass(dialog.modalClass);
|
||||
|
||||
//this is not entirely enough since the damn
|
||||
//webforms scriploader still complains
|
||||
if(dialog.iframe){
|
||||
//push the modal into the global modal collection
|
||||
//we halt the .push because a link click will trigger a closeAll right away
|
||||
$timeout(function () {
|
||||
dialogs.push(dialog);
|
||||
}, 500);
|
||||
|
||||
|
||||
dialog.close = function (data) {
|
||||
if (dialog.closeCallback) {
|
||||
dialog.closeCallback(data);
|
||||
}
|
||||
|
||||
if (dialog.element) {
|
||||
dialog.element.modal('hide');
|
||||
|
||||
//this is not entirely enough since the damn
|
||||
//webforms scriploader still complains
|
||||
if (dialog.iframe) {
|
||||
dialog.element.find("iframe").attr("src", "about:blank");
|
||||
$timeout(function(){
|
||||
dialog.element.remove();
|
||||
}, 1000);
|
||||
}else{
|
||||
$timeout(function () {
|
||||
//we need to do more than just remove the element, this will not destroy the
|
||||
// scope in angular 1.1x, in angular 1.2x this is taken care of but if we dont
|
||||
// take care of this ourselves we have memory leaks.
|
||||
dialog.element.remove();
|
||||
dialog.scope.$destroy();
|
||||
}, 1000);
|
||||
} else {
|
||||
//we need to do more than just remove the element, this will not destroy the
|
||||
// scope in angular 1.1x, in angular 1.2x this is taken care of but if we dont
|
||||
// take care of this ourselves we have memory leaks.
|
||||
dialog.element.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
dialog.scope.$destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//if iframe is enabled, inject that instead of a template
|
||||
if (dialog.iframe) {
|
||||
var html = $("<iframe src='" + dialog.template + "' class='auto-expand' style='border: none; width: 100%; height: 100%;'></iframe>");
|
||||
dialog.element.html(html);
|
||||
|
||||
//append to body or whatever element is passed in as options.containerElement
|
||||
dialog.container.append(dialog.element);
|
||||
//if iframe is enabled, inject that instead of a template
|
||||
if (dialog.iframe) {
|
||||
var html = $("<iframe src='" + dialog.template + "' class='auto-expand' style='border: none; width: 100%; height: 100%;'></iframe>");
|
||||
dialog.element.html(html);
|
||||
|
||||
// Compile modal content
|
||||
$timeout(function () {
|
||||
$compile(dialog.element)(dialog.scope);
|
||||
});
|
||||
//append to body or whatever element is passed in as options.containerElement
|
||||
dialog.container.append(dialog.element);
|
||||
|
||||
dialog.element.css("width", dialog.width);
|
||||
// Compile modal content
|
||||
$timeout(function () {
|
||||
$compile(dialog.element)(dialog.scope);
|
||||
});
|
||||
|
||||
//Autoshow
|
||||
if (dialog.show) {
|
||||
dialog.element.modal('show');
|
||||
}
|
||||
dialog.element.css("width", dialog.width);
|
||||
|
||||
dialog.scope = scope;
|
||||
return dialog;
|
||||
}
|
||||
else {
|
||||
|
||||
//We need to load the template with an httpget and once it's loaded we'll compile and assign the result to the container
|
||||
// object. However since the result could be a promise or just data we need to use a $q.when. We still need to return the
|
||||
// $modal object so we'll actually return the modal object synchronously without waiting for the promise. Otherwise this openDialog
|
||||
// method will always need to return a promise which gets nasty because of promises in promises plus the result just needs a reference
|
||||
// to the $modal object which will not change (only it's contents will change).
|
||||
$q.when($templateCache.get(dialog.template) || $http.get(dialog.template, { cache: true }).then(function(res) { return res.data; }))
|
||||
.then(function onSuccess(template) {
|
||||
//Autoshow
|
||||
if (dialog.show) {
|
||||
dialog.element.modal('show');
|
||||
}
|
||||
|
||||
// Build modal object
|
||||
dialog.element.html(template);
|
||||
dialog.scope = scope;
|
||||
return dialog;
|
||||
}
|
||||
else {
|
||||
|
||||
//append to body or other container element
|
||||
dialog.container.append(dialog.element);
|
||||
|
||||
// Compile modal content
|
||||
$timeout(function() {
|
||||
$compile(dialog.element)(scope);
|
||||
});
|
||||
//We need to load the template with an httpget and once it's loaded we'll compile and assign the result to the container
|
||||
// object. However since the result could be a promise or just data we need to use a $q.when. We still need to return the
|
||||
// $modal object so we'll actually return the modal object synchronously without waiting for the promise. Otherwise this openDialog
|
||||
// method will always need to return a promise which gets nasty because of promises in promises plus the result just needs a reference
|
||||
// to the $modal object which will not change (only it's contents will change).
|
||||
$q.when($templateCache.get(dialog.template) || $http.get(dialog.template, { cache: true }).then(function (res) { return res.data; }))
|
||||
.then(function onSuccess(template) {
|
||||
|
||||
scope.dialogOptions = dialog;
|
||||
|
||||
//Scope to handle data from the modal form
|
||||
scope.dialogData = dialog.dialogData ? dialog.dialogData : {};
|
||||
scope.dialogData.selection = [];
|
||||
// Build modal object
|
||||
dialog.element.html(template);
|
||||
|
||||
// Provide scope display functions
|
||||
//this passes the modal to the current scope
|
||||
scope.$modal = function(name) {
|
||||
dialog.element.modal(name);
|
||||
};
|
||||
//append to body or other container element
|
||||
dialog.container.append(dialog.element);
|
||||
|
||||
scope.swipeHide = function(e){
|
||||
if(appState.getGlobalState("touchDevice")){
|
||||
// Compile modal content
|
||||
$timeout(function () {
|
||||
$compile(dialog.element)(scope);
|
||||
});
|
||||
|
||||
scope.dialogOptions = dialog;
|
||||
|
||||
//Scope to handle data from the modal form
|
||||
scope.dialogData = dialog.dialogData ? dialog.dialogData : {};
|
||||
scope.dialogData.selection = [];
|
||||
|
||||
// Provide scope display functions
|
||||
//this passes the modal to the current scope
|
||||
scope.$modal = function (name) {
|
||||
dialog.element.modal(name);
|
||||
};
|
||||
|
||||
scope.swipeHide = function (e) {
|
||||
if (appState.getGlobalState("touchDevice")) {
|
||||
var selection = window.getSelection();
|
||||
if(selection.type !== "Range"){
|
||||
scope.hide();
|
||||
if (selection.type !== "Range") {
|
||||
scope.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
scope.hide = function() {
|
||||
dialog.element.modal('hide');
|
||||
scope.hide = function () {
|
||||
dialog.element.modal('hide');
|
||||
|
||||
dialog.element.remove();
|
||||
$("#" + dialog.element.attr("id")).remove();
|
||||
};
|
||||
dialog.element.remove();
|
||||
$("#" + dialog.element.attr("id")).remove();
|
||||
//we need to do more than just remove the element, this will not destroy the
|
||||
// scope in angular 1.1x, in angular 1.2x this is taken care of but if we dont
|
||||
// take care of this ourselves we have memory leaks.
|
||||
dialog.scope.$destroy();
|
||||
};
|
||||
|
||||
//basic events for submitting and closing
|
||||
scope.submit = function(data) {
|
||||
if (dialog.callback) {
|
||||
dialog.callback(data);
|
||||
}
|
||||
//basic events for submitting and closing
|
||||
scope.submit = function (data) {
|
||||
if (dialog.callback) {
|
||||
dialog.callback(data);
|
||||
}
|
||||
|
||||
dialog.element.modal('hide');
|
||||
dialog.element.remove();
|
||||
$("#" + dialog.element.attr("id")).remove();
|
||||
};
|
||||
dialog.element.modal('hide');
|
||||
dialog.element.remove();
|
||||
$("#" + dialog.element.attr("id")).remove();
|
||||
//we need to do more than just remove the element, this will not destroy the
|
||||
// scope in angular 1.1x, in angular 1.2x this is taken care of but if we dont
|
||||
// take care of this ourselves we have memory leaks.
|
||||
dialog.scope.$destroy();
|
||||
};
|
||||
|
||||
scope.close = function(data) {
|
||||
scope.close = function (data) {
|
||||
dialog.close(data);
|
||||
};
|
||||
};
|
||||
|
||||
scope.show = function() {
|
||||
dialog.element.modal('show');
|
||||
};
|
||||
scope.show = function () {
|
||||
dialog.element.modal('show');
|
||||
};
|
||||
|
||||
scope.select = function(item) {
|
||||
scope.select = function (item) {
|
||||
var i = scope.dialogData.selection.indexOf(item);
|
||||
if (i < 0) {
|
||||
scope.dialogData.selection.push(item);
|
||||
}else{
|
||||
if (i < 0) {
|
||||
scope.dialogData.selection.push(item);
|
||||
} else {
|
||||
scope.dialogData.selection.splice(i, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
scope.dismiss = scope.hide;
|
||||
scope.dismiss = scope.hide;
|
||||
|
||||
// Emit modal events
|
||||
angular.forEach(['show', 'shown', 'hide', 'hidden'], function(name) {
|
||||
dialog.element.on(name, function(ev) {
|
||||
scope.$emit('modal-' + name, ev);
|
||||
});
|
||||
});
|
||||
// Emit modal events
|
||||
angular.forEach(['show', 'shown', 'hide', 'hidden'], function (name) {
|
||||
dialog.element.on(name, function (ev) {
|
||||
scope.$emit('modal-' + name, ev);
|
||||
});
|
||||
});
|
||||
|
||||
// Support autofocus attribute
|
||||
dialog.element.on('shown', function(event) {
|
||||
$('input[autofocus]', dialog.element).first().trigger('focus');
|
||||
});
|
||||
// Support autofocus attribute
|
||||
dialog.element.on('shown', function (event) {
|
||||
$('input[autofocus]', dialog.element).first().trigger('focus');
|
||||
});
|
||||
|
||||
//Autoshow
|
||||
if (dialog.show) {
|
||||
dialog.element.modal('show');
|
||||
}
|
||||
//Autoshow
|
||||
if (dialog.show) {
|
||||
dialog.element.modal('show');
|
||||
}
|
||||
|
||||
dialog.scope = scope;
|
||||
});
|
||||
|
||||
//Return the modal object outside of the promise!
|
||||
return dialog;
|
||||
}
|
||||
}
|
||||
dialog.scope = scope;
|
||||
});
|
||||
|
||||
/** Handles the closeDialogs event */
|
||||
eventsService.on("app.closeDialogs", function (evt, args) {
|
||||
removeAllDialogs(args);
|
||||
});
|
||||
//Return the modal object outside of the promise!
|
||||
return dialog;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#open
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a modal rendering a given template url.
|
||||
*
|
||||
* @param {Object} options rendering options
|
||||
* @param {DomElement} options.container the DOM element to inject the modal into, by default set to body
|
||||
* @param {Function} options.callback function called when the modal is submitted
|
||||
* @param {String} options.template the url of the template
|
||||
* @param {String} options.animation animation csss class, by default set to "fade"
|
||||
* @param {String} options.modalClass modal css class, by default "umb-modal"
|
||||
* @param {Bool} options.show show the modal instantly
|
||||
* @param {Object} options.scope scope to attach the modal to, by default rootScope.new()
|
||||
* @param {Bool} options.iframe load template in an iframe, only needed for serverside templates
|
||||
* @param {Int} options.width set a width on the modal, only needed for iframes
|
||||
* @param {Bool} options.inline strips the modal from any animation and wrappers, used when you want to inject a dialog into an existing container
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
open: function (options) {
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#close
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Closes a specific dialog
|
||||
* @param {Object} dialog the dialog object to close
|
||||
* @param {Object} args if specified this object will be sent to any callbacks registered on the dialogs.
|
||||
*/
|
||||
close: function (dialog, args) {
|
||||
if(dialog){
|
||||
dialog.close(args);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#closeAll
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Closes all dialogs
|
||||
* @param {Object} args if specified this object will be sent to any callbacks registered on the dialogs.
|
||||
*/
|
||||
closeAll: function(args) {
|
||||
removeAllDialogs(args);
|
||||
},
|
||||
/** Handles the closeDialogs event */
|
||||
eventsService.on("app.closeDialogs", function (evt, args) {
|
||||
removeAllDialogs(args);
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#mediaPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a media picker in a modal, the callback returns an array of selected media items
|
||||
* @param {Object} options mediapicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Boolean} options.onlyImages Only display files that have an image file-extension
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
mediaPicker: function (options) {
|
||||
return {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#open
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a modal rendering a given template url.
|
||||
*
|
||||
* @param {Object} options rendering options
|
||||
* @param {DomElement} options.container the DOM element to inject the modal into, by default set to body
|
||||
* @param {Function} options.callback function called when the modal is submitted
|
||||
* @param {String} options.template the url of the template
|
||||
* @param {String} options.animation animation csss class, by default set to "fade"
|
||||
* @param {String} options.modalClass modal css class, by default "umb-modal"
|
||||
* @param {Bool} options.show show the modal instantly
|
||||
* @param {Object} options.scope scope to attach the modal to, by default rootScope.new()
|
||||
* @param {Bool} options.iframe load template in an iframe, only needed for serverside templates
|
||||
* @param {Int} options.width set a width on the modal, only needed for iframes
|
||||
* @param {Bool} options.inline strips the modal from any animation and wrappers, used when you want to inject a dialog into an existing container
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
open: function (options) {
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#close
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Closes a specific dialog
|
||||
* @param {Object} dialog the dialog object to close
|
||||
* @param {Object} args if specified this object will be sent to any callbacks registered on the dialogs.
|
||||
*/
|
||||
close: function (dialog, args) {
|
||||
if (dialog) {
|
||||
dialog.close(args);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#closeAll
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Closes all dialogs
|
||||
* @param {Object} args if specified this object will be sent to any callbacks registered on the dialogs.
|
||||
*/
|
||||
closeAll: function (args) {
|
||||
removeAllDialogs(args);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#mediaPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a media picker in a modal, the callback returns an array of selected media items
|
||||
* @param {Object} options mediapicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Boolean} options.onlyImages Only display files that have an image file-extension
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
mediaPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/mediaPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#contentPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a content picker tree in a modal, the callback returns an array of selected documents
|
||||
* @param {Object} options content picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.multipicker should the picker return one or multiple items
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
contentPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/contentPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#contentPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a content picker tree in a modal, the callback returns an array of selected documents
|
||||
* @param {Object} options content picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.multipicker should the picker return one or multiple items
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
contentPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/contentPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#linkPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a link picker tree in a modal, the callback returns a single link
|
||||
* @param {Object} options content picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
linkPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/linkPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#linkPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a link picker tree in a modal, the callback returns a single link
|
||||
* @param {Object} options content picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
linkPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/linkPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#macroPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a mcaro picker in a modal, the callback returns a object representing the macro and it's parameters
|
||||
* @param {Object} options macropicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
macroPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/insertmacro.html';
|
||||
options.show = true;
|
||||
options.modalClass = "span7 umb-modal";
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#macroPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a mcaro picker in a modal, the callback returns a object representing the macro and it's parameters
|
||||
* @param {Object} options macropicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
macroPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/insertmacro.html';
|
||||
options.show = true;
|
||||
options.modalClass = "span7 umb-modal";
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#memberPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a member picker in a modal, the callback returns a object representing the selected member
|
||||
* @param {Object} options member picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.multiPicker should the tree pick one or multiple members before returning
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
memberPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/memberPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#memberGroupPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a member group picker in a modal, the callback returns a object representing the selected member
|
||||
* @param {Object} options member group picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.multiPicker should the tree pick one or multiple members before returning
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
memberGroupPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/memberGroupPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#memberPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a member picker in a modal, the callback returns a object representing the selected member
|
||||
* @param {Object} options member picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.multiPicker should the tree pick one or multiple members before returning
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
memberPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/memberPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#iconPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a icon picker in a modal, the callback returns a object representing the selected icon
|
||||
* @param {Object} options iconpicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
iconPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/iconPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#memberGroupPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a member group picker in a modal, the callback returns a object representing the selected member
|
||||
* @param {Object} options member group picker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.multiPicker should the tree pick one or multiple members before returning
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
memberGroupPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/memberGroupPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#treePicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a tree picker in a modal, the callback returns a object representing the selected tree item
|
||||
* @param {Object} options iconpicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.section tree section to display
|
||||
* @param {$scope} options.treeAlias specific tree to display
|
||||
* @param {$scope} options.multiPicker should the tree pick one or multiple items before returning
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
treePicker: function (options) {
|
||||
options.template = 'views/common/dialogs/treePicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#iconPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a icon picker in a modal, the callback returns a object representing the selected icon
|
||||
* @param {Object} options iconpicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
iconPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/iconPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#propertyDialog
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a dialog with a chosen property editor in, a value can be passed to the modal, and this value is returned in the callback
|
||||
* @param {Object} options mediapicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @param {String} editor editor to use to edit a given value and return on callback
|
||||
* @param {Object} value value sent to the property editor
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
propertyDialog: function (options) {
|
||||
options.template = 'views/common/dialogs/property.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#ysodDialog
|
||||
* @methodOf umbraco.services.dialogService
|
||||
* @description
|
||||
* Opens a dialog to an embed dialog
|
||||
*/
|
||||
embedDialog: function (options) {
|
||||
options.template = 'views/common/dialogs/rteembed.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#ysodDialog
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a dialog to show a custom YSOD
|
||||
*/
|
||||
ysodDialog: function (ysodError) {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#treePicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a tree picker in a modal, the callback returns a object representing the selected tree item
|
||||
* @param {Object} options iconpicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.section tree section to display
|
||||
* @param {$scope} options.treeAlias specific tree to display
|
||||
* @param {$scope} options.multiPicker should the tree pick one or multiple items before returning
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
treePicker: function (options) {
|
||||
options.template = 'views/common/dialogs/treePicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
var newScope = $rootScope.$new();
|
||||
newScope.error = ysodError;
|
||||
return openDialog({
|
||||
modalClass: "umb-modal wide",
|
||||
scope: newScope,
|
||||
//callback: options.callback,
|
||||
template: 'views/common/dialogs/ysod.html',
|
||||
show: true
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#propertyDialog
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a dialog with a chosen property editor in, a value can be passed to the modal, and this value is returned in the callback
|
||||
* @param {Object} options mediapicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @param {String} editor editor to use to edit a given value and return on callback
|
||||
* @param {Object} value value sent to the property editor
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
propertyDialog: function (options) {
|
||||
options.template = 'views/common/dialogs/property.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#ysodDialog
|
||||
* @methodOf umbraco.services.dialogService
|
||||
* @description
|
||||
* Opens a dialog to an embed dialog
|
||||
*/
|
||||
embedDialog: function (options) {
|
||||
options.template = 'views/common/dialogs/rteembed.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#ysodDialog
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a dialog to show a custom YSOD
|
||||
*/
|
||||
ysodDialog: function (ysodError) {
|
||||
|
||||
var newScope = $rootScope.$new();
|
||||
newScope.error = ysodError;
|
||||
return openDialog({
|
||||
modalClass: "umb-modal wide",
|
||||
scope: newScope,
|
||||
//callback: options.callback,
|
||||
template: 'views/common/dialogs/ysod.html',
|
||||
show: true
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -28,18 +28,25 @@
|
||||
* </pre>
|
||||
*/
|
||||
angular.module('umbraco.services')
|
||||
.factory('historyService', function ($rootScope, $timeout, angularHelper) {
|
||||
.factory('historyService', function ($rootScope, $timeout, angularHelper, eventsService) {
|
||||
|
||||
var nArray = [];
|
||||
|
||||
function add(item) {
|
||||
|
||||
var any = _.where(nArray, {link: item.link});
|
||||
if (!item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var listWithoutThisItem = _.reject(nArray, function(i) {
|
||||
return i.link === item.link;
|
||||
});
|
||||
|
||||
//put it at the top and reassign
|
||||
listWithoutThisItem.splice(0, 0, item);
|
||||
nArray = listWithoutThisItem;
|
||||
return nArray[0];
|
||||
|
||||
if(any.length === 0){
|
||||
nArray.splice(0,0,item);
|
||||
return nArray[0];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -60,7 +67,9 @@ angular.module('umbraco.services')
|
||||
add: function (item) {
|
||||
var icon = item.icon || "icon-file";
|
||||
angularHelper.safeApply($rootScope, function () {
|
||||
return add({name: item.name, icon: icon, link: item.link, time: new Date() });
|
||||
var result = add({ name: item.name, icon: icon, link: item.link, time: new Date() });
|
||||
eventsService.emit("historyService.add", {added: result, all: nArray});
|
||||
return result;
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -75,7 +84,8 @@ angular.module('umbraco.services')
|
||||
*/
|
||||
remove: function (index) {
|
||||
angularHelper.safeApply($rootScope, function() {
|
||||
nArray.splice(index, 1);
|
||||
var result = nArray.splice(index, 1);
|
||||
eventsService.emit("historyService.remove", { removed: result, all: nArray });
|
||||
});
|
||||
},
|
||||
|
||||
@@ -89,21 +99,11 @@ angular.module('umbraco.services')
|
||||
*/
|
||||
removeAll: function () {
|
||||
angularHelper.safeApply($rootScope, function() {
|
||||
nArray = [];
|
||||
nArray = [];
|
||||
eventsService.emit("historyService.removeAll");
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc property
|
||||
* @name umbraco.services.historyService#current
|
||||
* @propertyOf umbraco.services.historyService
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* @returns {Array} Array of history entries for the current user, newest items first
|
||||
*/
|
||||
current: nArray,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.historyService#getCurrent
|
||||
|
||||
@@ -139,7 +139,8 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
|
||||
return { height: minDisplayHeight, imgCount: 1 };
|
||||
}
|
||||
else if (idealImages.length === idealImgPerRow && targetHeight < maxRowHeight) {
|
||||
//if we're already dealing with the ideal images per row and it's not quite there, we can scale up a little bit so
|
||||
|
||||
//if we're already dealing with the ideal images per row and it's not quite wide enough, we can scale up a little bit so
|
||||
// long as the targetHeight is currently less than the maxRowHeight. The scale up will be half-way between our current
|
||||
// target height and the maxRowHeight (we won't loop forever though - if there's a difference of 5 px we'll just quit)
|
||||
|
||||
@@ -152,9 +153,8 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
|
||||
}
|
||||
}
|
||||
|
||||
//Ok, we couldn't actually scale it up with the ideal row count (TBH I'm not sure that this would ever happen but we'll take it into account)
|
||||
// we'll just recurse with another image count.
|
||||
return this.getRowHeightForImages(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow + 1, margin);
|
||||
//Ok, we couldn't actually scale it up with the ideal row count we'll just recurse with a lesser image count.
|
||||
return this.getRowHeightForImages(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow - 1, margin);
|
||||
}
|
||||
else {
|
||||
//we have additional images so we'll recurse and add 1 to the idealImgPerRow until it fits
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Dialogs.UserController", function ($scope, $location, $timeout, userService, historyService, eventsService) {
|
||||
|
||||
|
||||
$scope.user = userService.getCurrentUser();
|
||||
$scope.history = historyService.current;
|
||||
$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) {
|
||||
$scope.history = args.all;
|
||||
}));
|
||||
evtHandlers.push(eventsService.on("historyService.remove", function (e, args) {
|
||||
$scope.history = args.all;
|
||||
}));
|
||||
evtHandlers.push(eventsService.on("historyService.removeAll", function (e, args) {
|
||||
$scope.history = [];
|
||||
}));
|
||||
|
||||
$scope.logout = function () {
|
||||
|
||||
@@ -16,38 +26,44 @@ angular.module("umbraco")
|
||||
});
|
||||
|
||||
//perform the path change, if it is successful then the promise will resolve otherwise it will fail
|
||||
$location.path("/logout");
|
||||
};
|
||||
$location.path("/logout");
|
||||
};
|
||||
|
||||
$scope.gotoHistory = function (link) {
|
||||
$location.path(link);
|
||||
$scope.hide();
|
||||
};
|
||||
$scope.gotoHistory = function (link) {
|
||||
$location.path(link);
|
||||
$scope.hide();
|
||||
};
|
||||
|
||||
//Manually update the remaining timeout seconds
|
||||
function updateTimeout() {
|
||||
$timeout(function () {
|
||||
if ($scope.remainingAuthSeconds > 0) {
|
||||
$scope.remainingAuthSeconds--;
|
||||
$scope.$digest();
|
||||
//recurse
|
||||
updateTimeout();
|
||||
}
|
||||
|
||||
}, 1000, false); // 1 second, do NOT execute a global digest
|
||||
}
|
||||
|
||||
//get the user
|
||||
userService.getCurrentUser().then(function (user) {
|
||||
$scope.user = user;
|
||||
if ($scope.user) {
|
||||
$scope.remainingAuthSeconds = $scope.user.remainingAuthSeconds;
|
||||
$scope.canEditProfile = _.indexOf($scope.user.allowedSections, "users") > -1;
|
||||
//set the timer
|
||||
updateTimeout();
|
||||
}
|
||||
});
|
||||
function updateTimeout() {
|
||||
$timeout(function () {
|
||||
if ($scope.remainingAuthSeconds > 0) {
|
||||
$scope.remainingAuthSeconds--;
|
||||
$scope.$digest();
|
||||
//recurse
|
||||
updateTimeout();
|
||||
}
|
||||
|
||||
}, 1000, false); // 1 second, do NOT execute a global digest
|
||||
}
|
||||
|
||||
//get the user
|
||||
userService.getCurrentUser().then(function (user) {
|
||||
$scope.user = user;
|
||||
if ($scope.user) {
|
||||
$scope.remainingAuthSeconds = $scope.user.remainingAuthSeconds;
|
||||
$scope.canEditProfile = _.indexOf($scope.user.allowedSections, "users") > -1;
|
||||
//set the timer
|
||||
updateTimeout();
|
||||
}
|
||||
});
|
||||
|
||||
//remove all event handlers
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var i = 0; i < evtHandlers.length; i++) {
|
||||
evtHandlers[i]();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
@@ -34,7 +34,7 @@
|
||||
<div class="umb-pane">
|
||||
<h5><localize key="user_yourHistory" /></h5>
|
||||
<ul class="umb-tree">
|
||||
<li ng-repeat="item in history | orderBy:'time'">
|
||||
<li ng-repeat="item in history | orderBy:'time':true">
|
||||
<a ng-href="{{item.link}}" ng-click="gotoHistory(item.link)" prevent-default>
|
||||
<i class="{{item.icon}}"></i> {{item.name}}</a>
|
||||
</li>
|
||||
|
||||
+32
-30
@@ -1,4 +1,4 @@
|
||||
function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService) {
|
||||
function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService, $element) {
|
||||
|
||||
//lists the custom language files that we currently support
|
||||
var customLangs = ["pt-BR"];
|
||||
@@ -31,37 +31,39 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
|
||||
|
||||
//get the current user to see if we can localize this picker
|
||||
userService.getCurrentUser().then(function (user) {
|
||||
|
||||
assetsService.loadCss('lib/datetimepicker/bootstrap-datetimepicker.min.css').then(function() {
|
||||
var filesToLoad = ["lib/datetimepicker/bootstrap-datetimepicker.min.js"];
|
||||
|
||||
//if we support this custom culture, set it, then we'll need to load in that lang file
|
||||
if (_.contains(customLangs, user.locale)) {
|
||||
$scope.model.config.language = user.locale;
|
||||
filesToLoad.push("lib/datetimepicker/langs/datetimepicker." + user.locale + ".js");
|
||||
}
|
||||
|
||||
assetsService.load(filesToLoad).then(
|
||||
function () {
|
||||
//The Datepicker js and css files are available and all components are ready to use.
|
||||
|
||||
// Get the id of the datepicker button that was clicked
|
||||
var pickerId = $scope.model.alias;
|
||||
// Open the datepicker and add a changeDate eventlistener
|
||||
$element.find("div:first")
|
||||
.datetimepicker($scope.model.config)
|
||||
.on("changeDate", applyDate);
|
||||
|
||||
//now assign the date
|
||||
$("#datepicker" + pickerId).val($scope.model.value);
|
||||
|
||||
//Ensure to remove the event handler when this instance is destroyted
|
||||
$scope.$on('$destroy', function () {
|
||||
$element.find("div:first").datetimepicker("destroy");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var filesToLoad = ["lib/datetimepicker/bootstrap-datetimepicker.min.js"];
|
||||
|
||||
//if we support this custom culture, set it, then we'll need to load in that lang file
|
||||
if (_.contains(customLangs, user.locale)) {
|
||||
$scope.model.config.language = user.locale;
|
||||
filesToLoad.push("lib/datetimepicker/langs/datetimepicker." + user.locale + ".js");
|
||||
}
|
||||
|
||||
assetsService.load(filesToLoad).then(
|
||||
function() {
|
||||
//The Datepicker js and css files are available and all components are ready to use.
|
||||
|
||||
// Get the id of the datepicker button that was clicked
|
||||
var pickerId = $scope.model.alias;
|
||||
// Open the datepicker and add a changeDate eventlistener
|
||||
$("#datepicker" + pickerId)
|
||||
//.datetimepicker(config);
|
||||
.datetimepicker($scope.model.config)
|
||||
.on("changeDate", applyDate);
|
||||
|
||||
//now assign the date
|
||||
$("#datepicker" + pickerId).val($scope.model.value);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
assetsService.loadCss(
|
||||
'lib/datetimepicker/bootstrap-datetimepicker.min.css'
|
||||
);
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.DatepickerController", dateTimePickerController);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.RTEController" class="umb-editor umb-rte">
|
||||
<div ng-if="isLoading">Loading...</div>
|
||||
<textarea ng-style="{ visibility : isLoading ? 'hidden' : 'visible'}" ng-model="model.value" rows="10" id="{{model.alias}}_rte"></textarea>
|
||||
<textarea ng-style="{ visibility : isLoading ? 'hidden' : 'visible'}"
|
||||
ng-model="model.value" rows="10" id="{{model.alias}}_rte"></textarea>
|
||||
</div>
|
||||
@@ -12,13 +12,21 @@ angular.module("umbraco")
|
||||
//load current value
|
||||
$scope.currentTags = [];
|
||||
if ($scope.model.value) {
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
if ($scope.model.config.storageType && $scope.model.config.storageType === "Json") {
|
||||
//it's a json array already
|
||||
$scope.currentTags = $scope.model.value;
|
||||
}
|
||||
else {
|
||||
//it is csv
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Helper method to add a tag on enter or on typeahead select
|
||||
function addTag(tagToAdd) {
|
||||
if (tagToAdd.length > 0) {
|
||||
if ($scope.currentTags.indexOf(tagToAdd) < 0) {
|
||||
if ($scope.currentTags.indexOf(tagToAdd) < 0) {
|
||||
$scope.currentTags.push(tagToAdd);
|
||||
}
|
||||
}
|
||||
@@ -34,6 +42,7 @@ angular.module("umbraco")
|
||||
e.preventDefault();
|
||||
//we need to use jquery because typeahead duplicates the text box
|
||||
addTag($scope.tagToAdd);
|
||||
$scope.tagToAdd = "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,16 +55,24 @@ angular.module("umbraco")
|
||||
}
|
||||
};
|
||||
|
||||
//sync model on submit (needed since we convert an array to string)
|
||||
//sync model on submit, always push up a json array
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = $scope.currentTags.join();
|
||||
$scope.model.value = $scope.currentTags;
|
||||
});
|
||||
|
||||
//vice versa
|
||||
$scope.model.onValueChanged = function (newVal, oldVal) {
|
||||
//update the display val again if it has changed from the server
|
||||
$scope.model.val = newVal;
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
$scope.model.value = newVal;
|
||||
|
||||
if ($scope.model.config.storageType && $scope.model.config.storageType === "Json") {
|
||||
//it's a json array already
|
||||
$scope.currentTags = $scope.model.value;
|
||||
}
|
||||
else {
|
||||
//it is csv
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
}
|
||||
};
|
||||
|
||||
//configure the tags data source
|
||||
@@ -111,15 +128,17 @@ angular.module("umbraco")
|
||||
}).bind("typeahead:selected", function (obj, datum, name) {
|
||||
angularHelper.safeApply($scope, function () {
|
||||
addTag(datum["value"]);
|
||||
$scope.tagToAdd = "";
|
||||
});
|
||||
|
||||
}).bind("typeahead:autocompleted", function (obj, datum, name) {
|
||||
angularHelper.safeApply($scope, function () {
|
||||
addTag(datum["value"]);
|
||||
$scope.tagToAdd = "";
|
||||
});
|
||||
|
||||
}).bind("typeahead:opened", function (obj) {
|
||||
console.log("opened ");
|
||||
//console.log("opened ");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.TagsController" class="umb-editor umb-tags">
|
||||
|
||||
|
||||
<div ng-if="isLoading">
|
||||
Loading...
|
||||
</div>
|
||||
|
||||
<ng-form>
|
||||
<div ng-if="!isLoading">
|
||||
<span ng-repeat="tag in currentTags" ng-click="removeTag(tag)" class="label label-primary tag">{{tag}} <i class="icon icon-delete"></i></span>
|
||||
<div ng-if="!isLoading">
|
||||
<span ng-repeat="tag in currentTags" ng-click="removeTag(tag)" class="label label-primary tag">
|
||||
<span ng-bind-html="tag"></span>
|
||||
<i class="icon icon-delete"></i>
|
||||
</span>
|
||||
|
||||
<input type="text"
|
||||
class="typeahead tags-{{model.alias}}"
|
||||
ng-keydown="addTag($event)"
|
||||
placeholder="Type to add tags.."
|
||||
ng-model="tagToAdd" />
|
||||
</div>
|
||||
</ng-form>
|
||||
|
||||
<input type="text"
|
||||
class="typeahead tags-{{model.alias}}"
|
||||
ng-model="$parent.tagToAdd"
|
||||
ng-keydown="$parent.addTag($event)"
|
||||
placeholder="Type to add tags.." />
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<div >
|
||||
|
||||
<select name="dropDownList"
|
||||
class="umb-editor umb-dropdown"
|
||||
ng-model="model.value">
|
||||
<option>Csv</option>
|
||||
<option>Json</option>
|
||||
</select>
|
||||
|
||||
</div>
|
||||
+21
-1
@@ -31,7 +31,7 @@ describe('umbPhotoFolderHelper tests', function () {
|
||||
|
||||
});
|
||||
|
||||
it('Build a row by removing an item to scale up to fit', function () {
|
||||
it('Builds a row by removing an item to scale up to fit', function () {
|
||||
|
||||
var images = [
|
||||
{ "properties": [{ "id": 8737, "value": "/media/2173/Save-The-Date.jpg", "alias": "umbracoFile" }, { "id": 8738, "value": "443", "alias": "umbracoWidth" }, { "id": 8739, "value": "500", "alias": "umbracoHeight" }, { "id": 8740, "value": "30830", "alias": "umbracoBytes" }, { "id": 8741, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:56", "createDate": "2013-12-10 14:21:26", "published": false, "owner": { "id": 0, "name": "admin" }, "updator": null, "contentTypeAlias": "Image", "sortOrder": 5, "name": "Save-The-Date.jpg", "id": 1349, "icon": "mediaPhoto.gif", "key": "8eb67ae3-49da-4a25-ab39-185667a9b412", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1349", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 443, "originalHeight": 500 },
|
||||
@@ -52,6 +52,26 @@ describe('umbPhotoFolderHelper tests', function () {
|
||||
expect(result.images.length).toBe(4);
|
||||
|
||||
});
|
||||
|
||||
it('Builds a row by removing an item to scale up to fit, then attempts to upscale remaining 2 images, but that doesnt fit so drops another and we end up with one', function () {
|
||||
|
||||
var images = [
|
||||
{ "properties": [{ "id": 8737, "value": "/media/2173/Save-The-Date.jpg", "alias": "umbracoFile" }, { "id": 8738, "value": "198", "alias": "umbracoWidth" }, { "id": 8739, "value": "220", "alias": "umbracoHeight" }, { "id": 8740, "value": "30830", "alias": "umbracoBytes" }, { "id": 8741, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:56", "createDate": "2013-12-10 14:21:26", "published": false, "owner": { "id": 0, "name": "admin" }, "updator": null, "contentTypeAlias": "Image", "sortOrder": 5, "name": "Save-The-Date.jpg", "id": 1349, "icon": "mediaPhoto.gif", "key": "8eb67ae3-49da-4a25-ab39-185667a9b412", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1349", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 198, "originalHeight": 220 },
|
||||
{ "properties": [{ "id": 8742, "value": "/media/2174/IMG_2980.JPG", "alias": "umbracoFile" }, { "id": 8743, "value": "211", "alias": "umbracoWidth" }, { "id": 8744, "value": "500", "alias": "umbracoHeight" }, { "id": 8745, "value": "113311", "alias": "umbracoBytes" }, { "id": 8746, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:51", "createDate": "2013-12-10 14:22:33", "published": false, "owner": { "id": 0, "name": "admin" }, "updator": null, "contentTypeAlias": "Image", "sortOrder": 6, "name": "IMG_2980.JPG", "id": 1350, "icon": "mediaPhoto.gif", "key": "0a9618ea-9b4a-4d34-bf53-e76a0d252048", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1350", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1350", "originalWidth": 211, "originalHeight": 500 },
|
||||
{ "properties": [{ "id": 8747, "value": "/media/2175/IMG_3023.JPG", "alias": "umbracoFile" }, { "id": 8748, "value": "940", "alias": "umbracoWidth" }, { "id": 8749, "value": "317", "alias": "umbracoHeight" }, { "id": 8750, "value": "106365", "alias": "umbracoBytes" }, { "id": 8751, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:46", "createDate": "2013-12-10 14:39:28", "published": false, "owner": { "id": 0, "name": "admin" }, "updator": null, "contentTypeAlias": "Image", "sortOrder": 7, "name": "IMG_3023.JPG", "id": 1351, "icon": "mediaPhoto.gif", "key": "44cb1ee0-e3d7-40f7-b27c-ae05fb1a8e0c", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1351", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1351", "originalWidth": 940, "originalHeight": 317 }
|
||||
];
|
||||
var maxRowHeight = 250;
|
||||
var minDisplayHeight = 105;
|
||||
var maxRowWidth = 400;
|
||||
var idealImgPerRow = 3;
|
||||
var margin = 5;
|
||||
|
||||
var result = umbPhotoFolderHelper.buildRow(images, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
|
||||
|
||||
|
||||
expect(result.images.length).toBe(1);
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
@@ -2530,9 +2530,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7120</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7130</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7120</IISUrl>
|
||||
<IISUrl>http://localhost:7130</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
@@ -2564,7 +2564,10 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
</Target>
|
||||
<Target Name="BelleBuild" BeforeTargets="Rebuild">
|
||||
<!-- Only runs when a Rebuild is requested -->
|
||||
<Exec WorkingDirectory="$(ProjectDir)\..\..\build\" Command="BuildBelle.bat" ConsoleToMSBuild="true" IgnoreExitCode="true" ContinueOnError="WarnAndContinue" />
|
||||
<ReadLinesFromFile File="$(ProjectDir)\..\..\build\UmbracoVersion.txt">
|
||||
<Output TaskParameter="Lines" PropertyName="VersionNumber" />
|
||||
</ReadLinesFromFile>
|
||||
<Exec WorkingDirectory="$(ProjectDir)\..\..\build\" Command="BuildBelle.bat $(VersionNumber)" ConsoleToMSBuild="true" IgnoreExitCode="true" ContinueOnError="WarnAndContinue" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.10\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.10\tools\Microsoft.Bcl.Build.targets')" />
|
||||
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<!-- SlideShare Settings -->
|
||||
<provider name="SlideShare" type="Umbraco.Web.Media.EmbedProviders.OEmbedRich, umbraco">
|
||||
<urlShemeRegex><![CDATA[slideshare\.net/]]></urlShemeRegex>
|
||||
<apiEndpoint><![CDATA[http://www.slideshare.net/api/oembed/1]]></apiEndpoint>
|
||||
<apiEndpoint><![CDATA[http://www.slideshare.net/api/oembed/2]]></apiEndpoint>
|
||||
<requestParams type="Umbraco.Web.Media.EmbedProviders.Settings.Dictionary, umbraco">
|
||||
<param name="format">xml</param>
|
||||
</requestParams>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<!-- SlideShare Settings -->
|
||||
<provider name="SlideShare" type="Umbraco.Web.Media.EmbedProviders.OEmbedRich, umbraco">
|
||||
<urlShemeRegex><![CDATA[slideshare\.net/]]></urlShemeRegex>
|
||||
<apiEndpoint><![CDATA[http://www.slideshare.net/api/oembed/1]]></apiEndpoint>
|
||||
<apiEndpoint><![CDATA[http://www.slideshare.net/api/oembed/2]]></apiEndpoint>
|
||||
<requestParams type="Umbraco.Web.Media.EmbedProviders.Settings.Dictionary, umbraco">
|
||||
<param name="format">xml</param>
|
||||
</requestParams>
|
||||
|
||||
@@ -23,20 +23,7 @@
|
||||
$(".fileChooser input[type='text']").not(txt).val("");
|
||||
//reset other drop downs
|
||||
$(".fileChooser select").not($(this)).val("");
|
||||
});
|
||||
|
||||
//disable 'add macro property validators' when save or delete is clicked
|
||||
$("#body_save,.delete-button").click(function (evt) {
|
||||
$(".add-validator").each(function() {
|
||||
ValidatorEnable($(this).get(0), false);
|
||||
});
|
||||
});
|
||||
//enable the addmacro property validators when the add button is clicked
|
||||
$(".add-button").click(function(evt) {
|
||||
$(".add-validator").each(function () {
|
||||
ValidatorEnable($(this).get(0), true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
UmbClientMgr.appActions().bindSaveShortCut();
|
||||
|
||||
@@ -182,15 +169,15 @@
|
||||
<FooterTemplate>
|
||||
<tr>
|
||||
<td>
|
||||
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" CssClass="add-validator" runat="server" ControlToValidate="macroPropertyAliasNew" Display="Dynamic" ForeColor="#b94a48">Required<br/></asp:RequiredFieldValidator>
|
||||
<asp:TextBox runat="server" ID="macroPropertyAliasNew" PlaceHolder='New Alias' OnTextChanged="macroPropertyCreate" />
|
||||
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" EnableViewState="false" Enabled="false" EnableClientScript="false" runat="server" ControlToValidate="macroPropertyAliasNew" Display="Dynamic" ForeColor="#b94a48">Required<br/></asp:RequiredFieldValidator>
|
||||
<asp:TextBox runat="server" ID="macroPropertyAliasNew" PlaceHolder='New Alias' />
|
||||
</td>
|
||||
<td>
|
||||
<asp:RequiredFieldValidator ID="RequiredFieldValidator4" CssClass="add-validator" runat="server" ControlToValidate="macroPropertyNameNew" Display="Dynamic" ForeColor="#b94a48">Required<br/></asp:RequiredFieldValidator>
|
||||
<asp:RequiredFieldValidator ID="RequiredFieldValidator4" EnableViewState="false" Enabled="false" EnableClientScript="false" runat="server" ControlToValidate="macroPropertyNameNew" Display="Dynamic" ForeColor="#b94a48">Required<br/></asp:RequiredFieldValidator>
|
||||
<asp:TextBox runat="server" ID="macroPropertyNameNew" PlaceHolder='New Name' />
|
||||
</td>
|
||||
<td>
|
||||
<asp:RequiredFieldValidator ID="RequiredFieldValidator5" CssClass="add-validator" runat="server" ControlToValidate="macroPropertyTypeNew" Display="Dynamic" ForeColor="#b94a48">Required<br/></asp:RequiredFieldValidator>
|
||||
<asp:RequiredFieldValidator ID="RequiredFieldValidator5" EnableViewState="false" Enabled="false" EnableClientScript="false" runat="server" ControlToValidate="macroPropertyTypeNew" Display="Dynamic" ForeColor="#b94a48">Required<br/></asp:RequiredFieldValidator>
|
||||
<asp:DropDownList OnPreRender="AddChooseList" runat="server" ID="macroPropertyTypeNew"
|
||||
DataTextField="Name"
|
||||
DataValueField="Alias"
|
||||
@@ -198,7 +185,7 @@
|
||||
</asp:DropDownList>
|
||||
</td>
|
||||
<td>
|
||||
<asp:Button ID="createNew" Text="Add" runat="server" CssClass="btn btn-default add-button" />
|
||||
<asp:Button ID="createNew" Text="Add" runat="server" CssClass="btn btn-default add-button" OnClick="macroPropertyCreate" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -17,25 +17,30 @@ function duplicatePropertyNameAsSafeAlias(propertySelector) {
|
||||
var prop = $(this);
|
||||
var inputName = prop.find('.prop-name');
|
||||
var inputAlias = prop.find('.prop-alias');
|
||||
inputName.on('input', function (event) {
|
||||
inputName.on('input blur', function (event) {
|
||||
getSafeAlias(inputAlias, inputName.val(), false, function (alias) {
|
||||
inputAlias.val(alias);
|
||||
if (!inputAlias.data('dirty'))
|
||||
inputAlias.val(alias);
|
||||
});
|
||||
}).on('blur', function (event) {
|
||||
$(this).off('input');
|
||||
});
|
||||
inputAlias.on('input', function(event) {
|
||||
inputName.off('input blur');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function checkAlias(aliasSelector) {
|
||||
$(aliasSelector).keyup(function (event) {
|
||||
$(aliasSelector).on('input', function (event) {
|
||||
var input = $(this);
|
||||
input.data('dirty', true);
|
||||
var value = input.val();
|
||||
validateSafeAlias(input, value, false, function (isSafe) {
|
||||
input.toggleClass('highlight-error', !isSafe);
|
||||
});
|
||||
}).blur(function(event) {
|
||||
}).on('blur', function(event) {
|
||||
var input = $(this);
|
||||
if (!input.data('dirty')) return;
|
||||
input.removeData('dirty');
|
||||
var value = input.val();
|
||||
getSafeAlias(input, value, true, function (alias) {
|
||||
if (value.toLowerCase() != alias.toLowerCase())
|
||||
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Caching;
|
||||
using umbraco.interfaces;
|
||||
using System.Linq;
|
||||
|
||||
@@ -155,6 +156,7 @@ namespace Umbraco.Web.Cache
|
||||
|
||||
payloads.ForEach(payload =>
|
||||
{
|
||||
|
||||
//if there's no path, then just use id (this will occur on permanent deletion like emptying recycle bin)
|
||||
if (payload.Path.IsNullOrWhiteSpace())
|
||||
{
|
||||
@@ -165,6 +167,12 @@ namespace Umbraco.Web.Cache
|
||||
{
|
||||
foreach (var idPart in payload.Path.Split(','))
|
||||
{
|
||||
int idPartAsInt;
|
||||
if (int.TryParse(idPart, out idPartAsInt))
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IMedia), idPartAsInt);
|
||||
}
|
||||
|
||||
ApplicationContext.Current.ApplicationCache.ClearCacheByKeySearch(
|
||||
string.Format("{0}_{1}_True", CacheKeys.MediaCacheKey, idPart));
|
||||
|
||||
|
||||
@@ -3,22 +3,16 @@ using System.Web.Script.Serialization;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Models;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.Caching;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache refresher used for non-published content, this is primarily to notify Examine indexes to update
|
||||
/// A cache refresher used for non-published content, this is primarily to notify Examine indexes to update and to refresh the RuntimeCacheRefresher
|
||||
/// </summary>
|
||||
public sealed class UnpublishedPageCacheRefresher : TypedCacheRefresherBase<UnpublishedPageCacheRefresher, IContent>, IJsonCacheRefresher
|
||||
{
|
||||
|
||||
//NOTE: There is no functionality for this cache refresher, it is here simply to emit events on each server for which examine
|
||||
// binds to. We could put the Examine index functionality in here but we've kept it all in the ExamineEvents class so that all of
|
||||
// the logic is in one place. In the future we may put the examine logic in a cache refresher instead (that would make sense) but we'd
|
||||
// want to get this done before making more cache refreshers:
|
||||
// http://issues.umbraco.org/issue/U4-2633
|
||||
|
||||
protected override UnpublishedPageCacheRefresher Instance
|
||||
{
|
||||
get { return this; }
|
||||
@@ -78,12 +72,48 @@ namespace Umbraco.Web.Cache
|
||||
|
||||
#endregion
|
||||
|
||||
public override void RefreshAll()
|
||||
{
|
||||
RuntimeCacheProvider.Current.Clear(typeof(IContent));
|
||||
base.RefreshAll();
|
||||
}
|
||||
|
||||
public override void Refresh(int id)
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), id);
|
||||
base.Refresh(id);
|
||||
}
|
||||
|
||||
public override void Remove(int id)
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), id);
|
||||
base.Remove(id);
|
||||
}
|
||||
|
||||
|
||||
public override void Refresh(IContent instance)
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), instance.Id);
|
||||
base.Refresh(instance);
|
||||
}
|
||||
|
||||
public override void Remove(IContent instance)
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), instance.Id);
|
||||
base.Remove(instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement the IJsonCacheRefresher so that we can bulk delete the cache based on multiple IDs for when the recycle bin is emptied
|
||||
/// </summary>
|
||||
/// <param name="jsonPayload"></param>
|
||||
public void Refresh(string jsonPayload)
|
||||
{
|
||||
foreach (var payload in DeserializeFromJsonPayload(jsonPayload))
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), payload.Id);
|
||||
}
|
||||
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Helpers;
|
||||
using System.Web.Http;
|
||||
@@ -59,18 +60,14 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public HttpResponseMessage IsAuthenticated()
|
||||
public bool IsAuthenticated()
|
||||
{
|
||||
var attempt = UmbracoContext.Security.AuthorizeRequest();
|
||||
if (attempt == ValidateRequestAttempt.Success)
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
//return BadRequest (400), we don't want to return a 401 because that get's intercepted
|
||||
// by our angular helper because it thinks that we need to re-perform the request once we are
|
||||
// authorized and we don't want to return a 403 because angular will show a warning msg indicating
|
||||
// that the user doesn't have access to perform this function, we just want to return a normal invalid msg.
|
||||
return Request.CreateResponse(HttpStatusCode.BadRequest);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,15 +43,15 @@ namespace Umbraco.Web.Editors
|
||||
LogHelper.Error<TagExtractor>("Could not create custom " + attribute.TagPropertyDefinitionType + " tag definition", ex);
|
||||
throw;
|
||||
}
|
||||
SetPropertyTags(content, property, convertedPropertyValue, def.Delimiter, def.ReplaceTags, def.TagGroup, attribute.ValueType);
|
||||
SetPropertyTags(content, property, convertedPropertyValue, def.Delimiter, def.ReplaceTags, def.TagGroup, attribute.ValueType, def.StorageType);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPropertyTags(content, property, convertedPropertyValue, attribute.Delimiter, attribute.ReplaceTags, attribute.TagGroup, attribute.ValueType);
|
||||
SetPropertyTags(content, property, convertedPropertyValue, attribute.Delimiter, attribute.ReplaceTags, attribute.TagGroup, attribute.ValueType, attribute.StorageType);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetPropertyTags(IContentBase content, Property property, object convertedPropertyValue, string delimiter, bool replaceTags, string tagGroup, TagValueType valueType)
|
||||
public static void SetPropertyTags(IContentBase content, Property property, object convertedPropertyValue, string delimiter, bool replaceTags, string tagGroup, TagValueType valueType, TagCacheStorageType storageType)
|
||||
{
|
||||
if (convertedPropertyValue == null)
|
||||
{
|
||||
@@ -62,14 +62,14 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
case TagValueType.FromDelimitedValue:
|
||||
var tags = convertedPropertyValue.ToString().Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries);
|
||||
content.SetTags(property.Alias, tags, replaceTags, tagGroup);
|
||||
content.SetTags(storageType, property.Alias, tags, replaceTags, tagGroup);
|
||||
break;
|
||||
case TagValueType.CustomTagList:
|
||||
//for this to work the object value must be IENumerable<string>
|
||||
var stringList = convertedPropertyValue as IEnumerable<string>;
|
||||
if (stringList != null)
|
||||
{
|
||||
content.SetTags(property.Alias, stringList, replaceTags, tagGroup);
|
||||
content.SetTags(storageType, property.Alias, stringList, replaceTags, tagGroup);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ using System;
|
||||
using System.Globalization;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
using umbraco;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
@@ -10,28 +12,64 @@ using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
//NOTE: all of these require an UmbracoContext because currently to send the notifications we need an HttpContext, this is based on legacy code
|
||||
// for which probably requires updating so that these can be sent outside of the http context.
|
||||
|
||||
internal static class NotificationServiceExtensions
|
||||
{
|
||||
internal static void SendNotification(this INotificationService service, IUmbracoEntity entity, IAction action, ApplicationContext applicationContext)
|
||||
{
|
||||
if (global::Umbraco.Web.UmbracoContext.Current == null) return;
|
||||
service.SendNotification(entity, action, global::Umbraco.Web.UmbracoContext.Current);
|
||||
if (UmbracoContext.Current == null)
|
||||
{
|
||||
LogHelper.Warn(typeof(NotificationServiceExtensions), "Cannot send notifications, there is no current UmbracoContext");
|
||||
return;
|
||||
}
|
||||
service.SendNotification(entity, action, UmbracoContext.Current);
|
||||
}
|
||||
|
||||
internal static void SendNotification(this INotificationService service, IUmbracoEntity entity, IAction action, UmbracoContext umbracoContext)
|
||||
{
|
||||
if (umbracoContext == null) return;
|
||||
if (umbracoContext == null)
|
||||
{
|
||||
LogHelper.Warn(typeof(NotificationServiceExtensions), "Cannot send notifications, there is no current UmbracoContext");
|
||||
return;
|
||||
}
|
||||
service.SendNotification(entity, action, umbracoContext, umbracoContext.Application);
|
||||
}
|
||||
|
||||
internal static void SendNotification(this INotificationService service, IUmbracoEntity entity, IAction action, UmbracoContext umbracoContext, ApplicationContext applicationContext)
|
||||
{
|
||||
if (umbracoContext == null)
|
||||
{
|
||||
LogHelper.Warn(typeof(NotificationServiceExtensions), "Cannot send notifications, there is no current UmbracoContext");
|
||||
return;
|
||||
}
|
||||
|
||||
var user = umbracoContext.Security.CurrentUser;
|
||||
|
||||
//if there is no current user, then use the admin
|
||||
if (user == null)
|
||||
{
|
||||
LogHelper.Warn(typeof(NotificationServiceExtensions), "There is no current Umbraco user logged in, the notifications will be sent from the administrator");
|
||||
user = applicationContext.Services.UserService.GetUserById(0);
|
||||
if (user == null)
|
||||
{
|
||||
LogHelper.Warn(typeof(NotificationServiceExtensions), "Noticiations can not be sent, no admin user with id 0 could be resolved");
|
||||
return;
|
||||
}
|
||||
}
|
||||
service.SendNotification(user, entity, action, umbracoContext, applicationContext);
|
||||
}
|
||||
|
||||
internal static void SendNotification(this INotificationService service, IUser sender, IUmbracoEntity entity, IAction action, UmbracoContext umbracoContext, ApplicationContext applicationContext)
|
||||
{
|
||||
if (sender == null) throw new ArgumentNullException("sender");
|
||||
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
|
||||
if (applicationContext == null) throw new ArgumentNullException("applicationContext");
|
||||
|
||||
var user = umbracoContext.Security.CurrentUser;
|
||||
|
||||
applicationContext.Services.NotificationService.SendNotifications(
|
||||
user,
|
||||
sender,
|
||||
entity,
|
||||
action.Letter.ToString(CultureInfo.InvariantCulture),
|
||||
ui.Text("actions", action.Alias),
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using System;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to dynamically change the tag group based on the pre-values
|
||||
/// Used to dynamically change the tag group and storage type based on the pre-values
|
||||
/// </summary>
|
||||
internal class TagPropertyEditorTagDefinition : TagPropertyDefinition
|
||||
{
|
||||
@@ -21,5 +24,16 @@ namespace Umbraco.Web.PropertyEditors
|
||||
return preVals.ContainsKey("group") ? preVals["group"].Value : "default";
|
||||
}
|
||||
}
|
||||
|
||||
public override TagCacheStorageType StorageType
|
||||
{
|
||||
get
|
||||
{
|
||||
var preVals = PropertySaving.PreValues.FormatAsDictionary();
|
||||
return preVals.ContainsKey("storageType")
|
||||
? Enum<TagCacheStorageType>.Parse(preVals["storageType"].Value)
|
||||
: TagCacheStorageType.Csv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Editors;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[SupportTags(typeof(TagPropertyEditorTagDefinition))]
|
||||
[SupportTags(typeof(TagPropertyEditorTagDefinition), ValueType = TagValueType.CustomTagList)]
|
||||
[PropertyEditor(Constants.PropertyEditors.TagsAlias, "Tags", "tags")]
|
||||
public class TagsPropertyEditor : PropertyEditor
|
||||
{
|
||||
@@ -12,7 +17,8 @@ namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
_defaultPreVals = new Dictionary<string, object>
|
||||
{
|
||||
{"group", "default"}
|
||||
{"group", "default"},
|
||||
{"storageType", TagCacheStorageType.Csv.ToString()}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,11 +33,36 @@ namespace Umbraco.Web.PropertyEditors
|
||||
set { _defaultPreVals = value; }
|
||||
}
|
||||
|
||||
protected override PropertyValueEditor CreateValueEditor()
|
||||
{
|
||||
return new TagPropertyValueEditor(base.CreateValueEditor());
|
||||
}
|
||||
|
||||
protected override PreValueEditor CreatePreValueEditor()
|
||||
{
|
||||
return new TagPreValueEditor();
|
||||
}
|
||||
|
||||
internal class TagPropertyValueEditor : PropertyValueEditorWrapper
|
||||
{
|
||||
public TagPropertyValueEditor(PropertyValueEditor wrapped)
|
||||
: base(wrapped)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This needs to return IEnumerable{string}
|
||||
/// </summary>
|
||||
/// <param name="editorValue"></param>
|
||||
/// <param name="currentValue"></param>
|
||||
/// <returns></returns>
|
||||
public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
|
||||
{
|
||||
var json = editorValue.Value as JArray;
|
||||
return json == null ? null : json.Select(x => x.Value<string>());
|
||||
}
|
||||
}
|
||||
|
||||
internal class TagPreValueEditor : PreValueEditor
|
||||
{
|
||||
public TagPreValueEditor()
|
||||
@@ -43,11 +74,26 @@ namespace Umbraco.Web.PropertyEditors
|
||||
Name = "Tag group",
|
||||
View = "requiredfield"
|
||||
});
|
||||
|
||||
Fields.Add(new PreValueField(new ManifestPropertyValidator {Type = "Required"})
|
||||
{
|
||||
Description = "Select whether to store the tags in cache as CSV (default) or as JSON. The only benefits of storage as JSON is that you are able to have commas in a tag value but this will require parsing the json in your views or using a property value converter",
|
||||
Key = "storageType",
|
||||
Name = "Storage Type",
|
||||
View = "views/propertyeditors/tags/tags.prevalues.html"
|
||||
});
|
||||
}
|
||||
|
||||
public override IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, Core.Models.PreValueCollection persistedPreVals)
|
||||
public override IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
|
||||
{
|
||||
var result = base.ConvertDbToEditor(defaultPreVals, persistedPreVals);
|
||||
|
||||
//This is required because we've added this pre-value so old installs that don't have it will need to have a default.
|
||||
if (result.ContainsKey("storageType") == false || result["storageType"] == null || result["storageType"].ToString().IsNullOrWhiteSpace())
|
||||
{
|
||||
result["storageType"] = TagCacheStorageType.Csv.ToString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Umbraco.Web.WebServices
|
||||
public class CoreStringsController : UmbracoAuthorizedController
|
||||
{
|
||||
[HttpGet]
|
||||
[ValidateInput(false)]
|
||||
public JsonResult ToSafeAlias(string value, bool camelCase = true)
|
||||
{
|
||||
// always return a proper camel-cased alias
|
||||
|
||||
@@ -85,31 +85,32 @@ namespace umbraco
|
||||
var rval = pval == null ? string.Empty : pval.ToString();
|
||||
_fieldContent = rval.IsNullOrWhiteSpace() ? _fieldContent : rval;
|
||||
}
|
||||
else if (elements[_fieldName] != null && string.IsNullOrEmpty(elements[_fieldName].ToString()) == false)
|
||||
{
|
||||
else
|
||||
{
|
||||
//get the vaue the legacy way (this will not parse locallinks, etc... since that is handled with ipublishedcontent)
|
||||
_fieldContent = elements[_fieldName].ToString().Trim();
|
||||
var elt = elements[_fieldName];
|
||||
if (elt != null && string.IsNullOrEmpty(elt.ToString()) == false)
|
||||
_fieldContent = elt.ToString().Trim();
|
||||
}
|
||||
|
||||
//now we check if the value is still empty and if so we'll check useIfEmpty
|
||||
if (string.IsNullOrEmpty(_fieldContent))
|
||||
{
|
||||
//if useIfEmpty is true
|
||||
if (string.IsNullOrEmpty(helper.FindAttribute(attributes, "useIfEmpty")) == false)
|
||||
var altFieldName = helper.FindAttribute(attributes, "useIfEmpty");
|
||||
if (string.IsNullOrEmpty(altFieldName) == false)
|
||||
{
|
||||
var altFieldName = helper.FindAttribute(attributes, "useIfEmpty");
|
||||
|
||||
//check for published content and get its value using that
|
||||
if (publishedContent != null && publishedContent.HasProperty(altFieldName))
|
||||
{
|
||||
var pval = publishedContent.GetPropertyValue(altFieldName);
|
||||
var rval = pval == null ? string.Empty : pval.ToString();
|
||||
_fieldContent = rval.IsNullOrWhiteSpace() ? _fieldContent : rval;
|
||||
}
|
||||
else if (elements[altFieldName] != null && string.IsNullOrEmpty(elements[altFieldName].ToString()) == false)
|
||||
else
|
||||
{
|
||||
//get the vaue the legacy way (this will not parse locallinks, etc... since that is handled with ipublishedcontent)
|
||||
_fieldContent = elements[altFieldName].ToString().Trim();
|
||||
var elt = elements[altFieldName];
|
||||
if (elt != null && string.IsNullOrEmpty(elt.ToString()) == false)
|
||||
_fieldContent = elt.ToString().Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,6 +342,9 @@ namespace umbraco
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.WarnWithException<macro>(
|
||||
"Error loading partial view macro (View: " + Model.ScriptName + ")", true, e);
|
||||
|
||||
renderFailed = true;
|
||||
Exceptions.Add(e);
|
||||
macroControl = handleError(e);
|
||||
@@ -1666,6 +1669,12 @@ namespace umbraco
|
||||
|
||||
public static string MacroContentByHttp(int PageID, Guid PageVersion, Hashtable attributes)
|
||||
{
|
||||
|
||||
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted)
|
||||
{
|
||||
return "<span style='color: red'>Cannot render macro content in the rich text editor when the application is running in a Partial Trust environment</span>";
|
||||
}
|
||||
|
||||
string tempAlias = (attributes["macroalias"] != null)
|
||||
? attributes["macroalias"].ToString()
|
||||
: attributes["macroAlias"].ToString();
|
||||
|
||||
@@ -39,9 +39,8 @@ namespace umbraco.cms.presentation.developer
|
||||
{
|
||||
_macro = Services.MacroService.GetById(Convert.ToInt32(Request.QueryString["macroID"]));
|
||||
|
||||
if (!IsPostBack)
|
||||
if (IsPostBack == false)
|
||||
{
|
||||
|
||||
ClientTools
|
||||
.SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree<loadMacros>().Tree.Alias)
|
||||
.SyncTree("-1,init," + _macro.Id.ToString(), false);
|
||||
@@ -77,57 +76,6 @@ namespace umbraco.cms.presentation.developer
|
||||
userControlList.Items.Insert(0, new ListItem("Browse usercontrols on server...", string.Empty));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Page.Validate();
|
||||
|
||||
ClientTools
|
||||
.SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree<loadMacros>().Tree.Alias)
|
||||
.SyncTree("-1,init," + _macro.Id.ToInvariantString(), true); //true forces the reload
|
||||
|
||||
var tempMacroAssembly = macroAssembly.Text;
|
||||
var tempMacroType = macroType.Text;
|
||||
var tempCachePeriod = cachePeriod.Text;
|
||||
if (tempCachePeriod == string.Empty)
|
||||
tempCachePeriod = "0";
|
||||
if (tempMacroAssembly == string.Empty && macroUserControl.Text != string.Empty)
|
||||
tempMacroType = macroUserControl.Text;
|
||||
|
||||
SetMacroValuesFromPostBack(_macro, Convert.ToInt32(tempCachePeriod), tempMacroAssembly, tempMacroType);
|
||||
|
||||
// Save elements
|
||||
var sort = 0;
|
||||
foreach (RepeaterItem item in macroProperties.Items)
|
||||
{
|
||||
var macroPropertyId = (HtmlInputHidden)item.FindControl("macroPropertyID");
|
||||
var macroElementName = (TextBox)item.FindControl("macroPropertyName");
|
||||
var macroElementAlias = (TextBox)item.FindControl("macroPropertyAlias");
|
||||
var macroElementType = (DropDownList)item.FindControl("macroPropertyType");
|
||||
|
||||
var prop = _macro.Properties.Single(x => x.Id == int.Parse(macroPropertyId.Value));
|
||||
prop.Alias = macroElementAlias.Text.Trim();
|
||||
prop.Name = macroElementName.Text.Trim();
|
||||
prop.EditorAlias = macroElementType.SelectedValue;
|
||||
prop.SortOrder = sort;
|
||||
sort++;
|
||||
}
|
||||
|
||||
Services.MacroService.Save(_macro);
|
||||
|
||||
ClientTools.ShowSpeechBubble(speechBubbleIcon.save, "Macro saved", "");
|
||||
|
||||
// Check for assemblyBrowser
|
||||
if (tempMacroType.IndexOf(".ascx", StringComparison.Ordinal) > 0)
|
||||
assemblyBrowserUserControl.Controls.Add(
|
||||
new LiteralControl("<br/><button onClick=\"UmbClientMgr.openModalWindow('developer/macros/assemblyBrowser.aspx?fileName=" + macroUserControl.Text +
|
||||
"¯oID=" + Request.QueryString["macroID"] +
|
||||
"', 'Browse Properties', true, 500, 475); return false\" class=\"guiInputButton\"><img src=\"../../images/editor/propertiesNew.gif\" align=\"absmiddle\" style=\"width: 18px; height: 17px; padding-right: 5px;\"/> Browse properties</button>"));
|
||||
else if (tempMacroType != string.Empty && tempMacroAssembly != string.Empty)
|
||||
assemblyBrowser.Controls.Add(
|
||||
new LiteralControl("<br/><button onClick=\"UmbClientMgr.openModalWindow('developer/macros/assemblyBrowser.aspx?fileName=" + macroAssembly.Text +
|
||||
"¯oID=" + Request.QueryString["macroID"] + "&type=" + macroType.Text +
|
||||
"', 'Browse Properties', true, 500, 475); return false\" class=\"guiInputButton\"><img src=\"../../images/editor/propertiesNew.gif\" align=\"absmiddle\" style=\"width: 18px; height: 17px; padding-right: 5px;\"/> Browse properties</button>"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -267,7 +215,17 @@ namespace umbraco.cms.presentation.developer
|
||||
}
|
||||
|
||||
public void macroPropertyCreate(object sender, EventArgs e)
|
||||
{
|
||||
{
|
||||
//enable add validators
|
||||
var val1 = (RequiredFieldValidator)((Control)sender).Parent.FindControl("RequiredFieldValidator1");
|
||||
var val2 = (RequiredFieldValidator)((Control)sender).Parent.FindControl("RequiredFieldValidator4");
|
||||
var val3 = (RequiredFieldValidator)((Control)sender).Parent.FindControl("RequiredFieldValidator5");
|
||||
val1.Enabled = true;
|
||||
val2.Enabled = true;
|
||||
val3.Enabled = true;
|
||||
|
||||
Page.Validate();
|
||||
|
||||
if (Page.IsValid == false)
|
||||
{
|
||||
return;
|
||||
@@ -336,25 +294,90 @@ namespace umbraco.cms.presentation.developer
|
||||
}
|
||||
|
||||
protected override void OnInit(EventArgs e)
|
||||
{
|
||||
// Tab setup
|
||||
InfoTabPage = TabView1.NewTabPage("Macro Properties");
|
||||
InfoTabPage.Controls.Add(Pane1);
|
||||
InfoTabPage.Controls.Add(Pane1_2);
|
||||
InfoTabPage.Controls.Add(Pane1_3);
|
||||
InfoTabPage.Controls.Add(Pane1_4);
|
||||
{
|
||||
base.OnInit(e);
|
||||
EnsureChildControls();
|
||||
}
|
||||
|
||||
Parameters = TabView1.NewTabPage("Parameters");
|
||||
Parameters.Controls.Add(Panel2);
|
||||
protected override void CreateChildControls()
|
||||
{
|
||||
base.CreateChildControls();
|
||||
|
||||
// Tab setup
|
||||
InfoTabPage = TabView1.NewTabPage("Macro Properties");
|
||||
InfoTabPage.Controls.Add(Pane1);
|
||||
InfoTabPage.Controls.Add(Pane1_2);
|
||||
InfoTabPage.Controls.Add(Pane1_3);
|
||||
InfoTabPage.Controls.Add(Pane1_4);
|
||||
|
||||
Parameters = TabView1.NewTabPage("Parameters");
|
||||
Parameters.Controls.Add(Panel2);
|
||||
|
||||
MenuButton save = TabView1.Menu.NewButton();
|
||||
save.ButtonType = MenuButtonType.Primary;
|
||||
save.Text = ui.Text("save");
|
||||
save.ID = "save";
|
||||
base.OnInit(e);
|
||||
}
|
||||
save.Click += Save_Click;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
void Save_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
Page.Validate();
|
||||
|
||||
ClientTools
|
||||
.SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree<loadMacros>().Tree.Alias)
|
||||
.SyncTree("-1,init," + _macro.Id.ToInvariantString(), true); //true forces the reload
|
||||
|
||||
var tempMacroAssembly = macroAssembly.Text;
|
||||
var tempMacroType = macroType.Text;
|
||||
var tempCachePeriod = cachePeriod.Text;
|
||||
if (tempCachePeriod == string.Empty)
|
||||
tempCachePeriod = "0";
|
||||
if (tempMacroAssembly == string.Empty && macroUserControl.Text != string.Empty)
|
||||
tempMacroType = macroUserControl.Text;
|
||||
|
||||
SetMacroValuesFromPostBack(_macro, Convert.ToInt32(tempCachePeriod), tempMacroAssembly, tempMacroType);
|
||||
|
||||
// Save elements
|
||||
var sort = 0;
|
||||
foreach (RepeaterItem item in macroProperties.Items)
|
||||
{
|
||||
var macroPropertyId = (HtmlInputHidden)item.FindControl("macroPropertyID");
|
||||
var macroElementName = (TextBox)item.FindControl("macroPropertyName");
|
||||
var macroElementAlias = (TextBox)item.FindControl("macroPropertyAlias");
|
||||
var macroElementType = (DropDownList)item.FindControl("macroPropertyType");
|
||||
|
||||
var prop = _macro.Properties.Single(x => x.Id == int.Parse(macroPropertyId.Value));
|
||||
|
||||
_macro.Properties.UpdateProperty(
|
||||
prop.Alias,
|
||||
macroElementName.Text.Trim(),
|
||||
sort,
|
||||
macroElementType.SelectedValue,
|
||||
macroElementAlias.Text.Trim());
|
||||
|
||||
sort++;
|
||||
}
|
||||
|
||||
Services.MacroService.Save(_macro);
|
||||
|
||||
ClientTools.ShowSpeechBubble(speechBubbleIcon.save, "Macro saved", "");
|
||||
|
||||
// Check for assemblyBrowser
|
||||
if (tempMacroType.IndexOf(".ascx", StringComparison.Ordinal) > 0)
|
||||
assemblyBrowserUserControl.Controls.Add(
|
||||
new LiteralControl("<br/><button onClick=\"UmbClientMgr.openModalWindow('developer/macros/assemblyBrowser.aspx?fileName=" + macroUserControl.Text +
|
||||
"¯oID=" + Request.QueryString["macroID"] +
|
||||
"', 'Browse Properties', true, 500, 475); return false\" class=\"guiInputButton\"><img src=\"../../images/editor/propertiesNew.gif\" align=\"absmiddle\" style=\"width: 18px; height: 17px; padding-right: 5px;\"/> Browse properties</button>"));
|
||||
else if (tempMacroType != string.Empty && tempMacroAssembly != string.Empty)
|
||||
assemblyBrowser.Controls.Add(
|
||||
new LiteralControl("<br/><button onClick=\"UmbClientMgr.openModalWindow('developer/macros/assemblyBrowser.aspx?fileName=" + macroAssembly.Text +
|
||||
"¯oID=" + Request.QueryString["macroID"] + "&type=" + macroType.Text +
|
||||
"', 'Browse Properties', true, 500, 475); return false\" class=\"guiInputButton\"><img src=\"../../images/editor/propertiesNew.gif\" align=\"absmiddle\" style=\"width: 18px; height: 17px; padding-right: 5px;\"/> Browse properties</button>"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TabView1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
||||
@@ -551,7 +551,13 @@ namespace umbraco.NodeFactory
|
||||
{
|
||||
if (HttpContext.Current.Items["pageID"] == null)
|
||||
throw new InvalidOperationException("There is no current node.");
|
||||
return (int)HttpContext.Current.Items["pageID"];
|
||||
|
||||
var intAttempt = HttpContext.Current.Items["pageID"].TryConvertTo<int>();
|
||||
if (intAttempt == false)
|
||||
{
|
||||
throw new InvalidOperationException("The pageID value in the HttpContext.Items cannot be converted to an integer");
|
||||
}
|
||||
return intAttempt.Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -887,7 +887,7 @@ namespace umbraco.MacroEngines
|
||||
//this is from SqlMetal and just makes it a bit of fun to allow pluralisation
|
||||
private static string MakePluralName(string name)
|
||||
{
|
||||
if ((name.EndsWith("x", StringComparison.OrdinalIgnoreCase) || name.EndsWith("ch", StringComparison.OrdinalIgnoreCase)) || (name.EndsWith("ss", StringComparison.OrdinalIgnoreCase) || name.EndsWith("sh", StringComparison.OrdinalIgnoreCase)))
|
||||
if ((name.EndsWith("x", StringComparison.OrdinalIgnoreCase) || name.EndsWith("ch", StringComparison.OrdinalIgnoreCase)) || (name.EndsWith("s", StringComparison.OrdinalIgnoreCase) || name.EndsWith("sh", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
name = name + "es";
|
||||
return name;
|
||||
|
||||
Reference in New Issue
Block a user