Merge remote-tracking branch 'origin/7.0.0' into 7.0.0--property-editor-guid-to-alias
Conflicts: src/Umbraco.Core/Configuration/LegacyUmbracoSettings.cs src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs src/Umbraco.Core/XmlHelper.cs src/Umbraco.Tests/ObjectExtensionsTests.cs src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs src/Umbraco.Web/Routing/DefaultUrlProvider.cs src/Umbraco.Web/Umbraco.Web.csproj src/Umbraco.Web/umbraco.presentation/macro.cs
This commit is contained in:
@@ -100,7 +100,7 @@ namespace Umbraco.Core
|
||||
//
|
||||
public bool IsConfigured
|
||||
{
|
||||
// fixme - let's do this for the time being
|
||||
// fixme - we should not do this - ok for now
|
||||
get
|
||||
{
|
||||
return Configured;
|
||||
|
||||
+142
-112
@@ -2,135 +2,165 @@ using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public struct AttemptOutcome
|
||||
/// <summary>
|
||||
/// Provides ways to create attempts.
|
||||
/// </summary>
|
||||
public static class Attempt
|
||||
{
|
||||
private readonly bool _success;
|
||||
|
||||
public AttemptOutcome(bool success)
|
||||
/// <summary>
|
||||
/// Creates a successful attempt with a result.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The successful attempt.</returns>
|
||||
public static Attempt<T> Succeed<T>(T result)
|
||||
{
|
||||
_success = success;
|
||||
return Attempt<T>.Succeed(result);
|
||||
}
|
||||
|
||||
public AttemptOutcome IfFailed<T>(Func<Attempt<T>> nextAttempt, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
if (_success == false)
|
||||
{
|
||||
return ExecuteNextAttempt(nextAttempt, onSuccess, onFail);
|
||||
}
|
||||
|
||||
//return a successful outcome since the last one was successful, this allows the next AttemptOutcome chained to
|
||||
// continue properly.
|
||||
return new AttemptOutcome(true);
|
||||
}
|
||||
|
||||
public AttemptOutcome IfSuccessful<T>(Func<Attempt<T>> nextAttempt, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
if (_success)
|
||||
{
|
||||
return ExecuteNextAttempt(nextAttempt, onSuccess, onFail);
|
||||
}
|
||||
//return a failed outcome since the last one was not successful, this allows the next AttemptOutcome chained to
|
||||
// continue properly.
|
||||
return new AttemptOutcome(false);
|
||||
}
|
||||
|
||||
private AttemptOutcome ExecuteNextAttempt<T>(Func<Attempt<T>> nextAttempt, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
var attempt = nextAttempt();
|
||||
if (attempt.Success)
|
||||
{
|
||||
onSuccess(attempt.Result);
|
||||
return new AttemptOutcome(true);
|
||||
}
|
||||
|
||||
if (onFail != null)
|
||||
{
|
||||
onFail(attempt.Error);
|
||||
}
|
||||
return new AttemptOutcome(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the result of an operation attempt
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks></remarks>
|
||||
[Serializable]
|
||||
public struct Attempt<T>
|
||||
{
|
||||
private readonly bool _success;
|
||||
private readonly T _result;
|
||||
private readonly Exception _error;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Attempt{T}"/> represents a successful operation.
|
||||
/// </summary>
|
||||
/// <remarks></remarks>
|
||||
public bool Success
|
||||
{
|
||||
get { return _success; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error associated with an unsuccessful attempt.
|
||||
/// </summary>
|
||||
/// <value>The error.</value>
|
||||
public Exception Error { get { return _error; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parse result.
|
||||
/// </summary>
|
||||
/// <remarks></remarks>
|
||||
public T Result
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform the attempt with callbacks
|
||||
/// Creates a failed attempt with a result.
|
||||
/// </summary>
|
||||
/// <param name="attempt"></param>
|
||||
/// <param name="onSuccess"></param>
|
||||
/// <param name="onFail"></param>
|
||||
public static AttemptOutcome Try(Attempt<T> attempt, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail<T>(T result)
|
||||
{
|
||||
return Attempt<T>.Fail(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with a result and an exception.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail<T>(T result, Exception exception)
|
||||
{
|
||||
return Attempt<T>.Fail(result, exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful or a failed attempt, with a result.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="success">A value indicating whether the attempt is successful.</param>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The attempt.</returns>
|
||||
public static Attempt<T> If<T>(bool success, T result)
|
||||
{
|
||||
return Attempt<T>.SucceedIf(success, result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executes an attempt function, with callbacks.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="attempt">The attempt returned by the attempt function.</param>
|
||||
/// <param name="onSuccess">An action to execute in case the attempt succeeds.</param>
|
||||
/// <param name="onFail">An action to execute in case the attempt fails.</param>
|
||||
/// <returns>The outcome of the attempt.</returns>
|
||||
/// <remarks>Runs <paramref name="onSuccess"/> or <paramref name="onFail"/> depending on the
|
||||
/// whether the attempt function reports a success or a failure.</remarks>
|
||||
public static Outcome Try<T>(Attempt<T> attempt, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
if (attempt.Success)
|
||||
{
|
||||
onSuccess(attempt.Result);
|
||||
return new AttemptOutcome(true);
|
||||
return Outcome.Success;
|
||||
}
|
||||
|
||||
if (onFail != null)
|
||||
{
|
||||
onFail(attempt.Error);
|
||||
onFail(attempt.Exception);
|
||||
}
|
||||
return new AttemptOutcome(false);
|
||||
|
||||
return Outcome.Failure;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an unsuccessful parse operation
|
||||
/// </summary>
|
||||
public static readonly Attempt<T> False = new Attempt<T>(false, default(T));
|
||||
/// <summary>
|
||||
/// Represents the outcome of an attempt.
|
||||
/// </summary>
|
||||
/// <remarks>Can be a success or a failure, and allows for attempts chaining.</remarks>
|
||||
public struct Outcome
|
||||
{
|
||||
private readonly bool _success;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Attempt{T}"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="success">If set to <c>true</c> this tuple represents a successful parse result.</param>
|
||||
/// <param name="result">The parse result.</param>
|
||||
/// <remarks></remarks>
|
||||
public Attempt(bool success, T result)
|
||||
{
|
||||
_success = success;
|
||||
_result = result;
|
||||
_error = null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets an outcome representing a success.
|
||||
/// </summary>
|
||||
public static readonly Outcome Success = new Outcome(true);
|
||||
|
||||
public Attempt(Exception error)
|
||||
{
|
||||
_success = false;
|
||||
_result = default(T);
|
||||
_error = error;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets an outcome representing a failure.
|
||||
/// </summary>
|
||||
public static readonly Outcome Failure = new Outcome(false);
|
||||
|
||||
private Outcome(bool success)
|
||||
{
|
||||
_success = success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes another attempt function, if the previous one failed, with callbacks.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="nextFunction">The attempt function to execute, returning an attempt.</param>
|
||||
/// <param name="onSuccess">An action to execute in case the attempt succeeds.</param>
|
||||
/// <param name="onFail">An action to execute in case the attempt fails.</param>
|
||||
/// <returns>If it executes, returns the outcome of the attempt, else returns a success outcome.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Executes only if the previous attempt failed, else does not execute and return a success outcome.</para>
|
||||
/// <para>If it executes, then runs <paramref name="onSuccess"/> or <paramref name="onFail"/> depending on the
|
||||
/// whether the attempt function reports a success or a failure.</para>
|
||||
/// </remarks>
|
||||
public Outcome OnFailure<T>(Func<Attempt<T>> nextFunction, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
return _success
|
||||
? Success
|
||||
: ExecuteNextFunction(nextFunction, onSuccess, onFail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes another attempt function, if the previous one succeeded, with callbacks.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
/// <param name="nextFunction">The attempt function to execute, returning an attempt.</param>
|
||||
/// <param name="onSuccess">An action to execute in case the attempt succeeds.</param>
|
||||
/// <param name="onFail">An action to execute in case the attempt fails.</param>
|
||||
/// <returns>If it executes, returns the outcome of the attempt, else returns a failed outcome.</returns>
|
||||
/// <remarks>
|
||||
/// <para>Executes only if the previous attempt succeeded, else does not execute and return a success outcome.</para>
|
||||
/// <para>If it executes, then runs <paramref name="onSuccess"/> or <paramref name="onFail"/> depending on the
|
||||
/// whether the attempt function reports a success or a failure.</para>
|
||||
/// </remarks>
|
||||
public Outcome OnSuccess<T>(Func<Attempt<T>> nextFunction, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
return _success
|
||||
? ExecuteNextFunction(nextFunction, onSuccess, onFail)
|
||||
: Failure;
|
||||
}
|
||||
|
||||
private static Outcome ExecuteNextFunction<T>(Func<Attempt<T>> nextFunction, Action<T> onSuccess, Action<Exception> onFail = null)
|
||||
{
|
||||
var attempt = nextFunction();
|
||||
|
||||
if (attempt.Success)
|
||||
{
|
||||
onSuccess(attempt.Result);
|
||||
return Success;
|
||||
}
|
||||
|
||||
if (onFail != null)
|
||||
{
|
||||
onFail(attempt.Exception);
|
||||
}
|
||||
|
||||
return Failure;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using Umbraco.Core.Dynamics;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the result of an operation attempt.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the attempted operation result.</typeparam>
|
||||
[Serializable]
|
||||
public struct Attempt<T>
|
||||
{
|
||||
private readonly bool _success;
|
||||
private readonly T _result;
|
||||
private readonly Exception _exception;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="Attempt{T}"/> was successful.
|
||||
/// </summary>
|
||||
public bool Success
|
||||
{
|
||||
get { return _success; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception associated with an unsuccessful attempt.
|
||||
/// </summary>
|
||||
public Exception Exception { get { return _exception; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exception associated with an unsuccessful attempt.
|
||||
/// </summary>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete(".Error is obsolete, you should use .Exception instead.", false)]
|
||||
public Exception Error { get { return _exception; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attempt result.
|
||||
/// </summary>
|
||||
public T Result
|
||||
{
|
||||
get { return _result; }
|
||||
}
|
||||
|
||||
// optimize, use a singleton failed attempt
|
||||
private static readonly Attempt<T> Failed = new Attempt<T>(false, default(T), null);
|
||||
|
||||
/// <summary>
|
||||
/// Represents an unsuccessful attempt.
|
||||
/// </summary>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete(".Failed is obsolete, you should use Attempt<T>.Fail() instead.", false)]
|
||||
public static readonly Attempt<T> False = Failed;
|
||||
|
||||
// private - use Succeed() or Fail() methods to create attempts
|
||||
private Attempt(bool success, T result, Exception exception)
|
||||
{
|
||||
_success = success;
|
||||
_result = result;
|
||||
_exception = exception;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="Attempt{T}"/> struct with a result.
|
||||
/// </summary>
|
||||
/// <param name="success">A value indicating whether the attempt is successful.</param>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete("Attempt ctors are obsolete, you should use Attempt<T>.Succeed(), Attempt<T>.Fail() or Attempt<T>.If() instead.", false)]
|
||||
public Attempt(bool success, T result)
|
||||
: this(success, result, null)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="Attempt{T}"/> struct representing a failed attempt, with an exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <remarks>Keep it for backward compatibility sake.</remarks>
|
||||
[Obsolete("Attempt ctors are obsolete, you should use Attempt<T>.Succeed(), Attempt<T>.Fail() or Attempt<T>.If() instead.", false)]
|
||||
public Attempt(Exception exception)
|
||||
: this(false, default(T), exception)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful attempt.
|
||||
/// </summary>
|
||||
/// <returns>The successful attempt.</returns>
|
||||
public static Attempt<T> Succeed()
|
||||
{
|
||||
return new Attempt<T>(true, default(T), null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful attempt with a result.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The successful attempt.</returns>
|
||||
public static Attempt<T> Succeed(T result)
|
||||
{
|
||||
return new Attempt<T>(true, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt.
|
||||
/// </summary>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail()
|
||||
{
|
||||
return Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with an exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(Exception exception)
|
||||
{
|
||||
return new Attempt<T>(false, default(T), exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with a result.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(T result)
|
||||
{
|
||||
return new Attempt<T>(false, result, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a failed attempt with a result and an exception.
|
||||
/// </summary>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <param name="exception">The exception causing the failure of the attempt.</param>
|
||||
/// <returns>The failed attempt.</returns>
|
||||
public static Attempt<T> Fail(T result, Exception exception)
|
||||
{
|
||||
return new Attempt<T>(false, result, exception);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful or a failed attempt.
|
||||
/// </summary>
|
||||
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
||||
/// <returns>The attempt.</returns>
|
||||
public static Attempt<T> SucceedIf(bool condition)
|
||||
{
|
||||
return condition ? new Attempt<T>(true, default(T), null) : Failed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a successful or a failed attempt, with a result.
|
||||
/// </summary>
|
||||
/// <param name="condition">A value indicating whether the attempt is successful.</param>
|
||||
/// <param name="result">The result of the attempt.</param>
|
||||
/// <returns>The attempt.</returns>
|
||||
public static Attempt<T> SucceedIf(bool condition, T result)
|
||||
{
|
||||
return new Attempt<T>(condition, result, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,14 +50,14 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
try
|
||||
{
|
||||
var converted = (T)input;
|
||||
return new Attempt<T>(true, converted);
|
||||
return Attempt.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<T>(e);
|
||||
return Attempt<T>.Fail(e);
|
||||
}
|
||||
}
|
||||
return !result.Success ? Attempt<T>.False : new Attempt<T>(true, (T)result.Result);
|
||||
return !result.Success ? Attempt<T>.Fail() : Attempt.Succeed((T)result.Result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,22 +69,22 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
/// <returns></returns>
|
||||
public static Attempt<object> TryConvertTo(this object input, Type destinationType)
|
||||
{
|
||||
if (input == null) return Attempt<object>.False;
|
||||
if (input == null) return Attempt<object>.Fail();
|
||||
|
||||
if (destinationType == typeof(object)) return new Attempt<object>(true, input);
|
||||
if (destinationType == typeof(object)) return Attempt.Succeed(input);
|
||||
|
||||
if (input.GetType() == destinationType) return new Attempt<object>(true, input);
|
||||
if (input.GetType() == destinationType) return Attempt.Succeed(input);
|
||||
|
||||
if (input is string && destinationType.IsEnum)
|
||||
{
|
||||
try
|
||||
{
|
||||
var output = Enum.Parse(destinationType, (string)input, true);
|
||||
return new Attempt<object>(true, output);
|
||||
return Attempt.Succeed(output);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
{
|
||||
return Attempt<object>.Succeed(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,11 +99,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
try
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return new Attempt<object>(true, casted);
|
||||
return Attempt<object>.Succeed(casted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,11 +114,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
try
|
||||
{
|
||||
var converted = inputConverter.ConvertTo(input, destinationType);
|
||||
return new Attempt<object>(true, converted);
|
||||
return Attempt<object>.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,11 +130,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
try
|
||||
{
|
||||
var converted = boolConverter.ConvertFrom(input);
|
||||
return new Attempt<object>(true, converted);
|
||||
return Attempt<object>.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,11 +145,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
try
|
||||
{
|
||||
var converted = outputConverter.ConvertFrom(input);
|
||||
return new Attempt<object>(true, converted);
|
||||
return Attempt<object>.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,15 +159,15 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
try
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return new Attempt<object>(true, casted);
|
||||
return Attempt<object>.Succeed(casted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
|
||||
public static void CheckThrowObjectDisposed(this IDisposable disposable, bool isDisposed, string objectname)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
public static class Examine
|
||||
{
|
||||
/// <summary>
|
||||
/// The alias of the internal member searcher
|
||||
/// </summary>
|
||||
public const string InternalMemberSearcher = "InternalMemberSearcher";
|
||||
|
||||
/// <summary>
|
||||
/// The alias of the internal content searcher
|
||||
/// </summary>
|
||||
public const string InternalSearcher = "InternalSearcher";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ namespace Umbraco.Core.Dynamics
|
||||
null,
|
||||
thisObject,
|
||||
args);
|
||||
return new Attempt<TryInvokeMemberResult>(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty));
|
||||
return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty));
|
||||
}
|
||||
catch (MissingMethodException)
|
||||
{
|
||||
@@ -97,7 +97,7 @@ namespace Umbraco.Core.Dynamics
|
||||
null,
|
||||
thisObject,
|
||||
args);
|
||||
return new Attempt<TryInvokeMemberResult>(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod));
|
||||
return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod));
|
||||
}
|
||||
catch (MissingMethodException)
|
||||
{
|
||||
@@ -106,13 +106,13 @@ namespace Umbraco.Core.Dynamics
|
||||
try
|
||||
{
|
||||
result = FindAndExecuteExtensionMethod(thisObject, args, binder.Name, findExtensionMethodsOnTypes);
|
||||
return new Attempt<TryInvokeMemberResult>(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod));
|
||||
return Attempt.Succeed(new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod));
|
||||
}
|
||||
catch (TargetInvocationException ext)
|
||||
{
|
||||
//don't log here, we return this exception because the caller may need to do something specific when
|
||||
//this exception occurs.
|
||||
return new Attempt<TryInvokeMemberResult>(ext);
|
||||
return Attempt<TryInvokeMemberResult>.Fail(ext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -124,16 +124,16 @@ namespace Umbraco.Core.Dynamics
|
||||
sb.Append(t + ",");
|
||||
}
|
||||
LogHelper.Error<DynamicInstanceHelper>(sb.ToString(), ex);
|
||||
return new Attempt<TryInvokeMemberResult>(ex);
|
||||
return Attempt<TryInvokeMemberResult>.Fail(ex);
|
||||
}
|
||||
}
|
||||
return Attempt<TryInvokeMemberResult>.False;
|
||||
return Attempt<TryInvokeMemberResult>.Fail();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<DynamicInstanceHelper>("An unhandled exception occurred in method TryInvokeMember", ex);
|
||||
return new Attempt<TryInvokeMemberResult>(ex);
|
||||
return Attempt<TryInvokeMemberResult>.Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
//this is the result of an extension method execution gone wrong so we return dynamic null
|
||||
if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod
|
||||
&& attempt.Error != null && attempt.Error is TargetInvocationException)
|
||||
&& attempt.Exception != null && attempt.Exception is TargetInvocationException)
|
||||
{
|
||||
result = new DynamicNull();
|
||||
return true;
|
||||
@@ -261,7 +261,7 @@ namespace Umbraco.Core.Dynamics
|
||||
var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray();
|
||||
if (attributes.Any())
|
||||
{
|
||||
return new Attempt<IEnumerable<string>>(true, attributes);
|
||||
return Attempt<IEnumerable<string>>.Succeed(attributes);
|
||||
}
|
||||
|
||||
if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
|
||||
@@ -271,12 +271,12 @@ namespace Umbraco.Core.Dynamics
|
||||
if (childElements.Any())
|
||||
{
|
||||
//we've found a match by the first child of an element called 'root' (strange, but sure)
|
||||
return new Attempt<IEnumerable<string>>(true, childElements);
|
||||
return Attempt<IEnumerable<string>>.Succeed(childElements);
|
||||
}
|
||||
}
|
||||
|
||||
//no deal
|
||||
return Attempt<IEnumerable<string>>.False;
|
||||
return Attempt<IEnumerable<string>>.Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -293,7 +293,7 @@ namespace Umbraco.Core.Dynamics
|
||||
//Check if we've got any matches, if so then return true
|
||||
if (elements.Any())
|
||||
{
|
||||
return new Attempt<IEnumerable<XElement>>(true, elements);
|
||||
return Attempt<IEnumerable<XElement>>.Succeed(elements);
|
||||
}
|
||||
|
||||
if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
|
||||
@@ -303,12 +303,12 @@ namespace Umbraco.Core.Dynamics
|
||||
if (childElements.Any())
|
||||
{
|
||||
//we've found a match by the first child of an element called 'root' (strange, but sure)
|
||||
return new Attempt<IEnumerable<XElement>>(true, childElements);
|
||||
return Attempt<IEnumerable<XElement>>.Succeed(childElements);
|
||||
}
|
||||
}
|
||||
|
||||
//no deal
|
||||
return Attempt<IEnumerable<XElement>>.False;
|
||||
return Attempt<IEnumerable<XElement>>.Fail();
|
||||
}
|
||||
|
||||
private bool HandleIEnumerableXElement(IEnumerable<XElement> elements, out object result)
|
||||
|
||||
@@ -58,14 +58,14 @@ namespace Umbraco.Core
|
||||
try
|
||||
{
|
||||
var converted = (T) input;
|
||||
return new Attempt<T>(true, converted);
|
||||
return Attempt<T>.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<T>(e);
|
||||
return Attempt<T>.Fail(e);
|
||||
}
|
||||
}
|
||||
return !result.Success ? Attempt<T>.False : new Attempt<T>(true, (T)result.Result);
|
||||
return !result.Success ? Attempt<T>.Fail() : Attempt<T>.Succeed((T)result.Result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -80,15 +80,18 @@ namespace Umbraco.Core
|
||||
//if it is null and it is nullable, then return success with null
|
||||
if (input == null && destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof (Nullable<>))
|
||||
{
|
||||
return new Attempt<object>(true, null);
|
||||
return Attempt<object>.Succeed(null);
|
||||
}
|
||||
|
||||
//if its not nullable then return false
|
||||
if (input == null) return Attempt<object>.False;
|
||||
if (input == null) return Attempt<object>.Fail();
|
||||
|
||||
if (destinationType == typeof(object)) return new Attempt<object>(true, input);
|
||||
if (destinationType == typeof(object)) return Attempt.Succeed(input);
|
||||
|
||||
if (input.GetType() == destinationType) return new Attempt<object>(true, input);
|
||||
if (input.GetType() == destinationType) return Attempt.Succeed(input);
|
||||
|
||||
//check for string so that overloaders of ToString() can take advantage of the conversion.
|
||||
if (destinationType == typeof(string)) return Attempt<object>.Succeed(input.ToString());
|
||||
|
||||
if (!destinationType.IsGenericType || destinationType.GetGenericTypeDefinition() != typeof(Nullable<>))
|
||||
{
|
||||
@@ -101,11 +104,11 @@ namespace Umbraco.Core
|
||||
try
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return new Attempt<object>(true, casted);
|
||||
return Attempt.Succeed(casted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,11 +119,11 @@ namespace Umbraco.Core
|
||||
try
|
||||
{
|
||||
var converted = inputConverter.ConvertTo(input, destinationType);
|
||||
return new Attempt<object>(true, converted);
|
||||
return Attempt.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,11 +135,11 @@ namespace Umbraco.Core
|
||||
try
|
||||
{
|
||||
var converted = boolConverter.ConvertFrom(input);
|
||||
return new Attempt<object>(true, converted);
|
||||
return Attempt.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,11 +150,11 @@ namespace Umbraco.Core
|
||||
try
|
||||
{
|
||||
var converted = outputConverter.ConvertFrom(input);
|
||||
return new Attempt<object>(true, converted);
|
||||
return Attempt.Succeed(converted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,15 +164,15 @@ namespace Umbraco.Core
|
||||
try
|
||||
{
|
||||
var casted = Convert.ChangeType(input, destinationType);
|
||||
return new Attempt<object>(true, casted);
|
||||
return Attempt.Succeed(casted);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new Attempt<object>(e);
|
||||
return Attempt<object>.Fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
|
||||
internal static void CheckThrowObjectDisposed(this IDisposable disposable, bool isDisposed, string objectname)
|
||||
@@ -358,11 +361,11 @@ namespace Umbraco.Core
|
||||
try
|
||||
{
|
||||
var output = value.ToXmlString(type);
|
||||
return new Attempt<string>(true, output);
|
||||
return Attempt.Succeed(output);
|
||||
}
|
||||
catch (NotSupportedException ex)
|
||||
{
|
||||
return new Attempt<string>(ex);
|
||||
return Attempt<string>.Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,19 +67,19 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
|
||||
if (mapper == null)
|
||||
{
|
||||
return Attempt<BaseMapper>.False;
|
||||
return Attempt<BaseMapper>.Fail();
|
||||
}
|
||||
try
|
||||
{
|
||||
var instance = Activator.CreateInstance(mapper) as BaseMapper;
|
||||
return instance != null
|
||||
? new Attempt<BaseMapper>(true, instance)
|
||||
: Attempt<BaseMapper>.False;
|
||||
? Attempt<BaseMapper>.Succeed(instance)
|
||||
: Attempt<BaseMapper>.Fail();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error(typeof(MappingResolver), "Could not instantiate mapper of type " + mapper, ex);
|
||||
return new Attempt<BaseMapper>(ex);
|
||||
return Attempt<BaseMapper>.Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
|
||||
// SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Column.Name),
|
||||
// SqlSyntaxContext.SqlSyntaxProvider.Format(Column));
|
||||
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn,
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.Format(Column));
|
||||
|
||||
|
||||
@@ -118,9 +118,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var rEntity = _cache.GetById(typeof(TEntity), key);
|
||||
if (rEntity != null)
|
||||
{
|
||||
return new Attempt<TEntity>(true, (TEntity) rEntity);
|
||||
return Attempt.Succeed((TEntity) rEntity);
|
||||
}
|
||||
return Attempt<TEntity>.False;
|
||||
return Attempt<TEntity>.Fail();
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<TEntity> PerformGetAll(params TId[] ids);
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
var filePath = GetPluginListFilePath();
|
||||
if (!File.Exists(filePath))
|
||||
return Attempt<IEnumerable<string>>.False;
|
||||
return Attempt<IEnumerable<string>>.Fail();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -263,7 +263,7 @@ namespace Umbraco.Core
|
||||
|
||||
|
||||
if (xml.Root == null)
|
||||
return Attempt<IEnumerable<string>>.False;
|
||||
return Attempt<IEnumerable<string>>.Fail();
|
||||
|
||||
var typeElement = xml.Root.Elements()
|
||||
.SingleOrDefault(x =>
|
||||
@@ -273,18 +273,16 @@ namespace Umbraco.Core
|
||||
|
||||
//return false but specify this exception type so we can detect it
|
||||
if (typeElement == null)
|
||||
return new Attempt<IEnumerable<string>>(new CachedPluginNotFoundInFile());
|
||||
return Attempt<IEnumerable<string>>.Fail(new CachedPluginNotFoundInFile());
|
||||
|
||||
//return success
|
||||
return new Attempt<IEnumerable<string>>(
|
||||
true,
|
||||
typeElement.Elements("add")
|
||||
return Attempt.Succeed(typeElement.Elements("add")
|
||||
.Select(x => (string)x.Attribute("type")));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//if the file is corrupted, etc... return false
|
||||
return new Attempt<IEnumerable<string>>(ex);
|
||||
return Attempt<IEnumerable<string>>.Fail(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +653,7 @@ namespace Umbraco.Core
|
||||
//here we need to identify if the CachedPluginNotFoundInFile was the exception, if it was then we need to re-scan
|
||||
//in some cases the plugin will not have been scanned for on application startup, but the assemblies haven't changed
|
||||
//so in this instance there will never be a result.
|
||||
if (fileCacheResult.Error != null && fileCacheResult.Error is CachedPluginNotFoundInFile)
|
||||
if (fileCacheResult.Exception != null && fileCacheResult.Exception is CachedPluginNotFoundInFile)
|
||||
{
|
||||
//we don't have a cache for this so proceed to look them up by scanning
|
||||
LoadViaScanningAndUpdateCacheFile<T>(typeList, resolutionType, finder);
|
||||
|
||||
@@ -143,16 +143,16 @@ namespace Umbraco.Core.Profiling
|
||||
private Attempt<HttpRequestBase> TryGetRequest(object sender)
|
||||
{
|
||||
var app = sender as HttpApplication;
|
||||
if (app == null) return Attempt<HttpRequestBase>.False;
|
||||
if (app == null) return Attempt<HttpRequestBase>.Fail();
|
||||
|
||||
try
|
||||
{
|
||||
var req = app.Request;
|
||||
return new Attempt<HttpRequestBase>(true, new HttpRequestWrapper(req));
|
||||
return Attempt<HttpRequestBase>.Succeed(new HttpRequestWrapper(req));
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
return new Attempt<HttpRequestBase>(ex);
|
||||
return Attempt<HttpRequestBase>.Fail(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
internal static Attempt<object> ConvertPropertyValue(object currentValue, PublishedPropertyDefinition propertyDefinition)
|
||||
{
|
||||
if (currentValue == null) return Attempt<object>.False;
|
||||
if (currentValue == null) return Attempt<object>.Fail();
|
||||
|
||||
//First, we need to check the v7+ PropertyValueConverters
|
||||
var converters = PropertyValueConvertersResolver.Current.Converters
|
||||
@@ -135,7 +135,7 @@ namespace Umbraco.Core
|
||||
.Select(p => p.ConvertPropertyValue(currentValue))
|
||||
.Where(converted => converted.Success))
|
||||
{
|
||||
return new Attempt<object>(true, converted.Result);
|
||||
return Attempt.Succeed(converted.Result);
|
||||
}
|
||||
|
||||
//if none of the converters worked, then we'll process this from what we know
|
||||
@@ -148,17 +148,17 @@ namespace Umbraco.Core
|
||||
decimal dResult;
|
||||
if (decimal.TryParse(sResult, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.CurrentCulture, out dResult))
|
||||
{
|
||||
return new Attempt<object>(true, dResult);
|
||||
return Attempt<object>.Succeed(dResult);
|
||||
}
|
||||
}
|
||||
//process string booleans as booleans
|
||||
if (sResult.InvariantEquals("true"))
|
||||
{
|
||||
return new Attempt<object>(true, true);
|
||||
return Attempt<object>.Succeed(true);
|
||||
}
|
||||
if (sResult.InvariantEquals("false"))
|
||||
{
|
||||
return new Attempt<object>(true, false);
|
||||
return Attempt<object>.Succeed(false);
|
||||
}
|
||||
|
||||
//a really rough check to see if this may be valid xml
|
||||
@@ -177,16 +177,16 @@ namespace Umbraco.Core
|
||||
if (UmbracoConfiguration.Current.UmbracoSettings.Scripting.NotDynamicXmlDocumentElements.Any(
|
||||
tag => string.Equals(tag.Element, documentElement, StringComparison.CurrentCultureIgnoreCase)) == false)
|
||||
{
|
||||
return new Attempt<object>(true, new DynamicXml(e));
|
||||
return Attempt<object>.Succeed(new DynamicXml(e));
|
||||
}
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
}
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace Umbraco.Core.Publishing
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", content.Name, content.Id));
|
||||
return new Attempt<PublishStatus>(false, new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return new Attempt<PublishStatus>(false, new PublishStatus(content, PublishStatusType.FailedHasExpired));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedHasExpired));
|
||||
}
|
||||
|
||||
//Check if the Content is Awaiting Release to verify that it can in fact be published
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return new Attempt<PublishStatus>(false, new PublishStatus(content, PublishStatusType.FailedAwaitingRelease));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedAwaitingRelease));
|
||||
}
|
||||
|
||||
//Check if the Content is Trashed to verify that it can in fact be published
|
||||
@@ -53,7 +53,7 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
|
||||
content.Name, content.Id));
|
||||
return new Attempt<PublishStatus>(false, new PublishStatus(content, PublishStatusType.FailedIsTrashed));
|
||||
return Attempt<PublishStatus>.Fail(new PublishStatus(content, PublishStatusType.FailedIsTrashed));
|
||||
}
|
||||
|
||||
content.ChangePublishedState(PublishedState.Published);
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Core.Publishing
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
content.Name, content.Id));
|
||||
|
||||
return new Attempt<PublishStatus>(true, new PublishStatus(content));
|
||||
return Attempt.Succeed(new PublishStatus(content));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -125,7 +125,7 @@ namespace Umbraco.Core.Publishing
|
||||
//We're going to populate the statuses with all content that is already published because below we are only going to iterate over
|
||||
// content that is not published. We'll set the status to "AlreadyPublished"
|
||||
statuses.AddRange(fetchedContent.Where(x => x.Published)
|
||||
.Select(x => new Attempt<PublishStatus>(true, new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished))));
|
||||
.Select(x => Attempt.Succeed(new PublishStatus(x, PublishStatusType.SuccessAlreadyPublished))));
|
||||
|
||||
int? firstLevel = null;
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace Umbraco.Core.Publishing
|
||||
//the publishing has been cancelled.
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", item.Name, item.Id));
|
||||
statuses.Add(new Attempt<PublishStatus>(false, new PublishStatus(item, PublishStatusType.FailedCancelledByEvent)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published because some of it's content is not passing validation rules.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(new Attempt<PublishStatus>(false, new PublishStatus(item, PublishStatusType.FailedContentInvalid)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedContentInvalid)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -197,7 +197,7 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' has expired and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(new Attempt<PublishStatus>(false, new PublishStatus(item, PublishStatusType.FailedHasExpired)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedHasExpired)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -211,7 +211,7 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is awaiting release and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(new Attempt<PublishStatus>(false, new PublishStatus(item, PublishStatusType.FailedAwaitingRelease)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedAwaitingRelease)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -225,7 +225,7 @@ namespace Umbraco.Core.Publishing
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' is trashed and could not be published.",
|
||||
item.Name, item.Id));
|
||||
statuses.Add(new Attempt<PublishStatus>(false, new PublishStatus(item, PublishStatusType.FailedIsTrashed)));
|
||||
statuses.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedIsTrashed)));
|
||||
|
||||
//Does this document apply to our rule to cancel it's children being published?
|
||||
CheckCancellingOfChildPublishing(item, parentsIdsCancelled, includeUnpublishedDocuments);
|
||||
@@ -239,7 +239,7 @@ namespace Umbraco.Core.Publishing
|
||||
string.Format("Content '{0}' with Id '{1}' has been published.",
|
||||
item.Name, item.Id));
|
||||
|
||||
statuses.Add(new Attempt<PublishStatus>(true, new PublishStatus(item)));
|
||||
statuses.Add(Attempt.Succeed(new PublishStatus(item)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -349,7 +349,7 @@ namespace Umbraco.Core.Publishing
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(
|
||||
string.Format("Content '{0}' with Id '{1}' will not be published, the event was cancelled.", item.Name, item.Id));
|
||||
result.Add(new Attempt<PublishStatus>(false, new PublishStatus(item, PublishStatusType.FailedCancelledByEvent)));
|
||||
result.Add(Attempt.Fail(new PublishStatus(item, PublishStatusType.FailedCancelledByEvent)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ namespace Umbraco.Core.Publishing
|
||||
string.Format("Content '{0}' with Id '{1}' has been unpublished.",
|
||||
item.Name, item.Id));
|
||||
|
||||
result.Add(new Attempt<PublishStatus>(true, new PublishStatus(item)));
|
||||
result.Add(Attempt.Succeed(new PublishStatus(item)));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1482,7 +1482,7 @@ namespace Umbraco.Core.Services
|
||||
string.Format(
|
||||
"Content '{0}' with Id '{1}' could not be published because its parent or one of its ancestors is not published.",
|
||||
content.Name, content.Id));
|
||||
result.Add(new Attempt<PublishStatus>(false, new PublishStatus(content, PublishStatusType.FailedPathNotPublished)));
|
||||
result.Add(Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedPathNotPublished)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1493,7 +1493,7 @@ namespace Umbraco.Core.Services
|
||||
string.Format("Content '{0}' with Id '{1}' could not be published because of invalid properties.",
|
||||
content.Name, content.Id));
|
||||
result.Add(
|
||||
new Attempt<PublishStatus>(false,
|
||||
Attempt.Fail(
|
||||
new PublishStatus(content, PublishStatusType.FailedContentInvalid)
|
||||
{
|
||||
InvalidProperties = ((ContentBase) content).LastInvalidProperties
|
||||
@@ -1599,7 +1599,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
|
||||
{
|
||||
return new Attempt<PublishStatus>(false, new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
|
||||
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1669,7 +1669,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id);
|
||||
|
||||
return new Attempt<PublishStatus>(publishStatus.StatusType == PublishStatusType.Success, publishStatus);
|
||||
return Attempt.If(publishStatus.StatusType == PublishStatusType.Success, publishStatus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,11 +95,11 @@ namespace Umbraco.Core
|
||||
{
|
||||
if (types.Length == 0)
|
||||
{
|
||||
return Attempt<Type>.False;
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
if (types.Length == 1)
|
||||
{
|
||||
return new Attempt<Type>(true, types[0]);
|
||||
return Attempt.Succeed(types[0]);
|
||||
}
|
||||
|
||||
foreach (var curr in types)
|
||||
@@ -112,11 +112,11 @@ namespace Umbraco.Core
|
||||
//if this type is the base for all others
|
||||
if (isBase)
|
||||
{
|
||||
return new Attempt<Type>(true, curr);
|
||||
return Attempt.Succeed(curr);
|
||||
}
|
||||
}
|
||||
|
||||
return Attempt<Type>.False;
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
<Compile Include="ApplicationContext.cs" />
|
||||
<Compile Include="ApplicationEventHandler.cs" />
|
||||
<Compile Include="AssemblyExtensions.cs" />
|
||||
<Compile Include="Attempt.cs" />
|
||||
<Compile Include="Attempt{T}.cs" />
|
||||
<Compile Include="Auditing\AuditTrail.cs" />
|
||||
<Compile Include="Auditing\Audit.cs" />
|
||||
<Compile Include="Auditing\AuditTypes.cs" />
|
||||
@@ -239,6 +239,8 @@
|
||||
<Compile Include="Configuration\UmbracoSettings\ViewstateMoverModuleElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\WebRoutingElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoVersion.cs" />
|
||||
<Compile Include="Attempt.cs" />
|
||||
<Compile Include="Constants-Examine.cs" />
|
||||
<Compile Include="CoreBootManager.cs" />
|
||||
<Compile Include="DatabaseContext.cs" />
|
||||
<Compile Include="DataTableExtensions.cs" />
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
@@ -75,6 +73,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
internal static bool IsClientSideRequest(this Uri url)
|
||||
{
|
||||
// fixme - but really, is this OK? we should accept either no url, or .aspx, and everything else is out
|
||||
var toIgnore = new[] { ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif", ".html", ".svg" };
|
||||
return toIgnore.Any(x => Path.GetExtension(url.LocalPath).InvariantEquals(x));
|
||||
}
|
||||
@@ -88,7 +87,7 @@ namespace Umbraco.Core
|
||||
/// <remarks>Everything else remains unchanged, except for the fragment which is removed.</remarks>
|
||||
public static Uri Rewrite(this Uri uri, string path)
|
||||
{
|
||||
if (!path.StartsWith("/"))
|
||||
if (path.StartsWith("/") == false)
|
||||
throw new ArgumentException("Path must start with a slash.", "path");
|
||||
|
||||
return uri.IsAbsoluteUri
|
||||
@@ -106,9 +105,9 @@ namespace Umbraco.Core
|
||||
/// <remarks>Everything else remains unchanged, except for the fragment which is removed.</remarks>
|
||||
public static Uri Rewrite(this Uri uri, string path, string query)
|
||||
{
|
||||
if (!path.StartsWith("/"))
|
||||
if (path.StartsWith("/") == false)
|
||||
throw new ArgumentException("Path must start with a slash.", "path");
|
||||
if (query.Length > 0 && !query.StartsWith("?"))
|
||||
if (query.Length > 0 && query.StartsWith("?") == false)
|
||||
throw new ArgumentException("Query must start with a question mark.", "query");
|
||||
if (query == "?")
|
||||
query = "";
|
||||
@@ -171,15 +170,14 @@ namespace Umbraco.Core
|
||||
var path = uri.GetSafeAbsolutePath();
|
||||
if (uri.IsAbsoluteUri)
|
||||
{
|
||||
if (path != "/" && !path.EndsWith("/"))
|
||||
if (path != "/" && path.EndsWith("/") == false)
|
||||
uri = new Uri(uri.GetLeftPart(UriPartial.Authority) + path + "/" + uri.Query);
|
||||
return uri;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (path != "/" && !path.EndsWith("/"))
|
||||
uri = new Uri(path + "/" + uri.Query, UriKind.Relative);
|
||||
}
|
||||
|
||||
if (path != "/" && path.EndsWith("/") == false)
|
||||
uri = new Uri(path + "/" + uri.Query, UriKind.Relative);
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
doc = new XPathDocument(new XmlTextReader(new StringReader(xml)));
|
||||
doc = CreateXPathDocument(xml);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -63,23 +63,68 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XPathDocument</c> from a property value.
|
||||
/// </summary>
|
||||
/// <param name="alias">The alias of the property.</param>
|
||||
/// <param name="value">The value of the property.</param>
|
||||
/// <param name="doc">The XPath document.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the document.</returns>
|
||||
public static bool TryCreateXPathDocumentFromPropertyValue(string alias, object value, out XPathDocument doc)
|
||||
/// <remarks>The value can be anything... Performance-wise, this is bad.</remarks>
|
||||
public static bool TryCreateXPathDocumentFromPropertyValue(object value, out XPathDocument doc)
|
||||
{
|
||||
// In addition, DynamicNode strips dashes in elements or attributes
|
||||
// names but really, this is ugly enough, and using dashes should be
|
||||
// illegal in content type or property aliases anyway.
|
||||
// DynamicNode.ConvertPropertyValueByDataType first cleans the value by calling
|
||||
// XmlHelper.StripDashesInElementOrAttributeName - this is because the XML is
|
||||
// to be returned as a DynamicXml and element names such as "value-item" are
|
||||
// invalid and must be converted to "valueitem". But we don't have that sort of
|
||||
// problem here - and we don't need to bother with dashes nor dots, etc.
|
||||
|
||||
doc = null;
|
||||
var xml = value as string;
|
||||
if (xml == null) return false;
|
||||
xml = xml.Trim();
|
||||
if (xml.StartsWith("<") == false || xml.EndsWith(">") == false || xml.Contains('/') == false) return false;
|
||||
if (UmbracoConfiguration.Current.UmbracoSettings.Scripting.NotDynamicXmlDocumentElements.Any(x => x.Element.InvariantEquals(alias))) return false;
|
||||
return TryCreateXPathDocument(xml, out doc);
|
||||
if (xml == null) return false; // no a string
|
||||
if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml
|
||||
if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise
|
||||
if (TryCreateXPathDocument(xml, out doc) == false) return false; // string can't be parsed into xml
|
||||
|
||||
var nav = doc.CreateNavigator();
|
||||
if (nav.MoveToFirstChild())
|
||||
{
|
||||
var name = nav.LocalName; // must not match an excluded tag
|
||||
if (LegacyUmbracoSettings.NotDynamicXmlDocumentElements.All(x => x.InvariantEquals(name) == false)) return true;
|
||||
}
|
||||
|
||||
doc = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XElement</c> from a property value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the property.</param>
|
||||
/// <param name="elt">The Xml element.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the element.</returns>
|
||||
/// <remarks>The value can be anything... Performance-wise, this is bad.</remarks>
|
||||
public static bool TryCreateXElementFromPropertyValue(object value, out XElement elt)
|
||||
{
|
||||
// see note above in TryCreateXPathDocumentFromPropertyValue...
|
||||
|
||||
elt = null;
|
||||
var xml = value as string;
|
||||
if (xml == null) return false; // not a string
|
||||
if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml
|
||||
if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise
|
||||
|
||||
try
|
||||
{
|
||||
elt = XElement.Parse(xml, LoadOptions.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
elt = null;
|
||||
return false; // string can't be parsed into xml
|
||||
}
|
||||
|
||||
var name = elt.Name.LocalName; // must not match an excluded tag
|
||||
if (LegacyUmbracoSettings.NotDynamicXmlDocumentElements.All(x => x.InvariantEquals(name) == false)) return true;
|
||||
|
||||
elt = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -137,8 +182,8 @@ namespace Umbraco.Core
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// used by DynamicNode only, see note in TryCreateXPathDocumentFromPropertyValue
|
||||
public static string StripDashesInElementOrAttributeNames(string xml)
|
||||
{
|
||||
using (var outputms = new MemoryStream())
|
||||
@@ -289,17 +334,10 @@ namespace Umbraco.Core
|
||||
/// </returns>
|
||||
public static bool CouldItBeXml(string xml)
|
||||
{
|
||||
if (string.IsNullOrEmpty(xml) == false)
|
||||
{
|
||||
xml = xml.Trim();
|
||||
if (string.IsNullOrEmpty(xml)) return false;
|
||||
|
||||
if (xml.StartsWith("<") && xml.EndsWith(">") && xml.Contains("/"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
xml = xml.Trim();
|
||||
return xml.StartsWith("<") && xml.EndsWith(">") && xml.Contains('/');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
|
||||
@@ -7,26 +7,35 @@ namespace Umbraco.Tests
|
||||
[TestFixture]
|
||||
public class AttemptTests
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void Chained_Attempts()
|
||||
{
|
||||
Attempt<string>.Try(new Attempt<string>(true, "success!"),
|
||||
s => Assert.AreEqual("success!", s),
|
||||
exception => Assert.Fail("It was successful"))
|
||||
.IfFailed(() => new Attempt<int>(true, 123),
|
||||
i => Assert.Fail("The previous attempt was successful!"),
|
||||
exception => Assert.Fail("The previous attempt was successful!"))
|
||||
.IfSuccessful(() => new Attempt<double>(new Exception("Failed!")),
|
||||
d => Assert.Fail("An exception was thrown"),
|
||||
exception => Assert.AreEqual("Failed!", exception.Message))
|
||||
.IfSuccessful(() => new Attempt<int>(true, 987),
|
||||
i => Assert.Fail("The previous attempt failed!"),
|
||||
exception => Assert.Fail("The previous attempt failed!"))
|
||||
.IfFailed(() => new Attempt<string>(true, "finished"),
|
||||
i => Assert.AreEqual("finished", i),
|
||||
exception => Assert.Fail("It was successful"));
|
||||
}
|
||||
Attempt.Try(Attempt.Succeed("success!"),
|
||||
s => Assert.AreEqual("success!", s),
|
||||
exception => Assert.Fail("Should have been successful."))
|
||||
|
||||
// previous one was a success so that one SHOULD NOT run
|
||||
// and report success
|
||||
.OnFailure(() => Attempt.Succeed(123),
|
||||
i => Assert.Fail("The previous attempt was successful!"),
|
||||
exception => Assert.Fail("The previous attempt was successful!"))
|
||||
|
||||
// previous one did not run, last run was a success so that one SHOULD run
|
||||
// and report failure
|
||||
.OnSuccess(() => Attempt<double>.Fail(new Exception("Failed!")),
|
||||
d => Assert.Fail("Should have failed."),
|
||||
exception => Assert.AreEqual("Failed!", exception.Message))
|
||||
|
||||
// previous one did run and was a failure so that one SHOULD NOT run
|
||||
.OnSuccess(() => Attempt.Succeed(987),
|
||||
i => Assert.Fail("The previous attempt failed!"),
|
||||
exception => Assert.Fail("The previous attempt failed!"))
|
||||
|
||||
// previous one did not run, last run was a failure so that one SHOULD run
|
||||
// then why does it run?
|
||||
.OnFailure(() => Attempt.Succeed("finished"),
|
||||
i => Assert.AreEqual("finished", i),
|
||||
exception => Assert.Fail("Should have been successful."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,5 +113,22 @@ namespace Umbraco.Tests
|
||||
Assert.AreEqual(DateTime.Equals(dateTime.Date, result.Result.Date), testCase.Value);
|
||||
}
|
||||
}
|
||||
[Test]
|
||||
public virtual void CanConvertObjectToString_Using_ToString_Overload()
|
||||
{
|
||||
var result = new MyTestObject().TryConvertTo<string>();
|
||||
|
||||
Assert.IsTrue(result.Success);
|
||||
Assert.AreEqual("Hello world", result.Result);
|
||||
}
|
||||
|
||||
|
||||
private class MyTestObject
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return "Hello world";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Subpage which acts as the strongly typed model for a Doc Type
|
||||
/// with alias "Subpage" and "Subpage" as the allowed child type.
|
||||
///
|
||||
/// Similar to the Textpage this model could also be generated, but it could also
|
||||
/// act as a Code-First model by using the attributes shown on the various properties,
|
||||
/// which decorate the model with information about the Document Type, its
|
||||
/// Property Groups and Property Types.
|
||||
/// </summary>
|
||||
public class Subpage : TypedModelBase
|
||||
{
|
||||
public Subpage(IPublishedContent publishedContent) : base(publishedContent)
|
||||
{
|
||||
}
|
||||
|
||||
public string Title { get { return Resolve<string>(Property()); } }
|
||||
|
||||
public string BodyText { get { return Resolve<string>(Property()); } }
|
||||
|
||||
public Textpage Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
return Parent<Textpage>();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Subpage> Subpages
|
||||
{
|
||||
get
|
||||
{
|
||||
return Children<Subpage>(ContentTypeAlias());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Textpage which acts as the strongly typed model for a Doc Type
|
||||
/// with alias "Textpage" and "Subpage" as the allowed child type.
|
||||
///
|
||||
/// The basic properties are resolved by convention using the Resolve-Type-PropertyTypeAlias
|
||||
/// convention available through the base class' protected Resolve-method and Property-delegate.
|
||||
///
|
||||
/// The Textpage allows the use of Subpage and Textpage as child doc types, which are exposed as a
|
||||
/// collection using the Children-Type-ContentTypeAlias convention available through the
|
||||
/// base class' protected Children-method and ContentTypeAlias-delegate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This code can easily be generated using simple conventions for the types and names
|
||||
/// of the properties that this type of strongly typed model exposes.
|
||||
/// </remarks>
|
||||
public class Textpage : TypedModelBase
|
||||
{
|
||||
public Textpage(IPublishedContent publishedContent) : base(publishedContent)
|
||||
{
|
||||
}
|
||||
|
||||
public string Title { get { return Resolve<string>(Property()); } }
|
||||
|
||||
public string BodyText { get { return Resolve<string>(Property()); } }
|
||||
|
||||
public string AuthorName { get { return Resolve<string>(Property()); } }
|
||||
|
||||
public DateTime Date { get { return Resolve<DateTime>(Property()); } }
|
||||
|
||||
public Textpage Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
return Parent<Textpage>();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Textpage> Textpages
|
||||
{
|
||||
get
|
||||
{
|
||||
return Children<Textpage>(ContentTypeAlias());
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Subpage> Subpages
|
||||
{
|
||||
get
|
||||
{
|
||||
return Children<Subpage>(ContentTypeAlias());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
|
||||
{
|
||||
public class TextpageModel : TypedModelBase
|
||||
{
|
||||
public TextpageModel(IPublishedContent publishedContent) : base(publishedContent)
|
||||
{
|
||||
}
|
||||
|
||||
public string Title { get { return Resolve(Property(), DefaultString); } }
|
||||
|
||||
public string BodyText { get { return Resolve(Property(), DefaultString); } }
|
||||
|
||||
public string AuthorName { get { return Resolve<string>(Property()); } }
|
||||
|
||||
public DateTime Date { get { return Resolve(Property(), DefaultDateTime); } }
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Entity.Design.PluralizationServices;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
|
||||
{
|
||||
public abstract class TypedModelBase
|
||||
/// <summary>
|
||||
/// Represents the abstract base class for a 'TypedModel', which basically wraps IPublishedContent
|
||||
/// underneath a strongly typed model like "Textpage" and "Subpage".
|
||||
/// Because IPublishedContent is used under the hood there is no need for additional mapping, so the
|
||||
/// only added cost should be the creation of the objects, which the IPublishedContent instance is
|
||||
/// passed into.
|
||||
///
|
||||
/// This base class exposes a simple way to write property getters by convention without
|
||||
/// using the string alias of a PropertyType (this is resolved by the use of the Property delegate).
|
||||
///
|
||||
/// This base class also exposes query options like Parent, Children, Ancestors and Descendants,
|
||||
/// which can be used for collections of strongly typed child models/objects. These types of collections
|
||||
/// typically corresponds to 'allowed child content types' on a Doc Type (at different levels).
|
||||
///
|
||||
/// The IPublishedContent properties are also exposed through this base class, but only
|
||||
/// by casting the typed model to IPublishedContent, so the properties doesn't show up by default:
|
||||
/// ie. ((IPublishedContent)textpage).Url
|
||||
/// </summary>
|
||||
public abstract class TypedModelBase : IPublishedContent
|
||||
{
|
||||
private readonly IPublishedContent _publishedContent;
|
||||
|
||||
@@ -15,56 +37,168 @@ namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
|
||||
_publishedContent = publishedContent;
|
||||
}
|
||||
|
||||
public readonly Func<MethodBase> Property = MethodBase.GetCurrentMethod;
|
||||
public static string DefaultString = default(string);
|
||||
public static int DefaultInteger = default(int);
|
||||
public static bool DefaultBool = default(bool);
|
||||
public static DateTime DefaultDateTime = default(DateTime);
|
||||
protected readonly Func<MethodBase> Property = MethodBase.GetCurrentMethod;
|
||||
protected readonly Func<MethodBase> ContentTypeAlias = MethodBase.GetCurrentMethod;
|
||||
|
||||
public T Resolve<T>(MethodBase methodBase)
|
||||
#region Properties
|
||||
|
||||
protected T Resolve<T>(MethodBase methodBase)
|
||||
{
|
||||
var propertyTypeAlias = methodBase.ToUmbracoAlias();
|
||||
return Resolve<T>(propertyTypeAlias);
|
||||
}
|
||||
|
||||
protected T Resolve<T>(string propertyTypeAlias)
|
||||
{
|
||||
return _publishedContent.GetPropertyValue<T>(propertyTypeAlias);
|
||||
}
|
||||
|
||||
public T Resolve<T>(MethodBase methodBase, T ifCannotConvert)
|
||||
protected T Resolve<T>(MethodBase methodBase, T ifCannotConvert)
|
||||
{
|
||||
var propertyTypeAlias = methodBase.ToUmbracoAlias();
|
||||
return Resolve<T>(propertyTypeAlias, ifCannotConvert);
|
||||
}
|
||||
|
||||
protected T Resolve<T>(string propertyTypeAlias, T ifCannotConvert)
|
||||
{
|
||||
return _publishedContent.GetPropertyValue<T>(propertyTypeAlias, false, ifCannotConvert);
|
||||
}
|
||||
|
||||
public T Resolve<T>(MethodBase methodBase, bool recursive, T ifCannotConvert)
|
||||
protected T Resolve<T>(MethodBase methodBase, bool recursive, T ifCannotConvert)
|
||||
{
|
||||
var propertyTypeAlias = methodBase.ToUmbracoAlias();
|
||||
return Resolve<T>(propertyTypeAlias, recursive, ifCannotConvert);
|
||||
}
|
||||
|
||||
protected T Resolve<T>(string propertyTypeAlias, bool recursive, T ifCannotConvert)
|
||||
{
|
||||
return _publishedContent.GetPropertyValue<T>(propertyTypeAlias, recursive, ifCannotConvert);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public string ResolveString(MethodBase methodBase)
|
||||
#region Querying
|
||||
protected T Parent<T>() where T : TypedModelBase
|
||||
{
|
||||
return Resolve<string>(methodBase);
|
||||
var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) });
|
||||
if (constructorInfo == null)
|
||||
throw new Exception("No valid constructor found");
|
||||
|
||||
return (T) constructorInfo.Invoke(new object[] {_publishedContent.Parent});
|
||||
}
|
||||
|
||||
public int ResolveInt(MethodBase methodBase)
|
||||
protected IEnumerable<T> Children<T>(MethodBase methodBase) where T : TypedModelBase
|
||||
{
|
||||
return Resolve<int>(methodBase);
|
||||
var docTypeAlias = methodBase.CleanCallingMethodName();
|
||||
return Children<T>(docTypeAlias);
|
||||
}
|
||||
|
||||
public bool ResolveBool(MethodBase methodBase)
|
||||
protected IEnumerable<T> Children<T>(string docTypeAlias) where T : TypedModelBase
|
||||
{
|
||||
return Resolve<bool>(methodBase);
|
||||
var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) });
|
||||
if(constructorInfo == null)
|
||||
throw new Exception("No valid constructor found");
|
||||
|
||||
string singularizedDocTypeAlias = docTypeAlias.ToSingular();
|
||||
|
||||
return _publishedContent.Children.Where(x => x.DocumentTypeAlias == singularizedDocTypeAlias)
|
||||
.Select(x => (T)constructorInfo.Invoke(new object[] { x }));
|
||||
}
|
||||
|
||||
public DateTime ResolveDate(MethodBase methodBase)
|
||||
protected IEnumerable<T> Ancestors<T>(MethodBase methodBase) where T : TypedModelBase
|
||||
{
|
||||
return Resolve<DateTime>(methodBase);
|
||||
var docTypeAlias = methodBase.CleanCallingMethodName();
|
||||
return Ancestors<T>(docTypeAlias);
|
||||
}
|
||||
|
||||
protected IEnumerable<T> Ancestors<T>(string docTypeAlias) where T : TypedModelBase
|
||||
{
|
||||
var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) });
|
||||
if (constructorInfo == null)
|
||||
throw new Exception("No valid constructor found");
|
||||
|
||||
string singularizedDocTypeAlias = docTypeAlias.ToSingular();
|
||||
|
||||
return _publishedContent.Ancestors().Where(x => x.DocumentTypeAlias == singularizedDocTypeAlias)
|
||||
.Select(x => (T)constructorInfo.Invoke(new object[] { x }));
|
||||
}
|
||||
|
||||
protected IEnumerable<T> Descendants<T>(MethodBase methodBase) where T : TypedModelBase
|
||||
{
|
||||
var docTypeAlias = methodBase.CleanCallingMethodName();
|
||||
return Descendants<T>(docTypeAlias);
|
||||
}
|
||||
|
||||
protected IEnumerable<T> Descendants<T>(string docTypeAlias) where T : TypedModelBase
|
||||
{
|
||||
var constructorInfo = typeof(T).GetConstructor(new[] { typeof(IPublishedContent) });
|
||||
if (constructorInfo == null)
|
||||
throw new Exception("No valid constructor found");
|
||||
|
||||
string singularizedDocTypeAlias = docTypeAlias.ToSingular();
|
||||
|
||||
return _publishedContent.Descendants().Where(x => x.DocumentTypeAlias == singularizedDocTypeAlias)
|
||||
.Select(x => (T)constructorInfo.Invoke(new object[] { x }));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IPublishedContent
|
||||
int IPublishedContent.Id { get { return _publishedContent.Id; } }
|
||||
int IPublishedContent.TemplateId { get { return _publishedContent.TemplateId; } }
|
||||
int IPublishedContent.SortOrder { get { return _publishedContent.SortOrder; } }
|
||||
string IPublishedContent.Name { get { return _publishedContent.Name; } }
|
||||
string IPublishedContent.UrlName { get { return _publishedContent.UrlName; } }
|
||||
string IPublishedContent.DocumentTypeAlias { get { return _publishedContent.DocumentTypeAlias; } }
|
||||
int IPublishedContent.DocumentTypeId { get { return _publishedContent.DocumentTypeId; } }
|
||||
string IPublishedContent.WriterName { get { return _publishedContent.WriterName; } }
|
||||
string IPublishedContent.CreatorName { get { return _publishedContent.CreatorName; } }
|
||||
int IPublishedContent.WriterId { get { return _publishedContent.WriterId; } }
|
||||
int IPublishedContent.CreatorId { get { return _publishedContent.CreatorId; } }
|
||||
string IPublishedContent.Path { get { return _publishedContent.Path; } }
|
||||
DateTime IPublishedContent.CreateDate { get { return _publishedContent.CreateDate; } }
|
||||
DateTime IPublishedContent.UpdateDate { get { return _publishedContent.UpdateDate; } }
|
||||
Guid IPublishedContent.Version { get { return _publishedContent.Version; } }
|
||||
int IPublishedContent.Level { get { return _publishedContent.Level; } }
|
||||
string IPublishedContent.Url { get { return _publishedContent.Url; } }
|
||||
PublishedItemType IPublishedContent.ItemType { get { return _publishedContent.ItemType; } }
|
||||
IPublishedContent IPublishedContent.Parent { get { return _publishedContent.Parent; } }
|
||||
IEnumerable<IPublishedContent> IPublishedContent.Children { get { return _publishedContent.Children; } }
|
||||
|
||||
ICollection<IPublishedContentProperty> IPublishedContent.Properties { get { return _publishedContent.Properties; } }
|
||||
|
||||
object IPublishedContent.this[string propertyAlias] { get { return _publishedContent[propertyAlias]; } }
|
||||
|
||||
IPublishedContentProperty IPublishedContent.GetProperty(string alias)
|
||||
{
|
||||
return _publishedContent.GetProperty(alias);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for MethodBase, which are used to clean the name of the calling method "get_BodyText"
|
||||
/// to "BodyText" and then make it camel case according to the UmbracoAlias convention "bodyText".
|
||||
/// There is also a string extension for making plural words singular, which is used when going from
|
||||
/// something like "Subpages" to "Subpage" for Children/Ancestors/Descendants Doc Type aliases.
|
||||
/// </summary>
|
||||
public static class TypeExtensions
|
||||
{
|
||||
public static string CleanCallingMethodName(this MethodBase methodBase)
|
||||
{
|
||||
return methodBase.Name.Replace("get_", "");
|
||||
}
|
||||
|
||||
public static string ToUmbracoAlias(this MethodBase methodBase)
|
||||
{
|
||||
return methodBase.Name.Replace("get_", "").ToUmbracoAlias();
|
||||
return methodBase.CleanCallingMethodName().ToUmbracoAlias();
|
||||
}
|
||||
|
||||
public static string ToSingular(this string pluralWord)
|
||||
{
|
||||
var service = PluralizationService.CreateService(new CultureInfo("en-US"));
|
||||
if (service.IsPlural(pluralWord))
|
||||
return service.Singularize(pluralWord);
|
||||
|
||||
return pluralWord;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,12 @@ using Umbraco.Web.Mvc;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a basic extension of the UmbracoTemplatePage, which allows you to specify
|
||||
/// the type of a strongly typed model that inherits from TypedModelBase.
|
||||
/// The model is exposed as TypedModel.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the model to create/expose</typeparam>
|
||||
public abstract class UmbracoTemplatePage<T> : UmbracoTemplatePage where T : TypedModelBase
|
||||
{
|
||||
protected override void InitializePage()
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.Entity.Design" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
@@ -255,7 +256,8 @@
|
||||
<Compile Include="PropertyEditors\LegacyPropertyEditorIdToAliasConverterTests.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyEditorValueEditorTests.cs" />
|
||||
<Compile Include="PublishedContent\StronglyTypedModels\CallingMethodTests.cs" />
|
||||
<Compile Include="PublishedContent\StronglyTypedModels\TextpageModel.cs" />
|
||||
<Compile Include="PublishedContent\StronglyTypedModels\Subpage.cs" />
|
||||
<Compile Include="PublishedContent\StronglyTypedModels\Textpage.cs" />
|
||||
<Compile Include="PublishedContent\StronglyTypedModels\TypedModelBase.cs" />
|
||||
<Compile Include="PublishedContent\StronglyTypedModels\UmbracoTemplatePage`T.cs" />
|
||||
<Compile Include="Services\LocalizationServiceTests.cs" />
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
angular.module("umbraco.directives", ["umbraco.directives.editors"]);
|
||||
angular.module("umbraco.directives.editors", []);
|
||||
angular.module("umbraco.directives", ["umbraco.directives.editors", "umbraco.directives.html", "umbraco.directives.validation"]);
|
||||
angular.module("umbraco.directives.editors", []);
|
||||
angular.module("umbraco.directives.html", []);
|
||||
angular.module("umbraco.directives.validation", []);
|
||||
@@ -0,0 +1,2 @@
|
||||
The html directives does nothing but display html, with simple one-way binding
|
||||
and is therefore simpler to use then alot of the strict property bound ones
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbProperty
|
||||
* @restrict E
|
||||
**/
|
||||
angular.module("umbraco.directives.html")
|
||||
.directive('umbControlGroup', function () {
|
||||
return {
|
||||
scope: {
|
||||
label: "@",
|
||||
description: "@",
|
||||
hideLabel: "@",
|
||||
alias: "@"
|
||||
},
|
||||
transclude: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/directives/html/umb-control-group.html'
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbProperty
|
||||
* @restrict E
|
||||
**/
|
||||
angular.module("umbraco.directives.html")
|
||||
.directive('umbPane', function () {
|
||||
return {
|
||||
transclude: true,
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/directives/html/umb-pane.html'
|
||||
};
|
||||
});
|
||||
+13
-13
@@ -1,14 +1,14 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbPanel
|
||||
* @restrict E
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbPanel', function(){
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: 'true',
|
||||
templateUrl: 'views/directives/umb-panel.html'
|
||||
};
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbPanel
|
||||
* @restrict E
|
||||
**/
|
||||
angular.module("umbraco.directives.html")
|
||||
.directive('umbPanel', function(){
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: 'true',
|
||||
templateUrl: 'views/directives/html/umb-panel.html'
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* General-purpose validator for ngModel.
|
||||
* angular.js comes with several built-in validation mechanism for input fields (ngRequired, ngPattern etc.) but using
|
||||
* an arbitrary validation function requires creation of a custom formatters and / or parsers.
|
||||
* The ui-validate directive makes it easy to use any function(s) defined in scope as a validator function(s).
|
||||
* A validator function will trigger validation on both model and input changes.
|
||||
*
|
||||
* @example <input val-custom=" 'myValidatorFunction($value)' ">
|
||||
* @example <input val-custom="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }">
|
||||
* @example <input val-custom="{ foo : '$value > anotherModel' }" val-custom-watch=" 'anotherModel' ">
|
||||
* @example <input val-custom="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }" val-custom-watch=" { foo : 'anotherModel' } ">
|
||||
*
|
||||
* @param val-custom {string|object literal} If strings is passed it should be a scope's function to be used as a validator.
|
||||
* If an object literal is passed a key denotes a validation error key while a value should be a validator function.
|
||||
* In both cases validator function should take a value to validate as its argument and should return true/false indicating a validation result.
|
||||
*/
|
||||
|
||||
/*
|
||||
This code comes from the angular UI project, we had to change the directive name and module
|
||||
but other then that its unmodified
|
||||
*/
|
||||
angular.module('umbraco.directives.validation')
|
||||
.directive('valCustom', function () {
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
var validateFn, watch, validators = {},
|
||||
validateExpr = scope.$eval(attrs.valCustom);
|
||||
|
||||
if (!validateExpr){ return;}
|
||||
|
||||
if (angular.isString(validateExpr)) {
|
||||
validateExpr = { validator: validateExpr };
|
||||
}
|
||||
|
||||
angular.forEach(validateExpr, function (exprssn, key) {
|
||||
validateFn = function (valueToValidate) {
|
||||
var expression = scope.$eval(exprssn, { '$value' : valueToValidate });
|
||||
if (angular.isObject(expression) && angular.isFunction(expression.then)) {
|
||||
// expression is a promise
|
||||
expression.then(function(){
|
||||
ctrl.$setValidity(key, true);
|
||||
}, function(){
|
||||
ctrl.$setValidity(key, false);
|
||||
});
|
||||
return valueToValidate;
|
||||
} else if (expression) {
|
||||
// expression is true
|
||||
ctrl.$setValidity(key, true);
|
||||
return valueToValidate;
|
||||
} else {
|
||||
// expression is false
|
||||
ctrl.$setValidity(key, false);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
validators[key] = validateFn;
|
||||
ctrl.$formatters.push(validateFn);
|
||||
ctrl.$parsers.push(validateFn);
|
||||
});
|
||||
|
||||
function apply_watch(watch)
|
||||
{
|
||||
//string - update all validators on expression change
|
||||
if (angular.isString(watch))
|
||||
{
|
||||
scope.$watch(watch, function(){
|
||||
angular.forEach(validators, function(validatorFn){
|
||||
validatorFn(ctrl.$modelValue);
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
//array - update all validators on change of any expression
|
||||
if (angular.isArray(watch))
|
||||
{
|
||||
angular.forEach(watch, function(expression){
|
||||
scope.$watch(expression, function()
|
||||
{
|
||||
angular.forEach(validators, function(validatorFn){
|
||||
validatorFn(ctrl.$modelValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
//object - update appropriate validator
|
||||
if (angular.isObject(watch))
|
||||
{
|
||||
angular.forEach(watch, function(expression, validatorKey)
|
||||
{
|
||||
//value is string - look after one expression
|
||||
if (angular.isString(expression))
|
||||
{
|
||||
scope.$watch(expression, function(){
|
||||
validators[validatorKey](ctrl.$modelValue);
|
||||
});
|
||||
}
|
||||
|
||||
//value is array - look after all expressions in array
|
||||
if (angular.isArray(expression))
|
||||
{
|
||||
angular.forEach(expression, function(intExpression)
|
||||
{
|
||||
scope.$watch(intExpression, function(){
|
||||
validators[validatorKey](ctrl.$modelValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Support for val-custom-watch
|
||||
if (attrs.valCustomWatch){
|
||||
apply_watch( scope.$eval(attrs.valCustomWatch) );
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
+29
-29
@@ -1,30 +1,30 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valHighlight
|
||||
* @restrict A
|
||||
* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second
|
||||
**/
|
||||
function valHighlight($timeout) {
|
||||
return {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
|
||||
scope.$watch(function() {
|
||||
return scope.$eval(attrs.valHighlight);
|
||||
}, function(newVal, oldVal) {
|
||||
if (newVal === true) {
|
||||
element.addClass("highlight-error");
|
||||
$timeout(function () {
|
||||
//set the bound scope property to false
|
||||
scope[attrs.valHighlight] = false;
|
||||
}, 1000);
|
||||
}
|
||||
else {
|
||||
element.removeClass("highlight-error");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valHighlight
|
||||
* @restrict A
|
||||
* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second
|
||||
**/
|
||||
function valHighlight($timeout) {
|
||||
return {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
|
||||
scope.$watch(function() {
|
||||
return scope.$eval(attrs.valHighlight);
|
||||
}, function(newVal, oldVal) {
|
||||
if (newVal === true) {
|
||||
element.addClass("highlight-error");
|
||||
$timeout(function () {
|
||||
//set the bound scope property to false
|
||||
scope[attrs.valHighlight] = false;
|
||||
}, 1000);
|
||||
}
|
||||
else {
|
||||
element.removeClass("highlight-error");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("valHighlight", valHighlight);
|
||||
@@ -0,0 +1,22 @@
|
||||
angular.module('umbraco.directives.validation')
|
||||
.directive('valCompare',function () {
|
||||
return {
|
||||
require: "ngModel",
|
||||
link: function(scope, elem, attrs, ctrl) {
|
||||
var otherInput = elem.inheritedData("$formController")[attrs.valCompare];
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
if(value === otherInput.$viewValue) {
|
||||
ctrl.$setValidity("valCompare", true);
|
||||
return value;
|
||||
}
|
||||
ctrl.$setValidity("valCompare", false);
|
||||
});
|
||||
|
||||
otherInput.$parsers.push(function(value) {
|
||||
ctrl.$setValidity("valCompare", value === ctrl.$viewValue);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
+150
-150
@@ -1,151 +1,151 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valPropertyMsg
|
||||
* @restrict A
|
||||
* @element textarea
|
||||
* @requires formController
|
||||
* @description This directive is used to control the display of the property level validation message.
|
||||
* We will listen for server side validation changes
|
||||
* and when an error is detected for this property we'll show the error message
|
||||
**/
|
||||
function valPropertyMsg(serverValidationManager) {
|
||||
return {
|
||||
scope: {
|
||||
property: "=property"
|
||||
},
|
||||
require: "^form", //require that this directive is contained within an ngForm
|
||||
replace: true, //replace the element with the template
|
||||
restrict: "E", //restrict to element
|
||||
template: "<div ng-show=\"errorMsg != ''\" class='alert alert-error property-error' >{{errorMsg}}</div>",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller
|
||||
which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attrs, formCtrl) {
|
||||
|
||||
//assign the form control to our isolated scope so we can watch it's values
|
||||
scope.formCtrl = formCtrl;
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
var hasError = false;
|
||||
|
||||
//create properties on our custom scope so we can use it in our template
|
||||
scope.errorMsg = "";
|
||||
|
||||
//listen for error changes
|
||||
scope.$watch("formCtrl.$error", function () {
|
||||
if (formCtrl.$invalid) {
|
||||
|
||||
//first we need to check if the valPropertyMsg validity is invalid
|
||||
if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) {
|
||||
//since we already have an error we'll just return since this means we've already set the
|
||||
// hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe
|
||||
return;
|
||||
}
|
||||
else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) {
|
||||
//check if it's one of the properties that is invalid in the current content property
|
||||
hasError = true;
|
||||
//update the validation message if we don't already have one assigned.
|
||||
if (showValidation && scope.errorMsg === "") {
|
||||
var err;
|
||||
//this can be null if no property was assigned
|
||||
if (scope.property) {
|
||||
err = serverValidationManager.getPropertyError(scope.property.alias, "");
|
||||
}
|
||||
scope.errorMsg = err ? err.errorMsg : "Property has errors";
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}, true);
|
||||
|
||||
//listen for the forms saving event
|
||||
scope.$on("saving", function (ev, args) {
|
||||
showValidation = true;
|
||||
if (hasError && scope.errorMsg === "") {
|
||||
var err;
|
||||
//this can be null if no property was assigned
|
||||
if (scope.property) {
|
||||
err = serverValidationManager.getPropertyError(scope.property.alias, "");
|
||||
}
|
||||
scope.errorMsg = err ? err.errorMsg : "Property has errors";
|
||||
}
|
||||
else if (!hasError) {
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//listen for the forms saved event
|
||||
scope.$on("saved", function (ev, args) {
|
||||
showValidation = false;
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
});
|
||||
|
||||
//We need to subscribe to any changes to our model (based on user input)
|
||||
// This is required because when we have a server error we actually invalidate
|
||||
// the form which means it cannot be resubmitted.
|
||||
// So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
scope.$watch("property.value", function (newValue) {
|
||||
//we are explicitly checking for valServer errors here, since we shouldn't auto clear
|
||||
// based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg
|
||||
// is the only one, then we'll clear.
|
||||
|
||||
var errCount = 0;
|
||||
for (var e in scope.formCtrl.$error) {
|
||||
errCount++;
|
||||
}
|
||||
|
||||
if ((errCount === 1 && scope.formCtrl.$error.valPropertyMsg !== undefined) ||
|
||||
(formCtrl.$invalid && scope.formCtrl.$error.valServer !== undefined)) {
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
}
|
||||
}, true);
|
||||
|
||||
//listen for server validation changes
|
||||
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
|
||||
// validation changes to fields in the property this is because some server side validators may not
|
||||
// return the field name for which the error belongs too, just the property for which it belongs.
|
||||
// It's important to note that we need to subscribe to server validation changes here because we always must
|
||||
// indicate that a content property is invalid at the property level since developers may not actually implement
|
||||
// the correct field validation in their property editors.
|
||||
|
||||
if (scope.property) { //this can be null if no property was assigned
|
||||
serverValidationManager.subscribe(scope.property.alias, "", function(isValid, propertyErrors, allErrors) {
|
||||
hasError = !isValid;
|
||||
if (hasError) {
|
||||
//set the error message to the server message
|
||||
scope.errorMsg = propertyErrors[0].errorMsg;
|
||||
//flag that the current validator is invalid
|
||||
formCtrl.$setValidity('valPropertyMsg', false);
|
||||
}
|
||||
else {
|
||||
scope.errorMsg = "";
|
||||
//flag that the current validator is valid
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function() {
|
||||
serverValidationManager.unsubscribe(scope.property.alias, "");
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valPropertyMsg
|
||||
* @restrict A
|
||||
* @element textarea
|
||||
* @requires formController
|
||||
* @description This directive is used to control the display of the property level validation message.
|
||||
* We will listen for server side validation changes
|
||||
* and when an error is detected for this property we'll show the error message
|
||||
**/
|
||||
function valPropertyMsg(serverValidationManager) {
|
||||
return {
|
||||
scope: {
|
||||
property: "=property"
|
||||
},
|
||||
require: "^form", //require that this directive is contained within an ngForm
|
||||
replace: true, //replace the element with the template
|
||||
restrict: "E", //restrict to element
|
||||
template: "<div ng-show=\"errorMsg != ''\" class='alert alert-error property-error' >{{errorMsg}}</div>",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller
|
||||
which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attrs, formCtrl) {
|
||||
|
||||
//assign the form control to our isolated scope so we can watch it's values
|
||||
scope.formCtrl = formCtrl;
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
var hasError = false;
|
||||
|
||||
//create properties on our custom scope so we can use it in our template
|
||||
scope.errorMsg = "";
|
||||
|
||||
//listen for error changes
|
||||
scope.$watch("formCtrl.$error", function () {
|
||||
if (formCtrl.$invalid) {
|
||||
|
||||
//first we need to check if the valPropertyMsg validity is invalid
|
||||
if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) {
|
||||
//since we already have an error we'll just return since this means we've already set the
|
||||
// hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe
|
||||
return;
|
||||
}
|
||||
else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) {
|
||||
//check if it's one of the properties that is invalid in the current content property
|
||||
hasError = true;
|
||||
//update the validation message if we don't already have one assigned.
|
||||
if (showValidation && scope.errorMsg === "") {
|
||||
var err;
|
||||
//this can be null if no property was assigned
|
||||
if (scope.property) {
|
||||
err = serverValidationManager.getPropertyError(scope.property.alias, "");
|
||||
}
|
||||
scope.errorMsg = err ? err.errorMsg : "Property has errors";
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}, true);
|
||||
|
||||
//listen for the forms saving event
|
||||
scope.$on("saving", function (ev, args) {
|
||||
showValidation = true;
|
||||
if (hasError && scope.errorMsg === "") {
|
||||
var err;
|
||||
//this can be null if no property was assigned
|
||||
if (scope.property) {
|
||||
err = serverValidationManager.getPropertyError(scope.property.alias, "");
|
||||
}
|
||||
scope.errorMsg = err ? err.errorMsg : "Property has errors";
|
||||
}
|
||||
else if (!hasError) {
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//listen for the forms saved event
|
||||
scope.$on("saved", function (ev, args) {
|
||||
showValidation = false;
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
});
|
||||
|
||||
//We need to subscribe to any changes to our model (based on user input)
|
||||
// This is required because when we have a server error we actually invalidate
|
||||
// the form which means it cannot be resubmitted.
|
||||
// So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
scope.$watch("property.value", function (newValue) {
|
||||
//we are explicitly checking for valServer errors here, since we shouldn't auto clear
|
||||
// based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg
|
||||
// is the only one, then we'll clear.
|
||||
|
||||
var errCount = 0;
|
||||
for (var e in scope.formCtrl.$error) {
|
||||
errCount++;
|
||||
}
|
||||
|
||||
if ((errCount === 1 && scope.formCtrl.$error.valPropertyMsg !== undefined) ||
|
||||
(formCtrl.$invalid && scope.formCtrl.$error.valServer !== undefined)) {
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
}
|
||||
}, true);
|
||||
|
||||
//listen for server validation changes
|
||||
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
|
||||
// validation changes to fields in the property this is because some server side validators may not
|
||||
// return the field name for which the error belongs too, just the property for which it belongs.
|
||||
// It's important to note that we need to subscribe to server validation changes here because we always must
|
||||
// indicate that a content property is invalid at the property level since developers may not actually implement
|
||||
// the correct field validation in their property editors.
|
||||
|
||||
if (scope.property) { //this can be null if no property was assigned
|
||||
serverValidationManager.subscribe(scope.property.alias, "", function(isValid, propertyErrors, allErrors) {
|
||||
hasError = !isValid;
|
||||
if (hasError) {
|
||||
//set the error message to the server message
|
||||
scope.errorMsg = propertyErrors[0].errorMsg;
|
||||
//flag that the current validator is invalid
|
||||
formCtrl.$setValidity('valPropertyMsg', false);
|
||||
}
|
||||
else {
|
||||
scope.errorMsg = "";
|
||||
//flag that the current validator is valid
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function() {
|
||||
serverValidationManager.unsubscribe(scope.property.alias, "");
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("valPropertyMsg", valPropertyMsg);
|
||||
+44
-44
@@ -1,45 +1,45 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valRegex
|
||||
* @restrict A
|
||||
* @description A custom directive to allow for matching a value against a regex string.
|
||||
* NOTE: there's already an ng-pattern but this requires that a regex expression is set, not a regex string
|
||||
**/
|
||||
function valRegex() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
|
||||
var regex;
|
||||
try {
|
||||
regex = new RegExp(scope.$eval(attrs.valRegex));
|
||||
}
|
||||
catch(e) {
|
||||
regex = new RegExp(attrs.valRegex);
|
||||
}
|
||||
|
||||
var patternValidator = function (viewValue) {
|
||||
//NOTE: we don't validate on empty values, use required validator for that
|
||||
if (!viewValue || regex.test(viewValue)) {
|
||||
// it is valid
|
||||
ctrl.$setValidity('valRegex', true);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "";
|
||||
return viewValue;
|
||||
}
|
||||
else {
|
||||
// it is invalid, return undefined (no model update)
|
||||
ctrl.$setValidity('valRegex', false);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "Value is invalid, it does not match the correct pattern";
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
ctrl.$formatters.push(patternValidator);
|
||||
ctrl.$parsers.push(patternValidator);
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valRegex
|
||||
* @restrict A
|
||||
* @description A custom directive to allow for matching a value against a regex string.
|
||||
* NOTE: there's already an ng-pattern but this requires that a regex expression is set, not a regex string
|
||||
**/
|
||||
function valRegex() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
|
||||
var regex;
|
||||
try {
|
||||
regex = new RegExp(scope.$eval(attrs.valRegex));
|
||||
}
|
||||
catch(e) {
|
||||
regex = new RegExp(attrs.valRegex);
|
||||
}
|
||||
|
||||
var patternValidator = function (viewValue) {
|
||||
//NOTE: we don't validate on empty values, use required validator for that
|
||||
if (!viewValue || regex.test(viewValue)) {
|
||||
// it is valid
|
||||
ctrl.$setValidity('valRegex', true);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "";
|
||||
return viewValue;
|
||||
}
|
||||
else {
|
||||
// it is invalid, return undefined (no model update)
|
||||
ctrl.$setValidity('valRegex', false);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "Value is invalid, it does not match the correct pattern";
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
ctrl.$formatters.push(patternValidator);
|
||||
ctrl.$parsers.push(patternValidator);
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("valRegex", valRegex);
|
||||
+62
-62
@@ -1,63 +1,63 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServer
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content property with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServer(serverValidationManager) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
if (!scope.model || !scope.model.alias){
|
||||
throw "valServer can only be used in the scope of a content property object";
|
||||
}
|
||||
var currentProperty = scope.model;
|
||||
|
||||
//default to 'value' if nothing is set
|
||||
var fieldName = "value";
|
||||
if (attr.valServer) {
|
||||
fieldName = scope.$eval(attr.valServer);
|
||||
if (!fieldName) {
|
||||
//eval returned nothing so just use the string
|
||||
fieldName = attr.valServer;
|
||||
}
|
||||
}
|
||||
|
||||
//subscribe to the changed event of the view model. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
ctrl.$viewChangeListeners.push(function () {
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServer', true);
|
||||
}
|
||||
});
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
ctrl.$setValidity('valServer', false);
|
||||
//assign an error msg property to the current validator
|
||||
ctrl.errorMsg = propertyErrors[0].errorMsg;
|
||||
}
|
||||
else {
|
||||
ctrl.$setValidity('valServer', true);
|
||||
//reset the error message
|
||||
ctrl.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
serverValidationManager.unsubscribe(currentProperty.alias, fieldName);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServer
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content property with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServer(serverValidationManager) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
if (!scope.model || !scope.model.alias){
|
||||
throw "valServer can only be used in the scope of a content property object";
|
||||
}
|
||||
var currentProperty = scope.model;
|
||||
|
||||
//default to 'value' if nothing is set
|
||||
var fieldName = "value";
|
||||
if (attr.valServer) {
|
||||
fieldName = scope.$eval(attr.valServer);
|
||||
if (!fieldName) {
|
||||
//eval returned nothing so just use the string
|
||||
fieldName = attr.valServer;
|
||||
}
|
||||
}
|
||||
|
||||
//subscribe to the changed event of the view model. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
ctrl.$viewChangeListeners.push(function () {
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServer', true);
|
||||
}
|
||||
});
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
ctrl.$setValidity('valServer', false);
|
||||
//assign an error msg property to the current validator
|
||||
ctrl.errorMsg = propertyErrors[0].errorMsg;
|
||||
}
|
||||
else {
|
||||
ctrl.$setValidity('valServer', true);
|
||||
//reset the error message
|
||||
ctrl.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
serverValidationManager.unsubscribe(currentProperty.alias, fieldName);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("valServer", valServer);
|
||||
+53
-53
@@ -1,54 +1,54 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServerField
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content field (not user defined) with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServerField(serverValidationManager) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
if (!attr.valServerField) {
|
||||
throw "valServerField must have a field name for referencing server errors";
|
||||
}
|
||||
|
||||
var fieldName = attr.valServerField;
|
||||
|
||||
//subscribe to the changed event of the view model. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
ctrl.$viewChangeListeners.push(function () {
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
}
|
||||
});
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
ctrl.$setValidity('valServerField', false);
|
||||
//assign an error msg property to the current validator
|
||||
ctrl.errorMsg = fieldErrors[0].errorMsg;
|
||||
}
|
||||
else {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
//reset the error message
|
||||
ctrl.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
serverValidationManager.unsubscribe(null, fieldName);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServerField
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content field (not user defined) with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServerField(serverValidationManager) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
if (!attr.valServerField) {
|
||||
throw "valServerField must have a field name for referencing server errors";
|
||||
}
|
||||
|
||||
var fieldName = attr.valServerField;
|
||||
|
||||
//subscribe to the changed event of the view model. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
ctrl.$viewChangeListeners.push(function () {
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
}
|
||||
});
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
ctrl.$setValidity('valServerField', false);
|
||||
//assign an error msg property to the current validator
|
||||
ctrl.errorMsg = fieldErrors[0].errorMsg;
|
||||
}
|
||||
else {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
//reset the error message
|
||||
ctrl.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
serverValidationManager.unsubscribe(null, fieldName);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("valServerField", valServerField);
|
||||
+31
-31
@@ -1,32 +1,32 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valShowValidation
|
||||
* @restrict A
|
||||
* @description Used to toggle the show-validation class on the element containing the form elements to validate.
|
||||
* This is used because we don't want to show validation messages until after the form is submitted and then reset
|
||||
* the process when the form is successful. We do this by listening to the current controller's saving and saved events.
|
||||
**/
|
||||
function valShowValidation(serverValidationManager) {
|
||||
return {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
//we should show validation if there are any msgs in the server validation collection
|
||||
if (serverValidationManager.items.length > 0) {
|
||||
element.addClass("show-validation");
|
||||
}
|
||||
|
||||
//listen for the forms saving event
|
||||
scope.$on("saving", function (ev, args) {
|
||||
element.addClass("show-validation");
|
||||
});
|
||||
|
||||
//listen for the forms saved event
|
||||
scope.$on("saved", function (ev, args) {
|
||||
element.removeClass("show-validation");
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valShowValidation
|
||||
* @restrict A
|
||||
* @description Used to toggle the show-validation class on the element containing the form elements to validate.
|
||||
* This is used because we don't want to show validation messages until after the form is submitted and then reset
|
||||
* the process when the form is successful. We do this by listening to the current controller's saving and saved events.
|
||||
**/
|
||||
function valShowValidation(serverValidationManager) {
|
||||
return {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
//we should show validation if there are any msgs in the server validation collection
|
||||
if (serverValidationManager.items.length > 0) {
|
||||
element.addClass("show-validation");
|
||||
}
|
||||
|
||||
//listen for the forms saving event
|
||||
scope.$on("saving", function (ev, args) {
|
||||
element.addClass("show-validation");
|
||||
});
|
||||
|
||||
//listen for the forms saved event
|
||||
scope.$on("saved", function (ev, args) {
|
||||
element.removeClass("show-validation");
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("valShowValidation", valShowValidation);
|
||||
+39
-39
@@ -1,40 +1,40 @@
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valTab
|
||||
* @restrict A
|
||||
* @description Used to show validation warnings for a tab to indicate that the tab content has validations errors in its data.
|
||||
**/
|
||||
function valTab() {
|
||||
return {
|
||||
require: "^form",
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
var tabId = "tab" + scope.tab.id;
|
||||
|
||||
//assign the form control to our isolated scope so we can watch it's values
|
||||
scope.formCtrl = formCtrl;
|
||||
scope.tabHasError = false;
|
||||
|
||||
//watch the current form's validation for the current field name
|
||||
scope.$watch("formCtrl.$valid", function () {
|
||||
var tabContent = element.closest(".umb-panel").find("#" + tabId);
|
||||
|
||||
if (formCtrl.$invalid) {
|
||||
//check if the validation messages are contained inside of this tabs
|
||||
if (tabContent.find(".ng-invalid").length > 0) {
|
||||
scope.tabHasError = true;
|
||||
}
|
||||
else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valTab
|
||||
* @restrict A
|
||||
* @description Used to show validation warnings for a tab to indicate that the tab content has validations errors in its data.
|
||||
**/
|
||||
function valTab() {
|
||||
return {
|
||||
require: "^form",
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
var tabId = "tab" + scope.tab.id;
|
||||
|
||||
//assign the form control to our isolated scope so we can watch it's values
|
||||
scope.formCtrl = formCtrl;
|
||||
scope.tabHasError = false;
|
||||
|
||||
//watch the current form's validation for the current field name
|
||||
scope.$watch("formCtrl.$valid", function () {
|
||||
var tabContent = element.closest(".umb-panel").find("#" + tabId);
|
||||
|
||||
if (formCtrl.$invalid) {
|
||||
//check if the validation messages are contained inside of this tabs
|
||||
if (tabContent.find(".ng-invalid").length > 0) {
|
||||
scope.tabHasError = true;
|
||||
}
|
||||
else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("valTab", valTab);
|
||||
+63
-63
@@ -1,64 +1,64 @@
|
||||
function valToggleMsg(serverValidationManager) {
|
||||
return {
|
||||
require: "^form",
|
||||
restrict: "A",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
if (!attr.valToggleMsg){
|
||||
throw "valToggleMsg requires that a reference to a validator is specified";
|
||||
}
|
||||
if (!attr.valMsgFor){
|
||||
throw "valToggleMsg requires that the attribute valMsgFor exists on the element";
|
||||
}
|
||||
if (!formCtrl[attr.valMsgFor]) {
|
||||
throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name;
|
||||
}
|
||||
|
||||
//assign the form control to our isolated scope so we can watch it's values
|
||||
scope.formCtrl = formCtrl;
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
|
||||
//add a watch to the validator for the value (i.e. myForm.value.$error.required )
|
||||
scope.$watch("formCtrl." + attr.valMsgFor + ".$error." + attr.valToggleMsg, function () {
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) {
|
||||
element.show();
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on("saving", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
|
||||
element.show();
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on("saved", function (ev, args) {
|
||||
showValidation = false;
|
||||
element.hide();
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valToggleMsg
|
||||
* @restrict A
|
||||
* @element input
|
||||
* @requires formController
|
||||
* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ?
|
||||
**/
|
||||
function valToggleMsg(serverValidationManager) {
|
||||
return {
|
||||
require: "^form",
|
||||
restrict: "A",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
if (!attr.valToggleMsg){
|
||||
throw "valToggleMsg requires that a reference to a validator is specified";
|
||||
}
|
||||
if (!attr.valMsgFor){
|
||||
throw "valToggleMsg requires that the attribute valMsgFor exists on the element";
|
||||
}
|
||||
if (!formCtrl[attr.valMsgFor]) {
|
||||
throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name;
|
||||
}
|
||||
|
||||
//assign the form control to our isolated scope so we can watch it's values
|
||||
scope.formCtrl = formCtrl;
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
|
||||
//add a watch to the validator for the value (i.e. myForm.value.$error.required )
|
||||
scope.$watch("formCtrl." + attr.valMsgFor + ".$error." + attr.valToggleMsg, function () {
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) {
|
||||
element.show();
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on("saving", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
|
||||
element.show();
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on("saved", function (ev, args) {
|
||||
showValidation = false;
|
||||
element.hide();
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valToggleMsg
|
||||
* @restrict A
|
||||
* @element input
|
||||
* @requires formController
|
||||
* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ?
|
||||
**/
|
||||
angular.module('umbraco.directives').directive("valToggleMsg", valToggleMsg);
|
||||
@@ -263,6 +263,38 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
'Failed to retreive document data for ids ' + idQuery);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#searchDocuments
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets an array of content entities, given a query
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.searchDocuments("news")
|
||||
* .then(function(contentArray) {
|
||||
* var myDoc = contentArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {String} Query search query
|
||||
* @returns {Promise} resourcePromise object containing the entity array.
|
||||
*
|
||||
*/
|
||||
searchDocuments: function (query) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"SearchDocuments",
|
||||
query)),
|
||||
'Failed to retreive document data for query ' + query);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getMediaById
|
||||
@@ -329,8 +361,40 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
"GetMediaByIds",
|
||||
idQuery)),
|
||||
'Failed to retreive media data for ids ' + idQuery);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#searchMedia
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Gets an array of medoa entities, given a query
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.searchMedia("news")
|
||||
* .then(function(mediaArray) {
|
||||
* var myDoc = mediaArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {String} Query search query
|
||||
* @returns {Promise} resourcePromise object containing the entity array.
|
||||
*
|
||||
*/
|
||||
searchMedia: function (query) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"SearchMedia",
|
||||
query)),
|
||||
'Failed to retreive media data for query ' + query);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,36 @@ function userResource($q, $http, umbRequestHelper) {
|
||||
"userApiBaseUrl",
|
||||
"GetAll")),
|
||||
'Failed to retreive all users');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.userResource#changePassword
|
||||
* @methodOf umbraco.resources.userResource
|
||||
*
|
||||
* @description
|
||||
* Changes the current users password
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* contentResource.getAll()
|
||||
* .then(function(userArray) {
|
||||
* var myUsers = userArray;
|
||||
* alert('they are here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @returns {Promise} resourcePromise object containing the user array.
|
||||
*
|
||||
*/
|
||||
changePassword: function (oldPassword, newPassword) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"userApiBaseUrl",
|
||||
"PostChangePassword"),
|
||||
{ oldPassword: oldPassword, newPassword: newPassword }),
|
||||
'Failed to change password');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,13 +101,15 @@ angular.module('umbraco.services')
|
||||
};
|
||||
|
||||
scope.close = function(data) {
|
||||
if (dialog.closeCallback) {
|
||||
if (dialog.closeCallback) {
|
||||
dialog.closeCallback(data);
|
||||
}
|
||||
}
|
||||
|
||||
dialog.element.modal('hide');
|
||||
dialog.element.remove();
|
||||
$("#" + dialog.element.attr("id")).remove();
|
||||
if(dialog.element){
|
||||
dialog.element.modal('hide');
|
||||
dialog.element.remove();
|
||||
$("#" + dialog.element.attr("id")).remove();
|
||||
}
|
||||
};
|
||||
|
||||
//if iframe is enabled, inject that instead of a template
|
||||
@@ -260,8 +262,10 @@ angular.module('umbraco.services')
|
||||
* @param {Object} args if specified this object will be sent to any callbacks registered on the dialogs.
|
||||
*/
|
||||
close: function (dialog, args) {
|
||||
dialog.scope.close();
|
||||
|
||||
if(dialog && dialog.scope){
|
||||
dialog.scope.close();
|
||||
}
|
||||
|
||||
//removeDialog(dialog, args);
|
||||
},
|
||||
|
||||
@@ -323,7 +327,7 @@ angular.module('umbraco.services')
|
||||
*
|
||||
* @description
|
||||
* Opens a mcaro picker in a modal, the callback returns a object representing the macro and it's parameters
|
||||
* @param {Object} options mediapicker dialog options object
|
||||
* @param {Object} options macropicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
@@ -334,6 +338,44 @@ angular.module('umbraco.services')
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#iconPicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a icon picker in a modal, the callback returns a object representing the selected icon
|
||||
* @param {Object} options iconpicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
iconPicker: function (options) {
|
||||
options.template = 'views/common/dialogs/iconPicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#treePicker
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a tree picker in a modal, the callback returns a object representing the selected tree item
|
||||
* @param {Object} options iconpicker dialog options object
|
||||
* @param {$scope} options.scope dialog scope
|
||||
* @param {$scope} options.section tree section to display
|
||||
* @param {$scope} options.multiPicker should the tree pick one or multiple items before returning
|
||||
* @param {Function} options.callback callback function
|
||||
* @returns {Object} modal object
|
||||
*/
|
||||
treePicker: function (options) {
|
||||
options.template = 'views/common/dialogs/treePicker.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#propertyDialog
|
||||
@@ -354,6 +396,19 @@ angular.module('umbraco.services')
|
||||
return openDialog(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#ysodDialog
|
||||
* @methodOf umbraco.services.dialogService
|
||||
*
|
||||
* @description
|
||||
* Opens a dialog to an embed dialog
|
||||
*/
|
||||
embedDialog: function (options) {
|
||||
options.template = 'views/common/dialogs/rteembed.html';
|
||||
options.show = true;
|
||||
return openDialog(options);
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.dialogService#ysodDialog
|
||||
|
||||
@@ -114,7 +114,7 @@ angular.module('umbraco.services')
|
||||
* @param {string} sectionAlias The alias of the section the tree should load data from
|
||||
*/
|
||||
showTree: function (sectionAlias) {
|
||||
if (!this.ui.stickyNavigation && sectionAlias !== this.ui.currentSection) {
|
||||
if (sectionAlias !== this.ui.currentSection) {
|
||||
this.ui.currentSection = sectionAlias;
|
||||
setMode("tree");
|
||||
}
|
||||
@@ -346,7 +346,7 @@ angular.module('umbraco.services')
|
||||
|
||||
var dialog = dialogService.open(
|
||||
{
|
||||
container: $("#dialog div.umb-panel-body"),
|
||||
container: $("#dialog div.umb-modalcolumn-body"),
|
||||
scope: scope,
|
||||
inline: true,
|
||||
show: true,
|
||||
|
||||
@@ -72,7 +72,6 @@ angular.module('umbraco.services')
|
||||
},
|
||||
|
||||
logout: function () {
|
||||
|
||||
return authResource.performLogout()
|
||||
.then(function (data) {
|
||||
currentUser = null;
|
||||
|
||||
@@ -11,6 +11,19 @@
|
||||
margin-left: 0px !Important;
|
||||
}
|
||||
|
||||
small.umb-detail,
|
||||
label small {
|
||||
color: #b3b3b3 !important;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
font-weight: normal
|
||||
}
|
||||
label.control-label {
|
||||
padding-top: 8px !important;
|
||||
}
|
||||
|
||||
.controls-row label{padding: 0px 10px 0px 10px; vertical-align: center}
|
||||
|
||||
//utill styll to hide child untill hover
|
||||
.hover-show{visibility: hidden;}
|
||||
*:hover > .hover-show{visibility: visible;}
|
||||
@@ -436,10 +449,13 @@ input[type="checkbox"][readonly] {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//non-html5 states, pp: added default ng-invalid class
|
||||
input.highlight-error,
|
||||
select.highlight-error,
|
||||
textarea.highlight-error {
|
||||
textarea.highlight-error,
|
||||
input.ng-dirty.ng-invalid,
|
||||
select.ng-dirty.ng-invalid,
|
||||
textarea.ng-dirty.ng-invalid{
|
||||
border-color: #953b39 !important;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
|
||||
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
|
||||
|
||||
@@ -25,9 +25,6 @@ body {
|
||||
padding: 20px
|
||||
}
|
||||
|
||||
.fill {
|
||||
height: 100%
|
||||
}
|
||||
|
||||
#layout {
|
||||
position: relative;
|
||||
@@ -42,19 +39,17 @@ body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#contentwrapper {
|
||||
height: 100%;
|
||||
#contentwrapper, #contentcolumn {
|
||||
position: absolute;
|
||||
top: 0px; bottom: 0px; right: 0px; left: 80px;
|
||||
z-index: 10;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
#contentcolumn {
|
||||
position: relative;
|
||||
margin-left: 80px;
|
||||
z-index: 10;
|
||||
height: 100%;}
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.content-column-body{height: 100%;}
|
||||
#contentcolumn iframe {
|
||||
display: block;
|
||||
position: relative;
|
||||
@@ -121,20 +116,16 @@ body {
|
||||
|
||||
#tree {
|
||||
padding: 0px;
|
||||
position: relative;
|
||||
z-index: 100 !important;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#tree .umb-tree {
|
||||
padding: 15px 0px 20px 0px;
|
||||
padding: 0px 0px 20px 0px;
|
||||
}
|
||||
|
||||
#search-results {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
padding: 15px 0px 20px 0px;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
#contextMenu {
|
||||
|
||||
@@ -146,17 +146,7 @@ div.umb-codeeditor .umb-btn-toolbar {
|
||||
margin: auto
|
||||
}
|
||||
|
||||
small.umb-detail,
|
||||
label small {
|
||||
color: #b3b3b3 !important;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
label {
|
||||
padding-top: 8px !important;
|
||||
}
|
||||
|
||||
|
||||
/* FORM GRID */
|
||||
|
||||
@@ -3,44 +3,54 @@
|
||||
|
||||
/* Modalcolumn is used for menu panels */
|
||||
.umb-modalcolumn {
|
||||
background: #fff;
|
||||
background: white;
|
||||
border-left: #f6f6f6 1px solid;
|
||||
}
|
||||
.umb-modalcolumn .umb-panel-header {
|
||||
white-space: nowrap
|
||||
}
|
||||
.umb-modalcolumn .umb-panel-body {
|
||||
padding: 0px
|
||||
|
||||
.umb-modalcolumn-header {
|
||||
background: @grayLighter;
|
||||
border-bottom: 1px solid @grayLight;
|
||||
height: 79px;
|
||||
padding: 20px 20px 0px 20px;
|
||||
}
|
||||
.no-padding .umb-panel-body {
|
||||
|
||||
.umb-modalcolumn-header h1{
|
||||
margin: 0;
|
||||
font-size: @fontSizeLarge;
|
||||
font-weight: 400;
|
||||
padding-top: 10px !important;
|
||||
text-transform: capitalize !important;
|
||||
}
|
||||
|
||||
.umb-modalcolumn-body {
|
||||
padding: 0px;
|
||||
background: white;
|
||||
top: 101px;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
|
||||
.no-padding .umb-modalcolumn-body {
|
||||
padding: 0px
|
||||
}
|
||||
|
||||
.umb-modalcolumn .umb-panel-header .btn {
|
||||
.umb-modalcolumn .umb-modalcolumn-header .btn {
|
||||
position: absolute;
|
||||
top: 13px;
|
||||
right: 15px
|
||||
}
|
||||
|
||||
.umb-modalcolumn .umb-modal-close-icon {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
left: 27px;
|
||||
}
|
||||
.umb-modalcolumn .umb-modal-close-icon i {
|
||||
background: url(close.png);
|
||||
width: 18px;
|
||||
height: 18px
|
||||
}
|
||||
.umb-modalcolumn iframe {
|
||||
border: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
.umb-modalcolumn h1 {
|
||||
padding-top: 10px !important;
|
||||
text-transform: capitalize !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* umb.dialog is used for the dialogs on the conent tree*/
|
||||
@@ -131,7 +141,7 @@
|
||||
|
||||
|
||||
|
||||
.umb-modal .thumbnail {
|
||||
.umb-thumbnails .thumbnail {
|
||||
padding: 0;
|
||||
border:none;
|
||||
}
|
||||
@@ -140,43 +150,46 @@
|
||||
margin: 0 0 20px 0
|
||||
}*/
|
||||
|
||||
.umb-modal .thumbnails > li {
|
||||
.umb-thumbnails > li {
|
||||
margin: 0 20px 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.umb-modal .thumbnail img {
|
||||
/*height: 100px;*/
|
||||
}
|
||||
.umb-thumbnails i{margin: auto;}
|
||||
|
||||
.umb-modal .thumbnails .selected img, .umb-modal .thumbnails img:hover {
|
||||
.umb-thumbnails .selected img, .umb-thumbnails img:hover {
|
||||
opacity: 0.5
|
||||
}
|
||||
|
||||
.umb-modal .thumbnails > li.folder {
|
||||
.umb-thumbnails > li.folder {
|
||||
width: 100px;
|
||||
/*height: 100px;*/
|
||||
display: block;
|
||||
background: @grayLighter;
|
||||
text-align: center;
|
||||
font-size: 12px
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.umb-modal .thumbnails > li.folder .icon-folder{
|
||||
color: @grayLight;
|
||||
.umb-thumbnails a{
|
||||
outline: none;
|
||||
border:none !important;
|
||||
box-shadow:none !important;
|
||||
}
|
||||
|
||||
.umb-thumbnails > li.folder .icon-folder{
|
||||
display: block;
|
||||
font-size: 90px;
|
||||
height: 75px;
|
||||
width:100px;
|
||||
color: @grayLight;
|
||||
}
|
||||
|
||||
.umb-modal .thumbnails > li.folder a {
|
||||
.umb-thumbnails > li.folder a {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
display: block
|
||||
}
|
||||
|
||||
.umb-modal .thumbnails > li.folder a:hover {
|
||||
.umb-thumbnails > li.folder a:hover {
|
||||
text-decoration: none
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,30 @@
|
||||
// Panel
|
||||
// -------------------------
|
||||
.umb-panel{background: white;}
|
||||
.umb-panel{
|
||||
background: white;
|
||||
position: absolute;
|
||||
top: 0px; bottom: 0px; left: 0px; right: 0px;}
|
||||
|
||||
.umb-panel-nobody{padding-top: 100px;}
|
||||
|
||||
.umb-panel-header {
|
||||
height: 79px;
|
||||
padding: 20px 20px 0px 20px;
|
||||
background: @grayLighter;
|
||||
border-bottom: 1px solid @grayLight;
|
||||
height: 79px;
|
||||
position: absolute;
|
||||
height: 99px;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.umb-panel-body {
|
||||
top: 101px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 20px;
|
||||
position: relative;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.umb-panel-header h1.umb-headline-editor {
|
||||
cursor: text;
|
||||
@@ -18,20 +33,31 @@
|
||||
.umb-panel-header h1.umb-headline-editor {
|
||||
cursor: text;
|
||||
}
|
||||
.umb-headline-editor-wrapper,
|
||||
h1.headline{height: 40px; padding: 30px 0 0 20px;}
|
||||
|
||||
.umb-headline-editor-wrapper{height: 50px;}
|
||||
.umb-headline-editor-wrapper h1, h1.headline {
|
||||
margin: 0;
|
||||
font-size: @fontSizeLarge;
|
||||
font-weight: 400;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper .help-inline{display: none !Important;}
|
||||
.umb-headline-editor-wrapper.error h1{
|
||||
border-bottom: 1px dashed @red; color: @red; cursor: pointer;
|
||||
};
|
||||
|
||||
.umb-panel-header .umb-nav-tabs{
|
||||
bottom: -1px;
|
||||
position: absolute;
|
||||
padding: 0px 0px 0px 20px;
|
||||
}
|
||||
.umb-panel-header h1, {
|
||||
margin: 0;
|
||||
font-size: @fontSizeLarge;
|
||||
font-weight: 400;
|
||||
color: @gray;
|
||||
padding: 4px 0px 4px 6px;
|
||||
line-height: 22px;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -61,11 +87,10 @@
|
||||
|
||||
.umb-panel-header .umb-btn-toolbar {
|
||||
float: right;
|
||||
padding: 20px 20px 0 0;
|
||||
}
|
||||
|
||||
.umb-panel-body {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
.umb-panel-footer {
|
||||
margin: 0;
|
||||
|
||||
@@ -111,14 +111,15 @@
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.umb-tree ins:before {
|
||||
font-size: 11px;
|
||||
.umb-tree ins {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.umb-tree .icon {
|
||||
vertical-align: middle;
|
||||
margin: 1px 13px 1px 0px;
|
||||
color: #414141
|
||||
color: #414141;
|
||||
font-size: 15px;
|
||||
}
|
||||
.umb-tree i.noSpr {
|
||||
display: inline-block;
|
||||
@@ -448,7 +449,7 @@ height:1px;
|
||||
}
|
||||
|
||||
body.touch .umb-tree .icon{font-size: 17px;}
|
||||
body.touch .umb-tree ins{font-size: 20px; visibility: visible; padding: 7px;}
|
||||
body.touch .umb-tree ins{font-size: 14px; visibility: visible; padding: 7px;}
|
||||
body.touch .umb-tree li div {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<umb-panel val-show-validation>
|
||||
<umb-header tabs="dashboard.tabs">
|
||||
<div class="umb-headline-editor-wrapper span12">
|
||||
<h1 class="headline">{{dashboard.name}}</h1>
|
||||
<h1>{{dashboard.name}}</h1>
|
||||
</div>
|
||||
</umb-header>
|
||||
<umb-tab-view>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="umb-panel-body umb-scrollable" auto-scale="0">
|
||||
|
||||
<div class="umb-control-group">
|
||||
<ul class="thumbnails">
|
||||
<ul class="umb-thumbnails thumbnails">
|
||||
<li class="span1" ng-repeat="icon in icons|filter: searchTerm">
|
||||
<a href="#" title="{{icon}}" class="thumbnail" ng-click="submit(icon)" prevent-default>
|
||||
<i class="{{icon}} large" style="font-size: 32px"></i>
|
||||
|
||||
@@ -53,9 +53,10 @@ data-file-upload="options" data-file-upload-progress="" data-ng-class="{'fileupl
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="height: 10px; margin: 10px 0px 10px 0px" class="umb-loader" ng-hide="active() == 0"></div>
|
||||
<div style="height: 10px; margin: 10px 0px 10px 0px" class="umb-loader"
|
||||
ng-hide="active() == 0"></div>
|
||||
|
||||
<ul class="thumbnails">
|
||||
<ul class="umb-thumbnails thumbnails">
|
||||
<li class="span2 folder" ng-repeat="image in images | orderBy:'contentTypeAlias' | filter:searchTerm">
|
||||
<a href="#" class="thumbnail" ng-class="{selected: dialogData.selection.indexOf(image) > -1}"
|
||||
ng-click="selectMediaItem(image)"
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
angular.module("umbraco").controller("Umbraco.Dialogs.RteEmbedController", function ($scope, $http) {
|
||||
$scope.url = "";
|
||||
$scope.width = 500;
|
||||
$scope.height = 300;
|
||||
$scope.constrain = true;
|
||||
$scope.preview = "";
|
||||
$scope.success = false;
|
||||
|
||||
$scope.preview = function(){
|
||||
|
||||
if ($scope.url != "") {
|
||||
|
||||
$scope.preview = "<div class=\"umb-loader\">";
|
||||
|
||||
$scope.success = false;
|
||||
|
||||
$http({ method: 'GET', url: '/umbraco/UmbracoApi/RteEmbed/GetEmbed', params: { url: $scope.url, width: $scope.width, height: $scope.height } })
|
||||
.success(function(data) {
|
||||
$scope.preview = data.Markup;
|
||||
$scope.success = true;
|
||||
})
|
||||
.error(function() {
|
||||
$scope.preview = "";
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$scope.insert = function(){
|
||||
$scope.submit($scope.preview);
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
<div class="umb-panel" ng-controller="Umbraco.Dialogs.RteEmbedController">
|
||||
|
||||
<div class="umb-panel-header">
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar">
|
||||
<input type="button" ng-click="insert()" class="btn btn-primary" value="Insert" ng-disabled="!success" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body umb-scrollable" auto-scale="1">
|
||||
<div class="umb-panel">
|
||||
<div class="umb-control-group">
|
||||
|
||||
<label for="url">Url</label>
|
||||
<input id="url" type="text" ng-model="url" ng-change="preview()"/>
|
||||
|
||||
<label>Size:</label>
|
||||
<input type="text" ng-model="width"/> x <input type="text" ng-model="height" />
|
||||
<label for="constrain">Constrain:</label>
|
||||
<input id="constrain" type="checkbox" ng-model="constrain"/>
|
||||
|
||||
<div ng-bind-html-unsafe="preview">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
|
||||
function ($scope, eventsService, $log) {
|
||||
var dialogOptions = $scope.$parent.dialogOptions;
|
||||
$scope.dialogTreeEventHandler = $({});
|
||||
$scope.section = dialogOptions.section | "content";
|
||||
|
||||
$scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
|
||||
eventsService.publish("Umbraco.Dialogs.TreePickerController.Select", args).then(function(args){
|
||||
if(dialogOptions && dialogOptions.multipicker){
|
||||
$(args.event.target.parentElement)
|
||||
.find("i.umb-tree-icon")
|
||||
.attr("class", "icon umb-tree-icon sprTree icon-check blue");
|
||||
|
||||
$scope.select(args.node);
|
||||
}else{
|
||||
$scope.submit(args.node);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
<div class="umb-panel" ng-controller="Umbraco.Dialogs.TreePickerController">
|
||||
<div class="umb-panel-header">
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar">
|
||||
<input type="button" ng-click="submit(dialogData)" class="btn btn-primary" value="select" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body umb-scrollable">
|
||||
<div class="tab-content umb-control-group">
|
||||
<div class="umb-pane">
|
||||
<umb-tree
|
||||
section="{{section}}"
|
||||
cachekey="contentpickerDialog"
|
||||
showheader="false"
|
||||
showoptions="false"
|
||||
eventhandler="dialogTreeEventHandler">
|
||||
</umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -10,8 +10,7 @@
|
||||
<small>{{user.email}}</small>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="umb-panel-body umb-scrollable" auto-scale="1">
|
||||
<div class="umb-panel-body umb-scrollable">
|
||||
<div class="tab-content umb-control-group">
|
||||
<div class="umb-pane">
|
||||
<h5>Your profile</h5>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<form name="passwordForm" ng-controller="Umbraco.Dashboard.StartupChangePasswordController">
|
||||
<h3>Change password</h3>
|
||||
<p>Enter your current password, then repeat your new password to change it</p>
|
||||
|
||||
<umb-pane>
|
||||
<umb-control-group label="Old password">
|
||||
<input type="password" name="oldpass" ng-model="profile.oldPassword" required/>
|
||||
|
||||
<small class="help-inline"
|
||||
ng-show="passwordForm.oldpass.$error.required">
|
||||
Required
|
||||
</small>
|
||||
|
||||
<small class="help-inline"
|
||||
ng-show="passwordForm.passcompare.$error.serverside">
|
||||
Old password was not correct
|
||||
</small>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="New password">
|
||||
<input type="password" name="pass" ng-model="profile.newPassword" required/>
|
||||
|
||||
<span class="help-inline" val-msg-for="pass" val-toggle-msg="required">Required</span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="Repeat new password">
|
||||
<input type="password" name="passcompare"
|
||||
val-custom="{compare: '$value === profile.newPassword'}"
|
||||
val-custom-watch="'profile.newPassword'"
|
||||
ng-model="profile.repeatNewPassword" required/>
|
||||
|
||||
<small class="help-inline"
|
||||
ng-show="passwordForm.passcompare.$error.required">
|
||||
Required
|
||||
</small>
|
||||
|
||||
<small class="help-inline"
|
||||
ng-show="passwordForm.passcompare.$error.compare">
|
||||
You must re-enter the new password
|
||||
</small>
|
||||
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group hideLabel="1">
|
||||
<button class="btn btn-primary"
|
||||
ng-click="changePassword(profile)">Change</button>
|
||||
</umb-control-group>
|
||||
</umb-pane>
|
||||
</form>
|
||||
@@ -1,6 +1,4 @@
|
||||
function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
|
||||
|
||||
|
||||
//xmlHelper.parseFeed("http://umbraco.org/feeds/videos/getting-started").then(function(feed){
|
||||
|
||||
//});
|
||||
@@ -16,5 +14,22 @@ function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
|
||||
});
|
||||
});
|
||||
}
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
|
||||
function ChangePasswordDashboardController($scope, xmlhelper, $log, userResource) {
|
||||
//this is the model we will pass to the service
|
||||
$scope.profile = {};
|
||||
|
||||
$scope.changePassword = function (p) {
|
||||
userResource.changePassword(p.oldPassword, p.newPassword).then(function () {
|
||||
alert("changed");
|
||||
$scope.passwordForm.$setValidity(true);
|
||||
}, function () {
|
||||
alert("not changed");
|
||||
//this only happens if there is a wrong oldPassword sent along
|
||||
$scope.passwordForm.oldpass.$setValidity("oldPassword", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.StartupChangePasswordController", ChangePasswordDashboardController);
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
</umb-header>
|
||||
|
||||
<div class="umb-panel-body umb-scrollable row-fluid" auto-scale="1">
|
||||
<div class="umb-panel-body umb-scrollable row-fluid">
|
||||
<div class="tab-content form-horizontal">
|
||||
<div class="umb-pane">
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class="umb-property">
|
||||
<div class="control-group umb-control-group" ng-class="{hidelabel:hideLabel, error: propertyForm.$invalid}" >
|
||||
<div class="umb-el-wrap">
|
||||
<label class="control-label" ng-hide="hideLabel" for="{{alias}}">
|
||||
{{label}}
|
||||
<small>{{description}}</small>
|
||||
</label>
|
||||
|
||||
<div class="controls controls-row" ng-transclude>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="umb-pane" ng-transclude>
|
||||
|
||||
</div>
|
||||
+3
-3
@@ -1,3 +1,3 @@
|
||||
<div class="umb-panel tabbable" ng-transclude>
|
||||
|
||||
</div>
|
||||
<div class="umb-panel tabbable" ng-transclude>
|
||||
|
||||
</div>
|
||||
@@ -1,12 +1,12 @@
|
||||
<div id='contextMenu' class="umb-modalcolumn fill shadow umb-panel"
|
||||
<div id='contextMenu' class="umb-modalcolumn fill shadow"
|
||||
ng-swipe-left="nav.hideMenu()"
|
||||
ng-show="nav.ui.showContextMenu" ng-animate="'slide'">
|
||||
|
||||
<div class='umb-panel-header'>
|
||||
<div class='umb-modalcolumn-header'>
|
||||
<h1>{{nav.ui.dialogTitle}}</h1>
|
||||
</div>
|
||||
|
||||
<div class='umb-panel-body'>
|
||||
<div class='umb-modalcolumn-body'>
|
||||
<ul class="umb-actions">
|
||||
<li class="action" ng-class="{sep:action.seperator}" ng-repeat="action in nav.ui.actions">
|
||||
<a prevent-default
|
||||
|
||||
@@ -29,14 +29,15 @@
|
||||
</div>
|
||||
|
||||
<!-- navigation container -->
|
||||
<div id="navigation" class="fill shadow umb-panel umb-modalcolumn"
|
||||
<div id="navigation" class="fill shadow umb-modalcolumn"
|
||||
ng-show="nav.ui.showNavigation"
|
||||
ng-animate="'slide'">
|
||||
|
||||
<div ng-swipe-left="nav.hideNavigation()" class="navigation-inner-container span6">
|
||||
<div ng-swipe-left="nav.hideNavigation()" class="navigation-inner-container span6" style="z-index: 100">
|
||||
|
||||
<!-- the search -->
|
||||
<div id="search-form" ng-animate="'slide'">
|
||||
<div class="umb-panel-header">
|
||||
<div id="search-form">
|
||||
<div class="umb-modalcolumn-header">
|
||||
<form class="form-search" ng-controller="Umbraco.SearchController" novalidate>
|
||||
<i class="icon-search"></i>
|
||||
<input type="text"
|
||||
@@ -50,7 +51,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Search results -->
|
||||
<div id="search-results" class="umb-panel fill" ng-show="nav.ui.showSearchResults" ng-animate="'slide'">
|
||||
<div id="search-results" class="umb-modalcolumn-body"
|
||||
ng-show="nav.ui.showSearchResults">
|
||||
|
||||
<h5 class="umb-tree-header">Search results</h5>
|
||||
<ul class="umb-item-list" ng-repeat="resultGroup in nav.ui.searchResults">
|
||||
@@ -68,23 +70,23 @@
|
||||
|
||||
|
||||
<!-- the tree -->
|
||||
<div id="tree" class="umb-panel fill" ng-animate="'slide'">
|
||||
<div id="tree" class="umb-modalcolumn-body">
|
||||
<umb-tree eventhandler="treeEventHandler" section="{{nav.ui.currentSection}}" ></umb-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="offset6">
|
||||
<div class="offset6" style="z-index: 10">
|
||||
<!-- The context menu -->
|
||||
<umb-context-menu></umb-context-menu>
|
||||
|
||||
<!-- Tree dialogs -->
|
||||
<div id="dialog" class='umb-modalcolumn fill shadow umb-panel'
|
||||
<div id="dialog" class='umb-modalcolumn fill shadow'
|
||||
ng-swipe-left="nav.hideDialog()"
|
||||
ng-show="nav.ui.showContextMenuDialog" ng-animate="'slide'">
|
||||
<div class='umb-panel-header'>
|
||||
<div class='umb-modalcolumn-header'>
|
||||
<h1>{{nav.ui.dialogTitle}}</h1>
|
||||
</div>
|
||||
<div class='umb-panel-body'>
|
||||
<div class='umb-modalcolumn-body'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<div class="umb-pane">
|
||||
|
||||
</div>
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.FolderBrowserController",
|
||||
function ($rootScope, $scope, assetsService, $routeParams, umbRequestHelper, mediaResource, imageHelper) {
|
||||
var dialogOptions = $scope.$parent.dialogOptions;
|
||||
$scope.options = {
|
||||
url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"),
|
||||
autoUpload: true,
|
||||
formData:{
|
||||
currentFolder: $routeParams.id
|
||||
}
|
||||
};
|
||||
|
||||
$scope.loadChildren = function(id){
|
||||
mediaResource.getChildren(id)
|
||||
.then(function(data) {
|
||||
$scope.images = data;
|
||||
//update the thumbnail property
|
||||
_.each($scope.images, function(img) {
|
||||
img.thumbnail = imageHelper.getThumbnail({ imageModel: img, scope: $scope });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on('fileuploadstop', function(event, files){
|
||||
$scope.loadChildren($scope.options.formData.currentFolder);
|
||||
});
|
||||
|
||||
//init load
|
||||
$scope.loadChildren($routeParams.id);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,27 @@
|
||||
<form ng-controller="Umbraco.Editors.FolderBrowserController" id="fileupload"
|
||||
method="POST" enctype="multipart/form-data"
|
||||
data-file-upload="options" data-file-upload-progress="" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
|
||||
|
||||
<div style="height: 10px; margin: 10px 0px 10px 0px" class="umb-loader"
|
||||
ng-hide="active() == 0"></div>
|
||||
|
||||
<ul class="umb-thumbnails thumbnails">
|
||||
<li class="span2 folder" ng-repeat="image in images | orderBy:'contentTypeAlias' | filter:searchTerm">
|
||||
<a href="#/media/media/edit/{{image.id}}" class="thumbnail">
|
||||
<img ng-src="{{image.thumbnail}}" ng-switch-when="Image" alt="{{image.name}}"/>
|
||||
<div ng-switch on="!!image.thumbnail" >
|
||||
<img ng-src="{{image.thumbnail}}" class="image" ng-switch-when="true" alt="{{image.name}}"/>
|
||||
|
||||
<div ng-switch-default>
|
||||
<i class="icon-folder large"></i>
|
||||
{{image.name}}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -11,7 +11,7 @@ angular.module("umbraco")
|
||||
menubar : false,
|
||||
statusbar: false,
|
||||
height: 340,
|
||||
toolbar: "bold italic | styleselect | alignleft aligncenter alignright | bullist numlist | outdent indent | link image mediapicker iconpicker",
|
||||
toolbar: "bold italic | styleselect | alignleft aligncenter alignright | bullist numlist | outdent indent | link image mediapicker iconpicker embeddialog",
|
||||
setup : function(editor) {
|
||||
|
||||
|
||||
@@ -69,7 +69,20 @@ angular.module("umbraco")
|
||||
editor.insertContent(i);
|
||||
}});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
editor.addButton('embeddialog', {
|
||||
icon: 'media',
|
||||
tooltip: 'Embed',
|
||||
onclick: function () {
|
||||
dialogService.embedDialog({
|
||||
scope: $scope, callback: function (data) {
|
||||
editor.insertContent(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
angular.module('umbraco').controller("Umbraco.Editors.UserPickerController",
|
||||
function($rootScope, $scope, $log, userResource){
|
||||
|
||||
userResource.getAll().then(function (userArray) {
|
||||
$scope.users = userArray;
|
||||
});
|
||||
|
||||
if ($scope.model.value === null || $scope.model.value === undefined) {
|
||||
$scope.model.value = "";
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
<select
|
||||
ng-controller="Umbraco.Editors.UserPickerController"
|
||||
name="{{ model.alias }}"
|
||||
ng-model=" model.value"
|
||||
ng-options="user.id as user.name for user in users">
|
||||
<option value="">Select User</option>
|
||||
</select>
|
||||
@@ -14,14 +14,17 @@ describe('notification tests', function () {
|
||||
var not1 = notifications.success("success", "something great happened");
|
||||
var not2 = notifications.error("error", "something great happened");
|
||||
var not3 = notifications.warning("warning", "something great happened");
|
||||
var not4 = notifications.warning("warning", "");
|
||||
|
||||
expect(notifications.getCurrent().length).toBe(3);
|
||||
expect(notifications.getCurrent().length).toBe(4);
|
||||
|
||||
//remove at index 0
|
||||
notifications.remove(0);
|
||||
|
||||
expect(notifications.getCurrent().length).toEqual(2);
|
||||
expect(notifications.getCurrent()[0].headline).toBe("error");
|
||||
expect(notifications.getCurrent().length).toEqual(3);
|
||||
expect(notifications.getCurrent()[0].headline).toBe("error:");
|
||||
expect(notifications.getCurrent()[1].headline).toBe("warning:");
|
||||
expect(notifications.getCurrent()[2].headline).toBe("warning");
|
||||
|
||||
notifications.removeAll();
|
||||
expect(notifications.getCurrent().length).toEqual(0);
|
||||
|
||||
@@ -599,6 +599,7 @@
|
||||
<Compile Include="Umbraco\Umbraco.aspx.designer.cs">
|
||||
<DependentUpon>umbraco.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Content Include="Umbraco_Client\IconPicker\iconpicker.js" />
|
||||
<Content Include="App_Plugins\MyPackage\Common\Js\MyPackage.js" />
|
||||
<Content Include="App_Plugins\MyPackage\PropertyEditors\Js\CsvEditor.js" />
|
||||
<Content Include="App_Plugins\MyPackage\PropertyEditors\Js\PostcodeEditor.js" />
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="PartialView.ascx.cs" Inherits="Umbraco.Web.UI.Umbraco.Create.PartialView" %>
|
||||
<%@ Import Namespace="umbraco" %>
|
||||
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
|
||||
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
|
||||
|
||||
<umb:CssInclude runat="server" FilePath="Dialogs/CreateDialog.css" PathNameAlias="UmbracoClient" />
|
||||
<cc1:Pane runat="server">
|
||||
<cc1:PropertyPanel runat="server" text="Filename (without .cshtml)">
|
||||
<asp:TextBox id="FileName" Runat="server" CssClass="bigInput input-large-type input-block-level"></asp:TextBox>
|
||||
<asp:RequiredFieldValidator id="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="FileName" runat="server">*</asp:RequiredFieldValidator>
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
Filename (without .cshtml):
|
||||
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="FileName" runat="server">*</asp:RequiredFieldValidator>
|
||||
<cc1:PropertyPanel runat="server" Text="Template">
|
||||
<asp:ListBox id="PartialViewTemplate" Runat="server" Width="350" CssClass="bigInput input-large-type input-block-level" Rows="1" SelectionMode="Single">
|
||||
<asp:ListItem Value="clean.xslt">Clean</asp:ListItem>
|
||||
</asp:ListBox>
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
<cc1:PropertyPanel runat="server">
|
||||
<asp:CheckBox ID="CreateMacroCheckBox" Runat="server" Checked="true" Text="Create Macro"></asp:CheckBox>
|
||||
</cc1:PropertyPanel>
|
||||
</cc1:Pane>
|
||||
|
||||
<%--<input type="hidden" name="nodeType" value="-1">--%>
|
||||
<div>
|
||||
<asp:TextBox ID="FileName" runat="server" CssClass="bigInput"></asp:TextBox>
|
||||
</div>
|
||||
<div>
|
||||
Choose a template:<br />
|
||||
<asp:ListBox ID="PartialViewTemplate" runat="server" Width="350" CssClass="bigInput" Rows="1" SelectionMode="Single" />
|
||||
</div>
|
||||
<!-- added to support missing postback on enter in IE -->
|
||||
<asp:TextBox runat="server" style="visibility:hidden;display:none;" ID="Textbox1"/>
|
||||
<input type="hidden" name="nodeType" value="-1">
|
||||
|
||||
<div>
|
||||
<asp:CheckBox ID="CreateMacroCheckBox" runat="server" Checked="true" Text="Create Macro"></asp:CheckBox>
|
||||
</div>
|
||||
|
||||
<div class="submit-footer">
|
||||
<asp:Button ID="SubmitButton" runat="server" OnClick="SubmitButton_Click" Text='<%#ui.Text("create") %>'></asp:Button>
|
||||
<em><%= umbraco.ui.Text("or") %></em>
|
||||
<a href="#" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
|
||||
</div>
|
||||
<cc1:Pane runat="server" CssClass="btn-toolbar umb-btn-toolbar">
|
||||
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
|
||||
<asp:Button id="sbmt" Runat="server" CssClass="btn btn-primary" Text="Save" onclick="SubmitButton_Click"></asp:Button>
|
||||
</cc1:Pane>
|
||||
+20
-11
@@ -12,15 +12,6 @@ namespace Umbraco.Web.UI.Umbraco.Create {
|
||||
|
||||
public partial class PartialView {
|
||||
|
||||
/// <summary>
|
||||
/// RequiredFieldValidator1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
|
||||
|
||||
/// <summary>
|
||||
/// FileName control.
|
||||
/// </summary>
|
||||
@@ -30,6 +21,15 @@ namespace Umbraco.Web.UI.Umbraco.Create {
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.TextBox FileName;
|
||||
|
||||
/// <summary>
|
||||
/// RequiredFieldValidator1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1;
|
||||
|
||||
/// <summary>
|
||||
/// PartialViewTemplate control.
|
||||
/// </summary>
|
||||
@@ -49,12 +49,21 @@ namespace Umbraco.Web.UI.Umbraco.Create {
|
||||
protected global::System.Web.UI.WebControls.CheckBox CreateMacroCheckBox;
|
||||
|
||||
/// <summary>
|
||||
/// SubmitButton control.
|
||||
/// Textbox1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Button SubmitButton;
|
||||
protected global::System.Web.UI.WebControls.TextBox Textbox1;
|
||||
|
||||
/// <summary>
|
||||
/// sbmt control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Button sbmt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,9 @@
|
||||
</tab>
|
||||
|
||||
<tab caption="Change Password">
|
||||
<control addPanel="true">/umbraco/dashboard/changepassword.ascx</control>
|
||||
<control addPanel="true">
|
||||
views/dashboard/changepassword.html
|
||||
</control>
|
||||
</tab>
|
||||
|
||||
</section>
|
||||
|
||||
@@ -75,7 +75,9 @@
|
||||
<control addPanel="true" MaxRecords="30">/umbraco/dashboard/latestEdits.ascx</control>
|
||||
</tab>
|
||||
<tab caption="Change Password">
|
||||
<control addPanel="true">/umbraco/dashboard/changepassword.ascx</control>
|
||||
<control addPanel="true">
|
||||
views/dashboard/changepassword.html
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
<section alias="StartupMemberDashboardSection">
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
<umb-navigation></umb-navigation>
|
||||
|
||||
<section id="contentwrapper">
|
||||
<div id="contentcolumn">
|
||||
<div class="content-column-body" ng-view></div>
|
||||
<div id="contentcolumn" ng-view>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -56,12 +56,8 @@
|
||||
<cc2:Pane runat="server">
|
||||
<cc2:PropertyPanel ID="pp_icon" runat="server" Text="Icon">
|
||||
<div class="umbIconDropdownList">
|
||||
<asp:DropDownList ID="ddlIcons" CssClass="guiInputText guiInputStandardSize" runat="server"/>
|
||||
</div>
|
||||
</cc2:PropertyPanel>
|
||||
<cc2:PropertyPanel ID="pp_thumbnail" runat="server" Text="Thumbnail">
|
||||
<div class="umbThumbnailDropdownList">
|
||||
<asp:DropDownList ID="ddlThumbnails" CssClass="guiInputText guiInputStandardSize" runat="server"/>
|
||||
<a href="#">Choose...</a>
|
||||
<asp:TextBox ID="tb_icon" runat="server" />
|
||||
</div>
|
||||
</cc2:PropertyPanel>
|
||||
<cc2:PropertyPanel ID="pp_description" runat="server" Text="Description">
|
||||
|
||||
@@ -1,31 +1,37 @@
|
||||
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="DLRScripting.ascx.cs" Inherits="umbraco.presentation.create.DLRScripting" %>
|
||||
Filename (without extension): <asp:RequiredFieldValidator id="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="rename" runat="server">*</asp:RequiredFieldValidator><br />
|
||||
<input type="hidden" name="nodeType" value="-1">
|
||||
<%@ Import Namespace="umbraco" %>
|
||||
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
|
||||
|
||||
<asp:TextBox id="rename" Runat="server" CssClass="bigInput" Width="350"></asp:TextBox>
|
||||
<cc1:Pane runat="server">
|
||||
<cc1:PropertyPanel runat="server" text="Filename (without extension)">
|
||||
<asp:TextBox id="rename" Runat="server" CssClass="bigInput input-large-type input-block-level"></asp:TextBox>
|
||||
<asp:RequiredFieldValidator id="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="rename" runat="server">*</asp:RequiredFieldValidator>
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
|
||||
<ContentTemplate>
|
||||
<div style="MARGIN-TOP: 10px">Choose a language:<br />
|
||||
<asp:ListBox id="filetype" Runat="server" Width="350" CssClass="bigInput" Rows="1" SelectionMode="Single" AutoPostBack="true" OnSelectedIndexChanged="loadTemplates"></asp:ListBox>
|
||||
</div>
|
||||
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
|
||||
<ContentTemplate>
|
||||
<cc1:PropertyPanel runat="server" text="Choose a language">
|
||||
<asp:ListBox id="filetype" Runat="server" CssClass="bigInput input-large-type input-block-level" Rows="1"
|
||||
SelectionMode="Single" AutoPostBack="true" OnSelectedIndexChanged="loadTemplates">
|
||||
</asp:ListBox>
|
||||
</cc1:PropertyPanel>
|
||||
<cc1:PropertyPanel runat="server" text="Template">
|
||||
<asp:ListBox id="template" Runat="server" CssClass="bigInput input-large-type input-block-level" Rows="1" SelectionMode="Single">
|
||||
</asp:ListBox>
|
||||
</cc1:PropertyPanel>
|
||||
</ContentTemplate>
|
||||
</asp:UpdatePanel>
|
||||
|
||||
<div style="MARGIN-TOP: 10px">Choose a template:<br />
|
||||
<asp:ListBox id="template" Runat="server" Width="350" CssClass="bigInput" Rows="1" SelectionMode="Single"></asp:ListBox>
|
||||
</div>
|
||||
</ContentTemplate>
|
||||
</asp:UpdatePanel>
|
||||
<cc1:PropertyPanel runat="server">
|
||||
<asp:CheckBox ID="createMacro" Runat="server" Checked="true" Text="Create Macro"></asp:CheckBox>
|
||||
</cc1:PropertyPanel>
|
||||
</cc1:Pane>
|
||||
|
||||
|
||||
<div style="MARGIN-TOP: 10px">
|
||||
<asp:CheckBox ID="createMacro" Runat="server" Checked="true" Text="Create Macro"></asp:CheckBox>
|
||||
</div>
|
||||
<cc1:Pane runat="server" CssClass="btn-toolbar umb-btn-toolbar">
|
||||
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
|
||||
<asp:Button id="sbmt" Runat="server" CssClass="btn btn-primary" Text="Save" onclick="sbmt_Click"></asp:Button>
|
||||
</cc1:Pane>
|
||||
|
||||
<!-- added to support missing postback on enter in IE -->
|
||||
<asp:TextBox runat="server" style="visibility:hidden;display:none;" ID="Textbox1"/>
|
||||
|
||||
<div style="MARGIN-TOP: 15px;">
|
||||
<asp:Button id="sbmt" Runat="server" style="MARGIN-TOP: 14px" Width="90" onclick="sbmt_Click"></asp:Button>
|
||||
<em><%= umbraco.ui.Text("or") %></em>
|
||||
<a href="#" style="color: blue" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
|
||||
</div>
|
||||
<input type="hidden" name="nodeType" value="-1">
|
||||
@@ -1,25 +1,30 @@
|
||||
<%@ Control Language="c#" AutoEventWireup="True" Codebehind="xslt.ascx.cs" Inherits="umbraco.presentation.create.xslt" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
|
||||
Filename (without .xslt): <asp:RequiredFieldValidator id="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="rename" runat="server">*</asp:RequiredFieldValidator><br />
|
||||
<input type="hidden" name="nodeType" value="-1">
|
||||
<asp:TextBox id="rename" Runat="server" CssClass="bigInput" Width="350"></asp:TextBox>
|
||||
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
|
||||
|
||||
<cc1:Pane runat="server">
|
||||
<cc1:PropertyPane runat="server" text="Filename (without .xslt)">
|
||||
<asp:TextBox id="rename" Runat="server" CssClass="input-larger-type input-block-input"></asp:TextBox>
|
||||
<asp:RequiredFieldValidator id="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="rename" runat="server">*</asp:RequiredFieldValidator>
|
||||
</cc1:PropertyPane>
|
||||
|
||||
<div style="MARGIN-TOP: 10px">Choose a template:<br />
|
||||
<asp:ListBox id="xsltTemplate" Runat="server" Width="350" CssClass="bigInput" Rows="1" SelectionMode="Single">
|
||||
<asp:ListItem Value="clean.xslt">Clean</asp:ListItem>
|
||||
</asp:ListBox>
|
||||
</div>
|
||||
|
||||
<div style="MARGIN-TOP: 10px">
|
||||
<asp:CheckBox ID="createMacro" Runat="server" Checked="true" Text="Create Macro"></asp:CheckBox>
|
||||
</div>
|
||||
<cc1:PropertyPanel runat="server" Text="Template">
|
||||
<asp:ListBox id="xsltTemplate" Runat="server" Width="350" CssClass="bigInput input-large-type input-block-level" Rows="1" SelectionMode="Single">
|
||||
<asp:ListItem Value="clean.xslt">Clean</asp:ListItem>
|
||||
</asp:ListBox>
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
<cc1:PropertyPanel runat="server" Text="Create macro">
|
||||
<asp:CheckBox ID="createMacro" Runat="server" Checked="true" Text="Create Macro"></asp:CheckBox>
|
||||
</cc1:PropertyPanel>
|
||||
</cc1:Pane>
|
||||
|
||||
<!-- added to support missing postback on enter in IE -->
|
||||
<asp:TextBox runat="server" style="visibility:hidden;display:none;" ID="Textbox1"/>
|
||||
<input type="hidden" name="nodeType" value="-1">
|
||||
|
||||
|
||||
<div style="MARGIN-TOP: 15px;">
|
||||
<asp:Button id="sbmt" Runat="server" style="MARGIN-TOP: 14px" Width="90" onclick="sbmt_Click"></asp:Button>
|
||||
<em><%= umbraco.ui.Text("or") %></em>
|
||||
<a href="#" style="color: blue" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
|
||||
</div>
|
||||
<cc1:Pane runat="server" CssClass="btn-toolbar umb-btn-toolbar">
|
||||
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
|
||||
<asp:Button id="sbmt" Runat="server" CssClass="btn btn-primary" onclick="sbmt_Click"></asp:Button>
|
||||
</cc1:Pane>
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
</asp:DropDownList>
|
||||
</td>
|
||||
<td>
|
||||
<asp:Button ID="createNew" Text="Add" runat="server" CssClass="guiInputButton" />
|
||||
<asp:Button ID="createNew" Text="Add" runat="server" CssClass="btn btn-default" />
|
||||
</td>
|
||||
</tr>
|
||||
</tfooter>
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<umb:Pane ID="directionPane" runat="server" Text="">
|
||||
|
||||
<umb:PropertyPanel runat="server" id="dualPropertyPanel" Text="Direction">
|
||||
<asp:RadioButtonList ID="dualRadioButtonList" runat="server" RepeatDirection="Horizontal">
|
||||
<asp:RadioButtonList ID="dualRadioButtonList" runat="server" RepeatDirection="Vertical">
|
||||
<asp:ListItem Enabled="true" Selected="False" Text="Parent to Child" Value="0" />
|
||||
<asp:ListItem Enabled="true" Selected="False" Text="Bidirectional" Value="1"/>
|
||||
</asp:RadioButtonList>
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
<asp:Repeater ID="relationsRepeater" runat="server">
|
||||
<HeaderTemplate>
|
||||
<table class="relations">
|
||||
<table class="table relations">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="objectTypeIcon"> </th>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%@ Page Language="C#" MasterPageFile="../MasterPages/UmbracoPage.Master" AutoEventWireup="true" CodeBehind="EditMacro.aspx.cs" Inherits="Umbraco.Web.UI.Umbraco.Dialogs.EditMacro" %>
|
||||
<%@ Page Language="C#" MasterPageFile="../MasterPages/UmbracoDialog.Master" AutoEventWireup="true" CodeBehind="EditMacro.aspx.cs" Inherits="Umbraco.Web.UI.Umbraco.Dialogs.EditMacro" %>
|
||||
|
||||
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
|
||||
|
||||
@@ -24,17 +24,23 @@
|
||||
|
||||
</asp:Content>
|
||||
<asp:Content ContentPlaceHolderID="body" runat="server">
|
||||
|
||||
|
||||
<asp:Panel ID="pl_edit" runat="server" Visible="false">
|
||||
|
||||
|
||||
<cc2:Pane ID="pane_edit" runat="server">
|
||||
<div class="macro-properties">
|
||||
<asp:PlaceHolder ID="macroProperties" runat="server" />
|
||||
</div>
|
||||
</cc2:Pane>
|
||||
<p>
|
||||
<input data-bind="click: updateMacro" type="button" value="<%=umbraco.ui.Text("general", "ok", this.getUser())%>" />
|
||||
<em>or </em>
|
||||
<a data-bind="click: cancelModal" ><%=umbraco.ui.Text("general", "cancel", this.getUser())%></a>
|
||||
</p>
|
||||
|
||||
|
||||
<cc2:Pane runat="server" CssClass="btn-toolbar umb-btn-toolbar">
|
||||
<a class="btn btn-link" data-bind="click: cancelModal" ><%=umbraco.ui.Text("general", "cancel", this.getUser())%></a>
|
||||
<input data-bind="click: updateMacro" class="btn btn-primary" type="button" value="<%=umbraco.ui.Text("general", "ok", this.getUser())%>" />
|
||||
</cc2:Pane>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
@@ -49,18 +55,20 @@
|
||||
</script>
|
||||
|
||||
</asp:Panel>
|
||||
|
||||
<asp:Panel ID="pl_insert" runat="server">
|
||||
<cc2:Pane ID="pane_insert" runat="server">
|
||||
<cc2:PropertyPanel ID="pp_chooseMacro" runat="server" Text="Choose a macro">
|
||||
<asp:ListBox Rows="1" ID="umb_macroAlias" runat="server"></asp:ListBox>
|
||||
</cc2:PropertyPanel>
|
||||
</cc2:Pane>
|
||||
<p>
|
||||
<asp:Button ID="bt_insert" runat="server" Text="ok" OnClick="renderProperties"></asp:Button>
|
||||
<em>or </em>
|
||||
<a data-bind="click: cancelModal" ><%=umbraco.ui.Text("general", "cancel", this.getUser())%></a>
|
||||
</p>
|
||||
|
||||
<cc2:Pane runat="server" CssClass="btn-toolbar umb-btn-toolbar">
|
||||
<a class="btn btn-link" data-bind="click: cancelModal" ><%=umbraco.ui.Text("general", "cancel", this.getUser())%></a>
|
||||
<asp:Button ID="bt_insert" runat="server" CssClass="btn btn-primary" Text="ok" OnClick="renderProperties"></asp:Button>
|
||||
</cc2:Pane>
|
||||
</asp:Panel>
|
||||
|
||||
<div id="renderContent" style="display: none">
|
||||
<asp:PlaceHolder ID="renderHolder" runat="server"></asp:PlaceHolder>
|
||||
</div>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
<asp:Content ContentPlaceHolderID="body" runat="server">
|
||||
<uc1:ContentTypeControlNew ID="ContentTypeControlNew1" runat="server"></uc1:ContentTypeControlNew>
|
||||
|
||||
<cc1:Pane ID="tmpPane" runat="server">
|
||||
<cc1:PropertyPanel Text="Allowed templates" runat="server">
|
||||
<div class="guiInputStandardSize" style="border: #ccc 1px solid; background: #fff;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
//todo
|
||||
function openIconPicker(element) {
|
||||
|
||||
}
|
||||
@@ -235,7 +235,7 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
//initialize this to successful
|
||||
var publishStatus = new Attempt<PublishStatus>(true, null);
|
||||
var publishStatus = Attempt<PublishStatus>.Succeed();
|
||||
|
||||
if (contentItem.Action == ContentSaveAction.Save || contentItem.Action == ContentSaveAction.SaveNew)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,9 @@ using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Examine;
|
||||
using Examine.LuceneEngine.SearchCriteria;
|
||||
using Examine.SearchCriteria;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -47,6 +50,22 @@ namespace Umbraco.Web.Editors
|
||||
return GetEntitiesById(ids, UmbracoObjectTypes.Document);
|
||||
}
|
||||
|
||||
[FilterAllowedOutgoingContent(typeof(IEnumerable<EntityBasic>))]
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Content)]
|
||||
public IEnumerable<EntityBasic> SearchDocuments([FromUri]string query)
|
||||
{
|
||||
var internalSearcher = ExamineManager.Instance.SearchProviderCollection[Constants.Examine.InternalSearcher];
|
||||
var criteria = internalSearcher.CreateSearchCriteria("content", BooleanOperation.Or);
|
||||
var fields = new[] { "id", "__nodeName", "bodyText" };
|
||||
var term = new[] { query.ToLower().Escape() };
|
||||
var operation = criteria.GroupedOr(fields, term).Compile();
|
||||
|
||||
var results = internalSearcher.Search(operation)
|
||||
.Select(x => int.Parse(x["id"]));
|
||||
|
||||
return GetDocumentsByIds(results.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user must have access to either content or media for this to return data
|
||||
/// </summary>
|
||||
@@ -76,6 +95,31 @@ namespace Umbraco.Web.Editors
|
||||
return GetChildren(id, UmbracoObjectTypes.Media);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user must have access to either content or media for this to return data
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[UmbracoApplicationAuthorizeAttribute(
|
||||
Constants.Applications.Media,
|
||||
Constants.Applications.Content)]
|
||||
[EnsureUserPermissionForMedia("id")]
|
||||
[FilterAllowedOutgoingMedia(typeof(IEnumerable<EntityBasic>))]
|
||||
public IEnumerable<EntityBasic> SearchMedia([FromUri]string query)
|
||||
{
|
||||
var internalSearcher = ExamineManager.Instance.SearchProviderCollection[Constants.Examine.InternalSearcher];
|
||||
var criteria = internalSearcher.CreateSearchCriteria("media", BooleanOperation.Or);
|
||||
var fields = new[] { "id", "__nodeName"};
|
||||
var term = new[] { query.ToLower().Escape() };
|
||||
var operation = criteria.GroupedOr(fields, term).Compile();
|
||||
|
||||
var results = internalSearcher.Search(operation)
|
||||
.Select(x => int.Parse(x["id"]));
|
||||
|
||||
return GetMediaByIds(results.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The user must have access to either content or media for this to return data
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Examine.LuceneEngine.SearchCriteria;
|
||||
using Examine.SearchCriteria;
|
||||
|
||||
using umbraco.cms.businesslogic.member;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Examine;
|
||||
using System.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
/// <remarks>
|
||||
/// This controller is decorated with the UmbracoApplicationAuthorizeAttribute which means that any user requesting
|
||||
/// access to ALL of the methods on this controller will need access to the member application.
|
||||
/// </remarks>
|
||||
[PluginController("UmbracoApi")]
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Members)]
|
||||
public class MemberController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
public IEnumerable<MemberEntityBasic> Search(string query)
|
||||
{
|
||||
if (string.IsNullOrEmpty(query))
|
||||
throw new ArgumentException("A search query must be defined", "query");
|
||||
|
||||
|
||||
//this will change when we add the new members API, but for now, we need to live with this setup
|
||||
if (Member.InUmbracoMemberMode())
|
||||
{
|
||||
var internalSearcher = ExamineManager.Instance.SearchProviderCollection[Constants.Examine.InternalMemberSearcher];
|
||||
var criteria = internalSearcher.CreateSearchCriteria("member", BooleanOperation.Or);
|
||||
var fields = new[] { "id", "__nodeName", "email" };
|
||||
var term = new[] { query.ToLower().Escape() };
|
||||
var operation = criteria.GroupedOr(fields, term).Compile();
|
||||
|
||||
var results = internalSearcher.Search(operation)
|
||||
.Select(x => new MemberEntityBasic
|
||||
{
|
||||
Id = int.Parse(x["id"]),
|
||||
Name = x["nodeName"],
|
||||
Email = x["email"],
|
||||
LoginName = x["loginName"],
|
||||
Icon = ".icon-user"
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
else
|
||||
{
|
||||
IEnumerable<MemberEntityBasic> results;
|
||||
|
||||
if (query.Contains("@"))
|
||||
{
|
||||
results = from MembershipUser x in Membership.FindUsersByEmail(query)
|
||||
select
|
||||
new MemberEntityBasic()
|
||||
{
|
||||
//how do we get ID?
|
||||
Id = 0,
|
||||
Email = x.Email,
|
||||
LoginName = x.UserName,
|
||||
Name = x.UserName,
|
||||
Icon = "icon-user"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
results = from MembershipUser x in Membership.FindUsersByName(query + "%")
|
||||
select
|
||||
new MemberEntityBasic()
|
||||
{
|
||||
//how do we get ID?
|
||||
Id = 0,
|
||||
Email = x.Email,
|
||||
LoginName = x.UserName,
|
||||
Name = x.UserName,
|
||||
Icon = "icon-user"
|
||||
};
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ using Umbraco.Web.Models.Mapping;
|
||||
using Umbraco.Web.Mvc;
|
||||
|
||||
using legacyUser = umbraco.BusinessLogic.User;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
@@ -37,6 +39,24 @@ namespace Umbraco.Web.Editors
|
||||
return Mapper.Map<UserDetail>(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the users password
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponseMessage PostChangePassword(UserPasswordChange data)
|
||||
{
|
||||
|
||||
var u = UmbracoContext.Security.CurrentUser;
|
||||
if (!UmbracoContext.Security.ValidateBackOfficeCredentials(u.Username, data.OldPassword))
|
||||
return new HttpResponseMessage(HttpStatusCode.Forbidden);
|
||||
|
||||
if(!UmbracoContext.Security.ChangePassword(data.OldPassword, data.NewPassword))
|
||||
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
|
||||
|
||||
return new HttpResponseMessage(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all active users
|
||||
/// </summary>
|
||||
|
||||
@@ -104,12 +104,6 @@ namespace Umbraco.Web.Macros
|
||||
if (currentPage == null) throw new ArgumentNullException("currentPage");
|
||||
if (macro.ScriptName.IsNullOrWhiteSpace()) throw new ArgumentException("The ScriptName property of the macro object cannot be null or empty");
|
||||
|
||||
if (!macro.ScriptName.StartsWith(SystemDirectories.MvcViews + "/MacroPartials/")
|
||||
&& (!Regex.IsMatch(macro.ScriptName, "~/App_Plugins/.+?/Views/MacroPartials", RegexOptions.Compiled)))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot render the Partial View Macro with file: " + macro.ScriptName + ". All Partial View Macros must exist in the " + SystemDirectories.MvcViews + "/MacroPartials/ folder");
|
||||
}
|
||||
|
||||
var http = _getHttpContext();
|
||||
var umbCtx = _getUmbracoContext();
|
||||
var routeVals = new RouteData();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Models.Validation;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
public class MemberEntityBasic : EntityBasic
|
||||
{
|
||||
[DataMember(Name = "email", IsRequired = true)]
|
||||
[RequiredForPersistence(AllowEmptyStrings = false, ErrorMessage = "Required")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[DataMember(Name = "loginName", IsRequired = true)]
|
||||
[RequiredForPersistence(AllowEmptyStrings = false, ErrorMessage = "Required")]
|
||||
public string LoginName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
public class UserPasswordChange
|
||||
{
|
||||
public string OldPassword { get; set; }
|
||||
public string NewPassword { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ namespace Umbraco.Web.Models
|
||||
|
||||
//this is the result of an extension method execution gone wrong so we return dynamic null
|
||||
if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod
|
||||
&& attempt.Error != null && attempt.Error is TargetInvocationException)
|
||||
&& attempt.Exception != null && attempt.Exception is TargetInvocationException)
|
||||
{
|
||||
result = new DynamicNull();
|
||||
return true;
|
||||
@@ -150,7 +150,7 @@ namespace Umbraco.Web.Models
|
||||
{
|
||||
if (binder.Name.InvariantEquals("ChildrenAsList") || binder.Name.InvariantEquals("Children"))
|
||||
{
|
||||
return new Attempt<object>(true, Children);
|
||||
return Attempt<object>.Succeed(Children);
|
||||
}
|
||||
|
||||
if (binder.Name.InvariantEquals("parentId"))
|
||||
@@ -160,9 +160,9 @@ namespace Umbraco.Web.Models
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("The node {0} does not have a parent", Id));
|
||||
}
|
||||
return new Attempt<object>(true, parent.Id);
|
||||
return Attempt<object>.Succeed(parent.Id);
|
||||
}
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,10 +182,10 @@ namespace Umbraco.Web.Models
|
||||
.ToArray();
|
||||
if (filteredTypeChildren.Any())
|
||||
{
|
||||
return new Attempt<object>(true,
|
||||
return Attempt<object>.Succeed(
|
||||
new DynamicPublishedContentList(filteredTypeChildren.Select(x => new DynamicPublishedContent(x))));
|
||||
}
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -201,9 +201,7 @@ namespace Umbraco.Web.Models
|
||||
? reflectedProperty.Value
|
||||
: null;
|
||||
|
||||
return result == null
|
||||
? Attempt<object>.False
|
||||
: new Attempt<object>(true, result);
|
||||
return Attempt.If(result != null, result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -225,7 +223,7 @@ namespace Umbraco.Web.Models
|
||||
|
||||
if (userProperty == null)
|
||||
{
|
||||
return Attempt<object>.False;
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
|
||||
var result = userProperty.Value;
|
||||
@@ -250,7 +248,7 @@ namespace Umbraco.Web.Models
|
||||
result = converted.Result;
|
||||
}
|
||||
|
||||
return new Attempt<object>(true, result);
|
||||
return Attempt<object>.Succeed(result);
|
||||
|
||||
}
|
||||
|
||||
@@ -385,7 +383,7 @@ namespace Umbraco.Web.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Attempt<object>(true,
|
||||
return Attempt<object>.Succeed(
|
||||
content.GetType().InvokeMember(memberAlias,
|
||||
System.Reflection.BindingFlags.GetProperty |
|
||||
System.Reflection.BindingFlags.Instance |
|
||||
@@ -396,7 +394,7 @@ namespace Umbraco.Web.Models
|
||||
}
|
||||
catch (MissingMethodException ex)
|
||||
{
|
||||
return new Attempt<object>(ex);
|
||||
return Attempt<object>.Fail(ex);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ namespace Umbraco.Web.Models
|
||||
|
||||
//this is the result of an extension method execution gone wrong so we return dynamic null
|
||||
if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod
|
||||
&& attempt.Error != null && attempt.Error is TargetInvocationException)
|
||||
&& attempt.Exception != null && attempt.Exception is TargetInvocationException)
|
||||
{
|
||||
result = new DynamicNull();
|
||||
return true;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user