Compare commits
91 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 03b60d4923 | |||
| 27e96d6d5b | |||
| d2b4345773 | |||
| c5bbf97921 | |||
| 19e4fe5059 | |||
| 311d503d8b | |||
| f0fc3313e4 | |||
| dc7cb08824 | |||
| 5ddcf42bc3 | |||
| af112f6b20 | |||
| cbef51eaf0 | |||
| 85ba41dd06 | |||
| e5cf7b089c | |||
| 5fae61b196 | |||
| db5c204d8c | |||
| b9082cf390 | |||
| 9469b0b844 | |||
| 5737cdfbe2 | |||
| 1a082464e9 | |||
| e004ad31b5 | |||
| 6cf25f0043 | |||
| c0f50a4c1b | |||
| 00fbc6dfcb | |||
| 3a9ad91f8f | |||
| c2cfd26ee6 | |||
| c5f26c7c15 | |||
| f742c0a958 | |||
| 8cefe22bee | |||
| fad3599f50 | |||
| 37b219f6e1 | |||
| 4e9667a067 | |||
| 300a46f1b2 | |||
| 9aa5df43bf | |||
| 02b0e4dd6a | |||
| 9c1d3fabb8 | |||
| e9e84a7faa | |||
| 137d8553de | |||
| 7210c6cd95 | |||
| 6856f9f341 | |||
| d24ef3650e | |||
| 2feef247ed | |||
| 4974e2a2ce | |||
| 3eb0dac48a | |||
| a44b19da18 | |||
| 3ee4234968 | |||
| f06a468fb4 | |||
| 420c334af4 | |||
| 20b21c86ea | |||
| d2083673be | |||
| fe40b8fe99 | |||
| dd477a0cbe | |||
| 2834ccdc2b | |||
| b3f6f48834 | |||
| 4544520b66 | |||
| 017663833a | |||
| 9a5923771d | |||
| 0932c980e9 | |||
| 7e9261d4bc | |||
| 0ce503b369 | |||
| 6d5d8fb39c | |||
| 9613772036 | |||
| 604779667d | |||
| 46212904ef | |||
| b7bb98d824 | |||
| f31d2ca7cf | |||
| 88ae95150e | |||
| 97a085d12b | |||
| 74d0ec949d | |||
| 9a042fbbdf | |||
| 834b780d8e | |||
| 8905878a87 | |||
| 36bed40db0 | |||
| f708a24401 | |||
| d32cf12c6f | |||
| 100485f748 | |||
| 56017a340c | |||
| 21c70462c9 | |||
| 9b254f8bf9 | |||
| 6dd63e8a01 | |||
| bac940d4ed | |||
| c1c090faab | |||
| 32bedfaa6a | |||
| b003c027e5 | |||
| 0295aaba3b | |||
| bb04f83a49 | |||
| 793ba42f9e | |||
| ded1def8e2 | |||
| 5a2a3c3b1e | |||
| 6f2fa2ed4d | |||
| 9c8e6ab864 | |||
| fec70fcf47 |
+2
-1
@@ -29,8 +29,9 @@ SET nuGetFolder=%CD%\..\src\packages\
|
||||
..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder%
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder%
|
||||
|
||||
ECHO Removing the belle build folder to make sure everything is clean as a whistle
|
||||
ECHO Removing the belle build folder and bower_components folder to make sure everything is clean as a whistle
|
||||
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
|
||||
RD ..\src\Umbraco.Web.UI.Client\bower_components /Q /S
|
||||
|
||||
ECHO Removing existing built files to make sure everything is clean as a whistle
|
||||
RMDIR /Q /S _BuildOutput
|
||||
|
||||
+1
-1
@@ -327,7 +327,7 @@
|
||||
ReplacementText="$(BUILD_RELEASE)"/>
|
||||
|
||||
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="CurrentComment { get { return "([a-zA-Z]+)?""
|
||||
Regex="CurrentComment { get { return "(.+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)""/>
|
||||
|
||||
<XmlPoke XmlInputPath=".\NuSpecs\build\UmbracoCms.props"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
|
||||
<dependency id="MySql.Data" version="[6.6.5]" />
|
||||
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.8.2.1, 2.0.0)" />
|
||||
<dependency id="ClientDependency" version="[1.8.3.1, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
|
||||
|
||||
@@ -63,7 +63,6 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\MySql.Data.dll) { Remove-Item $umbracoBinFolder\MySql.Data.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.Helpers.dll) { Remove-Item $umbracoBinFolder\System.Web.Helpers.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.Http.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.Http.WebHost.dll) { Remove-Item $umbracoBinFolder\System.Web.Http.WebHost.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.Mvc.dll) { Remove-Item $umbracoBinFolder\System.Web.Mvc.dll -Force -Confirm:$false }
|
||||
|
||||
@@ -47,85 +47,31 @@ if ($project) {
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
}
|
||||
|
||||
$copyWebconfig = $false
|
||||
|
||||
# SJ - What can I say: big up for James Newton King for teaching us a hack for detecting if this is a new install vs. an upgrade!
|
||||
# https://github.com/JamesNK/Newtonsoft.Json/pull/387 - would never have seen this without the controversial pull request..
|
||||
Try
|
||||
$copyWebconfig = $true
|
||||
$destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
|
||||
|
||||
if(Test-Path $destinationWebConfig)
|
||||
{
|
||||
# see if user is installing from VS NuGet console
|
||||
# get reference to the window, the console host and the input history
|
||||
# copy web.config if "install-package UmbracoCms" was last input
|
||||
# this is in a try-catch as they might be using the regular NuGet dialog
|
||||
# instead of package manager console
|
||||
|
||||
$dte2 = Get-Interface $dte ([EnvDTE80.DTE2])
|
||||
|
||||
$consoleWindow = $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow])
|
||||
Try
|
||||
{
|
||||
[xml]$config = Get-Content $destinationWebConfig
|
||||
|
||||
$props = $consoleWindow.GetType().GetProperties([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
|
||||
|
||||
$prop = $props | ? { $_.Name -eq "ActiveHostInfo" } | select -first 1
|
||||
|
||||
$hostInfo = $prop.GetValue($consoleWindow)
|
||||
|
||||
$history = $hostInfo.WpfConsole.InputHistory.History
|
||||
|
||||
$lastCommand = $history | select -last 1
|
||||
|
||||
if ($lastCommand)
|
||||
{
|
||||
$lastCommand = $lastCommand.Trim().ToLower()
|
||||
if ($lastCommand.StartsWith("install-package") -and $lastCommand.Contains("umbracocms"))
|
||||
{
|
||||
$copyWebconfig = $true
|
||||
$config.configuration.appSettings.ChildNodes | ForEach-Object {
|
||||
if($_.key -eq "umbracoConfigurationStatus")
|
||||
{
|
||||
# The web.config has an umbraco-specific appSetting in it
|
||||
# don't overwrite it and let config transforms do their thing
|
||||
$copyWebconfig = $false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch { }
|
||||
}
|
||||
Catch { }
|
||||
|
||||
Try
|
||||
{
|
||||
# user is installing from VS NuGet dialog
|
||||
# get reference to the window, then smart output console provider
|
||||
# copy web.config if messages in buffered console contains "installing...UmbracoCms" in last operation
|
||||
|
||||
$instanceField = [NuGet.Dialog.PackageManagerWindow].GetField("CurrentInstance", [System.Reflection.BindingFlags]::Static -bor [System.Reflection.BindingFlags]::NonPublic)
|
||||
$consoleField = [NuGet.Dialog.PackageManagerWindow].GetField("_smartOutputConsoleProvider", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
|
||||
|
||||
$instance = $instanceField.GetValue($null)
|
||||
|
||||
$consoleProvider = $consoleField.GetValue($instance)
|
||||
|
||||
$console = $consoleProvider.CreateOutputConsole($false)
|
||||
|
||||
$messagesField = $console.GetType().GetField("_messages", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
|
||||
|
||||
$messages = $messagesField.GetValue($console)
|
||||
|
||||
$operations = $messages -split "=============================="
|
||||
|
||||
$lastOperation = $operations | select -last 1
|
||||
|
||||
if ($lastOperation)
|
||||
{
|
||||
$lastOperation = $lastOperation.ToLower()
|
||||
$lines = $lastOperation -split "`r`n"
|
||||
$installMatch = $lines | ? { $_.Contains("...umbracocms ") } | select -first 1
|
||||
|
||||
if ($installMatch)
|
||||
{
|
||||
$copyWebconfig = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
Catch { }
|
||||
|
||||
if($copyWebconfig -eq $true)
|
||||
{
|
||||
$packageWebConfigSource = Join-Path $rootPath "UmbracoFiles\Web.config"
|
||||
$destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
|
||||
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.2.2
|
||||
7.2.4
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <summary>
|
||||
/// Extensions for strongly typed access
|
||||
/// </summary>
|
||||
internal static class CacheProviderExtensions
|
||||
public static class CacheProviderExtensions
|
||||
{
|
||||
public static T GetCacheItem<T>(this IRuntimeCacheProvider provider,
|
||||
string cacheKey,
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
bool InternalRedirectPreservesTemplate { get; }
|
||||
|
||||
bool DisableAlternativeTemplates { get; }
|
||||
|
||||
string UrlProviderMode { get; }
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return (bool) base["internalRedirectPreservesTemplate"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("disableAlternativeTemplates", DefaultValue = "false")]
|
||||
public bool DisableAlternativeTemplates
|
||||
{
|
||||
get { return (bool) base["disableAlternativeTemplates"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("urlProviderMode", DefaultValue = "AutoLegacy")]
|
||||
public string UrlProviderMode
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.2.2");
|
||||
private static readonly Version Version = new Version("7.2.4");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
@@ -21,6 +23,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Macros;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Core.Strings;
|
||||
@@ -259,8 +262,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
PropertyEditorResolver.Current = new PropertyEditorResolver(() => PluginManager.Current.ResolvePropertyEditors());
|
||||
ParameterEditorResolver.Current = new ParameterEditorResolver(() => PluginManager.Current.ResolveParameterEditors());
|
||||
var builder = new ManifestBuilder(
|
||||
ApplicationCache.RuntimeCache,
|
||||
new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), ApplicationCache.RuntimeCache));
|
||||
|
||||
PropertyEditorResolver.Current = new PropertyEditorResolver(() => PluginManager.Current.ResolvePropertyEditors(), builder);
|
||||
ParameterEditorResolver.Current = new ParameterEditorResolver(() => PluginManager.Current.ResolveParameterEditors(), builder);
|
||||
|
||||
//setup the validators resolver with our predefined validators
|
||||
ValidatorsResolver.Current = new ValidatorsResolver(new[]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
@@ -114,13 +115,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> other)
|
||||
{
|
||||
var matches = true;
|
||||
foreach (var i in other)
|
||||
{
|
||||
matches = source.Contains(i);
|
||||
if (!matches) break;
|
||||
}
|
||||
return matches;
|
||||
return other.Except(source).Any() == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,7 +127,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
public static bool ContainsAny<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> other)
|
||||
{
|
||||
return other.Any(i => source.Contains(i));
|
||||
return other.Any(source.Contains);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -224,7 +219,7 @@ namespace Umbraco.Core
|
||||
return sequence.Select(
|
||||
x =>
|
||||
{
|
||||
if (typeof(TActual).IsAssignableFrom(x.GetType()))
|
||||
if (x is TActual)
|
||||
{
|
||||
var casted = x as TActual;
|
||||
projection.Invoke(casted);
|
||||
@@ -276,6 +271,34 @@ namespace Umbraco.Core
|
||||
///<param name="items">The enumerable to search.</param>
|
||||
///<param name="item">The item to find.</param>
|
||||
///<returns>The index of the first matching item, or -1 if the item was not found.</returns>
|
||||
public static int IndexOf<T>(this IEnumerable<T> items, T item) { return items.FindIndex(i => EqualityComparer<T>.Default.Equals(item, i)); }
|
||||
public static int IndexOf<T>(this IEnumerable<T> items, T item)
|
||||
{
|
||||
return items.FindIndex(i => EqualityComparer<T>.Default.Equals(item, i));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if 2 lists have equal elements within them regardless of how they are sorted
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// The logic for this is taken from:
|
||||
/// http://stackoverflow.com/questions/4576723/test-whether-two-ienumerablet-have-the-same-values-with-the-same-frequencies
|
||||
///
|
||||
/// There's a few answers, this one seems the best for it's simplicity and based on the comment of Eamon
|
||||
/// </remarks>
|
||||
public static bool UnsortedSequenceEqual<T>(this IEnumerable<T> source, IEnumerable<T> other)
|
||||
{
|
||||
if (source == null && other == null) return true;
|
||||
if (source == null || other == null) return false;
|
||||
|
||||
var list1Groups = source.ToLookup(i => i);
|
||||
var list2Groups = other.ToLookup(i => i);
|
||||
return list1Groups.Count == list2Groups.Count
|
||||
&& list1Groups.All(g => g.Count() == list2Groups[g.Key].Count());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Macros
|
||||
internal class MacroTagParser
|
||||
{
|
||||
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""']([\w\.]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// This formats the persisted string to something useful for the rte so that the macro renders properly since we
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
@@ -11,73 +13,92 @@ namespace Umbraco.Core.Manifest
|
||||
/// </summary>
|
||||
internal class ManifestBuilder
|
||||
{
|
||||
private readonly IRuntimeCacheProvider _cache;
|
||||
private readonly ManifestParser _parser;
|
||||
|
||||
private static readonly ConcurrentDictionary<string, object> StaticCache = new ConcurrentDictionary<string, object>();
|
||||
|
||||
private const string ManifestKey = "manifests";
|
||||
public ManifestBuilder(IRuntimeCacheProvider cache, ManifestParser parser)
|
||||
{
|
||||
_cache = cache;
|
||||
_parser = parser;
|
||||
}
|
||||
|
||||
private const string GridEditorsKey = "grideditors";
|
||||
private const string PropertyEditorsKey = "propertyeditors";
|
||||
private const string ParameterEditorsKey = "parametereditors";
|
||||
|
||||
/// <summary>
|
||||
/// Returns all property editors found in the manfifests
|
||||
/// Returns all grid editors found in the manfifests
|
||||
/// </summary>
|
||||
internal static IEnumerable<PropertyEditor> PropertyEditors
|
||||
internal IEnumerable<GridEditor> GridEditors
|
||||
{
|
||||
get
|
||||
{
|
||||
return (IEnumerable<PropertyEditor>) StaticCache.GetOrAdd(
|
||||
PropertyEditorsKey,
|
||||
s =>
|
||||
return _cache.GetCacheItem<IEnumerable<GridEditor>>(
|
||||
typeof (ManifestBuilder) + GridEditorsKey,
|
||||
() =>
|
||||
{
|
||||
var editors = new List<GridEditor>();
|
||||
foreach (var manifest in _parser.GetManifests())
|
||||
{
|
||||
var editors = new List<PropertyEditor>();
|
||||
foreach (var manifest in GetManifests())
|
||||
if (manifest.GridEditors != null)
|
||||
{
|
||||
if (manifest.PropertyEditors != null)
|
||||
{
|
||||
editors.AddRange(ManifestParser.GetPropertyEditors(manifest.PropertyEditors));
|
||||
}
|
||||
|
||||
editors.AddRange(ManifestParser.GetGridEditors(manifest.GridEditors));
|
||||
}
|
||||
return editors;
|
||||
});
|
||||
|
||||
}
|
||||
return editors;
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all property editors found in the manfifests
|
||||
/// </summary>
|
||||
internal IEnumerable<PropertyEditor> PropertyEditors
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cache.GetCacheItem<IEnumerable<PropertyEditor>>(
|
||||
typeof(ManifestBuilder) + PropertyEditorsKey,
|
||||
() =>
|
||||
{
|
||||
var editors = new List<PropertyEditor>();
|
||||
foreach (var manifest in _parser.GetManifests())
|
||||
{
|
||||
if (manifest.PropertyEditors != null)
|
||||
{
|
||||
editors.AddRange(ManifestParser.GetPropertyEditors(manifest.PropertyEditors));
|
||||
}
|
||||
|
||||
}
|
||||
return editors;
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all parameter editors found in the manfifests and all property editors that are flagged to be parameter editors
|
||||
/// </summary>
|
||||
internal static IEnumerable<ParameterEditor> ParameterEditors
|
||||
internal IEnumerable<ParameterEditor> ParameterEditors
|
||||
{
|
||||
get
|
||||
{
|
||||
return (IEnumerable<ParameterEditor>)StaticCache.GetOrAdd(
|
||||
ParameterEditorsKey,
|
||||
s =>
|
||||
return _cache.GetCacheItem<IEnumerable<ParameterEditor>>(
|
||||
typeof (ManifestBuilder) + ParameterEditorsKey,
|
||||
() =>
|
||||
{
|
||||
var editors = new List<ParameterEditor>();
|
||||
foreach (var manifest in GetManifests())
|
||||
foreach (var manifest in _parser.GetManifests())
|
||||
{
|
||||
if (manifest.ParameterEditors != null)
|
||||
{
|
||||
editors.AddRange(ManifestParser.GetParameterEditors(manifest.ParameterEditors));
|
||||
editors.AddRange(ManifestParser.GetParameterEditors(manifest.ParameterEditors));
|
||||
}
|
||||
}
|
||||
return editors;
|
||||
});
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the manifests are found and loaded into memory
|
||||
/// </summary>
|
||||
private static IEnumerable<PackageManifest> GetManifests()
|
||||
{
|
||||
return (IEnumerable<PackageManifest>) StaticCache.GetOrAdd(ManifestKey, s =>
|
||||
{
|
||||
var parser = new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")));
|
||||
return parser.GetManifests();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -17,15 +18,28 @@ namespace Umbraco.Core.Manifest
|
||||
internal class ManifestParser
|
||||
{
|
||||
private readonly DirectoryInfo _pluginsDir;
|
||||
|
||||
private readonly IRuntimeCacheProvider _cache;
|
||||
|
||||
//used to strip comments
|
||||
private static readonly Regex CommentsSurround = new Regex(@"/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/", RegexOptions.Compiled);
|
||||
private static readonly Regex CommentsLine = new Regex(@"//.*?$", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
private static readonly Regex CommentsLine = new Regex(@"^\s*//.*?$", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
|
||||
public ManifestParser(DirectoryInfo pluginsDir)
|
||||
public ManifestParser(DirectoryInfo pluginsDir, IRuntimeCacheProvider cache)
|
||||
{
|
||||
if (pluginsDir == null) throw new ArgumentNullException("pluginsDir");
|
||||
_pluginsDir = pluginsDir;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse the grid editors from the json array
|
||||
/// </summary>
|
||||
/// <param name="jsonEditors"></param>
|
||||
/// <returns></returns>
|
||||
internal static IEnumerable<GridEditor> GetGridEditors(JArray jsonEditors)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<IEnumerable<GridEditor>>(
|
||||
jsonEditors.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -57,11 +71,17 @@ namespace Umbraco.Core.Manifest
|
||||
/// Get all registered manifests
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This ensures that we only build and look for all manifests once per Web app (based on the IRuntimeCache)
|
||||
/// </remarks>
|
||||
public IEnumerable<PackageManifest> GetManifests()
|
||||
{
|
||||
//get all Manifest.js files in the appropriate folders
|
||||
var manifestFileContents = GetAllManifestFileContents(_pluginsDir);
|
||||
return CreateManifests(manifestFileContents.ToArray());
|
||||
return _cache.GetCacheItem<IEnumerable<PackageManifest>>(typeof (ManifestParser) + "GetManifests", () =>
|
||||
{
|
||||
//get all Manifest.js files in the appropriate folders
|
||||
var manifestFileContents = GetAllManifestFileContents(_pluginsDir);
|
||||
return CreateManifests(manifestFileContents.ToArray());
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,6 +174,20 @@ namespace Umbraco.Core.Manifest
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'propertyEditors' element");
|
||||
}
|
||||
|
||||
//validate the parameterEditors section
|
||||
var paramEditors = deserialized.Properties().Where(x => x.Name == "parameterEditors").ToArray();
|
||||
if (paramEditors.Length > 1)
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'parameterEditors' element");
|
||||
}
|
||||
|
||||
//validate the gridEditors section
|
||||
var gridEditors = deserialized.Properties().Where(x => x.Name == "gridEditors").ToArray();
|
||||
if (gridEditors.Length > 1)
|
||||
{
|
||||
throw new FormatException("The manifest is not formatted correctly contains more than one 'gridEditors' element");
|
||||
}
|
||||
|
||||
var jConfig = init.Any() ? (JArray)deserialized["javascript"] : new JArray();
|
||||
ReplaceVirtualPaths(jConfig);
|
||||
|
||||
@@ -181,7 +215,8 @@ namespace Umbraco.Core.Manifest
|
||||
JavaScriptInitialize = jConfig,
|
||||
StylesheetInitialize = cssConfig,
|
||||
PropertyEditors = propEditors.Any() ? (JArray)deserialized["propertyEditors"] : new JArray(),
|
||||
ParameterEditors = propEditors.Any() ? (JArray)deserialized["parameterEditors"] : new JArray()
|
||||
ParameterEditors = propEditors.Any() ? (JArray)deserialized["parameterEditors"] : new JArray(),
|
||||
GridEditors = propEditors.Any() ? (JArray)deserialized["gridEditors"] : new JArray()
|
||||
};
|
||||
result.Add(manifest);
|
||||
}
|
||||
|
||||
@@ -26,5 +26,10 @@ namespace Umbraco.Core.Manifest
|
||||
/// The json array of parameter editors
|
||||
/// </summary>
|
||||
public JArray ParameterEditors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The json array of grid editors
|
||||
/// </summary>
|
||||
public JArray GridEditors { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -460,10 +460,14 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Content)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to manually clone this since it's not settable
|
||||
clone._contentType = (IContentType)ContentType.DeepClone();
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
|
||||
|
||||
@@ -90,7 +90,11 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
_allowedTemplates = value;
|
||||
return _allowedTemplates;
|
||||
}, _allowedTemplates, AllowedTemplatesSelector);
|
||||
}, _allowedTemplates, AllowedTemplatesSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<ITemplate>>(
|
||||
(templates, enumerable) => templates.UnsortedSequenceEqual(enumerable),
|
||||
templates => templates.GetHashCode()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -351,7 +351,11 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
return _allowedContentTypes;
|
||||
}, _allowedContentTypes, AllowedContentTypesSelector);
|
||||
}, _allowedContentTypes, AllowedContentTypesSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<ContentTypeSort>>(
|
||||
(sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable),
|
||||
sorts => sorts.GetHashCode()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,13 +613,18 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (ContentTypeBase)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//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;
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -255,11 +255,15 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (ContentTypeCompositionBase)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to manually assign since this is an internal field and will not be automatically mapped
|
||||
clone.RemovedContentTypeKeyTracker = new List<int>();
|
||||
clone._contentTypeComposition = ContentTypeComposition.Select(x => (IContentTypeComposition)x.DeepClone()).ToList();
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,20 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public class ContentTypeSort : IValueObject, IDeepCloneable
|
||||
{
|
||||
[Obsolete("This parameterless constructor should never be used")]
|
||||
public ContentTypeSort()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Object"/> class.
|
||||
/// </summary>
|
||||
public ContentTypeSort(int id, int sortOrder)
|
||||
{
|
||||
Id = new Lazy<int>(() => id);
|
||||
SortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public ContentTypeSort(Lazy<int> id, int sortOrder, string @alias)
|
||||
{
|
||||
Id = id;
|
||||
@@ -45,7 +55,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
protected bool Equals(ContentTypeSort other)
|
||||
{
|
||||
return Id.Value.Equals(other.Id.Value) && string.Equals(Alias, other.Alias);
|
||||
return Id.Value.Equals(other.Id.Value) && string.Equals(Alias, other.Alias);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
@@ -60,7 +70,9 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Id.GetHashCode()*397) ^ Alias.GetHashCode();
|
||||
//The hash code will just be the alias if one is assigned, otherwise it will be the hash code of the Id.
|
||||
//In some cases the alias can be null of the non lazy ctor is used, in that case, the lazy Id will already have a value created.
|
||||
return Alias != null ? Alias.GetHashCode() : (Id.Value.GetHashCode() * 397);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,11 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
_translations = value;
|
||||
return _translations;
|
||||
}, _translations, TranslationsSelector);
|
||||
}, _translations, TranslationsSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>>(
|
||||
(enumerable, translations) => enumerable.UnsortedSequenceEqual(translations),
|
||||
enumerable => enumerable.GetHashCode()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -236,9 +236,17 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
//Memberwise clone on Entity 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 = (Entity)MemberwiseClone();
|
||||
//ensure the clone has it's own dictionaries
|
||||
clone.ResetChangeTrackingCollections();
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//Automatically deep clone ref properties that are IDeepCloneable
|
||||
DeepCloneHelper.DeepCloneRefProperties(this, clone);
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
@@ -18,7 +19,9 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
public virtual IEnumerable<string> GetDirtyProperties()
|
||||
{
|
||||
return _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _changeTrackingEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the properties that have changed
|
||||
@@ -41,6 +44,9 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// <param name="propertyInfo">The property info.</param>
|
||||
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
|
||||
{
|
||||
//return if we're not tracking changes
|
||||
if (_changeTrackingEnabled == false) return;
|
||||
|
||||
_propertyChangedInfo[propertyInfo.Name] = true;
|
||||
|
||||
if (PropertyChanged != null)
|
||||
@@ -132,6 +138,22 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
_propertyChangedInfo = new Dictionary<string, bool>();
|
||||
}
|
||||
|
||||
protected void ResetChangeTrackingCollections()
|
||||
{
|
||||
_propertyChangedInfo = new Dictionary<string, bool>();
|
||||
_lastPropertyChangedInfo = new Dictionary<string, bool>();
|
||||
}
|
||||
|
||||
protected void DisableChangeTracking()
|
||||
{
|
||||
_changeTrackingEnabled = false;
|
||||
}
|
||||
|
||||
protected void EnableChangeTracking()
|
||||
{
|
||||
_changeTrackingEnabled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by inheritors to set the value of properties, this will detect if the property value actually changed and if it did
|
||||
/// it will ensure that the property has a dirty flag set.
|
||||
@@ -145,17 +167,51 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set
|
||||
/// to the same value, so it's really not dirty.
|
||||
/// </remarks>
|
||||
internal virtual bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector)
|
||||
internal bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector)
|
||||
{
|
||||
if ((typeof(T) == typeof(string) == false) && TypeHelper.IsTypeAssignableFrom<IEnumerable>(typeof(T)))
|
||||
{
|
||||
throw new InvalidOperationException("This method does not support IEnumerable instances. For IEnumerable instances a manual custom equality check will be required");
|
||||
}
|
||||
|
||||
return SetPropertyValueAndDetectChanges(setValue, value, propertySelector,
|
||||
new DelegateEqualityComparer<T>(
|
||||
//Standard Equals comparison
|
||||
(arg1, arg2) => Equals(arg1, arg2),
|
||||
arg => arg.GetHashCode()));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by inheritors to set the value of properties, this will detect if the property value actually changed and if it did
|
||||
/// it will ensure that the property has a dirty flag set.
|
||||
/// </summary>
|
||||
/// <param name="setValue"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="propertySelector"></param>
|
||||
/// <param name="comparer">The equality comparer to use</param>
|
||||
/// <returns>returns true if the value changed</returns>
|
||||
/// <remarks>
|
||||
/// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we
|
||||
/// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set
|
||||
/// to the same value, so it's really not dirty.
|
||||
/// </remarks>
|
||||
internal bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector, IEqualityComparer<T> comparer)
|
||||
{
|
||||
var initVal = value;
|
||||
var newVal = setValue(value);
|
||||
|
||||
if (Equals(initVal, newVal) == false)
|
||||
//don't track changes, just set the value (above)
|
||||
if (_changeTrackingEnabled == false) return false;
|
||||
|
||||
if (comparer.Equals(initVal, newVal) == false)
|
||||
{
|
||||
OnPropertyChanged(propertySelector);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -113,12 +113,15 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (File)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to manually assign since they are readonly properties
|
||||
clone._alias = Alias;
|
||||
clone._name = Name;
|
||||
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -399,14 +399,17 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Macro)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
clone._addedProperties = new List<string>();
|
||||
clone._removedProperties = new List<string>();
|
||||
clone._properties = (MacroPropertyCollection)Properties.DeepClone();
|
||||
//re-assign the event handler
|
||||
clone._properties.CollectionChanged += clone.PropertiesChanged;
|
||||
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -617,10 +617,14 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Member)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to manually clone this since it's not settable
|
||||
clone._contentType = (IMemberType)ContentType.DeepClone();
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// Gets/sets the user type for the user
|
||||
/// </summary>
|
||||
IUserType UserType { get; set; }
|
||||
|
||||
|
||||
//TODO: This should be a private set
|
||||
/// <summary>
|
||||
/// The default permission set for the user
|
||||
/// </summary>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
if (userType == null) throw new ArgumentNullException("userType");
|
||||
|
||||
_userType = userType;
|
||||
_defaultPermissions = _userType.Permissions;
|
||||
_defaultPermissions = _userType.Permissions == null ? Enumerable.Empty<string>() : new List<string>(_userType.Permissions);
|
||||
//Groups = new List<object> { userType };
|
||||
SessionTimeout = 60;
|
||||
_sectionCollection = new ObservableCollection<string>();
|
||||
@@ -71,7 +71,9 @@ namespace Umbraco.Core.Models.Membership
|
||||
private bool _isApproved;
|
||||
private bool _isLockedOut;
|
||||
private string _language;
|
||||
private IEnumerable<string> _defaultPermissions;
|
||||
|
||||
private IEnumerable<string> _defaultPermissions;
|
||||
|
||||
private bool _defaultToLiveEditing;
|
||||
|
||||
private static readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.SessionTimeout);
|
||||
@@ -86,7 +88,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
private static readonly PropertyInfo IsLockedOutSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsLockedOut);
|
||||
private static readonly PropertyInfo IsApprovedSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsApproved);
|
||||
private static readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Language);
|
||||
private static readonly PropertyInfo DefaultPermissionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.DefaultPermissions);
|
||||
|
||||
private static readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.DefaultToLiveEditing);
|
||||
private static readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo<User, IUserType>(x => x.UserType);
|
||||
|
||||
@@ -319,19 +321,13 @@ namespace Umbraco.Core.Models.Membership
|
||||
}, _language, LanguageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO: This should be a private set
|
||||
[DataMember]
|
||||
public IEnumerable<string> DefaultPermissions
|
||||
{
|
||||
get { return _defaultPermissions; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_defaultPermissions = value;
|
||||
return _defaultPermissions;
|
||||
}, _defaultPermissions, DefaultPermissionsSelector);
|
||||
}
|
||||
get { return _defaultPermissions;}
|
||||
set { _defaultPermissions = value; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
@@ -415,15 +411,19 @@ namespace Umbraco.Core.Models.Membership
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (User)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to create new collections otherwise they'll get copied by ref
|
||||
clone._addedSections = new List<string>();
|
||||
clone._removedSections = new List<string>();
|
||||
clone._sectionCollection = new ObservableCollection<string>(_sectionCollection.ToList());
|
||||
clone._defaultPermissions = new List<string>(_defaultPermissions.ToList());
|
||||
//re-create the event handler
|
||||
clone._sectionCollection.CollectionChanged += clone.SectionCollectionChanged;
|
||||
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -67,7 +68,11 @@ namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
_permissions = value;
|
||||
return _permissions;
|
||||
}, _permissions, PermissionsSelector);
|
||||
}, _permissions, PermissionsSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<string>>(
|
||||
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
|
||||
enum1 => enum1.GetHashCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -120,7 +123,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
bool typeValidation = _propertyType.IsPropertyTypeValid(value);
|
||||
|
||||
if (!typeValidation)
|
||||
if (typeValidation == false)
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'",
|
||||
@@ -130,7 +133,21 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
_value = value;
|
||||
return _value;
|
||||
}, _value, ValueSelector);
|
||||
}, _value, ValueSelector,
|
||||
new DelegateEqualityComparer<object>(
|
||||
(o, o1) =>
|
||||
{
|
||||
//Custom comparer for enumerable if it is enumerable
|
||||
if (o == null && o1 == null) return true;
|
||||
if (o == null || o1 == null) return false;
|
||||
var enum1 = o as IEnumerable;
|
||||
var enum2 = o1 as IEnumerable;
|
||||
if (enum1 != null && enum2 != null)
|
||||
{
|
||||
return enum1.Cast<object>().UnsortedSequenceEqual(enum2.Cast<object>());
|
||||
}
|
||||
return o.Equals(o1);
|
||||
}, o => o.GetHashCode()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,10 +177,14 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Property)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to manually assign since this is a readonly property
|
||||
clone._propertyType = (PropertyType)PropertyType.DeepClone();
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -456,14 +456,17 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (PropertyType)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to manually assign the Lazy value as it will not be automatically mapped
|
||||
if (PropertyGroupId != null)
|
||||
{
|
||||
clone._propertyGroupId = new Lazy<int>(() => PropertyGroupId.Value);
|
||||
}
|
||||
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -193,12 +193,15 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (Template)base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//need to manually assign since they are readonly properties
|
||||
clone._alias = Alias;
|
||||
clone._name = Name;
|
||||
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -288,7 +288,8 @@ namespace Umbraco.Core.Models
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (UmbracoEntity) base.DeepClone();
|
||||
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//This ensures that any value in the dictionary that is deep cloneable is cloned too
|
||||
foreach (var key in clone.AdditionalData.Keys.ToArray())
|
||||
{
|
||||
@@ -298,7 +299,10 @@ namespace Umbraco.Core.Models
|
||||
clone.AdditionalData[key] = deepCloneable.DeepClone();
|
||||
}
|
||||
}
|
||||
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
clone.EnableChangeTracking();
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -23,13 +24,21 @@ namespace Umbraco.Core.Models
|
||||
|
||||
internal static CultureInfo GetUserCulture(string userLanguage, ILocalizedTextService textService)
|
||||
{
|
||||
return textService.GetSupportedCultures()
|
||||
.FirstOrDefault(culture =>
|
||||
//match on full name first
|
||||
culture.Name.InvariantEquals(userLanguage.Replace("_", "-")) ||
|
||||
//then match on the 2 letter name
|
||||
culture.TwoLetterISOLanguageName.InvariantEquals(userLanguage));
|
||||
}
|
||||
try
|
||||
{
|
||||
var culture = CultureInfo.GetCultureInfo(userLanguage.Replace("_", "-"));
|
||||
//TODO: This is a hack because we store the user language as 2 chars instead of the full culture
|
||||
// which is actually stored in the language files (which are also named with 2 chars!) so we need to attempt
|
||||
// to convert to a supported full culture
|
||||
var result = textService.ConvertToSupportedCultureWithRegionCode(culture);
|
||||
return result;
|
||||
}
|
||||
catch (CultureNotFoundException)
|
||||
{
|
||||
//return the default one
|
||||
return CultureInfo.GetCultureInfo("en");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the user has access to the content item based on their start noe
|
||||
|
||||
@@ -32,9 +32,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
IsLockedOut = dto.NoConsole,
|
||||
IsApproved = dto.Disabled == false,
|
||||
Email = dto.Email,
|
||||
Language = dto.UserLanguage,
|
||||
//NOTE: The default permission come from the user type's default permissions
|
||||
DefaultPermissions = _userType.Permissions
|
||||
Language = dto.UserLanguage
|
||||
};
|
||||
|
||||
foreach (var app in dto.User2AppDtos)
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
internal abstract class ContentTypeBaseRepository<TEntity> : PetaPocoRepositoryBase<int, TEntity>
|
||||
where TEntity : class, IContentTypeComposition
|
||||
{
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work)
|
||||
: base(work)
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work)
|
||||
: base(work)
|
||||
{
|
||||
}
|
||||
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
|
||||
: base(work, cache)
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
|
||||
: base(work, cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ AND umbracoNode.id <> @id",
|
||||
.Where<ContentTypeAllowedContentTypeDto>(x => x.Id == id);
|
||||
|
||||
var allowedContentTypeDtos = Database.Fetch<ContentTypeAllowedContentTypeDto, ContentTypeDto>(sql);
|
||||
return allowedContentTypeDtos.Select(x => new ContentTypeSort { Id = new Lazy<int>(() => x.AllowedId), Alias = x.ContentTypeDto.Alias, SortOrder = x.SortOrder }).ToList();
|
||||
return allowedContentTypeDtos.Select(x => new ContentTypeSort(new Lazy<int>(() => x.AllowedId), x.SortOrder, x.ContentTypeDto.Alias)).ToList();
|
||||
}
|
||||
|
||||
protected PropertyGroupCollection GetPropertyGroupCollection(int id, DateTime createDate, DateTime updateDate)
|
||||
@@ -694,20 +694,20 @@ AND umbracoNode.id <> @id",
|
||||
mediaTypeIds = mediaTypeIds.Distinct().ToArray();
|
||||
|
||||
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId
|
||||
FROM cmsContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
ON AllowedTypes.Id = cmsContentType.nodeId
|
||||
LEFT JOIN cmsContentType2ContentType as ParentTypes
|
||||
@@ -801,30 +801,30 @@ AND umbracoNode.id <> @id",
|
||||
contentTypeIds = contentTypeIds.Distinct().ToArray();
|
||||
|
||||
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
|
||||
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
Template.alias as tAlias, Template.nodeId as tId,Template.text as tText
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
Template.alias as tAlias, Template.nodeId as tId,Template.text as tText
|
||||
FROM cmsContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id
|
||||
LEFT JOIN cmsDocumentType
|
||||
ON cmsDocumentType.contentTypeNodeId = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
ON AllowedTypes.Id = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT * FROM cmsTemplate
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsTemplate.nodeId = umbracoNode.id
|
||||
SELECT * FROM cmsTemplate
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsTemplate.nodeId = umbracoNode.id
|
||||
) as Template
|
||||
ON Template.nodeId = cmsDocumentType.templateNodeId
|
||||
LEFT JOIN cmsContentType2ContentType as ParentTypes
|
||||
@@ -872,8 +872,8 @@ AND umbracoNode.id <> @id",
|
||||
//get the unique list of associated templates
|
||||
var defaultTemplates = result
|
||||
.Where(x => x.ctId == currentCtId)
|
||||
//use a tuple so that distinct checks both values
|
||||
.Select(x => new Tuple<bool?, int?>(x.dtIsDefault, x.dtTemplateId))
|
||||
//use a tuple so that distinct checks both values (in some rare cases the dtIsDefault will not compute as bool?, so we force it with Convert.ToBoolean)
|
||||
.Select(x => new Tuple<bool?, int?>(Convert.ToBoolean(x.dtIsDefault), x.dtTemplateId))
|
||||
.Where(x => x.Item1.HasValue && x.Item2.HasValue)
|
||||
.Distinct()
|
||||
.OrderByDescending(x => x.Item1.Value)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
internal class GridEditor
|
||||
{
|
||||
public GridEditor()
|
||||
{
|
||||
Config = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
[JsonProperty("name", Required = Required.Always)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("alias", Required = Required.Always)]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[JsonProperty("view", Required = Required.Always)]
|
||||
public string View { get; set; }
|
||||
|
||||
[JsonProperty("render")]
|
||||
public string Render { get; set; }
|
||||
|
||||
[JsonProperty("icon", Required = Required.Always)]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[JsonProperty("config")]
|
||||
public IDictionary<string, object> Config { get; set; }
|
||||
|
||||
protected bool Equals(GridEditor other)
|
||||
{
|
||||
return string.Equals(Alias, other.Alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the specified object is equal to the current object; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="obj">The object to compare with the current object. </param>
|
||||
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((GridEditor) obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a particular type.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for the current <see cref="T:System.Object"/>.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Alias.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,14 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </remarks>
|
||||
internal class ParameterEditorResolver : LazyManyObjectsResolverBase<ParameterEditorResolver, IParameterEditor>
|
||||
{
|
||||
public ParameterEditorResolver(Func<IEnumerable<Type>> typeListProducerList)
|
||||
private readonly ManifestBuilder _builder;
|
||||
|
||||
public ParameterEditorResolver(Func<IEnumerable<Type>> typeListProducerList, ManifestBuilder builder)
|
||||
: base(typeListProducerList, ObjectLifetimeScope.Application)
|
||||
{
|
||||
_builder = builder;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the parameter editors
|
||||
/// </summary>
|
||||
@@ -38,9 +41,9 @@ namespace Umbraco.Core.PropertyEditors
|
||||
//exclude the non parameter editor c# property editors
|
||||
.Except(filtered)
|
||||
//include the manifest parameter editors
|
||||
.Union(ManifestBuilder.ParameterEditors)
|
||||
.Union(_builder.ParameterEditors)
|
||||
//include the manifest prop editors that are parameter editors
|
||||
.Union(ManifestBuilder.PropertyEditors.Where(x => x.IsParameterEditor));
|
||||
.Union(_builder.PropertyEditors.Where(x => x.IsParameterEditor));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
@@ -17,14 +19,27 @@ namespace Umbraco.Core.PropertyEditors
|
||||
public PropertyEditorResolver(Func<IEnumerable<Type>> typeListProducerList)
|
||||
: base(typeListProducerList, ObjectLifetimeScope.Application)
|
||||
{
|
||||
var builder = new ManifestBuilder(
|
||||
ApplicationContext.Current.ApplicationCache.RuntimeCache,
|
||||
new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), ApplicationContext.Current.ApplicationCache.RuntimeCache));
|
||||
|
||||
_unioned = new Lazy<List<PropertyEditor>>(() => Values.Union(builder.PropertyEditors).ToList());
|
||||
}
|
||||
|
||||
internal PropertyEditorResolver(Func<IEnumerable<Type>> typeListProducerList, ManifestBuilder builder)
|
||||
: base(typeListProducerList, ObjectLifetimeScope.Application)
|
||||
{
|
||||
_unioned = new Lazy<List<PropertyEditor>>(() => Values.Union(builder.PropertyEditors).ToList());
|
||||
}
|
||||
|
||||
private readonly Lazy<List<PropertyEditor>> _unioned;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the property editors
|
||||
/// </summary>
|
||||
public IEnumerable<PropertyEditor> PropertyEditors
|
||||
{
|
||||
get { return Values.Union(ManifestBuilder.PropertyEditors); }
|
||||
get { return _unioned.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace Umbraco.Core.Services
|
||||
return list;
|
||||
|
||||
|
||||
});
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,5 +33,19 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerable<CultureInfo> GetSupportedCultures();
|
||||
|
||||
/// <summary>
|
||||
/// Tries to resolve a full 4 letter culture from a 2 letter culture name
|
||||
/// </summary>
|
||||
/// <param name="currentCulture">
|
||||
/// The culture to determine if it is only a 2 letter culture, if so we'll try to convert it, otherwise it will just be returned
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// TODO: This is just a hack due to the way we store the language files, they should be stored with 4 letters since that
|
||||
/// is what they reference but they are stored with 2, further more our user's languages are stored with 2. So this attempts
|
||||
/// to resolve the full culture if possible.
|
||||
/// </remarks>
|
||||
CultureInfo ConvertToSupportedCultureWithRegionCode(CultureInfo currentCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public class LocalizedTextService : ILocalizedTextService
|
||||
{
|
||||
private readonly LocalizedTextServiceFileSources _fileSources;
|
||||
private readonly IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> _dictionarySource;
|
||||
private readonly IDictionary<CultureInfo, Lazy<XDocument>> _xmlSource;
|
||||
|
||||
@@ -22,7 +23,8 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="fileSources"></param>
|
||||
public LocalizedTextService(LocalizedTextServiceFileSources fileSources)
|
||||
{
|
||||
_xmlSource = fileSources.GetXmlSources();
|
||||
if (fileSources == null) throw new ArgumentNullException("fileSources");
|
||||
_fileSources = fileSources;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -49,6 +51,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
Mandate.ParameterNotNull(culture, "culture");
|
||||
|
||||
//TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
|
||||
culture = ConvertToSupportedCultureWithRegionCode(culture);
|
||||
|
||||
//This is what the legacy ui service did
|
||||
if (string.IsNullOrEmpty(key))
|
||||
return string.Empty;
|
||||
@@ -57,10 +62,14 @@ namespace Umbraco.Core.Services
|
||||
var area = keyParts.Length > 1 ? keyParts[0] : null;
|
||||
var alias = keyParts.Length > 1 ? keyParts[1] : keyParts[0];
|
||||
|
||||
if (_xmlSource != null)
|
||||
var xmlSource = _xmlSource ?? (_fileSources != null
|
||||
? _fileSources.GetXmlSources()
|
||||
: null);
|
||||
|
||||
if (xmlSource != null)
|
||||
{
|
||||
return GetFromXmlSource(culture, area, alias, tokens);
|
||||
}
|
||||
return GetFromXmlSource(xmlSource, culture, area, alias, tokens);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetFromDictionarySource(culture, area, alias, tokens);
|
||||
@@ -75,18 +84,25 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (culture == null) throw new ArgumentNullException("culture");
|
||||
|
||||
//TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
|
||||
culture = ConvertToSupportedCultureWithRegionCode(culture);
|
||||
|
||||
var result = new Dictionary<string, string>();
|
||||
|
||||
if (_xmlSource != null)
|
||||
var xmlSource = _xmlSource ?? (_fileSources != null
|
||||
? _fileSources.GetXmlSources()
|
||||
: null);
|
||||
|
||||
if (xmlSource != null)
|
||||
{
|
||||
if (_xmlSource.ContainsKey(culture) == false)
|
||||
if (xmlSource.ContainsKey(culture) == false)
|
||||
{
|
||||
LogHelper.Warn<LocalizedTextService>("The culture specified {0} was not found in any configured sources for this service", () => culture);
|
||||
return result;
|
||||
}
|
||||
|
||||
//convert all areas + keys to a single key with a '/'
|
||||
var areas = _xmlSource[culture].Value.XPathSelectElements("//area");
|
||||
var areas = xmlSource[culture].Value.XPathSelectElements("//area");
|
||||
foreach (var area in areas)
|
||||
{
|
||||
var keys = area.XPathSelectElements("./key");
|
||||
@@ -133,7 +149,36 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IEnumerable<CultureInfo> GetSupportedCultures()
|
||||
{
|
||||
return _xmlSource != null ? _xmlSource.Keys : _dictionarySource.Keys;
|
||||
var xmlSource = _xmlSource ?? (_fileSources != null
|
||||
? _fileSources.GetXmlSources()
|
||||
: null);
|
||||
|
||||
return xmlSource != null ? xmlSource.Keys : _dictionarySource.Keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to resolve a full 4 letter culture from a 2 letter culture name
|
||||
/// </summary>
|
||||
/// <param name="currentCulture">
|
||||
/// The culture to determine if it is only a 2 letter culture, if so we'll try to convert it, otherwise it will just be returned
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// TODO: This is just a hack due to the way we store the language files, they should be stored with 4 letters since that
|
||||
/// is what they reference but they are stored with 2, further more our user's languages are stored with 2. So this attempts
|
||||
/// to resolve the full culture if possible.
|
||||
///
|
||||
/// This only works when this service is constructed with the LocalizedTextServiceFileSources
|
||||
/// </remarks>
|
||||
public CultureInfo ConvertToSupportedCultureWithRegionCode(CultureInfo currentCulture)
|
||||
{
|
||||
if (currentCulture == null) throw new ArgumentNullException("currentCulture");
|
||||
|
||||
if (_fileSources == null) return currentCulture;
|
||||
if (currentCulture.Name.Length > 2) return currentCulture;
|
||||
|
||||
var attempt = _fileSources.TryConvert2LetterCultureTo4Letter(currentCulture.TwoLetterISOLanguageName);
|
||||
return attempt ? attempt.Result : currentCulture;
|
||||
}
|
||||
|
||||
private string GetFromDictionarySource(CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
|
||||
@@ -174,15 +219,15 @@ namespace Umbraco.Core.Services
|
||||
return "[" + key + "]";
|
||||
}
|
||||
|
||||
private string GetFromXmlSource(CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
|
||||
private static string GetFromXmlSource(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
|
||||
{
|
||||
if (_xmlSource.ContainsKey(culture) == false)
|
||||
if (xmlSource.ContainsKey(culture) == false)
|
||||
{
|
||||
LogHelper.Warn<LocalizedTextService>("The culture specified {0} was not found in any configured sources for this service", () => culture);
|
||||
return "[" + key + "]";
|
||||
}
|
||||
|
||||
var cultureSource = _xmlSource[culture].Value;
|
||||
var cultureSource = xmlSource[culture].Value;
|
||||
|
||||
var xpath = area.IsNullOrWhiteSpace()
|
||||
? string.Format("//key [@alias = '{0}']", key)
|
||||
@@ -213,7 +258,7 @@ namespace Umbraco.Core.Services
|
||||
/// we support a dictionary which means in the future we can really have any sort of token system.
|
||||
/// Currently though, the token key's will need to be an integer and sequential - though we aren't going to throw exceptions if that is not the case.
|
||||
/// </remarks>
|
||||
internal string ParseTokens(string value, IDictionary<string, string> tokens)
|
||||
internal static string ParseTokens(string value, IDictionary<string, string> tokens)
|
||||
{
|
||||
if (tokens == null || tokens.Any() == false)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -16,12 +17,86 @@ namespace Umbraco.Core.Services
|
||||
private readonly IRuntimeCacheProvider _cache;
|
||||
private readonly DirectoryInfo _fileSourceFolder;
|
||||
|
||||
//TODO: See other notes in this class, this is purely a hack because we store 2 letter culture file names that contain 4 letter cultures :(
|
||||
private readonly Dictionary<string, CultureInfo> _twoLetterCultureConverter = new Dictionary<string, CultureInfo>();
|
||||
|
||||
private readonly Lazy<Dictionary<CultureInfo, Lazy<XDocument>>> _xmlSources;
|
||||
|
||||
public LocalizedTextServiceFileSources(IRuntimeCacheProvider cache, DirectoryInfo fileSourceFolder)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
if (fileSourceFolder == null) throw new ArgumentNullException("fileSourceFolder");
|
||||
|
||||
_cache = cache;
|
||||
|
||||
//Create the lazy source for the _xmlSources
|
||||
_xmlSources = new Lazy<Dictionary<CultureInfo, Lazy<XDocument>>>(() =>
|
||||
{
|
||||
var result = new Dictionary<CultureInfo, Lazy<XDocument>>();
|
||||
|
||||
if (_fileSourceFolder == null) return result;
|
||||
|
||||
foreach (var fileInfo in _fileSourceFolder.GetFiles("*.xml"))
|
||||
{
|
||||
var localCopy = fileInfo;
|
||||
var filename = Path.GetFileNameWithoutExtension(localCopy.FullName).Replace("_", "-");
|
||||
|
||||
//TODO: Fix this nonsense... would have to wait until v8 to store the language files with their correct
|
||||
// names instead of storing them as 2 letters but actually having a 4 letter culture. wtf. So now, we
|
||||
// need to check if the file is 2 letters, then open it to try to find it's 4 letter culture, then use that
|
||||
// if it's successful. We're going to assume (though it seems assuming in the legacy logic is never a great idea)
|
||||
// that any 4 letter file is named with the actual culture that it is!
|
||||
CultureInfo culture = null;
|
||||
if (filename.Length == 2)
|
||||
{
|
||||
//we need to open the file to see if we can read it's 'real' culture, we'll use XmlReader since we don't
|
||||
//want to load in the entire doc into mem just to read a single value
|
||||
using (var fs = fileInfo.OpenRead())
|
||||
using (var reader = XmlReader.Create(fs))
|
||||
{
|
||||
if (reader.IsStartElement())
|
||||
{
|
||||
if (reader.Name == "language")
|
||||
{
|
||||
if (reader.MoveToAttribute("culture"))
|
||||
{
|
||||
var cultureVal = reader.Value;
|
||||
try
|
||||
{
|
||||
culture = CultureInfo.GetCultureInfo(cultureVal);
|
||||
//add to the tracked dictionary
|
||||
_twoLetterCultureConverter[filename] = culture;
|
||||
}
|
||||
catch (CultureNotFoundException)
|
||||
{
|
||||
LogHelper.Warn<LocalizedTextServiceFileSources>(
|
||||
string.Format("The culture {0} found in the file {1} is not a valid culture", cultureVal, fileInfo.FullName));
|
||||
//If the culture in the file is invalid, we'll just hope the file name is a valid culture below, otherwise
|
||||
// an exception will be thrown.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (culture == null)
|
||||
{
|
||||
culture = CultureInfo.GetCultureInfo(filename);
|
||||
}
|
||||
|
||||
//get the lazy value from cache
|
||||
result.Add(culture, new Lazy<XDocument>(() => _cache.GetCacheItem<XDocument>(
|
||||
string.Format("{0}-{1}", typeof(LocalizedTextServiceFileSources).Name, culture.Name), () =>
|
||||
{
|
||||
using (var fs = localCopy.OpenRead())
|
||||
{
|
||||
return XDocument.Load(fs);
|
||||
}
|
||||
}, isSliding: true, timeout: TimeSpan.FromMinutes(10), dependentFiles: new[] { localCopy.FullName })));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
if (fileSourceFolder.Exists == false)
|
||||
{
|
||||
LogHelper.Warn<LocalizedTextServiceFileSources>("The folder does not exist: {0}, therefore no sources will be discovered", () => fileSourceFolder.FullName);
|
||||
@@ -38,26 +113,20 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IDictionary<CultureInfo, Lazy<XDocument>> GetXmlSources()
|
||||
{
|
||||
var result = new Dictionary<CultureInfo, Lazy<XDocument>>();
|
||||
return _xmlSources.Value;
|
||||
}
|
||||
|
||||
if (_fileSourceFolder == null) return result;
|
||||
//TODO: See other notes in this class, this is purely a hack because we store 2 letter culture file names that contain 4 letter cultures :(
|
||||
public Attempt<CultureInfo> TryConvert2LetterCultureTo4Letter(string twoLetterCulture)
|
||||
{
|
||||
if (twoLetterCulture.Length != 2) Attempt<CultureInfo>.Fail();
|
||||
|
||||
foreach (var fileInfo in _fileSourceFolder.GetFiles("*.xml"))
|
||||
{
|
||||
var localCopy = fileInfo;
|
||||
var filename = Path.GetFileNameWithoutExtension(localCopy.FullName).Replace("_", "-");
|
||||
var culture = CultureInfo.GetCultureInfo(filename);
|
||||
//get the lazy value from cache
|
||||
result.Add(culture, new Lazy<XDocument>(() => _cache.GetCacheItem<XDocument>(
|
||||
string.Format("{0}-{1}", typeof (LocalizedTextServiceFileSources).Name, culture.TwoLetterISOLanguageName), () =>
|
||||
{
|
||||
using (var fs = localCopy.OpenRead())
|
||||
{
|
||||
return XDocument.Load(fs);
|
||||
}
|
||||
}, isSliding: true, timeout: TimeSpan.FromMinutes(10), dependentFiles: new[] {localCopy.FullName})));
|
||||
}
|
||||
return result;
|
||||
//This needs to be resolved before continuing so that the _twoLetterCultureConverter cache is initialized
|
||||
var resolved = _xmlSources.Value;
|
||||
|
||||
return _twoLetterCultureConverter.ContainsKey(twoLetterCulture)
|
||||
? Attempt.Succeed(_twoLetterCultureConverter[twoLetterCulture])
|
||||
: Attempt<CultureInfo>.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
return list;
|
||||
|
||||
});
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
|
||||
internal void LoadXml(Func<XDocument, bool> callback, bool saveAfterCallbackIfChanged)
|
||||
|
||||
@@ -347,6 +347,7 @@
|
||||
<Compile Include="IO\ResizedImage.cs" />
|
||||
<Compile Include="IO\UmbracoMediaFile.cs" />
|
||||
<Compile Include="Models\IPartialView.cs" />
|
||||
<Compile Include="PropertyEditors\GridEditor.cs" />
|
||||
<Compile Include="Services\LocalizedTextService.cs" />
|
||||
<Compile Include="Services\ILocalizedTextService.cs" />
|
||||
<Compile Include="Macros\XsltExtension.cs" />
|
||||
@@ -1124,6 +1125,7 @@
|
||||
<Compile Include="Standalone\ServiceContextManager.cs" />
|
||||
<Compile Include="Standalone\StandaloneCoreApplication.cs" />
|
||||
<Compile Include="Standalone\StandaloneCoreBootManager.cs" />
|
||||
<Compile Include="Strategies\RelateOnCopyHandler.cs" />
|
||||
<Compile Include="Strings\ContentBaseExtensions.cs" />
|
||||
<Compile Include="Strings\Diff.cs" />
|
||||
<Compile Include="Sync\CurrentServerEnvironmentStatus.cs" />
|
||||
|
||||
@@ -347,12 +347,10 @@ namespace Umbraco.Tests.CodeFirst.Definitions
|
||||
{
|
||||
if(type == currentType) continue;//If the referenced type is equal to the current type we skip it to avoid a circular dependency
|
||||
|
||||
var contentTypeSort = new ContentTypeSort();
|
||||
|
||||
var isResolved = _contentTypeCache.ContainsKey(type.FullName);
|
||||
var lazy = isResolved ? _contentTypeCache[type.FullName].ContentType : GetContentTypeDefinition(type);
|
||||
contentTypeSort.Id = new Lazy<int>(() => lazy.Value.Id);
|
||||
contentTypeSort.Alias = lazy.Value.Alias;
|
||||
contentTypeSort.SortOrder = order;
|
||||
var contentTypeSort = new ContentTypeSort(new Lazy<int>(() => lazy.Value.Id), order, lazy.Value.Alias);
|
||||
contentTypeSorts.Add(contentTypeSort);
|
||||
order++;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,35 @@ namespace Umbraco.Tests
|
||||
public class EnumerableExtensionsTests
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void Unsorted_Sequence_Equal()
|
||||
{
|
||||
var list1 = new[] { 1, 2, 3, 4, 5, 6 };
|
||||
var list2 = new[] { 6, 5, 3, 2, 1, 4 };
|
||||
var list3 = new[] { 6, 5, 4, 3, 2, 2 };
|
||||
|
||||
Assert.IsTrue(list1.UnsortedSequenceEqual(list2));
|
||||
Assert.IsTrue(list2.UnsortedSequenceEqual(list1));
|
||||
Assert.IsFalse(list1.UnsortedSequenceEqual(list3));
|
||||
|
||||
Assert.IsTrue(((IEnumerable<object>)null).UnsortedSequenceEqual(null));
|
||||
Assert.IsFalse(((IEnumerable<int>)null).UnsortedSequenceEqual(list1));
|
||||
Assert.IsFalse(list1.UnsortedSequenceEqual(null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Contains_All()
|
||||
{
|
||||
var list1 = new[] {1, 2, 3, 4, 5, 6};
|
||||
var list2 = new[] {6, 5, 3, 2, 1, 4};
|
||||
var list3 = new[] {6, 5, 4, 3};
|
||||
|
||||
Assert.IsTrue(list1.ContainsAll(list2));
|
||||
Assert.IsTrue(list2.ContainsAll(list1));
|
||||
Assert.IsTrue(list1.ContainsAll(list3));
|
||||
Assert.IsFalse(list3.ContainsAll(list1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Flatten_List_2()
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Umbraco.Tests.Macros
|
||||
{
|
||||
var content = @"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<?UMBRACO_MACRO macroAlias=""My.Map.isCool"" />
|
||||
<?UMBRACO_MACRO macroAlias=""My.Map.isCool eh[boy!]"" />
|
||||
<p>asdfasdf</p>";
|
||||
var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary<string, string>() { { "test1", "value1" }, { "test2", "value2" } });
|
||||
|
||||
@@ -34,8 +34,8 @@ namespace Umbraco.Tests.Macros
|
||||
Assert.AreEqual(@"<p>asdfasdf</p>
|
||||
<p>asdfsadf</p>
|
||||
<div class=""umb-macro-holder mceNonEditable"" test1=""value1"" test2=""value2"">
|
||||
<!-- <?UMBRACO_MACRO macroAlias=""My.Map.isCool"" /> -->
|
||||
<ins>Macro alias: <strong>My.Map.isCool</strong></ins></div>
|
||||
<!-- <?UMBRACO_MACRO macroAlias=""My.Map.isCool eh[boy!]"" /> -->
|
||||
<ins>Macro alias: <strong>My.Map.isCool eh[boy!]</strong></ins></div>
|
||||
<p>asdfasdf</p>".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty));
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,61 @@ namespace Umbraco.Tests.Manifest
|
||||
Assert.AreEqual(0, parser.ElementAt(0).PreValueEditor.Fields.ElementAt(1).Validators.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_Grid_Editors()
|
||||
{
|
||||
var a = JsonConvert.DeserializeObject<JArray>(@"[
|
||||
{
|
||||
alias: 'Test.Test1',
|
||||
name: 'Test 1',
|
||||
view: 'blah',
|
||||
icon: 'hello'
|
||||
},
|
||||
{
|
||||
alias: 'Test.Test2',
|
||||
name: 'Test 2',
|
||||
config: { key1: 'some default val' },
|
||||
view: '/hello/world.cshtml',
|
||||
icon: 'helloworld'
|
||||
},
|
||||
{
|
||||
alias: 'Test.Test3',
|
||||
name: 'Test 3',
|
||||
config: { key1: 'some default val' },
|
||||
view: '/hello/world.html',
|
||||
render: '/hello/world.cshtml',
|
||||
icon: 'helloworld'
|
||||
}
|
||||
]");
|
||||
var parser = ManifestParser.GetGridEditors(a).ToArray();
|
||||
|
||||
Assert.AreEqual(3, parser.Count());
|
||||
|
||||
Assert.AreEqual("Test.Test1", parser.ElementAt(0).Alias);
|
||||
Assert.AreEqual("Test 1", parser.ElementAt(0).Name);
|
||||
Assert.AreEqual("blah", parser.ElementAt(0).View);
|
||||
Assert.AreEqual("hello", parser.ElementAt(0).Icon);
|
||||
Assert.IsNull(parser.ElementAt(0).Render);
|
||||
Assert.AreEqual(0, parser.ElementAt(0).Config.Count);
|
||||
|
||||
Assert.AreEqual("Test.Test2", parser.ElementAt(1).Alias);
|
||||
Assert.AreEqual("Test 2", parser.ElementAt(1).Name);
|
||||
Assert.AreEqual("/hello/world.cshtml", parser.ElementAt(1).View);
|
||||
Assert.AreEqual("helloworld", parser.ElementAt(1).Icon);
|
||||
Assert.IsNull(parser.ElementAt(1).Render);
|
||||
Assert.AreEqual(1, parser.ElementAt(1).Config.Count);
|
||||
Assert.AreEqual("some default val", parser.ElementAt(1).Config["key1"]);
|
||||
|
||||
Assert.AreEqual("Test.Test3", parser.ElementAt(2).Alias);
|
||||
Assert.AreEqual("Test 3", parser.ElementAt(2).Name);
|
||||
Assert.AreEqual("/hello/world.html", parser.ElementAt(2).View);
|
||||
Assert.AreEqual("helloworld", parser.ElementAt(2).Icon);
|
||||
Assert.AreEqual("/hello/world.cshtml", parser.ElementAt(2).Render);
|
||||
Assert.AreEqual(1, parser.ElementAt(2).Config.Count);
|
||||
Assert.AreEqual("some default val", parser.ElementAt(2).Config["key1"]);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Parse_Property_Editors()
|
||||
{
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace Umbraco.Tests.Models
|
||||
Assert.AreEqual(clone.UserType, item.UserType);
|
||||
Assert.AreEqual(clone.AllowedSections.Count(), item.AllowedSections.Count());
|
||||
|
||||
Assert.AreNotSame(clone.DefaultPermissions, item.DefaultPermissions);
|
||||
Assert.AreEqual(clone.DefaultPermissions.Count(), item.DefaultPermissions.Count());
|
||||
|
||||
//Verify normal properties with reflection
|
||||
var allProps = clone.GetType().GetProperties();
|
||||
foreach (var propertyInfo in allProps)
|
||||
|
||||
@@ -172,12 +172,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var contentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
|
||||
contentType.AllowedContentTypes = new List<ContentTypeSort>
|
||||
{
|
||||
new ContentTypeSort
|
||||
{
|
||||
Alias = contentType.Alias,
|
||||
Id = new Lazy<int>(() => contentType.Id),
|
||||
SortOrder = 0
|
||||
}
|
||||
new ContentTypeSort(new Lazy<int>(() => contentType.Id), 0, contentType.Alias)
|
||||
};
|
||||
var parentPage = MockedContent.CreateSimpleContent(contentType);
|
||||
contentTypeRepository.AddOrUpdate(contentType);
|
||||
|
||||
@@ -386,18 +386,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var contentType = repository.Get(NodeDto.NodeIdSeed);
|
||||
contentType.AllowedContentTypes = new List<ContentTypeSort>
|
||||
{
|
||||
new ContentTypeSort
|
||||
{
|
||||
Alias = subpageContentType.Alias,
|
||||
Id = new Lazy<int>(() => subpageContentType.Id),
|
||||
SortOrder = 0
|
||||
},
|
||||
new ContentTypeSort
|
||||
{
|
||||
Alias = simpleSubpageContentType.Alias,
|
||||
Id = new Lazy<int>(() => simpleSubpageContentType.Id),
|
||||
SortOrder = 1
|
||||
}
|
||||
new ContentTypeSort(new Lazy<int>(() => subpageContentType.Id), 0, subpageContentType.Alias),
|
||||
new ContentTypeSort(new Lazy<int>(() => simpleSubpageContentType.Id), 1, simpleSubpageContentType.Alias)
|
||||
};
|
||||
repository.AddOrUpdate(contentType);
|
||||
unitOfWork.Commit();
|
||||
|
||||
@@ -82,8 +82,8 @@ namespace Umbraco.Tests.Plugins
|
||||
var originalTypesFound = TypeFinderOriginal.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
|
||||
|
||||
Assert.AreEqual(originalTypesFound.Count(), typesFound.Count());
|
||||
Assert.AreEqual(5, typesFound.Count());
|
||||
Assert.AreEqual(5, originalTypesFound.Count());
|
||||
Assert.AreEqual(6, typesFound.Count());
|
||||
Assert.AreEqual(6, originalTypesFound.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -112,5 +112,17 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
var urlString = mediaPath.GetCropUrl(width: 100, height: 270, imageCropMode: ImageCropMode.Crop, imageCropAnchor: ImageCropAnchor.Center);
|
||||
Assert.AreEqual(mediaPath + "?mode=crop&anchor=center&width=100&height=270", urlString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test for preferFocalPoint when focal point is centered
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void GetCropUrl_PreferFocalPointCenter()
|
||||
{
|
||||
var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}";
|
||||
|
||||
var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, width: 300, height: 150, preferFocalPoint:true);
|
||||
Assert.AreEqual(mediaPath + "?anchor=center&mode=crop&width=300&height=150", urlString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,12 +239,7 @@ namespace Umbraco.Tests.Services
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
contentType1.AllowedContentTypes = new List<ContentTypeSort>
|
||||
{
|
||||
new ContentTypeSort
|
||||
{
|
||||
Alias = contentType1.Alias,
|
||||
Id = new Lazy<int>(() => contentType1.Id),
|
||||
SortOrder = 0
|
||||
}
|
||||
new ContentTypeSort(new Lazy<int>(() => contentType1.Id), 0, contentType1.Alias)
|
||||
};
|
||||
var result = new List<IContent>();
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
|
||||
@@ -58,9 +58,9 @@
|
||||
<Reference Include="AutoMapper.Net4">
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.60.2941, Culture=neutral, processorArchitecture=MSIL">
|
||||
<Reference Include="Examine, Version=0.1.61.2941, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Examine.0.1.60.2941\lib\Examine.dll</HintPath>
|
||||
<HintPath>..\packages\Examine.0.1.61.2941\lib\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.60.2941" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.61.2941" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"rgrove-lazyload": "*",
|
||||
"jquery": "2.0.3",
|
||||
"jquery-file-upload": "~9.4.0",
|
||||
"jquery-ui": "1.10.3"
|
||||
"jquery-ui": "1.10.3",
|
||||
"angular-dynamic-locale": "~0.1.27"
|
||||
},
|
||||
"exportsOverride": {
|
||||
"rgrove-lazyload": {
|
||||
@@ -33,6 +34,9 @@
|
||||
"underscore": {
|
||||
"": "underscore-min.{js,map}"
|
||||
},
|
||||
"angular-dynamic-locale": {
|
||||
"": "tmhDynamicLocale.min.{js,js.map}"
|
||||
},
|
||||
"jquery": {
|
||||
"": "jquery.min.{js,map}"
|
||||
},
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
( function(window) {
|
||||
'use strict';
|
||||
angular.module('tmh.dynamicLocale', []).provider('tmhDynamicLocale', function() {
|
||||
|
||||
var defaultLocale,
|
||||
localeLocationPattern = 'angular/i18n/angular-locale_{{locale}}.js',
|
||||
storageFactory = 'tmhDynamicLocaleStorageCache',
|
||||
storage,
|
||||
storeKey = 'tmhDynamicLocale.locale',
|
||||
promiseCache = {},
|
||||
activeLocale;
|
||||
|
||||
/**
|
||||
* Loads a script asynchronously
|
||||
*
|
||||
* @param {string} url The url for the script
|
||||
@ @param {function) callback A function to be called once the script is loaded
|
||||
*/
|
||||
function loadScript(url, callback, errorCallback, $timeout) {
|
||||
var script = document.createElement('script'),
|
||||
body = document.getElementsByTagName('body')[0],
|
||||
removed = false;
|
||||
|
||||
script.type = 'text/javascript';
|
||||
if (script.readyState) { // IE
|
||||
script.onreadystatechange = function () {
|
||||
if (script.readyState === 'complete' ||
|
||||
script.readyState === 'loaded') {
|
||||
script.onreadystatechange = null;
|
||||
$timeout(
|
||||
function () {
|
||||
if (removed) return;
|
||||
removed = true;
|
||||
body.removeChild(script);
|
||||
callback();
|
||||
}, 30, false);
|
||||
}
|
||||
};
|
||||
} else { // Others
|
||||
script.onload = function () {
|
||||
if (removed) return;
|
||||
removed = true;
|
||||
body.removeChild(script);
|
||||
callback();
|
||||
};
|
||||
script.onerror = function () {
|
||||
if (removed) return;
|
||||
removed = true;
|
||||
body.removeChild(script);
|
||||
errorCallback();
|
||||
};
|
||||
}
|
||||
script.src = url;
|
||||
script.async = false;
|
||||
body.appendChild(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a locale and replaces the properties from the current locale with the new locale information
|
||||
*
|
||||
* @param localeUrl The path to the new locale
|
||||
* @param $locale The locale at the curent scope
|
||||
*/
|
||||
function loadLocale(localeUrl, $locale, localeId, $rootScope, $q, localeCache, $timeout) {
|
||||
|
||||
function overrideValues(oldObject, newObject) {
|
||||
if (activeLocale !== localeId) {
|
||||
return;
|
||||
}
|
||||
angular.forEach(oldObject, function(value, key) {
|
||||
if (!newObject[key]) {
|
||||
delete oldObject[key];
|
||||
} else if (angular.isArray(newObject[key])) {
|
||||
oldObject[key].length = newObject[key].length;
|
||||
}
|
||||
});
|
||||
angular.forEach(newObject, function(value, key) {
|
||||
if (angular.isArray(newObject[key]) || angular.isObject(newObject[key])) {
|
||||
if (!oldObject[key]) {
|
||||
oldObject[key] = angular.isArray(newObject[key]) ? [] : {};
|
||||
}
|
||||
overrideValues(oldObject[key], newObject[key]);
|
||||
} else {
|
||||
oldObject[key] = newObject[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (promiseCache[localeId]) return promiseCache[localeId];
|
||||
|
||||
var cachedLocale,
|
||||
deferred = $q.defer();
|
||||
if (localeId === activeLocale) {
|
||||
deferred.resolve($locale);
|
||||
} else if ((cachedLocale = localeCache.get(localeId))) {
|
||||
activeLocale = localeId;
|
||||
$rootScope.$evalAsync(function() {
|
||||
overrideValues($locale, cachedLocale);
|
||||
$rootScope.$broadcast('$localeChangeSuccess', localeId, $locale);
|
||||
storage.put(storeKey, localeId);
|
||||
deferred.resolve($locale);
|
||||
});
|
||||
} else {
|
||||
activeLocale = localeId;
|
||||
promiseCache[localeId] = deferred.promise;
|
||||
loadScript(localeUrl, function () {
|
||||
// Create a new injector with the new locale
|
||||
var localInjector = angular.injector(['ngLocale']),
|
||||
externalLocale = localInjector.get('$locale');
|
||||
|
||||
overrideValues($locale, externalLocale);
|
||||
localeCache.put(localeId, externalLocale);
|
||||
delete promiseCache[localeId];
|
||||
|
||||
$rootScope.$apply(function () {
|
||||
$rootScope.$broadcast('$localeChangeSuccess', localeId, $locale);
|
||||
storage.put(storeKey, localeId);
|
||||
deferred.resolve($locale);
|
||||
});
|
||||
}, function () {
|
||||
delete promiseCache[localeId];
|
||||
|
||||
$rootScope.$apply(function () {
|
||||
$rootScope.$broadcast('$localeChangeError', localeId);
|
||||
deferred.reject(localeId);
|
||||
});
|
||||
}, $timeout);
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
this.localeLocationPattern = function(value) {
|
||||
if (value) {
|
||||
localeLocationPattern = value;
|
||||
return this;
|
||||
} else {
|
||||
return localeLocationPattern;
|
||||
}
|
||||
};
|
||||
|
||||
this.useStorage = function(storageName) {
|
||||
storageFactory = storageName;
|
||||
};
|
||||
|
||||
this.useCookieStorage = function() {
|
||||
this.useStorage('$cookieStore');
|
||||
};
|
||||
|
||||
this.defaultLocale = function (value) {
|
||||
defaultLocale = value;
|
||||
};
|
||||
|
||||
this.$get = ['$rootScope', '$injector', '$interpolate', '$locale', '$q', 'tmhDynamicLocaleCache', '$timeout', function($rootScope, $injector, interpolate, locale, $q, tmhDynamicLocaleCache, $timeout) {
|
||||
var localeLocation = interpolate(localeLocationPattern);
|
||||
|
||||
storage = $injector.get(storageFactory);
|
||||
$rootScope.$evalAsync(function () {
|
||||
var initialLocale;
|
||||
if ((initialLocale = (storage.get(storeKey) || defaultLocale))) {
|
||||
loadLocale(localeLocation({locale: initialLocale}), locale, initialLocale, $rootScope, $q, tmhDynamicLocaleCache, $timeout);
|
||||
}
|
||||
});
|
||||
return {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @description
|
||||
* @param {string=} value Sets the locale to the new locale. Changing the locale will trigger
|
||||
* a background task that will retrieve the new locale and configure the current $locale
|
||||
* instance with the information from the new locale
|
||||
*/
|
||||
set: function(value) {
|
||||
return loadLocale(localeLocation({locale: value}), locale, value, $rootScope, $q, tmhDynamicLocaleCache, $timeout);
|
||||
}
|
||||
};
|
||||
}];
|
||||
}).provider('tmhDynamicLocaleCache', function() {
|
||||
this.$get = ['$cacheFactory', function($cacheFactory) {
|
||||
return $cacheFactory('tmh.dynamicLocales');
|
||||
}];
|
||||
}).provider('tmhDynamicLocaleStorageCache', function() {
|
||||
this.$get = ['$cacheFactory', function($cacheFactory) {
|
||||
return $cacheFactory('tmh.dynamicLocales.store');
|
||||
}];
|
||||
}).run(['tmhDynamicLocale', angular.noop]);
|
||||
}(window) );
|
||||
@@ -31,7 +31,7 @@ function inArray(key, arr)
|
||||
|
||||
tinymce = parent.tinymce;
|
||||
editor = tinymce.activeEditor;
|
||||
var i, userSettings = editor.settings.codemirror ? JSON.parse(editor.settings.codemirror) : {};
|
||||
var i, userSettings = editor.settings.codemirror ? (typeof editor.settings.codemirror === 'object') ? editor.settings.codemirror : JSON.parse(editor.settings.codemirror) : {};
|
||||
CMsettings = {
|
||||
path: userSettings.path || 'CodeMirror',
|
||||
indentOnInit: userSettings.indentOnInit || false,
|
||||
|
||||
@@ -193,6 +193,7 @@ tinymce.PluginManager.add('umbracolink', function(editor) {
|
||||
});
|
||||
|
||||
selection.select(anchorElm);
|
||||
editor.execCommand('mceEndTyping');
|
||||
} else {
|
||||
editor.execCommand('mceInsertLink', false, {
|
||||
href: href,
|
||||
|
||||
@@ -15,12 +15,12 @@ var app = angular.module("Umbraco.canvasdesigner", ['colorpicker', 'ui.slider',
|
||||
$scope.pageUrl = "../dialogs/Preview.aspx?id=" + $location.search().id;
|
||||
$scope.valueAreLoaded = false;
|
||||
$scope.devices = [
|
||||
{ name: "desktop", css: "desktop", icon: "icon-display" },
|
||||
{ name: "laptop - 1366px", css: "laptop border", icon: "icon-laptop" },
|
||||
{ name: "iPad portrait - 768px", css: "iPad-portrait border", icon: "icon-ipad" },
|
||||
{ name: "iPad landscape - 1024px", css: "iPad-landscape border", icon: "icon-ipad flip" },
|
||||
{ name: "smartphone portrait - 480px", css: "smartphone-portrait border", icon: "icon-iphone" },
|
||||
{ name: "smartphone landscape - 320px", css: "smartphone-landscape border", icon: "icon-iphone flip" }
|
||||
{ name: "desktop", css: "desktop", icon: "icon-display", title: "Desktop" },
|
||||
{ name: "laptop - 1366px", css: "laptop border", icon: "icon-laptop", title: "Laptop" },
|
||||
{ name: "iPad portrait - 768px", css: "iPad-portrait border", icon: "icon-ipad", title: "Tablet portrait" },
|
||||
{ name: "iPad landscape - 1024px", css: "iPad-landscape border", icon: "icon-ipad flip", title: "Tablet landscape" },
|
||||
{ name: "smartphone portrait - 480px", css: "smartphone-portrait border", icon: "icon-iphone", title: "Smartphone portrait" },
|
||||
{ name: "smartphone landscape - 320px", css: "smartphone-landscape border", icon: "icon-iphone flip", title: "Smartphone landscape" }
|
||||
];
|
||||
$scope.previewDevice = $scope.devices[0];
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<ul class="sections" ng-class="{selected: showDevicesPreview}">
|
||||
<li ng-repeat="device in devices" ng-class="{ current:previewDevice==device }" ng-click="updatePreviewDevice(device)">
|
||||
<a href="#"><i class="icon {{device.icon}}"></i><span></span></a>
|
||||
<a href="#"><i class="icon {{device.icon}}" title="{{device.title}}"></i><span></span></a>
|
||||
</li>
|
||||
<li ng-click="closePreviewDevice()" ng-if="enableCanvasdesigner > 0">
|
||||
<a href="" class="more-options">
|
||||
|
||||
@@ -108,7 +108,7 @@ function umbImageFolder($rootScope, assetsService, $timeout, $log, umbRequestHel
|
||||
//check for the file size error which can only be done with dodgy string checking
|
||||
scope.$on('fileuploadfail', function (e, data) {
|
||||
if (data.jqXHR.status === 500 && data.jqXHR.responseText.indexOf("Maximum request length exceeded") >= 0) {
|
||||
notificationsService.error(data.errorThrown, "The image file size was too big, check with your site administrator to adjust the maximum size allowed");
|
||||
notificationsService.error(data.errorThrown, "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed");
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -33,7 +33,7 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
'<h5>' +
|
||||
'<i ng-if="enablecheckboxes == \'true\'" ng-class="selectEnabledNodeClass(tree.root)"></i>' +
|
||||
'<a href="#/{{section}}" ng-click="select(tree.root, $event)" class="root-link">{{tree.name}}</a></h5>' +
|
||||
'<a href class="umb-options" ng-hide="tree.root.isContainer || !tree.root.menuUrl" ng-click="options(tree.root, $event)" ng-swipe-right="options(tree.root, $event)"><i></i><i></i><i></i></a>' +
|
||||
'<a class="umb-options" ng-hide="tree.root.isContainer || !tree.root.menuUrl" ng-click="options(tree.root, $event)" ng-swipe-right="options(tree.root, $event)"><i></i><i></i><i></i></a>' +
|
||||
'</div>';
|
||||
template += '<ul>' +
|
||||
'<umb-tree-item ng-repeat="child in tree.root.children" eventhandler="eventhandler" node="child" current-node="currentNode" tree="this" section="{{section}}" ng-animate="animation()"></umb-tree-item>' +
|
||||
|
||||
@@ -41,9 +41,9 @@ angular.module("umbraco.directives")
|
||||
'<ins style="width:18px;"></ins>' +
|
||||
'<ins ng-class="{\'icon-navigation-right\': !node.expanded, \'icon-navigation-down\': node.expanded}" ng-click="load(node)"></ins>' +
|
||||
'<i class="icon umb-tree-icon sprTree"></i>' +
|
||||
'<a href ng-click="select(node, $event)" on-right-click="altSelect(node, $event)"></a>' +
|
||||
'<a ng-click="select(node, $event)"></a>' +
|
||||
//NOTE: These are the 'option' elipses
|
||||
'<a href class="umb-options" ng-click="options(node, $event)"><i></i><i></i><i></i></a>' +
|
||||
'<a class="umb-options" ng-click="options(node, $event)"><i></i><i></i><i></i></a>' +
|
||||
'<div ng-show="node.loading" class="l"><div></div></div>' +
|
||||
'</div>' +
|
||||
'</li>',
|
||||
@@ -59,6 +59,7 @@ angular.module("umbraco.directives")
|
||||
|
||||
// Helper function to emit tree events
|
||||
function emitEvent(eventName, args) {
|
||||
|
||||
if (scope.eventhandler) {
|
||||
$(scope.eventhandler).trigger(eventName, args);
|
||||
}
|
||||
|
||||
@@ -44,27 +44,36 @@ angular.module('umbraco.services')
|
||||
.factory('assetsService', function ($q, $log, angularHelper, umbRequestHelper, $rootScope, $http) {
|
||||
|
||||
var initAssetsLoaded = false;
|
||||
var appendRnd = function(url){
|
||||
var appendRnd = function (url) {
|
||||
//if we don't have a global umbraco obj yet, the app is bootstrapping
|
||||
if(!Umbraco.Sys.ServerVariables.application){
|
||||
if (!Umbraco.Sys.ServerVariables.application) {
|
||||
return url;
|
||||
}
|
||||
|
||||
var rnd = Umbraco.Sys.ServerVariables.application.version +"."+Umbraco.Sys.ServerVariables.application.cdf;
|
||||
var _op = (url.indexOf("?")>0) ? "&" : "?";
|
||||
var rnd = Umbraco.Sys.ServerVariables.application.version + "." + Umbraco.Sys.ServerVariables.application.cdf;
|
||||
var _op = (url.indexOf("?") > 0) ? "&" : "?";
|
||||
url = url + _op + "umb__rnd=" + rnd;
|
||||
return url;
|
||||
};
|
||||
|
||||
function convertVirtualPath(path) {
|
||||
//make this work for virtual paths
|
||||
if (path.startsWith("~/")) {
|
||||
path = umbRequestHelper.convertVirtualToAbsolutePath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
var service = {
|
||||
loadedAssets:{},
|
||||
|
||||
_getAssetPromise : function(path){
|
||||
if(this.loadedAssets[path]){
|
||||
loadedAssets: {},
|
||||
|
||||
_getAssetPromise: function (path) {
|
||||
|
||||
if (this.loadedAssets[path]) {
|
||||
return this.loadedAssets[path];
|
||||
}else{
|
||||
} else {
|
||||
var deferred = $q.defer();
|
||||
this.loadedAssets[path] = {deferred: deferred, state: "new", path: path};
|
||||
this.loadedAssets[path] = { deferred: deferred, state: "new", path: path };
|
||||
return this.loadedAssets[path];
|
||||
}
|
||||
},
|
||||
@@ -77,7 +86,7 @@ angular.module('umbraco.services')
|
||||
//here we need to ensure the required application assets are loaded
|
||||
if (initAssetsLoaded === false) {
|
||||
var self = this;
|
||||
self.loadJs(umbRequestHelper.getApiUrl("serverVarsJs", "", ""), $rootScope).then(function() {
|
||||
self.loadJs(umbRequestHelper.getApiUrl("serverVarsJs", "", ""), $rootScope).then(function () {
|
||||
initAssetsLoaded = true;
|
||||
|
||||
//now we need to go get the legacyTreeJs - but this can be done async without waiting.
|
||||
@@ -106,30 +115,33 @@ angular.module('umbraco.services')
|
||||
* @param {Number} timeout in milliseconds
|
||||
* @returns {Promise} Promise object which resolves when the file has loaded
|
||||
*/
|
||||
loadCss : function(path, scope, attributes, timeout){
|
||||
var asset = this._getAssetPromise(path); // $q.defer();
|
||||
var t = timeout || 5000;
|
||||
var a = attributes || undefined;
|
||||
|
||||
if(asset.state === "new"){
|
||||
asset.state = "loading";
|
||||
LazyLoad.css(appendRnd(path), function () {
|
||||
if (!scope) {
|
||||
asset.state = "loaded";
|
||||
asset.deferred.resolve(true);
|
||||
}else{
|
||||
asset.state = "loaded";
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
}else if(asset.state === "loaded"){
|
||||
asset.deferred.resolve(true);
|
||||
}
|
||||
return asset.deferred.promise;
|
||||
},
|
||||
|
||||
loadCss: function (path, scope, attributes, timeout) {
|
||||
|
||||
path = convertVirtualPath(path);
|
||||
|
||||
var asset = this._getAssetPromise(path); // $q.defer();
|
||||
var t = timeout || 5000;
|
||||
var a = attributes || undefined;
|
||||
|
||||
if (asset.state === "new") {
|
||||
asset.state = "loading";
|
||||
LazyLoad.css(appendRnd(path), function () {
|
||||
if (!scope) {
|
||||
asset.state = "loaded";
|
||||
asset.deferred.resolve(true);
|
||||
} else {
|
||||
asset.state = "loaded";
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (asset.state === "loaded") {
|
||||
asset.deferred.resolve(true);
|
||||
}
|
||||
return asset.deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.assetsService#loadJs
|
||||
@@ -144,28 +156,30 @@ angular.module('umbraco.services')
|
||||
* @param {Number} timeout in milliseconds
|
||||
* @returns {Promise} Promise object which resolves when the file has loaded
|
||||
*/
|
||||
loadJs : function(path, scope, attributes, timeout){
|
||||
|
||||
loadJs: function (path, scope, attributes, timeout) {
|
||||
|
||||
path = convertVirtualPath(path);
|
||||
|
||||
var asset = this._getAssetPromise(path); // $q.defer();
|
||||
var t = timeout || 5000;
|
||||
var a = attributes || undefined;
|
||||
|
||||
if(asset.state === "new"){
|
||||
|
||||
if (asset.state === "new") {
|
||||
asset.state = "loading";
|
||||
|
||||
LazyLoad.js(appendRnd(path), function () {
|
||||
if (!scope) {
|
||||
asset.state = "loaded";
|
||||
asset.deferred.resolve(true);
|
||||
}else{
|
||||
asset.state = "loaded";
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
if (!scope) {
|
||||
asset.state = "loaded";
|
||||
asset.deferred.resolve(true);
|
||||
} else {
|
||||
asset.state = "loaded";
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}else if(asset.state === "loaded"){
|
||||
} else if (asset.state === "loaded") {
|
||||
asset.deferred.resolve(true);
|
||||
}
|
||||
|
||||
@@ -192,7 +206,7 @@ angular.module('umbraco.services')
|
||||
throw "pathArray must be an array";
|
||||
}
|
||||
|
||||
var nonEmpty = _.reject(pathArray, function(item) {
|
||||
var nonEmpty = _.reject(pathArray, function (item) {
|
||||
return item === undefined || item === "";
|
||||
});
|
||||
|
||||
@@ -204,12 +218,14 @@ angular.module('umbraco.services')
|
||||
|
||||
//compile a list of promises
|
||||
//blocking
|
||||
_.each(nonEmpty, function(path){
|
||||
_.each(nonEmpty, function (path) {
|
||||
|
||||
path = convertVirtualPath(path);
|
||||
|
||||
var asset = service._getAssetPromise(path);
|
||||
//if not previously loaded, add to list of promises
|
||||
if(asset.state !== "loaded")
|
||||
{
|
||||
if(asset.state === "new"){
|
||||
if (asset.state !== "loaded") {
|
||||
if (asset.state === "new") {
|
||||
asset.state = "loading";
|
||||
assets.push(asset);
|
||||
}
|
||||
@@ -223,21 +239,21 @@ angular.module('umbraco.services')
|
||||
|
||||
//gives a central monitoring of all assets to load
|
||||
promise = $q.all(promises);
|
||||
|
||||
_.each(assets, function(asset){
|
||||
|
||||
_.each(assets, function (asset) {
|
||||
LazyLoad.js(appendRnd(asset.path), function () {
|
||||
if (!scope) {
|
||||
asset.state = "loaded";
|
||||
asset.deferred.resolve(true);
|
||||
}else{
|
||||
asset.state = "loaded";
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
if (!scope) {
|
||||
asset.state = "loaded";
|
||||
asset.deferred.resolve(true);
|
||||
} else {
|
||||
asset.state = "loaded";
|
||||
angularHelper.safeApply(scope, function () {
|
||||
asset.deferred.resolve(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
//return and resolve
|
||||
var deferred = $q.defer();
|
||||
promise = deferred.promise;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module('umbraco.services')
|
||||
.factory('gridService', function ($http, $q){
|
||||
|
||||
var configPath = "../config/grid.editors.config.js";
|
||||
var configPath = Umbraco.Sys.ServerVariables.umbracoUrls.gridConfig;
|
||||
var service = {
|
||||
getGridEditors: function () {
|
||||
return $http.get(configPath);
|
||||
|
||||
@@ -12,8 +12,10 @@ function macroService() {
|
||||
|
||||
/** parses the special macro syntax like <?UMBRACO_MACRO macroAlias="Map" /> and returns an object with the macro alias and it's parameters */
|
||||
parseMacroSyntax: function (syntax) {
|
||||
|
||||
var expression = /(<\?UMBRACO_MACRO macroAlias=["']([\w\.]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i;
|
||||
|
||||
//This regex will match an alias of anything except characters that are quotes or new lines (for legacy reasons, when new macros are created
|
||||
// their aliases are cleaned an invalid chars are stripped)
|
||||
var expression = /(<\?UMBRACO_MACRO macroAlias=["']([^\"\'\n\r]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i;
|
||||
var match = expression.exec(syntax);
|
||||
if (!match || match.length < 3) {
|
||||
return null;
|
||||
@@ -157,4 +159,4 @@ function macroService() {
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.services').factory('macroService', macroService);
|
||||
angular.module('umbraco.services').factory('macroService', macroService);
|
||||
|
||||
@@ -6,6 +6,30 @@
|
||||
function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogService, notificationsService) {
|
||||
return {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.umbRequestHelper#convertVirtualToAbsolutePath
|
||||
* @methodOf umbraco.services.umbRequestHelper
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* This will convert a virtual path (i.e. ~/App_Plugins/Blah/Test.html ) to an absolute path
|
||||
*
|
||||
* @param {string} a virtual path, if this is already an absolute path it will just be returned, if this is a relative path an exception will be thrown
|
||||
*/
|
||||
convertVirtualToAbsolutePath: function(virtualPath) {
|
||||
if (virtualPath.startsWith("/")) {
|
||||
return virtualPath;
|
||||
}
|
||||
if (!virtualPath.startsWith("~/")) {
|
||||
throw "The path " + virtualPath + " is not a virtual path";
|
||||
}
|
||||
if (!Umbraco.Sys.ServerVariables.application.applicationPath) {
|
||||
throw "No applicationPath defined in Umbraco.ServerVariables.application.applicationPath";
|
||||
}
|
||||
return Umbraco.Sys.ServerVariables.application.applicationPath + virtualPath.trimStart("~/");
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.umbRequestHelper#dictionaryToQueryString
|
||||
@@ -225,7 +249,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
|
||||
// we have to just check for the existence of a string value but currently that is the best way to
|
||||
// do this since it's very hacky/difficult to catch this on the server
|
||||
if (data.indexOf("Maximum request length exceeded") >= 0) {
|
||||
notificationsService.error("Server error", "The image file size was too big, check with your site administrator to adjust the maximum size allowed");
|
||||
notificationsService.error("Server error", "The uploaded file was too large, check with your site administrator to adjust the maximum size allowed");
|
||||
}
|
||||
else if (Umbraco.Sys.ServerVariables["isDebuggingEnabled"] === true) {
|
||||
//show a ysod dialog
|
||||
|
||||
@@ -124,11 +124,12 @@ IFRAME {overflow:hidden;}
|
||||
border: 1px dashed rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.usky-grid .tb:hover .usky-row{
|
||||
border-bottom:1px dashed rgba(182, 182, 182, 0.3);
|
||||
.umb-grid .tb:hover .usky-row{
|
||||
border-bottom:1px dashed rgba(182, 182, 182, 0) !important;
|
||||
}
|
||||
|
||||
/*.usky-grid .selectedRow {
|
||||
/*
|
||||
.usky-grid .selectedRow {
|
||||
border: 1px solid rgba(182, 182, 182, 0.3);
|
||||
}*/
|
||||
|
||||
@@ -155,6 +156,8 @@ IFRAME {overflow:hidden;}
|
||||
opacity: 0.3;
|
||||
z-index: 50;
|
||||
}
|
||||
//special rule to ensure forms doesnt overrride (forms will align in a later release)
|
||||
.umb-grid .cell-tools{width: 50px !important;}
|
||||
|
||||
.usky-grid .cell-tools.with-prompt {
|
||||
width:200px;
|
||||
@@ -233,7 +236,7 @@ IFRAME {overflow:hidden;}
|
||||
|
||||
.usky-grid .usky-control:hover{
|
||||
/*border: 1px solid rgba(182, 182, 182, 0.3);*/
|
||||
//border-bottom: 1px solid rgba(182, 182, 182, 0.3);
|
||||
/*border-bottom: 1px solid rgba(182, 182, 182, 0.3);*/
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-placeholder:hover{
|
||||
@@ -249,10 +252,40 @@ IFRAME {overflow:hidden;}
|
||||
border: 1px dashed @blue !important;
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-inner{
|
||||
min-height: 60px;
|
||||
.usky-grid .warnhighlight > ins.item-label{border-color: @red; color: @red;}
|
||||
.usky-grid .infohighlight > ins.item-label{border-color: @blue; color: @blue;}
|
||||
|
||||
|
||||
.usky-grid ins.item-label {
|
||||
position: absolute;
|
||||
top: -22px;
|
||||
left: -1px;
|
||||
text-decoration: none;
|
||||
padding: 0px 7px;
|
||||
display:none;
|
||||
font-size:0.8em;
|
||||
background-color: white;
|
||||
color: @grayLight;
|
||||
border: 1px dashed @grayLight;
|
||||
border-bottom: 1px solid white !important;
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.usky-grid .usky-row-inner > ins.item-label{
|
||||
top: -20px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-inner.selectedControl , .usky-grid .usky-row-inner.selectedRow{
|
||||
border: 1px dashed @grayLight;
|
||||
|
||||
> ins.item-label {
|
||||
display: block;
|
||||
z-index:100000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CONTROL PLACEHOLDER
|
||||
@@ -504,6 +537,7 @@ IFRAME {overflow:hidden;}
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .usky-cell{
|
||||
padding-top: 5px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
@@ -522,14 +556,18 @@ IFRAME {overflow:hidden;}
|
||||
border: 1px dashed transparent;
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-inner{
|
||||
.usky-grid .usky-control-inner {
|
||||
padding: 5px;
|
||||
margin-right: 45px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
border: 1px dashed transparent;
|
||||
min-height: 60px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* template */
|
||||
/**************************************************************************************************/
|
||||
|
||||
@@ -12,7 +12,7 @@ LazyLoad.js(
|
||||
|
||||
'lib/angular/angular-ui-sortable.js',
|
||||
|
||||
'lib/angular/tmhDynamicLocale.js',
|
||||
'lib/angular-dynamic-locale/tmhDynamicLocale.min.js',
|
||||
|
||||
/* App-wide file-upload helper */
|
||||
'lib/jquery-file-upload/jquery.fileupload.js',
|
||||
|
||||
@@ -8,7 +8,27 @@
|
||||
*
|
||||
*/
|
||||
function LegacyController($scope, $routeParams, $element) {
|
||||
$scope.legacyPath = decodeURIComponent($routeParams.url);
|
||||
|
||||
var url = decodeURIComponent($routeParams.url.toLowerCase().replace(/javascript\:/g, ""));
|
||||
//split into path and query
|
||||
var urlParts = url.split("?");
|
||||
var extIndex = urlParts[0].lastIndexOf(".");
|
||||
var ext = extIndex === -1 ? "" : urlParts[0].substr(extIndex);
|
||||
//path cannot be a js file
|
||||
if (ext !== ".js" || ext === "") {
|
||||
//path cannot contain any of these chars
|
||||
var toClean = "*(){}[];:<>\\|'\"";
|
||||
for (var i = 0; i < toClean.length; i++) {
|
||||
var reg = new RegExp("\\" + toClean[i], "g");
|
||||
urlParts[0] = urlParts[0].replace(reg, "");
|
||||
}
|
||||
//join cleaned path and query back together
|
||||
url = urlParts[0] + (urlParts.length === 1 ? "" : ("?" + urlParts[1]));
|
||||
$scope.legacyPath = url;
|
||||
}
|
||||
else {
|
||||
throw "Invalid url";
|
||||
}
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller('Umbraco.LegacyController', LegacyController);
|
||||
@@ -44,7 +44,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="btn-group" ng-show="content.template && !isNew">
|
||||
<div class="btn-group" ng-show="!isNew">
|
||||
<a class="btn" ng-click="preview(content)">
|
||||
<localize key="buttons_showPage">Preview page</localize>
|
||||
</a>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
name="name"
|
||||
localize="placeholder"
|
||||
class="umb-headline"
|
||||
localize="placeholder"
|
||||
select-on-focus
|
||||
placeholder="{{placeholder}}"
|
||||
ng-model="model"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<p class="red">Something went wrong with this editor, below is the data stored:</p>
|
||||
<pre>{{control | json}}</pre>
|
||||
+4
-1
@@ -8,7 +8,10 @@ angular.module("umbraco")
|
||||
dialogService.macroPicker({
|
||||
dialogData: {
|
||||
richTextEditor: true,
|
||||
macroData: $scope.control.value
|
||||
macroData: $scope.control.value || {
|
||||
macroAlias: $scope.control.editor.config && $scope.control.editor.config.macroAlias
|
||||
? $scope.control.editor.config.macroAlias : ""
|
||||
}
|
||||
},
|
||||
callback: function (data) {
|
||||
$scope.control.value = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GridController",
|
||||
function ($scope, $http, assetsService, $rootScope, dialogService, gridService, mediaResource, imageHelper, $timeout) {
|
||||
function ($scope, $http, assetsService, $rootScope, dialogService, gridService, mediaResource, imageHelper, $timeout, umbRequestHelper) {
|
||||
|
||||
// Grid status variables
|
||||
$scope.currentRow = null;
|
||||
@@ -63,7 +63,7 @@ angular.module("umbraco")
|
||||
handle: '.cell-tools-move',
|
||||
connectWith: ".usky-cell",
|
||||
forcePlaceholderSize: true,
|
||||
tolerance:"pointer",
|
||||
tolerance: "pointer",
|
||||
zIndex: 999999999999999999,
|
||||
scrollSensitivity: 100,
|
||||
cursorAt: {
|
||||
@@ -152,7 +152,7 @@ angular.module("umbraco")
|
||||
key: undefined
|
||||
};
|
||||
|
||||
$scope.addItemOverlay = function(event, area, index, key){
|
||||
$scope.addItemOverlay = function (event, area, index, key) {
|
||||
$scope.overlayMenu.area = area;
|
||||
$scope.overlayMenu.index = index;
|
||||
$scope.overlayMenu.style = {};
|
||||
@@ -163,10 +163,10 @@ angular.module("umbraco")
|
||||
var height = $(window).height();
|
||||
var width = $(window).width();
|
||||
|
||||
if((height-offset.top) < 250){
|
||||
if ((height - offset.top) < 250) {
|
||||
$scope.overlayMenu.style.bottom = 0;
|
||||
$scope.overlayMenu.style.top = "initial";
|
||||
}else if(offset.top < 300){
|
||||
} else if (offset.top < 300) {
|
||||
$scope.overlayMenu.style.top = 190;
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ angular.module("umbraco")
|
||||
$scope.model.value = angular.copy(template);
|
||||
|
||||
//default row data
|
||||
_.forEach($scope.model.value.sections, function(section){
|
||||
_.forEach($scope.model.value.sections, function (section) {
|
||||
$scope.initSection(section);
|
||||
});
|
||||
};
|
||||
@@ -221,14 +221,14 @@ angular.module("umbraco")
|
||||
$scope.currentInfohighlightRow = null;
|
||||
};
|
||||
|
||||
$scope.getAllowedLayouts = function(column){
|
||||
$scope.getAllowedLayouts = function (column) {
|
||||
var layouts = $scope.model.config.items.layouts;
|
||||
|
||||
if(column.allowed && column.allowed.length > 0){
|
||||
return _.filter(layouts, function(layout){
|
||||
if (column.allowed && column.allowed.length > 0) {
|
||||
return _.filter(layouts, function (layout) {
|
||||
return _.indexOf(column.allowed, layout.name) >= 0;
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
return layouts;
|
||||
}
|
||||
};
|
||||
@@ -242,8 +242,8 @@ angular.module("umbraco")
|
||||
row = $scope.initRow(row);
|
||||
|
||||
// Push the new row
|
||||
if(row){
|
||||
section.rows.push(row);
|
||||
if (row) {
|
||||
section.rows.push(row);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -264,7 +264,7 @@ angular.module("umbraco")
|
||||
gridItem: gridItem,
|
||||
config: $scope.model.config,
|
||||
itemType: itemType,
|
||||
callback: function(data){
|
||||
callback: function (data) {
|
||||
|
||||
gridItem.styles = data.styles;
|
||||
gridItem.config = data.config;
|
||||
@@ -286,11 +286,11 @@ angular.module("umbraco")
|
||||
$scope.currentCell = null;
|
||||
};
|
||||
|
||||
$scope.cellPreview = function(cell){
|
||||
if(cell && cell.$allowedEditors){
|
||||
$scope.cellPreview = function (cell) {
|
||||
if (cell && cell.$allowedEditors) {
|
||||
var editor = cell.$allowedEditors[0];
|
||||
return editor.icon;
|
||||
}else{
|
||||
} else {
|
||||
return "icon-layout";
|
||||
}
|
||||
};
|
||||
@@ -355,7 +355,7 @@ angular.module("umbraco")
|
||||
};
|
||||
})();
|
||||
|
||||
$scope.addControl = function (editor, cell, index){
|
||||
$scope.addControl = function (editor, cell, index) {
|
||||
$scope.closeItemOverlay();
|
||||
|
||||
var newControl = {
|
||||
@@ -369,18 +369,18 @@ angular.module("umbraco")
|
||||
}
|
||||
|
||||
//populate control
|
||||
$scope.initControl(newControl, index+1);
|
||||
$scope.initControl(newControl, index + 1);
|
||||
|
||||
cell.controls.splice(index + 1, 0, newControl);
|
||||
};
|
||||
|
||||
$scope.addTinyMce = function(cell){
|
||||
$scope.addTinyMce = function (cell) {
|
||||
var rte = $scope.getEditor("rte");
|
||||
$scope.addControl(rte, cell);
|
||||
};
|
||||
|
||||
$scope.getEditor = function(alias){
|
||||
return _.find($scope.availableEditors, function(editor){return editor.alias === alias;});
|
||||
$scope.getEditor = function (alias) {
|
||||
return _.find($scope.availableEditors, function (editor) { return editor.alias === alias; });
|
||||
};
|
||||
|
||||
$scope.removeControl = function (cell, $index) {
|
||||
@@ -388,12 +388,12 @@ angular.module("umbraco")
|
||||
cell.controls.splice($index, 1);
|
||||
};
|
||||
|
||||
$scope.percentage = function(spans){
|
||||
return (( spans/ $scope.model.config.items.columns ) *100).toFixed(1);
|
||||
$scope.percentage = function (spans) {
|
||||
return ((spans / $scope.model.config.items.columns) * 100).toFixed(1);
|
||||
};
|
||||
|
||||
|
||||
$scope.clearPrompt = function(scopedObject, e) {
|
||||
$scope.clearPrompt = function (scopedObject, e) {
|
||||
scopedObject.deletePrompt = false;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -416,68 +416,68 @@ angular.module("umbraco")
|
||||
// *********************************************
|
||||
// Init template + sections
|
||||
// *********************************************
|
||||
$scope.initContent = function() {
|
||||
$scope.initContent = function () {
|
||||
var clear = true;
|
||||
|
||||
//settings indicator shortcut
|
||||
if($scope.model.config.items.config || $scope.model.config.items.styles){
|
||||
if ($scope.model.config.items.config || $scope.model.config.items.styles) {
|
||||
$scope.hasSettings = true;
|
||||
}
|
||||
|
||||
//ensure the grid has a column value set, if nothing is found, set it to 12
|
||||
if($scope.model.config.items.columns && angular.isString($scope.model.config.items.columns)){
|
||||
if ($scope.model.config.items.columns && angular.isString($scope.model.config.items.columns)) {
|
||||
$scope.model.config.items.columns = parseInt($scope.model.config.items.columns);
|
||||
}else{
|
||||
} else {
|
||||
$scope.model.config.items.columns = 12;
|
||||
}
|
||||
|
||||
if ($scope.model.value && $scope.model.value.sections && $scope.model.value.sections.length > 0) {
|
||||
_.forEach($scope.model.value.sections, function(section, index){
|
||||
_.forEach($scope.model.value.sections, function (section, index) {
|
||||
|
||||
if(section.grid > 0){
|
||||
if (section.grid > 0) {
|
||||
$scope.initSection(section);
|
||||
|
||||
//we do this to ensure that the grid can be reset by deleting the last row
|
||||
if(section.rows.length > 0){
|
||||
if (section.rows.length > 0) {
|
||||
clear = false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
$scope.model.value.sections.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}else if($scope.model.config.items.templates && $scope.model.config.items.templates.length === 1){
|
||||
} else if ($scope.model.config.items.templates && $scope.model.config.items.templates.length === 1) {
|
||||
$scope.addTemplate($scope.model.config.items.templates[0]);
|
||||
}
|
||||
|
||||
if(clear){
|
||||
if (clear) {
|
||||
$scope.model.value = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.initSection = function(section){
|
||||
$scope.initSection = function (section) {
|
||||
section.$percentage = $scope.percentage(section.grid);
|
||||
|
||||
var layouts = $scope.model.config.items.layouts;
|
||||
|
||||
if(section.allowed && section.allowed.length > 0){
|
||||
section.$allowedLayouts = _.filter(layouts, function(layout){
|
||||
if (section.allowed && section.allowed.length > 0) {
|
||||
section.$allowedLayouts = _.filter(layouts, function (layout) {
|
||||
return _.indexOf(section.allowed, layout.name) >= 0;
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
section.$allowedLayouts = layouts;
|
||||
}
|
||||
|
||||
if(!section.rows){
|
||||
if (!section.rows) {
|
||||
section.rows = [];
|
||||
}else{
|
||||
_.forEach(section.rows, function(row, index){
|
||||
if(!row.$initialized){
|
||||
} else {
|
||||
_.forEach(section.rows, function (row, index) {
|
||||
if (!row.$initialized) {
|
||||
var initd = $scope.initRow(row);
|
||||
|
||||
//if init fails, remove
|
||||
if(!initd){
|
||||
if (!initd) {
|
||||
section.rows.splice(index, 1);
|
||||
}else{
|
||||
} else {
|
||||
section.rows[index] = initd;
|
||||
}
|
||||
}
|
||||
@@ -489,25 +489,25 @@ angular.module("umbraco")
|
||||
// *********************************************
|
||||
// Init layout / row
|
||||
// *********************************************
|
||||
$scope.initRow = function(row){
|
||||
$scope.initRow = function (row) {
|
||||
|
||||
//merge the layout data with the original config data
|
||||
//if there are no config info on this, splice it out
|
||||
var original = _.find($scope.model.config.items.layouts, function (o) { return o.name === row.name; });
|
||||
|
||||
if(!original){
|
||||
if (!original) {
|
||||
return null;
|
||||
}else{
|
||||
} else {
|
||||
//make a copy to not touch the original config
|
||||
original = angular.copy(original);
|
||||
original.styles = row.styles;
|
||||
original.config = row.config;
|
||||
|
||||
//sync area configuration
|
||||
_.each(original.areas, function(area, areaIndex){
|
||||
_.each(original.areas, function (area, areaIndex) {
|
||||
|
||||
|
||||
if(area.grid > 0){
|
||||
if (area.grid > 0) {
|
||||
var currentArea = row.areas[areaIndex];
|
||||
|
||||
if (currentArea) {
|
||||
@@ -516,14 +516,14 @@ angular.module("umbraco")
|
||||
}
|
||||
|
||||
//copy over existing controls into the new areas
|
||||
if(row.areas.length > areaIndex && row.areas[areaIndex].controls){
|
||||
if (row.areas.length > areaIndex && row.areas[areaIndex].controls) {
|
||||
area.controls = currentArea.controls;
|
||||
|
||||
_.forEach(area.controls, function(control, controlIndex){
|
||||
_.forEach(area.controls, function (control, controlIndex) {
|
||||
$scope.initControl(control, controlIndex);
|
||||
});
|
||||
|
||||
}else{
|
||||
} else {
|
||||
area.controls = [];
|
||||
}
|
||||
|
||||
@@ -532,19 +532,19 @@ angular.module("umbraco")
|
||||
area.$uniqueId = $scope.setUniqueId();
|
||||
|
||||
//set editor permissions
|
||||
if(!area.allowed || area.allowAll === true){
|
||||
if (!area.allowed || area.allowAll === true) {
|
||||
area.$allowedEditors = $scope.availableEditors;
|
||||
area.$allowsRTE = true;
|
||||
}else{
|
||||
area.$allowedEditors = _.filter($scope.availableEditors, function(editor){
|
||||
} else {
|
||||
area.$allowedEditors = _.filter($scope.availableEditors, function (editor) {
|
||||
return _.indexOf(area.allowed, editor.alias) >= 0;
|
||||
});
|
||||
|
||||
if(_.indexOf(area.allowed,"rte")>=0){
|
||||
if (_.indexOf(area.allowed, "rte") >= 0) {
|
||||
area.$allowsRTE = true;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
original.areas.splice(areaIndex, 1);
|
||||
}
|
||||
});
|
||||
@@ -568,26 +568,41 @@ angular.module("umbraco")
|
||||
// Init control
|
||||
// *********************************************
|
||||
|
||||
$scope.initControl = function(control, index){
|
||||
$scope.initControl = function (control, index) {
|
||||
control.$index = index;
|
||||
control.$uniqueId = $scope.setUniqueId();
|
||||
|
||||
if(!control.$editorPath){
|
||||
var editorConfig = $scope.getEditor(control.editor.alias);
|
||||
control.editor = editorConfig;
|
||||
//error handling in case of missing editor..
|
||||
//should only happen if stripped earlier
|
||||
if (!control.editor) {
|
||||
control.$editorPath = "views/propertyeditors/grid/editors/error.html";
|
||||
}
|
||||
|
||||
//if its a path
|
||||
if(_.indexOf(control.editor.view, "/") >= 0){
|
||||
control.$editorPath = control.editor.view;
|
||||
}else{
|
||||
//use convention
|
||||
control.$editorPath = "views/propertyeditors/grid/editors/" + control.editor.view + ".html";
|
||||
if (!control.$editorPath) {
|
||||
var editorConfig = $scope.getEditor(control.editor.alias);
|
||||
|
||||
if (editorConfig) {
|
||||
control.editor = editorConfig;
|
||||
|
||||
//if its an absolute path
|
||||
if (control.editor.view.startsWith("/") || control.editor.view.startsWith("~/")) {
|
||||
control.$editorPath = umbRequestHelper.convertVirtualToAbsolutePath(control.editor.view);
|
||||
}
|
||||
else {
|
||||
//use convention
|
||||
control.$editorPath = "views/propertyeditors/grid/editors/" + control.editor.view + ".html";
|
||||
}
|
||||
}
|
||||
else {
|
||||
control.$editorPath = "views/propertyeditors/grid/editors/error.html";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
gridService.getGridEditors().then(function(response){
|
||||
gridService.getGridEditors().then(function (response) {
|
||||
$scope.availableEditors = response.data;
|
||||
|
||||
$scope.contentReady = true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.GridController" class="usky-grid" id="usky-grid">
|
||||
<div ng-controller="Umbraco.PropertyEditors.GridController" class="usky-grid umb-editor umb-grid" id="usky-grid">
|
||||
|
||||
<div ng-if="contentReady">
|
||||
|
||||
@@ -57,7 +57,8 @@
|
||||
ng-mouseleave="disableCurrentRow()">
|
||||
|
||||
<!-- Row tool -->
|
||||
<div class="row-tools" ng-animate="'fade'" ng-if="currentRow === row && currentControl === null">
|
||||
<div class="row-tools" ng-animate="'fade'"
|
||||
ng-if="currentRow === row && currentControl === null">
|
||||
|
||||
<!-- delete row -->
|
||||
<div class="cell-tools-remove">
|
||||
@@ -72,7 +73,7 @@
|
||||
<a href ng-click="clearPrompt(row, $event)"><localize key="general_no" /></a>
|
||||
</span>
|
||||
|
||||
<i ng-if="!row.deletePrompt" class="icon icon-trash"></i>
|
||||
<i ng-if="!row.deletePrompt" class="icon icon-trash" title="@general_delete" localize="title"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -81,7 +82,7 @@
|
||||
ng-mouseover="setInfohighlightRow(row)"
|
||||
ng-mouseleave="disableInfohighlightRow(row)"
|
||||
href>
|
||||
<i class="icon icon-navigation"></i>
|
||||
<i class="icon icon-navigation" title="@general_move" localize="title"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +92,7 @@
|
||||
ng-mouseleave="disableInfohighlightRow(row)"
|
||||
ng-click="editGridItemSettings(row, 'row')"
|
||||
href>
|
||||
<i class="icon icon-settings"></i>
|
||||
<i class="icon icon-settings" title="@grid_settings" localize="title"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -99,8 +100,14 @@
|
||||
|
||||
<!-- row container -->
|
||||
<div class="{{row.cssClass}} mainContainer usky-row-inner"
|
||||
ng-class="{last:$last,first:$first,warnhighlight:currentWarnhighlightRow == row, infohighlight:currentInfohighlightRow == row}">
|
||||
ng-class="{last:$last,
|
||||
first:$first,
|
||||
warnhighlight:currentWarnhighlightRow == row,
|
||||
infohighlight:currentInfohighlightRow == row,
|
||||
selectedRow:currentRow == row && currentControl === null}">
|
||||
|
||||
<ins class="item-label">{{row.name}}</ins>
|
||||
|
||||
<div class="mainTb">
|
||||
<div class="tb">
|
||||
<div class="tr">
|
||||
@@ -138,7 +145,7 @@
|
||||
<a href ng-click="clearPrompt(control, $event)"><localize key="general_no" /></a>
|
||||
</span>
|
||||
|
||||
<i ng-if="!control.deletePrompt" class="icon icon-trash"></i>
|
||||
<i ng-if="!control.deletePrompt" class="icon icon-trash" title="@general_delete" localize="title"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -148,7 +155,7 @@
|
||||
ng-mouseover="setInfohighlightControl(control)"
|
||||
ng-mouseleave="disableInfohighlightControl(control)"
|
||||
href>
|
||||
<i class="icon icon-navigation"></i>
|
||||
<i class="icon icon-navigation" title="@general_move" localize="title"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -159,7 +166,7 @@
|
||||
ng-mouseleave="disableInfohighlightArea(area)"
|
||||
ng-click="editGridItemSettings(area, 'cell')"
|
||||
href>
|
||||
<i class="icon icon-settings"></i>
|
||||
<i class="icon icon-settings" title="@grid_settings" localize="title"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -169,6 +176,9 @@
|
||||
infohighlight:currentInfohighlightControl == control,
|
||||
warnhighlight:currentWarnhighlightControl == control,
|
||||
selectedControl:currentControl == control}">
|
||||
|
||||
<ins class="item-label">{{control.editor.name}}</ins>
|
||||
|
||||
<!-- Redering the editor for specific control -->
|
||||
<div ng-if="control && control.$editorPath"
|
||||
ng-include="control.$editorPath"
|
||||
@@ -191,7 +201,7 @@
|
||||
ng-animate="'fade'">
|
||||
|
||||
<a class="iconBox" href ng-click="addItemOverlay($event, area, 0, area.$uniqueId);">
|
||||
<i class=" icon icon-add"></i>
|
||||
<i class=" icon icon-add" title="@general_add" localize="title"></i>
|
||||
</a>
|
||||
|
||||
<div ng-if="overlayMenu.show && overlayMenu.key == area.$uniqueId" ng-include="'views/propertyeditors/grid/dialogs/additem.html'"></div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.RTEController",
|
||||
function ($rootScope, $scope, $q, dialogService, $log, imageHelper, assetsService, $timeout, tinyMceService, angularHelper, stylesheetResource) {
|
||||
|
||||
|
||||
$scope.isLoading = true;
|
||||
|
||||
//To id the html textarea we need to use the datetime ticks because we can have multiple rte's per a single property alias
|
||||
@@ -125,6 +125,31 @@ angular.module("umbraco")
|
||||
|
||||
|
||||
if (tinyMceConfig.customConfig) {
|
||||
|
||||
//if there is some custom config, we need to see if the string value of each item might actually be json and if so, we need to
|
||||
// convert it to json instead of having it as a string since this is what tinymce requires
|
||||
for (var i in tinyMceConfig.customConfig) {
|
||||
var val = tinyMceConfig.customConfig[i];
|
||||
if (val) {
|
||||
val = val.toString().trim();
|
||||
if (val.detectIsJson()) {
|
||||
try {
|
||||
tinyMceConfig.customConfig[i] = JSON.parse(val);
|
||||
//now we need to check if this custom config key is defined in our baseline, if it is we don't want to
|
||||
//overwrite the baseline config item if it is an array, we want to concat the items in the array, otherwise
|
||||
//if it's an object it will overwrite the baseline
|
||||
if (angular.isArray(baseLineConfigObj[i]) && angular.isArray(tinyMceConfig.customConfig[i])) {
|
||||
//concat it and below this concat'd array will overwrite the baseline in angular.extend
|
||||
tinyMceConfig.customConfig[i] = baseLineConfigObj[i].concat(tinyMceConfig.customConfig[i]);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
//cannot parse, we'll just leave it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.extend(baseLineConfigObj, tinyMceConfig.customConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,18 @@ describe('macro service tests', function () {
|
||||
expect(result.macroParamsDictionary.test2).not.toBeUndefined();
|
||||
expect(result.macroParamsDictionary.test2).toBe("hello");
|
||||
});
|
||||
|
||||
it('can parse syntax for macros with aliases containing whitespace and other chars', function () {
|
||||
|
||||
var result = macroService.parseMacroSyntax("<?UMBRACO_MACRO macroAlias='Map Test [Hello\\World]' test=\"asdf\" test2='hello' />");
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.macroAlias).toBe("Map Test [Hello\\World]");
|
||||
expect(result.macroParamsDictionary.test).not.toBeUndefined();
|
||||
expect(result.macroParamsDictionary.test).toBe("asdf");
|
||||
expect(result.macroParamsDictionary.test2).not.toBeUndefined();
|
||||
expect(result.macroParamsDictionary.test2).toBe("hello");
|
||||
});
|
||||
|
||||
it('can parse syntax for macros with body', function () {
|
||||
|
||||
|
||||
@@ -115,9 +115,9 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ClientDependency.Core, Version=1.8.2.1, Culture=neutral, processorArchitecture=MSIL">
|
||||
<Reference Include="ClientDependency.Core, Version=1.8.3.1, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\ClientDependency.1.8.2.1\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
<HintPath>..\packages\ClientDependency.1.8.3.1\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ClientDependency.Core.Mvc, Version=1.8.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -127,9 +127,9 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine">
|
||||
<HintPath>..\packages\Examine.0.1.60.2941\lib\Examine.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Reference Include="Examine, Version=0.1.61.2941, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Examine.0.1.61.2941\lib\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@@ -2547,9 +2547,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7220</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7240</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7220</IISUrl>
|
||||
<IISUrl>http://localhost:7240</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
if(cfg != null)
|
||||
foreach (JProperty property in cfg.Properties()) {
|
||||
attrs.Add(property.Name + "='" + property.Value.ToString() + "'");
|
||||
attrs.Add(property.Name + "=\"" + property.Value.ToString() + "\"");
|
||||
}
|
||||
|
||||
JObject style = contentItem.styles;
|
||||
@@ -76,7 +76,7 @@
|
||||
cssVals.Add(property.Name + ":" + property.Value.ToString() + ";");
|
||||
|
||||
if (cssVals.Any())
|
||||
attrs.Add("style='" + string.Join(" ", cssVals) + "'");
|
||||
attrs.Add("style=\"" + string.Join(" ", cssVals) + "\"");
|
||||
}
|
||||
|
||||
return new MvcHtmlString(string.Join(" ", attrs));
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
if(cfg != null)
|
||||
foreach (JProperty property in cfg.Properties()) {
|
||||
attrs.Add(property.Name + "='" + property.Value.ToString() + "'");
|
||||
attrs.Add(property.Name + "=\"" + property.Value.ToString() + "\"");
|
||||
}
|
||||
|
||||
JObject style = contentItem.styles;
|
||||
@@ -76,7 +76,7 @@
|
||||
cssVals.Add(property.Name + ":" + property.Value.ToString() + ";");
|
||||
|
||||
if (cssVals.Any())
|
||||
attrs.Add("style='" + string.Join(" ", cssVals) + "'");
|
||||
attrs.Add("style=\"" + string.Join(" ", cssVals) + "\"");
|
||||
}
|
||||
|
||||
return new MvcHtmlString(string.Join(" ", attrs));
|
||||
|
||||
@@ -132,10 +132,15 @@
|
||||
finder or by the alt. template. Set this option to true to preserve the template set by the finder
|
||||
or by the alt. template, in case of an internal redirect.
|
||||
(false by default, and in fact should remain false unless you know what you're doing)
|
||||
@disableAlternativeTemplates
|
||||
By default you can add a altTemplate querystring or append a template name to the current URL which
|
||||
will make Umbraco render the content on the current page with the template you requested, for example:
|
||||
http://mysite.com/about-us/?altTemplate=Home and http://mysite.com/about-us/Home would render the
|
||||
"About Us" page with a template with the alias Home. Setting this setting to true stops that behavior
|
||||
-->
|
||||
<web.routing
|
||||
trySkipIisCustomErrors="false"
|
||||
internalRedirectPreservesTemplate="false">
|
||||
internalRedirectPreservesTemplate="false" disableAlternativeTemplates="false">
|
||||
</web.routing>
|
||||
|
||||
</settings>
|
||||
|
||||
@@ -290,10 +290,15 @@
|
||||
finder or by the alt. template. Set this option to true to preserve the template set by the finder
|
||||
or by the alt. template, in case of an internal redirect.
|
||||
(false by default, and in fact should remain false unless you know what you're doing)
|
||||
@disableAlternativeTemplates
|
||||
By default you can add a altTemplate querystring or append a template name to the current URL which
|
||||
will make Umbraco render the content on the current page with the template you requested, for example:
|
||||
http://mysite.com/about-us/?altTemplate=Home and http://mysite.com/about-us/Home would render the
|
||||
"About Us" page with a template with the alias Home. Setting this setting to true stops that behavior
|
||||
-->
|
||||
<web.routing
|
||||
trySkipIisCustomErrors="false"
|
||||
internalRedirectPreservesTemplate="false">
|
||||
internalRedirectPreservesTemplate="false" disableAlternativeTemplates="false">
|
||||
</web.routing>
|
||||
|
||||
</settings>
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.8.2.1" targetFramework="net45" />
|
||||
<package id="ClientDependency" version="1.8.3.1" targetFramework="net45" />
|
||||
<package id="ClientDependency-Mvc" version="1.8.0.0" targetFramework="net45" />
|
||||
<package id="dotless" version="1.4.1.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.60.2941" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.61.2941" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="1.9.5.0" targetFramework="net45" />
|
||||
<package id="ImageProcessor.Web" version="3.3.1.0" targetFramework="net45" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
"umbracoUrls": {
|
||||
"authenticationApiBaseUrl": "@(Url.GetUmbracoApiServiceBaseUrl<AuthenticationController>(controller => controller.PostLogin(null)))",
|
||||
"serverVarsJs": '@Url.GetUrlWithCacheBust("ServerVariables", "BackOffice")'
|
||||
},
|
||||
"application": {
|
||||
"applicationPath" : "@Context.Request.ApplicationPath"
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</thead>
|
||||
<tbody data-bind="foreach: domains">
|
||||
<tr>
|
||||
<td valign="top"><input class="domain" data-bind="value: Name, uniqueName: true" /><input type="hidden" value="0" /></td>
|
||||
<td valign="top"><input class="domain" data-bind="value: Name, uniqueName: true" /><input type="hidden" value="0" data-bind="uniqueName: true"/></td>
|
||||
<td valign="top"><select class="language" data-bind="options: $parent.languages, optionsText: 'Code', optionsValue: 'Id', value: Lang, uniqueName: true"></select></td>
|
||||
<td valign="top"><a href="#" class="btn btn-danger" data-bind="click: $parent.removeDomain"><i class="icon icon-trash"></i></a></td>
|
||||
</tr>
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="endPreview.aspx.cs" Inherits="umbraco.presentation.endPreview" %>
|
||||
<%@ Page Language="C#" AutoEventWireup="true" Inherits="System.Web.UI.Page" %>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<script runat="server">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" >
|
||||
<head runat="server">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<form id="form1" runat="server">
|
||||
<div>
|
||||
Redirecting...
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
global::umbraco.presentation.preview.PreviewContent.ClearPreviewCookie();
|
||||
|
||||
if (!Uri.IsWellFormedUriString(Request.QueryString["redir"], UriKind.Relative))
|
||||
{
|
||||
Response.Redirect("/", true);
|
||||
}
|
||||
Uri url;
|
||||
if (!Uri.TryCreate(Request.QueryString["redir"], UriKind.Relative, out url))
|
||||
{
|
||||
Response.Redirect("/", true);
|
||||
}
|
||||
|
||||
Response.Redirect(url.ToString(), true);
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -52,9 +52,15 @@
|
||||
ko.applyBindings(self);
|
||||
|
||||
$.validator.addMethod("domain", function (value, element, param) {
|
||||
// beware! encode('test') == 'test-'
|
||||
// read eg https://rt.cpan.org/Public/Bug/Display.html?id=94347
|
||||
value = punycode.encode(value);
|
||||
var re = /^(http[s]?:\/\/)?([-\w]+(\.[-\w]+)*)(:\d+)?(\/[-\w]*)?$/gi;
|
||||
return this.optional(element) || re.test(value);
|
||||
// that regex is best-effort and certainly not exact
|
||||
var re = /^(http[s]?:\/\/)?([-\w]+(\.[-\w]+)*)(:\d+)?(\/[-\w]*|-)?$/gi;
|
||||
var isopt = this.optional(element);
|
||||
var retest = re.test(value);
|
||||
var ret = isopt || retest;
|
||||
return ret;
|
||||
}, self._opts.invalidDomain);
|
||||
|
||||
$.validator.addMethod("duplicate", function (value, element, param) {
|
||||
@@ -85,7 +91,7 @@
|
||||
return false;
|
||||
|
||||
var mask = $('#komask');
|
||||
var masked = mask.next();
|
||||
var masked = mask.parent();
|
||||
mask.height(masked.height());
|
||||
mask.width(masked.width());
|
||||
mask.show();
|
||||
|
||||
@@ -14,7 +14,11 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Trees;
|
||||
@@ -30,6 +34,7 @@ namespace Umbraco.Web.Editors
|
||||
/// A controller to render out the default back office view and JS results
|
||||
/// </summary>
|
||||
[UmbracoUseHttps]
|
||||
[DisableClientCache]
|
||||
public class BackOfficeController : UmbracoController
|
||||
{
|
||||
/// <summary>
|
||||
@@ -62,7 +67,9 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
var cultureInfo = culture == null
|
||||
//if the user is logged in, get their culture, otherwise default to 'en'
|
||||
? User.Identity.IsAuthenticated ? Security.CurrentUser.GetUserCulture(Services.TextService) : CultureInfo.GetCultureInfo("en")
|
||||
? User.Identity.IsAuthenticated && User.Identity is UmbracoBackOfficeIdentity
|
||||
? Security.CurrentUser.GetUserCulture(Services.TextService)
|
||||
: CultureInfo.GetCultureInfo("en")
|
||||
: CultureInfo.GetCultureInfo(culture);
|
||||
|
||||
var textForCulture = Services.TextService.GetAllStoredValues(cultureInfo)
|
||||
@@ -78,11 +85,11 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[MinifyJavaScriptResult(Order = 0)]
|
||||
[OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Any, Duration = 5000)]
|
||||
[OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)]
|
||||
public JavaScriptResult Application()
|
||||
{
|
||||
var plugins = new DirectoryInfo(Server.MapPath("~/App_Plugins"));
|
||||
var parser = new ManifestParser(plugins);
|
||||
var parser = new ManifestParser(plugins, ApplicationContext.ApplicationCache.RuntimeCache);
|
||||
var initJs = new JsInitialization(parser);
|
||||
var initCss = new CssInitialization(parser);
|
||||
|
||||
@@ -103,16 +110,75 @@ namespace Umbraco.Web.Editors
|
||||
[HttpGet]
|
||||
public JsonNetResult GetManifestAssetList()
|
||||
{
|
||||
var plugins = new DirectoryInfo(Server.MapPath("~/App_Plugins"));
|
||||
var parser = new ManifestParser(plugins);
|
||||
var initJs = new JsInitialization(parser);
|
||||
var initCss = new CssInitialization(parser);
|
||||
var jsResult = initJs.GetJavascriptInitializationArray(HttpContext, new JArray());
|
||||
var cssResult = initCss.GetStylesheetInitializationArray(HttpContext);
|
||||
Func<JArray> getResult = () =>
|
||||
{
|
||||
var plugins = new DirectoryInfo(Server.MapPath("~/App_Plugins"));
|
||||
var parser = new ManifestParser(plugins, ApplicationContext.ApplicationCache.RuntimeCache);
|
||||
var initJs = new JsInitialization(parser);
|
||||
var initCss = new CssInitialization(parser);
|
||||
var jsResult = initJs.GetJavascriptInitializationArray(HttpContext, new JArray());
|
||||
var cssResult = initCss.GetStylesheetInitializationArray(HttpContext);
|
||||
ManifestParser.MergeJArrays(jsResult, cssResult);
|
||||
return jsResult;
|
||||
};
|
||||
|
||||
ManifestParser.MergeJArrays(jsResult, cssResult);
|
||||
//cache the result if debugging is disabled
|
||||
var result = HttpContext.IsDebuggingEnabled
|
||||
? getResult()
|
||||
: ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<JArray>(
|
||||
typeof (BackOfficeController) + "GetManifestAssetList",
|
||||
() => getResult(),
|
||||
new TimeSpan(0, 10, 0));
|
||||
|
||||
return new JsonNetResult {Data = jsResult, Formatting = Formatting.Indented};
|
||||
return new JsonNetResult { Data = result, Formatting = Formatting.Indented };
|
||||
}
|
||||
|
||||
[UmbracoAuthorize(Order = 0)]
|
||||
[HttpGet]
|
||||
public JsonNetResult GetGridConfig()
|
||||
{
|
||||
Func<List<GridEditor>> getResult = () =>
|
||||
{
|
||||
var editors = new List<GridEditor>();
|
||||
var gridConfig = Server.MapPath("~/Config/grid.editors.config.js");
|
||||
if (System.IO.File.Exists(gridConfig))
|
||||
{
|
||||
try
|
||||
{
|
||||
var arr = JArray.Parse(System.IO.File.ReadAllText(gridConfig));
|
||||
//ensure the contents parse correctly to objects
|
||||
var parsed = ManifestParser.GetGridEditors(arr);
|
||||
editors.AddRange(parsed);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<BackOfficeController>("Could not parse the contents of grid.editors.config.js into a JSON array", ex);
|
||||
}
|
||||
}
|
||||
|
||||
var plugins = new DirectoryInfo(Server.MapPath("~/App_Plugins"));
|
||||
var parser = new ManifestParser(plugins, ApplicationContext.ApplicationCache.RuntimeCache);
|
||||
var builder = new ManifestBuilder(ApplicationContext.ApplicationCache.RuntimeCache, parser);
|
||||
foreach (var gridEditor in builder.GridEditors)
|
||||
{
|
||||
//no duplicates! (based on alias)
|
||||
if (editors.Contains(gridEditor) == false)
|
||||
{
|
||||
editors.Add(gridEditor);
|
||||
}
|
||||
}
|
||||
return editors;
|
||||
};
|
||||
|
||||
//cache the result if debugging is disabled
|
||||
var result = HttpContext.IsDebuggingEnabled
|
||||
? getResult()
|
||||
: ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<List<GridEditor>>(
|
||||
typeof(BackOfficeController) + "GetGridConfig",
|
||||
() => getResult(),
|
||||
new TimeSpan(0, 10, 0));
|
||||
|
||||
return new JsonNetResult { Data = result, Formatting = Formatting.Indented };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -121,172 +187,178 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
[UmbracoAuthorize(Order = 0)]
|
||||
[MinifyJavaScriptResult(Order = 1)]
|
||||
[OutputCache(Order = 2, VaryByParam = "none", Location = OutputCacheLocation.Any, Duration = 5000)]
|
||||
public JavaScriptResult ServerVariables()
|
||||
{
|
||||
//authenticationApiBaseUrl
|
||||
|
||||
//now we need to build up the variables
|
||||
var d = new Dictionary<string, object>
|
||||
Func<Dictionary<string, object>> getResult = () => new Dictionary<string, object>
|
||||
{
|
||||
{
|
||||
"umbracoUrls", new Dictionary<string, object>
|
||||
{
|
||||
"umbracoUrls", new Dictionary<string, object>
|
||||
{
|
||||
{"legacyTreeJs", Url.Action("LegacyTreeJs", "BackOffice")},
|
||||
{"manifestAssetList", Url.Action("GetManifestAssetList", "BackOffice")},
|
||||
{"serverVarsJs", Url.Action("Application", "BackOffice")},
|
||||
//API URLs
|
||||
{
|
||||
"embedApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<RteEmbedController>(
|
||||
controller => controller.GetEmbed("",0,0))
|
||||
},
|
||||
{
|
||||
"userApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<UserController>(
|
||||
controller => controller.PostDisableUser(0))
|
||||
},
|
||||
{
|
||||
"contentApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ContentController>(
|
||||
controller => controller.PostSave(null))
|
||||
},
|
||||
{
|
||||
"mediaApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaController>(
|
||||
controller => controller.GetRootMedia())
|
||||
},
|
||||
{
|
||||
"imagesApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ImagesController>(
|
||||
controller => controller.GetBigThumbnail(0))
|
||||
},
|
||||
{
|
||||
"sectionApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<SectionController>(
|
||||
controller => controller.GetSections())
|
||||
},
|
||||
{
|
||||
"treeApplicationApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ApplicationTreeController>(
|
||||
controller => controller.GetApplicationTrees(null, null, null))
|
||||
},
|
||||
{
|
||||
"contentTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ContentTypeController>(
|
||||
controller => controller.GetAllowedChildren(0))
|
||||
},
|
||||
{
|
||||
"mediaTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaTypeController>(
|
||||
controller => controller.GetAllowedChildren(0))
|
||||
},
|
||||
{
|
||||
"macroApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MacroController>(
|
||||
controller => controller.GetMacroParameters(0))
|
||||
},
|
||||
{
|
||||
"authenticationApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<AuthenticationController>(
|
||||
controller => controller.PostLogin(null))
|
||||
},
|
||||
{
|
||||
"currentUserApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<CurrentUserController>(
|
||||
controller => controller.GetMembershipProviderConfig())
|
||||
},
|
||||
{
|
||||
"legacyApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<LegacyController>(
|
||||
controller => controller.DeleteLegacyItem(null, null, null))
|
||||
},
|
||||
{
|
||||
"entityApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<EntityController>(
|
||||
controller => controller.GetById(0, UmbracoEntityTypes.Media))
|
||||
},
|
||||
{
|
||||
"dataTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<DataTypeController>(
|
||||
controller => controller.GetById(0))
|
||||
},
|
||||
{
|
||||
"dashboardApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<DashboardController>(
|
||||
controller => controller.GetDashboard(null))
|
||||
},
|
||||
{
|
||||
"logApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<LogController>(
|
||||
controller => controller.GetEntityLog(0))
|
||||
},
|
||||
{
|
||||
"memberApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MemberController>(
|
||||
controller => controller.GetByKey(Guid.Empty))
|
||||
},
|
||||
{
|
||||
"packageInstallApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<PackageInstallController>(
|
||||
controller => controller.Fetch(string.Empty))
|
||||
},
|
||||
{
|
||||
"rteApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<RichTextPreValueController>(
|
||||
controller => controller.GetConfiguration())
|
||||
},
|
||||
{
|
||||
"stylesheetApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<StylesheetController>(
|
||||
controller => controller.GetAll())
|
||||
},
|
||||
{
|
||||
"memberTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MemberTypeController>(
|
||||
controller => controller.GetAllTypes())
|
||||
},
|
||||
{
|
||||
"updateCheckApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<UpdateCheckController>(
|
||||
controller => controller.GetCheck())
|
||||
},
|
||||
{
|
||||
"tagApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<TagsController>(
|
||||
controller => controller.GetAllTags(null))
|
||||
},
|
||||
{
|
||||
"memberTreeBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MemberTreeController>(
|
||||
controller => controller.GetNodes("-1", null))
|
||||
},
|
||||
{
|
||||
"mediaTreeBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaTreeController>(
|
||||
controller => controller.GetNodes("-1", null))
|
||||
},
|
||||
{
|
||||
"contentTreeBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ContentTreeController>(
|
||||
controller => controller.GetNodes("-1", null))
|
||||
},
|
||||
{
|
||||
"tagsDataBaseUrl", Url.GetUmbracoApiServiceBaseUrl<TagsDataController>(
|
||||
controller => controller.GetTags(""))
|
||||
},
|
||||
{
|
||||
"examineMgmtBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ExamineManagementApiController>(
|
||||
controller => controller.GetIndexerDetails())
|
||||
},
|
||||
{
|
||||
"xmlDataIntegrityBaseUrl", Url.GetUmbracoApiServiceBaseUrl<XmlDataIntegrityController>(
|
||||
controller => controller.CheckContentXmlTable())
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"umbracoSettings", new Dictionary<string, object>
|
||||
{
|
||||
{"umbracoPath", GlobalSettings.Path},
|
||||
{"mediaPath", IOHelper.ResolveUrl(SystemDirectories.Media).TrimEnd('/')},
|
||||
{"appPluginsPath", IOHelper.ResolveUrl(SystemDirectories.AppPlugins).TrimEnd('/')},
|
||||
{
|
||||
"imageFileTypes",
|
||||
string.Join(",", UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes)
|
||||
},
|
||||
{"keepUserLoggedIn", UmbracoConfig.For.UmbracoSettings().Security.KeepUserLoggedIn},
|
||||
}
|
||||
},
|
||||
{
|
||||
"umbracoPlugins", new Dictionary<string, object>
|
||||
{
|
||||
{"trees", GetTreePluginsMetaData()}
|
||||
}
|
||||
},
|
||||
{"isDebuggingEnabled", HttpContext.IsDebuggingEnabled},
|
||||
{
|
||||
"application", GetApplicationState()
|
||||
{"legacyTreeJs", Url.Action("LegacyTreeJs", "BackOffice")},
|
||||
{"manifestAssetList", Url.Action("GetManifestAssetList", "BackOffice")},
|
||||
{"gridConfig", Url.Action("GetGridConfig", "BackOffice")},
|
||||
{"serverVarsJs", Url.Action("Application", "BackOffice")},
|
||||
//API URLs
|
||||
{
|
||||
"embedApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<RteEmbedController>(
|
||||
controller => controller.GetEmbed("", 0, 0))
|
||||
},
|
||||
{
|
||||
"userApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<UserController>(
|
||||
controller => controller.PostDisableUser(0))
|
||||
},
|
||||
{
|
||||
"contentApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ContentController>(
|
||||
controller => controller.PostSave(null))
|
||||
},
|
||||
{
|
||||
"mediaApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaController>(
|
||||
controller => controller.GetRootMedia())
|
||||
},
|
||||
{
|
||||
"imagesApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ImagesController>(
|
||||
controller => controller.GetBigThumbnail(0))
|
||||
},
|
||||
{
|
||||
"sectionApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<SectionController>(
|
||||
controller => controller.GetSections())
|
||||
},
|
||||
{
|
||||
"treeApplicationApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ApplicationTreeController>(
|
||||
controller => controller.GetApplicationTrees(null, null, null))
|
||||
},
|
||||
{
|
||||
"contentTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ContentTypeController>(
|
||||
controller => controller.GetAllowedChildren(0))
|
||||
},
|
||||
{
|
||||
"mediaTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaTypeController>(
|
||||
controller => controller.GetAllowedChildren(0))
|
||||
},
|
||||
{
|
||||
"macroApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MacroController>(
|
||||
controller => controller.GetMacroParameters(0))
|
||||
},
|
||||
{
|
||||
"authenticationApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<AuthenticationController>(
|
||||
controller => controller.PostLogin(null))
|
||||
},
|
||||
{
|
||||
"currentUserApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<CurrentUserController>(
|
||||
controller => controller.GetMembershipProviderConfig())
|
||||
},
|
||||
{
|
||||
"legacyApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<LegacyController>(
|
||||
controller => controller.DeleteLegacyItem(null, null, null))
|
||||
},
|
||||
{
|
||||
"entityApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<EntityController>(
|
||||
controller => controller.GetById(0, UmbracoEntityTypes.Media))
|
||||
},
|
||||
{
|
||||
"dataTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<DataTypeController>(
|
||||
controller => controller.GetById(0))
|
||||
},
|
||||
{
|
||||
"dashboardApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<DashboardController>(
|
||||
controller => controller.GetDashboard(null))
|
||||
},
|
||||
{
|
||||
"logApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<LogController>(
|
||||
controller => controller.GetEntityLog(0))
|
||||
},
|
||||
{
|
||||
"memberApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MemberController>(
|
||||
controller => controller.GetByKey(Guid.Empty))
|
||||
},
|
||||
{
|
||||
"packageInstallApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<PackageInstallController>(
|
||||
controller => controller.Fetch(string.Empty))
|
||||
},
|
||||
{
|
||||
"rteApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<RichTextPreValueController>(
|
||||
controller => controller.GetConfiguration())
|
||||
},
|
||||
{
|
||||
"stylesheetApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<StylesheetController>(
|
||||
controller => controller.GetAll())
|
||||
},
|
||||
{
|
||||
"memberTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MemberTypeController>(
|
||||
controller => controller.GetAllTypes())
|
||||
},
|
||||
{
|
||||
"updateCheckApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<UpdateCheckController>(
|
||||
controller => controller.GetCheck())
|
||||
},
|
||||
{
|
||||
"tagApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<TagsController>(
|
||||
controller => controller.GetAllTags(null))
|
||||
},
|
||||
{
|
||||
"memberTreeBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MemberTreeController>(
|
||||
controller => controller.GetNodes("-1", null))
|
||||
},
|
||||
{
|
||||
"mediaTreeBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaTreeController>(
|
||||
controller => controller.GetNodes("-1", null))
|
||||
},
|
||||
{
|
||||
"contentTreeBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ContentTreeController>(
|
||||
controller => controller.GetNodes("-1", null))
|
||||
},
|
||||
{
|
||||
"tagsDataBaseUrl", Url.GetUmbracoApiServiceBaseUrl<TagsDataController>(
|
||||
controller => controller.GetTags(""))
|
||||
},
|
||||
{
|
||||
"examineMgmtBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ExamineManagementApiController>(
|
||||
controller => controller.GetIndexerDetails())
|
||||
},
|
||||
{
|
||||
"xmlDataIntegrityBaseUrl", Url.GetUmbracoApiServiceBaseUrl<XmlDataIntegrityController>(
|
||||
controller => controller.CheckContentXmlTable())
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
{
|
||||
"umbracoSettings", new Dictionary<string, object>
|
||||
{
|
||||
{"umbracoPath", GlobalSettings.Path},
|
||||
{"mediaPath", IOHelper.ResolveUrl(SystemDirectories.Media).TrimEnd('/')},
|
||||
{"appPluginsPath", IOHelper.ResolveUrl(SystemDirectories.AppPlugins).TrimEnd('/')},
|
||||
{
|
||||
"imageFileTypes",
|
||||
string.Join(",", UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes)
|
||||
},
|
||||
{"keepUserLoggedIn", UmbracoConfig.For.UmbracoSettings().Security.KeepUserLoggedIn},
|
||||
}
|
||||
},
|
||||
{
|
||||
"umbracoPlugins", new Dictionary<string, object>
|
||||
{
|
||||
{"trees", GetTreePluginsMetaData()}
|
||||
}
|
||||
},
|
||||
{"isDebuggingEnabled", HttpContext.IsDebuggingEnabled},
|
||||
{"application", GetApplicationState()}
|
||||
};
|
||||
|
||||
//cache the result if debugging is disabled
|
||||
var result = HttpContext.IsDebuggingEnabled
|
||||
? getResult()
|
||||
: ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<Dictionary<string, object>>(
|
||||
typeof(BackOfficeController) + "ServerVariables",
|
||||
() => getResult(),
|
||||
new TimeSpan(0, 10, 0));
|
||||
|
||||
return JavaScript(ServerVariablesParser.Parse(d));
|
||||
return JavaScript(ServerVariablesParser.Parse(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the server variables regarding the application state
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Dictionary<string, object> GetApplicationState()
|
||||
{
|
||||
if (ApplicationContext.IsConfigured == false)
|
||||
@@ -303,6 +375,8 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
app.Add("version", version);
|
||||
app.Add("cdf", ClientDependency.Core.Config.ClientDependencySettings.Instance.Version);
|
||||
//useful for dealing with virtual paths on the client side when hosted in virtual directories especially
|
||||
app.Add("applicationPath", HttpContext.Request.ApplicationPath.EnsureEndsWith('/'));
|
||||
return app;
|
||||
}
|
||||
|
||||
@@ -339,18 +413,30 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
[UmbracoAuthorize(Order = 0)]
|
||||
[MinifyJavaScriptResult(Order = 1)]
|
||||
[OutputCache(Order = 2, VaryByParam = "none", Location = OutputCacheLocation.Any, Duration = 5000)]
|
||||
public JavaScriptResult LegacyTreeJs()
|
||||
{
|
||||
var javascript = new StringBuilder();
|
||||
javascript.AppendLine(LegacyTreeJavascript.GetLegacyTreeJavascript());
|
||||
javascript.AppendLine(LegacyTreeJavascript.GetLegacyIActionJavascript());
|
||||
//add all of the menu blocks
|
||||
foreach (var file in GetLegacyActionJs(LegacyJsActionType.JsBlock))
|
||||
{
|
||||
Func<string> getResult = () =>
|
||||
{
|
||||
javascript.AppendLine(file);
|
||||
}
|
||||
return JavaScript(javascript.ToString());
|
||||
var javascript = new StringBuilder();
|
||||
javascript.AppendLine(LegacyTreeJavascript.GetLegacyTreeJavascript());
|
||||
javascript.AppendLine(LegacyTreeJavascript.GetLegacyIActionJavascript());
|
||||
//add all of the menu blocks
|
||||
foreach (var file in GetLegacyActionJs(LegacyJsActionType.JsBlock))
|
||||
{
|
||||
javascript.AppendLine(file);
|
||||
}
|
||||
return javascript.ToString();
|
||||
};
|
||||
|
||||
//cache the result if debugging is disabled
|
||||
var result = HttpContext.IsDebuggingEnabled
|
||||
? getResult()
|
||||
: ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<string>(
|
||||
typeof(BackOfficeController) + "LegacyTreeJs",
|
||||
() => getResult(),
|
||||
new TimeSpan(0, 10, 0));
|
||||
|
||||
return JavaScript(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -40,10 +40,8 @@ namespace Umbraco.Web.Editors
|
||||
response = client.DownloadString(new Uri(googleWebFontAPIURL));
|
||||
}
|
||||
|
||||
var resp = new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent(response)
|
||||
};
|
||||
var resp = Request.CreateResponse();
|
||||
resp.Content = new StringContent(response);
|
||||
resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
return resp;
|
||||
|
||||
@@ -69,10 +67,8 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
// Response
|
||||
var resp = new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent("{" + String.Join(",", parameters) + "}")
|
||||
};
|
||||
var resp = Request.CreateResponse();
|
||||
resp.Content = new StringContent("{" + String.Join(",", parameters) + "}");
|
||||
resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
return resp;
|
||||
}
|
||||
@@ -89,10 +85,8 @@ namespace Umbraco.Web.Editors
|
||||
// Save and compile styles
|
||||
CanvasDesignerUtility.SaveAndPublishStyle(parameters, pageId, inherited);
|
||||
|
||||
var resp = new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent("ok")
|
||||
};
|
||||
var resp = Request.CreateResponse();
|
||||
resp.Content = new StringContent("ok");
|
||||
resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
return resp;
|
||||
|
||||
@@ -106,10 +100,8 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
CanvasDesignerUtility.DeleteStyle(int.Parse(pageId));
|
||||
|
||||
var resp = new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent("ok")
|
||||
};
|
||||
var resp = Request.CreateResponse();
|
||||
resp.Content = new StringContent("ok");
|
||||
resp.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||
return resp;
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using System.Globalization;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
namespace Umbraco.Web
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
internal static class ImageCropperBaseExtensions
|
||||
{
|
||||
|
||||
@@ -88,7 +86,7 @@ namespace Umbraco.Web
|
||||
cropUrl.Append("?center=" + cropDataSet.FocalPoint.Top.ToString(CultureInfo.InvariantCulture) + "," + cropDataSet.FocalPoint.Left.ToString(CultureInfo.InvariantCulture));
|
||||
cropUrl.Append("&mode=crop");
|
||||
}
|
||||
else if (crop != null && crop.Coordinates != null)
|
||||
else if (crop != null && crop.Coordinates != null && preferFocalPoint == false)
|
||||
{
|
||||
cropUrl.Append("?crop=");
|
||||
cropUrl.Append(crop.Coordinates.X1.ToString(CultureInfo.InvariantCulture)).Append(",");
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for getting ImageProcessor Url from the core Image Cropper property editor
|
||||
|
||||
@@ -21,13 +21,13 @@ namespace Umbraco.Web.Install.Controllers
|
||||
[HttpInstallAuthorize]
|
||||
public class InstallApiController : ApiController
|
||||
{
|
||||
protected InstallApiController()
|
||||
public InstallApiController()
|
||||
: this(UmbracoContext.Current)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected InstallApiController(UmbracoContext umbracoContext)
|
||||
public InstallApiController(UmbracoContext umbracoContext)
|
||||
{
|
||||
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
|
||||
UmbracoContext = umbracoContext;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public static class ContentExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the culture that would be selected to render a specified content,
|
||||
/// within the context of a specified current request.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <param name="current">The request Uri.</param>
|
||||
/// <returns>The culture that would be selected to render the content.</returns>
|
||||
public static CultureInfo GetCulture(this IContent content, Uri current = null)
|
||||
{
|
||||
return GetCulture(UmbracoContext.Current,
|
||||
ApplicationContext.Current.Services.LocalizationService,
|
||||
content.Id, content.Path,
|
||||
current);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the culture that would be selected to render a specified content,
|
||||
/// within the context of a specified current request.
|
||||
/// </summary>
|
||||
/// <param name="umbracoContext">An <see cref="UmbracoContext"/> instance.</param>
|
||||
/// <param name="localizationService">An <see cref="ILocalizationService"/> implementation.</param>
|
||||
/// <param name="contentId">The content identifier.</param>
|
||||
/// <param name="contentPath">The content path.</param>
|
||||
/// <param name="current">The request Uri.</param>
|
||||
/// <returns>The culture that would be selected to render the content.</returns>
|
||||
internal static CultureInfo GetCulture(UmbracoContext umbracoContext, ILocalizationService localizationService,
|
||||
int contentId, string contentPath, Uri current)
|
||||
{
|
||||
var route = umbracoContext.ContentCache.GetRouteById(contentId); // cached
|
||||
var pos = route.IndexOf('/');
|
||||
|
||||
var domain = pos == 0
|
||||
? null
|
||||
: DomainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current).Domain;
|
||||
|
||||
if (domain == null)
|
||||
{
|
||||
var defaultLanguage = localizationService.GetAllLanguages().FirstOrDefault();
|
||||
return defaultLanguage == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultLanguage.IsoCode);
|
||||
}
|
||||
|
||||
var wcDomain = DomainHelper.FindWildcardDomainInPath(DomainHelper.GetAllDomains(true), contentPath, domain.RootNodeId);
|
||||
return wcDomain == null
|
||||
? new CultureInfo(domain.Language.CultureAlias)
|
||||
: new CultureInfo(wcDomain.Language.CultureAlias);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Web.Models
|
||||
[DataMember(Name = "group")]
|
||||
public string Group { get; set; }
|
||||
|
||||
[DataMember(Name = "nodeCount`")]
|
||||
[DataMember(Name = "nodeCount")]
|
||||
public int NodeCount { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Umbraco.Web.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Will ensure that client-side cache does not occur by sending the correct response headers
|
||||
/// </summary>
|
||||
public class DisableClientCacheAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnResultExecuting(ResultExecutingContext filterContext)
|
||||
{
|
||||
if (filterContext.IsChildAction) base.OnResultExecuting(filterContext);
|
||||
|
||||
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
|
||||
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
|
||||
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
|
||||
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
|
||||
filterContext.HttpContext.Response.Cache.SetNoStore();
|
||||
|
||||
base.OnResultExecuting(filterContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user