Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/AB3323-SqlMainDom
This commit is contained in:
@@ -313,10 +313,6 @@
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI\umbraco\js", "*", "$tmp\WebApp\umbraco\js")
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI\umbraco\lib", "*", "$tmp\WebApp\umbraco\lib")
|
||||
$this.CopyFiles("$src\Umbraco.Web.UI\umbraco\views", "*", "$tmp\WebApp\umbraco\views")
|
||||
|
||||
# copied too much - delete the LESS map directory
|
||||
# that was copied over into "$tmp\WebApp\umbraco\assets\css\maps"
|
||||
Remove-Item "$tmp\WebApp\umbraco\assets\css\maps" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
})
|
||||
|
||||
$ubuild.DefineMethod("PackageZip",
|
||||
|
||||
@@ -18,19 +18,52 @@ namespace Umbraco.Core.Composing
|
||||
private readonly Composition _composition;
|
||||
private readonly IProfilingLogger _logger;
|
||||
private readonly IEnumerable<Type> _composerTypes;
|
||||
private readonly IEnumerable<Attribute> _enableDisableAttributes;
|
||||
|
||||
private const int LogThresholdMilliseconds = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Composers"/> class.
|
||||
/// Initializes a new instance of the <see cref="Composers" /> class.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="composerTypes">The composer types.</param>
|
||||
/// <param name="logger">A profiling logger.</param>
|
||||
/// <param name="composerTypes">The <see cref="IComposer" /> types.</param>
|
||||
/// <param name="logger">The profiling logger.</param>
|
||||
[Obsolete("This overload only gets the EnableComposer/DisableComposer attributes from the composerTypes assemblies.")]
|
||||
public Composers(Composition composition, IEnumerable<Type> composerTypes, IProfilingLogger logger)
|
||||
: this(composition, composerTypes, Enumerable.Empty<Attribute>(), logger)
|
||||
{
|
||||
var enableDisableAttributes = new List<Attribute>();
|
||||
|
||||
var assemblies = composerTypes.Select(t => t.Assembly).Distinct();
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
enableDisableAttributes.AddRange(assembly.GetCustomAttributes(typeof(EnableComposerAttribute)));
|
||||
enableDisableAttributes.AddRange(assembly.GetCustomAttributes(typeof(DisableComposerAttribute)));
|
||||
}
|
||||
|
||||
_enableDisableAttributes = enableDisableAttributes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Composers" /> class.
|
||||
/// </summary>
|
||||
/// <param name="composition">The composition.</param>
|
||||
/// <param name="composerTypes">The <see cref="IComposer" /> types.</param>
|
||||
/// <param name="enableDisableAttributes">The <see cref="EnableComposerAttribute" /> and/or <see cref="DisableComposerAttribute" /> attributes.</param>
|
||||
/// <param name="logger">The profiling logger.</param>
|
||||
/// <exception cref="ArgumentNullException">composition
|
||||
/// or
|
||||
/// composerTypes
|
||||
/// or
|
||||
/// enableDisableAttributes
|
||||
/// or
|
||||
/// logger</exception>
|
||||
|
||||
public Composers(Composition composition, IEnumerable<Type> composerTypes, IEnumerable<Attribute> enableDisableAttributes, IProfilingLogger logger)
|
||||
{
|
||||
_composition = composition ?? throw new ArgumentNullException(nameof(composition));
|
||||
_composerTypes = composerTypes ?? throw new ArgumentNullException(nameof(composerTypes));
|
||||
_enableDisableAttributes = enableDisableAttributes ?? throw new ArgumentNullException(nameof(enableDisableAttributes));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -103,7 +136,7 @@ namespace Umbraco.Core.Composing
|
||||
.ToList();
|
||||
|
||||
// enable or disable composers
|
||||
EnableDisableComposers(composerTypeList);
|
||||
EnableDisableComposers(_enableDisableAttributes, composerTypeList);
|
||||
|
||||
void GatherInterfaces<TAttribute>(Type type, Func<TAttribute, Type> getTypeInAttribute, HashSet<Type> iset, List<Type> set2)
|
||||
where TAttribute : Attribute
|
||||
@@ -218,7 +251,7 @@ namespace Umbraco.Core.Composing
|
||||
return text.ToString();
|
||||
}
|
||||
|
||||
private static void EnableDisableComposers(ICollection<Type> types)
|
||||
private static void EnableDisableComposers(IEnumerable<Attribute> enableDisableAttributes, ICollection<Type> types)
|
||||
{
|
||||
var enabled = new Dictionary<Type, EnableInfo>();
|
||||
|
||||
@@ -240,20 +273,16 @@ namespace Umbraco.Core.Composing
|
||||
enableInfo.Weight = weight2;
|
||||
}
|
||||
|
||||
var assemblies = types.Select(x => x.Assembly).Distinct();
|
||||
foreach (var assembly in assemblies)
|
||||
foreach (var attr in enableDisableAttributes.OfType<EnableComposerAttribute>())
|
||||
{
|
||||
foreach (var attr in assembly.GetCustomAttributes<EnableComposerAttribute>())
|
||||
{
|
||||
var type = attr.EnabledType;
|
||||
UpdateEnableInfo(type, 2, enabled, true);
|
||||
}
|
||||
var type = attr.EnabledType;
|
||||
UpdateEnableInfo(type, 2, enabled, true);
|
||||
}
|
||||
|
||||
foreach (var attr in assembly.GetCustomAttributes<DisableComposerAttribute>())
|
||||
{
|
||||
var type = attr.DisabledType;
|
||||
UpdateEnableInfo(type, 2, enabled, false);
|
||||
}
|
||||
foreach (var attr in enableDisableAttributes.OfType<DisableComposerAttribute>())
|
||||
{
|
||||
var type = attr.DisabledType;
|
||||
UpdateEnableInfo(type, 2, enabled, false);
|
||||
}
|
||||
|
||||
foreach (var composerType in types)
|
||||
|
||||
@@ -506,6 +506,49 @@ namespace Umbraco.Core.Composing
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Assembly Attributes
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly attributes of the specified type <typeparamref name="T" />.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The attribute type.</typeparam>
|
||||
/// <returns>
|
||||
/// The assembly attributes of the specified type <typeparamref name="T" />.
|
||||
/// </returns>
|
||||
public IEnumerable<T> GetAssemblyAttributes<T>()
|
||||
where T : Attribute
|
||||
{
|
||||
return AssembliesToScan.SelectMany(a => a.GetCustomAttributes<T>()).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the assembly attributes.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// All assembly attributes.
|
||||
/// </returns>
|
||||
public IEnumerable<Attribute> GetAssemblyAttributes()
|
||||
{
|
||||
return AssembliesToScan.SelectMany(a => a.GetCustomAttributes()).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly attributes of the specified <paramref name="attributeTypes" />.
|
||||
/// </summary>
|
||||
/// <param name="attributeTypes">The attribute types.</param>
|
||||
/// <returns>
|
||||
/// The assembly attributes of the specified types.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">attributeTypes</exception>
|
||||
public IEnumerable<Attribute> GetAssemblyAttributes(params Type[] attributeTypes)
|
||||
{
|
||||
if (attributeTypes == null) throw new ArgumentNullException(nameof(attributeTypes));
|
||||
|
||||
return AssembliesToScan.SelectMany(a => attributeTypes.SelectMany(at => a.GetCustomAttributes(at))).ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Get Types
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
public interface IKeepAliveSection : IUmbracoConfigurationSection
|
||||
{
|
||||
bool DisableKeepAliveTask { get; }
|
||||
string KeepAlivePingUrl { get; }
|
||||
}
|
||||
}
|
||||
@@ -15,5 +15,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
ILoggingSection Logging { get; }
|
||||
|
||||
IWebRoutingSection WebRouting { get; }
|
||||
|
||||
IKeepAliveSection KeepAlive { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class KeepAliveElement : ConfigurationElement, IKeepAliveSection
|
||||
{
|
||||
[ConfigurationProperty("disableKeepAliveTask", DefaultValue = "false")]
|
||||
public bool DisableKeepAliveTask => (bool)base["disableKeepAliveTask"];
|
||||
|
||||
[ConfigurationProperty("keepAlivePingUrl", DefaultValue = "{umbracoApplicationUrl}/api/keepalive/ping")]
|
||||
public string KeepAlivePingUrl => (string)base["keepAlivePingUrl"];
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
[ConfigurationProperty("logging")]
|
||||
internal LoggingElement Logging => (LoggingElement)this["logging"];
|
||||
|
||||
|
||||
[ConfigurationProperty("web.routing")]
|
||||
internal WebRoutingElement WebRouting => (WebRoutingElement)this["web.routing"];
|
||||
|
||||
[ConfigurationProperty("keepAlive")]
|
||||
internal KeepAliveElement KeepAlive => (KeepAliveElement)this["keepAlive"];
|
||||
|
||||
IContentSection IUmbracoSettingsSection.Content => Content;
|
||||
|
||||
ISecuritySection IUmbracoSettingsSection.Security => Security;
|
||||
@@ -34,5 +36,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
ILoggingSection IUmbracoSettingsSection.Logging => Logging;
|
||||
|
||||
IWebRoutingSection IUmbracoSettingsSection.WebRouting => WebRouting;
|
||||
|
||||
IKeepAliveSection IUmbracoSettingsSection.KeepAlive => KeepAlive;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
|
||||
@@ -23,6 +24,8 @@ namespace Umbraco.Core
|
||||
// this ain't pretty
|
||||
private static IMediaFileSystem _mediaFileSystem;
|
||||
private static IMediaFileSystem MediaFileSystem => _mediaFileSystem ?? (_mediaFileSystem = Current.MediaFileSystem);
|
||||
private static readonly PropertyEditorCollection _propertyEditors;
|
||||
private static PropertyEditorCollection PropertyEditors = _propertyEditors ?? (_propertyEditors = Current.PropertyEditors);
|
||||
|
||||
#region IContent
|
||||
|
||||
@@ -162,14 +165,12 @@ namespace Umbraco.Core
|
||||
// Fixes https://github.com/umbraco/Umbraco-CMS/issues/3937 - Assigning a new file to an
|
||||
// existing IMedia with extension SetValue causes exception 'Illegal characters in path'
|
||||
string oldpath = null;
|
||||
if (property.GetValue(culture, segment) is string svalue)
|
||||
var value = property.GetValue(culture, segment);
|
||||
|
||||
if (PropertyEditors.TryGet(propertyTypeAlias, out var editor)
|
||||
&& editor is IDataEditorWithMediaPath dataEditor)
|
||||
{
|
||||
if (svalue.DetectIsJson())
|
||||
{
|
||||
// the property value is a JSON serialized image crop data set - grab the "src" property as the file source
|
||||
var jObject = JsonConvert.DeserializeObject<JObject>(svalue);
|
||||
svalue = jObject != null ? jObject.GetValueAsString("src") : svalue;
|
||||
}
|
||||
var svalue = dataEditor.GetMediaPath(value);
|
||||
oldpath = MediaFileSystem.GetRelativePath(svalue);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace Umbraco.Core.Manifest
|
||||
// '-content/foo', // hide for content type 'foo'
|
||||
// '+content/*', // show for all other content types
|
||||
// '+media/*', // show for all media types
|
||||
// '-member/foo' // hide for member type 'foo'
|
||||
// '+member/*' // show for all member types
|
||||
// '+role/admin' // show for admin users. Role based permissions will override others.
|
||||
// ]
|
||||
// },
|
||||
@@ -56,6 +58,10 @@ namespace Umbraco.Core.Manifest
|
||||
partA = "media";
|
||||
partB = media.ContentType.Alias;
|
||||
break;
|
||||
case IMember member:
|
||||
partA = "member";
|
||||
partB = member.ContentType.Alias;
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -18,29 +16,12 @@ namespace Umbraco.Core.Models
|
||||
if (!media.Properties.TryGetValue(propertyAlias, out var property))
|
||||
return string.Empty;
|
||||
|
||||
// TODO: would need to be adjusted to variations, when media become variants
|
||||
if (!(property.GetValue() is string jsonString))
|
||||
return string.Empty;
|
||||
|
||||
if (property.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.UploadField)
|
||||
return jsonString;
|
||||
|
||||
if (property.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.Aliases.ImageCropper)
|
||||
if (Current.PropertyEditors.TryGet(property.PropertyType.PropertyEditorAlias, out var editor)
|
||||
&& editor is IDataEditorWithMediaPath dataEditor)
|
||||
{
|
||||
if (jsonString.DetectIsJson() == false)
|
||||
return jsonString;
|
||||
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<JObject>(jsonString);
|
||||
if (json["src"] != null)
|
||||
return json["src"].Value<string>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error<ImageCropperValueConverter>(ex, "Could not parse the string '{JsonString}' to a json object", jsonString);
|
||||
return string.Empty;
|
||||
}
|
||||
// TODO: would need to be adjusted to variations, when media become variants
|
||||
var value = property.GetValue();
|
||||
return dataEditor.GetMediaPath(value);
|
||||
}
|
||||
|
||||
// Without knowing what it is, just adding a string here might not be very nice
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
internal class ContentBaseFactory
|
||||
{
|
||||
private static readonly Regex MediaPathPattern = new Regex(@"(/media/.+?)(?:['""]|$)", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Builds an IContent item from a dto and content type.
|
||||
/// </summary>
|
||||
@@ -189,7 +187,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
/// <summary>
|
||||
/// Builds a dto from an IMedia item.
|
||||
/// </summary>
|
||||
public static MediaDto BuildDto(IMedia entity)
|
||||
public static MediaDto BuildDto(PropertyEditorCollection propertyEditors, IMedia entity)
|
||||
{
|
||||
var contentDto = BuildContentDto(entity, Constants.ObjectTypes.Media);
|
||||
|
||||
@@ -197,7 +195,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
NodeId = entity.Id,
|
||||
ContentDto = contentDto,
|
||||
MediaVersionDto = BuildMediaVersionDto(entity, contentDto)
|
||||
MediaVersionDto = BuildMediaVersionDto(propertyEditors, entity, contentDto)
|
||||
};
|
||||
|
||||
return dto;
|
||||
@@ -291,12 +289,20 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
return dto;
|
||||
}
|
||||
|
||||
private static MediaVersionDto BuildMediaVersionDto(IMedia entity, ContentDto contentDto)
|
||||
private static MediaVersionDto BuildMediaVersionDto(PropertyEditorCollection propertyEditors, IMedia entity, ContentDto contentDto)
|
||||
{
|
||||
// try to get a path from the string being stored for media
|
||||
// TODO: only considering umbracoFile
|
||||
|
||||
TryMatch(entity.GetValue<string>("umbracoFile"), out var path);
|
||||
string path = null;
|
||||
|
||||
if (entity.Properties.TryGetValue(Constants.Conventions.Media.File, out var property)
|
||||
&& propertyEditors.TryGet(property.PropertyType.PropertyEditorAlias, out var editor)
|
||||
&& editor is IDataEditorWithMediaPath dataEditor)
|
||||
{
|
||||
var value = property.GetValue();
|
||||
path = dataEditor.GetMediaPath(value);
|
||||
}
|
||||
|
||||
var dto = new MediaVersionDto
|
||||
{
|
||||
@@ -308,22 +314,5 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
// TODO: this should NOT be here?!
|
||||
// more dark magic ;-(
|
||||
internal static bool TryMatch(string text, out string path)
|
||||
{
|
||||
// In v8 we should allow exposing this via the property editor in a much nicer way so that the property editor
|
||||
// can tell us directly what any URL is for a given property if it contains an asset
|
||||
|
||||
path = null;
|
||||
if (string.IsNullOrWhiteSpace(text)) return false;
|
||||
|
||||
var m = MediaPathPattern.Match(text);
|
||||
if (!m.Success || m.Groups.Count != 2) return false;
|
||||
|
||||
path = m.Groups[1].Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
entity.SanitizeEntityPropertiesForXmlStorage();
|
||||
|
||||
// create the dto
|
||||
var dto = ContentBaseFactory.BuildDto(entity);
|
||||
var dto = ContentBaseFactory.BuildDto(PropertyEditors, entity);
|
||||
|
||||
// derive path and level from parent
|
||||
var parent = GetParentNodeDto(entity.ParentId);
|
||||
@@ -317,7 +317,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
}
|
||||
|
||||
// create the dto
|
||||
var dto = ContentBaseFactory.BuildDto(entity);
|
||||
var dto = ContentBaseFactory.BuildDto(PropertyEditors, entity);
|
||||
|
||||
// update the node dto
|
||||
var nodeDto = dto.ContentDto.NodeDto;
|
||||
@@ -542,6 +542,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
media.ResetDirtyProperties(false);
|
||||
return media;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Must be implemented by property editors that store media and return media paths
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently there are only 2x core editors that do this: upload and image cropper.
|
||||
/// It would be possible for developers to know implement their own media property editors whereas previously this was not possible.
|
||||
/// </remarks>
|
||||
public interface IDataEditorWithMediaPath
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the media path for the value stored for a property
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
string GetMediaPath(object value);
|
||||
}
|
||||
}
|
||||
@@ -170,8 +170,14 @@ namespace Umbraco.Core.Runtime
|
||||
|
||||
// get composers, and compose
|
||||
var composerTypes = ResolveComposerTypes(typeLoader);
|
||||
composition.WithCollectionBuilder<ComponentCollectionBuilder>();
|
||||
var composers = new Composers(composition, composerTypes, ProfilingLogger);
|
||||
|
||||
IEnumerable<Attribute> enableDisableAttributes;
|
||||
using (ProfilingLogger.DebugDuration<CoreRuntime>("Scanning enable/disable composer attributes"))
|
||||
{
|
||||
enableDisableAttributes = typeLoader.GetAssemblyAttributes(typeof(EnableComposerAttribute), typeof(DisableComposerAttribute));
|
||||
}
|
||||
|
||||
var composers = new Composers(composition, composerTypes, enableDisableAttributes, ProfilingLogger);
|
||||
composers.Compose();
|
||||
|
||||
// create the factory
|
||||
|
||||
@@ -104,5 +104,17 @@ namespace Umbraco.Core.Services
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the concrete assigned permissions for the provided user and node
|
||||
/// </summary>
|
||||
/// <param name="userService"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="nodeId"></param>
|
||||
internal static string[] GetAssignedPermissions(this IUserService userService, IUser user, int nodeId)
|
||||
{
|
||||
var permissionCollection = userService.GetPermissions(user, nodeId);
|
||||
return permissionCollection.SelectMany(c => c.AssignedPermissions).Distinct().ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,6 +284,7 @@
|
||||
<Compile Include="Models\PublishedContent\IPublishedContentType.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedPropertyType.cs" />
|
||||
<Compile Include="PropertyEditors\ConfigurationFieldsExtensions.cs" />
|
||||
<Compile Include="PropertyEditors\IDataEditorWithMediaPath.cs" />
|
||||
<Compile Include="PropertyEditors\IIgnoreUserStartNodesConfig.cs" />
|
||||
<Compile Include="PublishedContentExtensions.cs" />
|
||||
<Compile Include="Models\PublishedContent\UrlMode.cs" />
|
||||
@@ -355,6 +356,7 @@
|
||||
<Compile Include="Configuration\UmbracoSettings\ITourSection.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\IUmbracoSettingsSection.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\IWebRoutingSection.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\IKeepAliveSection.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\LoggingElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\NotificationsElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\RequestHandlerElement.cs" />
|
||||
@@ -364,6 +366,7 @@
|
||||
<Compile Include="Configuration\UmbracoSettings\UmbracoSettingsSection.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\UrlReplacingElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\WebRoutingElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoSettings\KeepAliveElement.cs" />
|
||||
<Compile Include="Configuration\UmbracoVersion.cs" />
|
||||
<Compile Include="Constants-Applications.cs" />
|
||||
<Compile Include="Constants-Conventions.cs" />
|
||||
|
||||
@@ -5,7 +5,6 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Compose;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -13,8 +12,6 @@ using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
[assembly:DisableComposer(typeof(Umbraco.Tests.Components.ComponentTests.Composer26))]
|
||||
|
||||
namespace Umbraco.Tests.Components
|
||||
{
|
||||
[TestFixture]
|
||||
@@ -65,10 +62,11 @@ namespace Umbraco.Tests.Components
|
||||
public void Boot1A()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = TypeArray<Composer1, Composer2, Composer3, Composer4>();
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
// 2 is Core and requires 4
|
||||
// 3 is User - goes away with RuntimeLevel.Unknown
|
||||
@@ -104,10 +102,11 @@ namespace Umbraco.Tests.Components
|
||||
public void Boot1B()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
var types = TypeArray<Composer1, Composer2, Composer3, Composer4>();
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
// 2 is Core and requires 4
|
||||
// 3 is User - stays with RuntimeLevel.Run
|
||||
@@ -120,10 +119,11 @@ namespace Umbraco.Tests.Components
|
||||
public void Boot2()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = TypeArray<Composer20, Composer21>();
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
// 21 is required by 20
|
||||
// => reorder components accordingly
|
||||
@@ -135,10 +135,11 @@ namespace Umbraco.Tests.Components
|
||||
public void Boot3()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = TypeArray<Composer22, Composer24, Composer25>();
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
// i23 requires 22
|
||||
// 24, 25 implement i23
|
||||
@@ -152,10 +153,11 @@ namespace Umbraco.Tests.Components
|
||||
public void BrokenRequire()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = TypeArray<Composer1, Composer2, Composer3>();
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
try
|
||||
{
|
||||
@@ -175,10 +177,11 @@ namespace Umbraco.Tests.Components
|
||||
public void BrokenRequired()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = TypeArray<Composer2, Composer4, Composer13>();
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
// 2 is Core and requires 4
|
||||
// 13 is required by 1
|
||||
@@ -196,6 +199,7 @@ namespace Umbraco.Tests.Components
|
||||
Terminated.Clear();
|
||||
|
||||
var register = MockRegister();
|
||||
var typeLoader = MockTypeLoader();
|
||||
var factory = MockFactory(m =>
|
||||
{
|
||||
m.Setup(x => x.TryGetInstance(It.Is<Type>(t => t == typeof (ISomeResource)))).Returns(() => new SomeResource());
|
||||
@@ -210,10 +214,10 @@ namespace Umbraco.Tests.Components
|
||||
throw new NotSupportedException(type.FullName);
|
||||
});
|
||||
});
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = new[] { typeof(Composer1), typeof(Composer5), typeof(Composer5a) };
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
|
||||
Assert.IsEmpty(Composed);
|
||||
composers.Compose();
|
||||
@@ -236,10 +240,11 @@ namespace Umbraco.Tests.Components
|
||||
public void Requires1()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = new[] { typeof(Composer6), typeof(Composer7), typeof(Composer8) };
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
Assert.AreEqual(2, Composed.Count);
|
||||
@@ -251,10 +256,11 @@ namespace Umbraco.Tests.Components
|
||||
public void Requires2A()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) };
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
Assert.AreEqual(2, Composed.Count);
|
||||
@@ -267,11 +273,12 @@ namespace Umbraco.Tests.Components
|
||||
public void Requires2B()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var typeLoader = MockTypeLoader();
|
||||
var factory = MockFactory();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
var types = new[] { typeof(Composer9), typeof(Composer2), typeof(Composer4) };
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
var builder = composition.WithCollectionBuilder<ComponentCollectionBuilder>();
|
||||
@@ -287,35 +294,36 @@ namespace Umbraco.Tests.Components
|
||||
public void WeakDependencies()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = new[] { typeof(Composer10) };
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
Assert.AreEqual(1, Composed.Count);
|
||||
Assert.AreEqual(typeof(Composer10), Composed[0]);
|
||||
|
||||
types = new[] { typeof(Composer11) };
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
Assert.Throws<Exception>(() => composers.Compose());
|
||||
Console.WriteLine("throws:");
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
var requirements = composers.GetRequirements(false);
|
||||
Console.WriteLine(Composers.GetComposersReport(requirements));
|
||||
|
||||
types = new[] { typeof(Composer2) };
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
Assert.Throws<Exception>(() => composers.Compose());
|
||||
Console.WriteLine("throws:");
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
requirements = composers.GetRequirements(false);
|
||||
Console.WriteLine(Composers.GetComposersReport(requirements));
|
||||
|
||||
types = new[] { typeof(Composer12) };
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
Assert.AreEqual(1, Composed.Count);
|
||||
@@ -326,10 +334,11 @@ namespace Umbraco.Tests.Components
|
||||
public void DisableMissing()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = new[] { typeof(Composer6), typeof(Composer8) }; // 8 disables 7 which is not in the list
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
Assert.AreEqual(2, Composed.Count);
|
||||
@@ -341,16 +350,18 @@ namespace Umbraco.Tests.Components
|
||||
public void AttributesPriorities()
|
||||
{
|
||||
var register = MockRegister();
|
||||
var composition = new Composition(register, MockTypeLoader(), Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
var typeLoader = MockTypeLoader();
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Unknown));
|
||||
|
||||
var types = new[] { typeof(Composer26) }; // 26 disabled by assembly attribute
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var types = new[] { typeof(Composer26) };
|
||||
var enableDisableAttributes = new[] { new DisableComposerAttribute(typeof(Composer26)) };
|
||||
var composers = new Composers(composition, types, enableDisableAttributes, Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
Assert.AreEqual(0, Composed.Count); // 26 gone
|
||||
|
||||
types = new[] { typeof(Composer26), typeof(Composer27) }; // 26 disabled by assembly attribute, enabled by 27
|
||||
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
composers = new Composers(composition, types, enableDisableAttributes, Mock.Of<IProfilingLogger>());
|
||||
Composed.Clear();
|
||||
composers.Compose();
|
||||
Assert.AreEqual(2, Composed.Count); // both
|
||||
@@ -367,7 +378,7 @@ namespace Umbraco.Tests.Components
|
||||
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
|
||||
|
||||
var types = typeLoader.GetTypes<IComposer>().Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web"));
|
||||
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
|
||||
var composers = new Composers(composition, types, Enumerable.Empty<Attribute>(), Mock.Of<IProfilingLogger>());
|
||||
var requirements = composers.GetRequirements();
|
||||
var report = Composers.GetComposersReport(requirements);
|
||||
Console.WriteLine(report);
|
||||
@@ -506,7 +517,6 @@ namespace Umbraco.Tests.Components
|
||||
public class Composer25 : TestComposerBase, IComposer23
|
||||
{ }
|
||||
|
||||
// disabled by assembly attribute
|
||||
public class Composer26 : TestComposerBase
|
||||
{ }
|
||||
|
||||
|
||||
@@ -4,13 +4,18 @@ using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.PublishedContent;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
namespace Umbraco.Tests.Routing
|
||||
@@ -25,7 +30,17 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
_mediaUrlProvider = new DefaultMediaUrlProvider();
|
||||
var logger = Mock.Of<ILogger>();
|
||||
var mediaFileSystemMock = Mock.Of<IMediaFileSystem>();
|
||||
var contentSection = Mock.Of<IContentSection>();
|
||||
var dataTypeService = Mock.Of<IDataTypeService>();
|
||||
|
||||
var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(new IDataEditor[]
|
||||
{
|
||||
new FileUploadPropertyEditor(logger, mediaFileSystemMock, contentSection),
|
||||
new ImageCropperPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService),
|
||||
}));
|
||||
_mediaUrlProvider = new DefaultMediaUrlProvider(propertyEditors);
|
||||
}
|
||||
|
||||
public override void TearDown()
|
||||
@@ -54,10 +69,10 @@ namespace Umbraco.Tests.Routing
|
||||
const string expected = "/media/rfeiw584/test.jpg";
|
||||
|
||||
var configuration = new ImageCropperConfiguration();
|
||||
var imageCropperValue = new ImageCropperValue
|
||||
var imageCropperValue = JsonConvert.SerializeObject(new ImageCropperValue
|
||||
{
|
||||
Src = expected
|
||||
};
|
||||
});
|
||||
|
||||
var umbracoContext = GetUmbracoContext("/", mediaUrlProviders: new[] { _mediaUrlProvider });
|
||||
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.ImageCropper, imageCropperValue, configuration);
|
||||
@@ -121,8 +136,8 @@ namespace Umbraco.Tests.Routing
|
||||
PropertyType = umbracoFilePropertyType,
|
||||
};
|
||||
|
||||
property.SetValue("en", enMediaUrl, true);
|
||||
property.SetValue("da", daMediaUrl);
|
||||
property.SetSourceValue("en", enMediaUrl, true);
|
||||
property.SetSourceValue("da", daMediaUrl);
|
||||
|
||||
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), new [] { umbracoFilePropertyType }, ContentVariation.Culture);
|
||||
var publishedContent = new SolidPublishedContent(contentType) {Properties = new[] {property}};
|
||||
@@ -131,7 +146,7 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual(daMediaUrl, resolvedUrl);
|
||||
}
|
||||
|
||||
private static IPublishedContent CreatePublishedContent(string propertyEditorAlias, object propertyValue, object dataTypeConfiguration)
|
||||
private static IPublishedContent CreatePublishedContent(string propertyEditorAlias, string propertyValue, object dataTypeConfiguration)
|
||||
{
|
||||
var umbracoFilePropertyType = CreatePropertyType(propertyEditorAlias, dataTypeConfiguration, ContentVariation.Nothing);
|
||||
|
||||
@@ -147,7 +162,7 @@ namespace Umbraco.Tests.Routing
|
||||
new SolidPublishedProperty
|
||||
{
|
||||
Alias = "umbracoFile",
|
||||
SolidValue = propertyValue,
|
||||
SolidSourceValue = propertyValue,
|
||||
SolidHasValue = true,
|
||||
PropertyType = umbracoFilePropertyType
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
var composerTypes = typeLoader.GetTypes<IComposer>() // all of them
|
||||
.Where(x => !x.FullName.StartsWith("Umbraco.Tests.")) // exclude test components
|
||||
.Where(x => x != typeof(WebInitialComposer) && x != typeof(WebFinalComposer)); // exclude web runtime
|
||||
var composers = new Composers(composition, composerTypes, profilingLogger);
|
||||
var composers = new Composers(composition, composerTypes, Enumerable.Empty<Attribute>(), profilingLogger);
|
||||
composers.Compose();
|
||||
|
||||
// must registers stuff that WebRuntimeComponent would register otherwise
|
||||
@@ -272,7 +272,7 @@ namespace Umbraco.Tests.Runtimes
|
||||
.Where(x => !x.FullName.StartsWith("Umbraco.Tests"));
|
||||
// single?
|
||||
//var componentTypes = new[] { typeof(CoreRuntimeComponent) };
|
||||
var composers = new Composers(composition, composerTypes, profilingLogger);
|
||||
var composers = new Composers(composition, composerTypes, Enumerable.Empty<Attribute>(), profilingLogger);
|
||||
|
||||
// get components to compose themselves
|
||||
composers.Compose();
|
||||
|
||||
@@ -184,7 +184,7 @@ namespace Umbraco.Tests.Services
|
||||
public void Can_Get_Media_With_Crop_By_Path()
|
||||
{
|
||||
var mediaService = ServiceContext.MediaService;
|
||||
var mediaType = MockedContentTypes.CreateImageMediaType("Image2");
|
||||
var mediaType = MockedContentTypes.CreateImageMediaTypeWithCrop("Image2");
|
||||
ServiceContext.MediaTypeService.Save(mediaType);
|
||||
|
||||
var media = MockedMedia.CreateMediaImageWithCrop(mediaType, -1);
|
||||
|
||||
@@ -420,10 +420,39 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
|
||||
var contentCollection = new PropertyTypeCollection(false);
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.UploadField, ValueStorageType.Nvarchar) { Alias = Constants.Conventions.Media.File, Name = "File", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = -90 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Width, Name = "Width", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -90 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Height, Name = "Height", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -90 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Bytes, Name = "Bytes", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -90 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar) { Alias = Constants.Conventions.Media.Extension, Name = "File Extension", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = -90 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Width, Name = "Width", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Height, Name = "Height", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Bytes, Name = "Bytes", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar) { Alias = Constants.Conventions.Media.Extension, Name = "File Extension", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
|
||||
mediaType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Media", SortOrder = 1 });
|
||||
|
||||
//ensure that nothing is marked as dirty
|
||||
mediaType.ResetDirtyProperties(false);
|
||||
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public static MediaType CreateImageMediaTypeWithCrop(string alias = Constants.Conventions.MediaTypes.Image)
|
||||
{
|
||||
var mediaType = new MediaType(-1)
|
||||
{
|
||||
Alias = alias,
|
||||
Name = "Image",
|
||||
Description = "ContentType used for images",
|
||||
Icon = ".sprTreeDoc3",
|
||||
Thumbnail = "doc.png",
|
||||
SortOrder = 1,
|
||||
CreatorId = 0,
|
||||
Trashed = false
|
||||
};
|
||||
|
||||
var contentCollection = new PropertyTypeCollection(false);
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.ImageCropper, ValueStorageType.Ntext) { Alias = Constants.Conventions.Media.File, Name = "File", Description = "", Mandatory = false, SortOrder = 1, DataTypeId = 1043 });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Width, Name = "Width", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Height, Name = "Height", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Integer) { Alias = Constants.Conventions.Media.Bytes, Name = "Bytes", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar) { Alias = Constants.Conventions.Media.Extension, Name = "File Extension", Description = "", Mandatory = false, SortOrder = 2, DataTypeId = Constants.System.DefaultLabelDataTypeId });
|
||||
|
||||
mediaType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Media", SortOrder = 1 });
|
||||
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
compile: {
|
||||
build: {
|
||||
sourcemaps: false
|
||||
},
|
||||
dev: {
|
||||
sourcemaps: true
|
||||
}
|
||||
},
|
||||
sources: {
|
||||
|
||||
// less files used by backoffice and preview
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('./config');
|
||||
var gulp = require('gulp');
|
||||
|
||||
function setDevelopmentMode(cb) {
|
||||
|
||||
config.compile.current = config.compile.dev;
|
||||
|
||||
return cb();
|
||||
};
|
||||
|
||||
module.exports = { setDevelopmentMode: setDevelopmentMode };
|
||||
@@ -19,14 +19,22 @@ module.exports = function(files, out) {
|
||||
|
||||
console.log("LESS: ", files, " -> ", config.root + config.targets.css + out)
|
||||
|
||||
var task = gulp.src(files)
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(less())
|
||||
.pipe(cleanCss())
|
||||
.pipe(postcss(processors))
|
||||
.pipe(rename(out))
|
||||
.pipe(sourcemaps.write('./maps'))
|
||||
.pipe(gulp.dest(config.root + config.targets.css));
|
||||
var task = gulp.src(files);
|
||||
|
||||
if(config.compile.current.sourcemaps === true) {
|
||||
task = task.pipe(sourcemaps.init());
|
||||
}
|
||||
|
||||
task = task.pipe(less());
|
||||
task = task.pipe(cleanCss());
|
||||
task = task.pipe(postcss(processors));
|
||||
task = task.pipe(rename(out));
|
||||
|
||||
if(config.compile.current.sourcemaps === true) {
|
||||
task = task.pipe(sourcemaps.write('./maps'));
|
||||
}
|
||||
|
||||
task = task.pipe(gulp.dest(config.root + config.targets.css));
|
||||
|
||||
return task;
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
const { src, dest, series, parallel, lastRun } = require('gulp');
|
||||
|
||||
const config = require('./gulp/config');
|
||||
const { setDevelopmentMode } = require('./gulp/modes');
|
||||
const { dependencies } = require('./gulp/tasks/dependencies');
|
||||
const { js } = require('./gulp/tasks/js');
|
||||
const { less } = require('./gulp/tasks/less');
|
||||
@@ -19,25 +21,14 @@ const { testE2e, testUnit } = require('./gulp/tasks/test');
|
||||
const { views } = require('./gulp/tasks/views');
|
||||
const { watchTask } = require('./gulp/tasks/watchTask');
|
||||
|
||||
// Load local overwrites, can be used to overwrite paths in your local setup.
|
||||
var fs = require('fs');
|
||||
var onlyScripts = require('./gulp/util/scriptFilter');
|
||||
try {
|
||||
if (fs.existsSync('./gulp/overwrites/')) {
|
||||
var overwrites = fs.readdirSync('./gulp/overwrites/').filter(onlyScripts);
|
||||
overwrites.forEach(function(overwrite) {
|
||||
require('./gulp/overwrites/' + overwrite);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
// set default current compile mode:
|
||||
config.compile.current = config.compile.build;
|
||||
|
||||
// ***********************************************************
|
||||
// These Exports are the new way of defining Tasks in Gulp 4.x
|
||||
// ***********************************************************
|
||||
exports.build = series(parallel(dependencies, js, less, views), testUnit);
|
||||
exports.dev = series(parallel(dependencies, js, less, views), watchTask);
|
||||
exports.dev = series(setDevelopmentMode, parallel(dependencies, js, less, views), watchTask);
|
||||
exports.watch = series(watchTask);
|
||||
//
|
||||
exports.runTests = series(js, testUnit);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"lazyload-js": "1.0.0",
|
||||
"moment": "2.22.2",
|
||||
"ng-file-upload": "12.2.13",
|
||||
"nouislider": "14.0.2",
|
||||
"nouislider": "14.1.1",
|
||||
"npm": "6.12.0",
|
||||
"signalr": "2.4.0",
|
||||
"spectrum-colorpicker": "1.8.0",
|
||||
|
||||
+1
-4
@@ -76,7 +76,6 @@
|
||||
// Check if it is a new user
|
||||
const inviteVal = $location.search().invite;
|
||||
|
||||
vm.baseTitle = $scope.$root.locationTitle;
|
||||
//1 = enter password, 2 = password set, 3 = invalid token
|
||||
if (inviteVal && (inviteVal === "1" || inviteVal === "2")) {
|
||||
|
||||
@@ -457,9 +456,7 @@
|
||||
break;
|
||||
}
|
||||
|
||||
if (title != null) {
|
||||
$scope.$root.locationTitle = title + " - " + vm.baseTitle;
|
||||
}
|
||||
$scope.$emit("$changeTitle", title);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -224,7 +224,8 @@ Use this directive to construct a header inside the main editor window.
|
||||
if (editorState.current) {
|
||||
//to do make work for user create/edit
|
||||
// to do make it work for user group create/ edit
|
||||
// to make it work for language edit/create
|
||||
// to do make it work for language edit/create
|
||||
// to do make it work for log viewer
|
||||
scope.isNew = editorState.current.id === 0 ||
|
||||
editorState.current.id === "0" ||
|
||||
editorState.current.id === -1 ||
|
||||
|
||||
+2
-1
@@ -80,7 +80,8 @@
|
||||
disabled: "<",
|
||||
required: "<",
|
||||
onChange: "&?",
|
||||
cssClass: "@?"
|
||||
cssClass: "@?",
|
||||
iconClass: "@?"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MemberNodeInfoDirective($timeout, $location, eventsService, userService, dateHelper, editorService) {
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
var evts = [];
|
||||
|
||||
//TODO: Infinite editing is not working yet.
|
||||
scope.allowChangeMemberType = false;
|
||||
|
||||
function onInit() {
|
||||
// make sure dates are formatted to the user's locale
|
||||
formatDatesToLocal();
|
||||
}
|
||||
|
||||
function formatDatesToLocal() {
|
||||
// get current backoffice user and format dates
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
scope.node.createDateFormatted = dateHelper.getLocalDate(scope.node.createDate, currentUser.locale, 'LLL');
|
||||
scope.node.updateDateFormatted = dateHelper.getLocalDate(scope.node.updateDate, currentUser.locale, 'LLL');
|
||||
});
|
||||
}
|
||||
|
||||
scope.openMemberType = function (memberType) {
|
||||
var editor = {
|
||||
id: memberType.id,
|
||||
submit: function (model) {
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
editorService.memberTypeEditor(editor);
|
||||
};
|
||||
|
||||
// watch for content updates - reload content when node is saved, published etc.
|
||||
scope.$watch('node.updateDate', function (newValue, oldValue) {
|
||||
if (!newValue) { return; }
|
||||
if (newValue === oldValue) { return; }
|
||||
|
||||
// Update the create and update dates
|
||||
formatDatesToLocal();
|
||||
});
|
||||
|
||||
//ensure to unregister from all events!
|
||||
scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
onInit();
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/member/umb-member-node-info.html',
|
||||
scope: {
|
||||
node: "="
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbMemberNodeInfo', MemberNodeInfoDirective);
|
||||
|
||||
})();
|
||||
+3
-1
@@ -90,7 +90,9 @@ angular.module("umbraco.directives")
|
||||
css.push("umb-tree-item--deleted");
|
||||
}
|
||||
|
||||
if (actionNode) {
|
||||
// checking the nodeType to ensure that this node and actionNode is from the same treeAlias
|
||||
if (actionNode && actionNode.nodeType === node.nodeType) {
|
||||
|
||||
if (actionNode.id === node.id && String(node.id) !== "-1") {
|
||||
css.push("active");
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,7 +10,8 @@
|
||||
templateUrl: 'views/components/umb-checkmark.html',
|
||||
scope: {
|
||||
size: "@?",
|
||||
checked: "="
|
||||
checked: "=",
|
||||
readonly: "@?"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
@@ -554,6 +554,7 @@
|
||||
property.validation.patternMessage = propertyModel.validation.patternMessage;
|
||||
property.showOnMemberProfile = propertyModel.showOnMemberProfile;
|
||||
property.memberCanEdit = propertyModel.memberCanEdit;
|
||||
property.isSensitiveData = propertyModel.isSensitiveData;
|
||||
property.isSensitiveValue = propertyModel.isSensitiveValue;
|
||||
property.allowCultureVariant = propertyModel.allowCultureVariant;
|
||||
|
||||
|
||||
@@ -359,6 +359,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
*
|
||||
* @param {Object} editor rendering options
|
||||
* @param {Boolean} editor.multiPicker Pick one or multiple items
|
||||
* @param {Int} editor.startNodeId Set the startnode of the picker (optional)
|
||||
* @param {Function} editor.submit Callback function when the submit button is clicked. Returns the editor model object
|
||||
* @param {Function} editor.close Callback function when the close button is clicked.
|
||||
*
|
||||
@@ -564,6 +565,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
* @description
|
||||
* Opens a media picker in infinite editing, the submit callback returns an array of selected media items
|
||||
* @param {Object} editor rendering options
|
||||
* @param {Int} editor.startNodeId Set the startnode of the picker (optional)
|
||||
* @param {Boolean} editor.multiPicker Pick one or multiple items
|
||||
* @param {Boolean} editor.onlyImages Only display files that have an image file-extension
|
||||
* @param {Boolean} editor.disableFolderSelect Disable folder selection
|
||||
@@ -608,8 +610,11 @@ When building a custom infinite editor view you can use the same components as a
|
||||
* @description
|
||||
* Opens the document type editor in infinite editing, the submit callback returns the alias of the saved document type.
|
||||
* @param {Object} editor rendering options
|
||||
* @param {Callback} editor.id Indicates the ID of the document type to be edited. Alternatively the ID may be set to `-1` in combination with `create` being set to `true` to open the document type editor for creating a new document type.
|
||||
* @param {Callback} editor.create Set to `true` to open the document type editor for creating a new document type.
|
||||
* @param {Number} editor.id Indicates the ID of the document type to be edited. Alternatively the ID may be set to `-1` in combination with `create` being set to `true` to open the document type editor for creating a new document type.
|
||||
* @param {Boolean} editor.create Set to `true` to open the document type editor for creating a new document type.
|
||||
* @param {Boolean} editor.noTemplate If `true` and in combination with `create` being set to `true`, the document type editor will not create a corresponding template by default. This is similar to selecting the "Document Type without a template" in the Create dialog.
|
||||
* @param {Boolean} editor.isElement If `true` and in combination with `create` being set to `true`, the "Is an Element type" option will be selected by default in the document type editor.
|
||||
* @param {Boolean} editor.allowVaryByCulture If `true` and in combination with `create`, the "Allow varying by culture" option will be selected by default in the document type editor.
|
||||
* @param {Callback} editor.submit Submits the editor.
|
||||
* @param {Callback} editor.close Closes the editor.
|
||||
* @returns {Object} editor object
|
||||
@@ -636,6 +641,23 @@ When building a custom infinite editor view you can use the same components as a
|
||||
open(editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.editorService#memberTypeEditor
|
||||
* @methodOf umbraco.services.editorService
|
||||
*
|
||||
* @description
|
||||
* Opens the member type editor in infinite editing, the submit callback returns the saved member type
|
||||
* @param {Object} editor rendering options
|
||||
* @param {Callback} editor.submit Submits the editor
|
||||
* @param {Callback} editor.close Closes the editor
|
||||
* @returns {Object} editor object
|
||||
*/
|
||||
function memberTypeEditor(editor) {
|
||||
editor.view = "views/membertypes/edit.html";
|
||||
open(editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.editorService#queryBuilder
|
||||
|
||||
@@ -16,7 +16,7 @@ function fileManager($rootScope) {
|
||||
var mgr = {
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.services.fileManager#addFiles
|
||||
* @name umbraco.services.fileManager#setFiles
|
||||
* @methodOf umbraco.services.fileManager
|
||||
* @function
|
||||
*
|
||||
|
||||
@@ -1,323 +1,325 @@
|
||||
// This service was based on OpenJS library available in BSD License
|
||||
// http://www.openjs.com/scripts/events/keyboard_shortcuts/index.php
|
||||
|
||||
function keyboardService($window, $timeout) {
|
||||
|
||||
var keyboardManagerService = {};
|
||||
|
||||
var defaultOpt = {
|
||||
'type': 'keydown',
|
||||
'propagate': false,
|
||||
'inputDisabled': false,
|
||||
'target': $window.document,
|
||||
'keyCode': false
|
||||
};
|
||||
|
||||
// Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
|
||||
var shift_nums = {
|
||||
"`": "~",
|
||||
"1": "!",
|
||||
"2": "@",
|
||||
"3": "#",
|
||||
"4": "$",
|
||||
"5": "%",
|
||||
"6": "^",
|
||||
"7": "&",
|
||||
"8": "*",
|
||||
"9": "(",
|
||||
"0": ")",
|
||||
"-": "_",
|
||||
"=": "+",
|
||||
";": ":",
|
||||
"'": "\"",
|
||||
",": "<",
|
||||
".": ">",
|
||||
"/": "?",
|
||||
"\\": "|"
|
||||
};
|
||||
|
||||
// Special Keys - and their codes
|
||||
var special_keys = {
|
||||
'esc': 27,
|
||||
'escape': 27,
|
||||
'tab': 9,
|
||||
'space': 32,
|
||||
'return': 13,
|
||||
'enter': 13,
|
||||
'backspace': 8,
|
||||
|
||||
'scrolllock': 145,
|
||||
'scroll_lock': 145,
|
||||
'scroll': 145,
|
||||
'capslock': 20,
|
||||
'caps_lock': 20,
|
||||
'caps': 20,
|
||||
'numlock': 144,
|
||||
'num_lock': 144,
|
||||
'num': 144,
|
||||
|
||||
'pause': 19,
|
||||
'break': 19,
|
||||
|
||||
'insert': 45,
|
||||
'home': 36,
|
||||
'delete': 46,
|
||||
'end': 35,
|
||||
|
||||
'pageup': 33,
|
||||
'page_up': 33,
|
||||
'pu': 33,
|
||||
|
||||
'pagedown': 34,
|
||||
'page_down': 34,
|
||||
'pd': 34,
|
||||
|
||||
'left': 37,
|
||||
'up': 38,
|
||||
'right': 39,
|
||||
'down': 40,
|
||||
|
||||
'f1': 112,
|
||||
'f2': 113,
|
||||
'f3': 114,
|
||||
'f4': 115,
|
||||
'f5': 116,
|
||||
'f6': 117,
|
||||
'f7': 118,
|
||||
'f8': 119,
|
||||
'f9': 120,
|
||||
'f10': 121,
|
||||
'f11': 122,
|
||||
'f12': 123
|
||||
};
|
||||
|
||||
var isMac = navigator.platform.toUpperCase().indexOf('MAC')>=0;
|
||||
|
||||
// The event handler for bound element events
|
||||
function eventHandler(e) {
|
||||
e = e || $window.event;
|
||||
|
||||
var code, k;
|
||||
|
||||
// Find out which key is pressed
|
||||
if (e.keyCode)
|
||||
{
|
||||
code = e.keyCode;
|
||||
}
|
||||
else if (e.which) {
|
||||
code = e.which;
|
||||
}
|
||||
|
||||
var character = String.fromCharCode(code).toLowerCase();
|
||||
|
||||
if (code === 188){character = ",";} // If the user presses , when the type is onkeydown
|
||||
if (code === 190){character = ".";} // If the user presses , when the type is onkeydown
|
||||
|
||||
var propagate = true;
|
||||
|
||||
//Now we need to determine which shortcut this event is for, we'll do this by iterating over each
|
||||
//registered shortcut to find the match. We use Find here so that the loop exits as soon
|
||||
//as we've found the one we're looking for
|
||||
_.find(_.keys(keyboardManagerService.keyboardEvent), function(key) {
|
||||
|
||||
var shortcutLabel = key;
|
||||
var shortcutVal = keyboardManagerService.keyboardEvent[key];
|
||||
|
||||
// Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
|
||||
var kp = 0;
|
||||
|
||||
// Some modifiers key
|
||||
var modifiers = {
|
||||
shift: {
|
||||
wanted: false,
|
||||
pressed: e.shiftKey ? true : false
|
||||
},
|
||||
ctrl: {
|
||||
wanted: false,
|
||||
pressed: e.ctrlKey ? true : false
|
||||
},
|
||||
alt: {
|
||||
wanted: false,
|
||||
pressed: e.altKey ? true : false
|
||||
},
|
||||
meta: { //Meta is Mac specific
|
||||
wanted: false,
|
||||
pressed: e.metaKey ? true : false
|
||||
}
|
||||
};
|
||||
|
||||
var keys = shortcutLabel.split("+");
|
||||
var opt = shortcutVal.opt;
|
||||
var callback = shortcutVal.callback;
|
||||
|
||||
// Foreach keys in label (split on +)
|
||||
var l = keys.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
|
||||
var k = keys[i];
|
||||
switch (k) {
|
||||
case 'ctrl':
|
||||
case 'control':
|
||||
kp++;
|
||||
modifiers.ctrl.wanted = true;
|
||||
break;
|
||||
case 'shift':
|
||||
case 'alt':
|
||||
case 'meta':
|
||||
kp++;
|
||||
modifiers[k].wanted = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (k.length > 1) { // If it is a special key
|
||||
if (special_keys[k] === code) {
|
||||
kp++;
|
||||
}
|
||||
}
|
||||
else if (opt['keyCode']) { // If a specific key is set into the config
|
||||
if (opt['keyCode'] === code) {
|
||||
kp++;
|
||||
}
|
||||
}
|
||||
else { // The special keys did not match
|
||||
if (character === k) {
|
||||
kp++;
|
||||
}
|
||||
else {
|
||||
if (shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase
|
||||
character = shift_nums[character];
|
||||
if (character === k) {
|
||||
kp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //for end
|
||||
|
||||
if (kp === keys.length &&
|
||||
modifiers.ctrl.pressed === modifiers.ctrl.wanted &&
|
||||
modifiers.shift.pressed === modifiers.shift.wanted &&
|
||||
modifiers.alt.pressed === modifiers.alt.wanted &&
|
||||
modifiers.meta.pressed === modifiers.meta.wanted) {
|
||||
|
||||
//found the right callback!
|
||||
|
||||
// Disable event handler when focus input and textarea
|
||||
if (opt['inputDisabled']) {
|
||||
var elt;
|
||||
if (e.target) {
|
||||
elt = e.target;
|
||||
} else if (e.srcElement) {
|
||||
elt = e.srcElement;
|
||||
}
|
||||
|
||||
if (elt.nodeType === 3) { elt = elt.parentNode; }
|
||||
if (elt.tagName === 'INPUT' || elt.tagName === 'TEXTAREA') {
|
||||
//This exits the Find loop
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$timeout(function () {
|
||||
callback(e);
|
||||
}, 1);
|
||||
|
||||
if (!opt['propagate']) { // Stop the event
|
||||
propagate = false;
|
||||
}
|
||||
|
||||
//This exits the Find loop
|
||||
return true;
|
||||
}
|
||||
|
||||
//we haven't found one so continue looking
|
||||
return false;
|
||||
|
||||
});
|
||||
|
||||
// Stop the event if required
|
||||
if (!propagate) {
|
||||
// e.cancelBubble is supported by IE - this will kill the bubbling process.
|
||||
e.cancelBubble = true;
|
||||
e.returnValue = false;
|
||||
|
||||
// e.stopPropagation works in Firefox.
|
||||
if (e.stopPropagation) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Store all keyboard combination shortcuts
|
||||
keyboardManagerService.keyboardEvent = {};
|
||||
|
||||
// Add a new keyboard combination shortcut
|
||||
keyboardManagerService.bind = function (label, callback, opt) {
|
||||
|
||||
//replace ctrl key with meta key
|
||||
if(isMac && label !== "ctrl+space"){
|
||||
label = label.replace("ctrl","meta");
|
||||
}
|
||||
|
||||
var elt;
|
||||
// Initialize opt object
|
||||
opt = angular.extend({}, defaultOpt, opt);
|
||||
label = label.toLowerCase();
|
||||
elt = opt.target;
|
||||
if(typeof opt.target === 'string'){
|
||||
elt = document.getElementById(opt.target);
|
||||
}
|
||||
|
||||
//Ensure we aren't double binding to the same element + type otherwise we'll end up multi-binding
|
||||
// and raising events for now reason. So here we'll check if the event is already registered for the element
|
||||
var boundValues = _.values(keyboardManagerService.keyboardEvent);
|
||||
var found = _.find(boundValues, function (i) {
|
||||
return i.target === elt && i.event === opt['type'];
|
||||
});
|
||||
|
||||
// Store shortcut
|
||||
keyboardManagerService.keyboardEvent[label] = {
|
||||
'callback': callback,
|
||||
'target': elt,
|
||||
'opt': opt
|
||||
};
|
||||
|
||||
if (!found) {
|
||||
//Attach the function with the event
|
||||
if (elt.addEventListener) {
|
||||
elt.addEventListener(opt['type'], eventHandler, false);
|
||||
} else if (elt.attachEvent) {
|
||||
elt.attachEvent('on' + opt['type'], eventHandler);
|
||||
} else {
|
||||
elt['on' + opt['type']] = eventHandler;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
// Remove the shortcut - just specify the shortcut and I will remove the binding
|
||||
keyboardManagerService.unbind = function (label) {
|
||||
label = label.toLowerCase();
|
||||
var binding = keyboardManagerService.keyboardEvent[label];
|
||||
delete(keyboardManagerService.keyboardEvent[label]);
|
||||
|
||||
if(!binding){return;}
|
||||
|
||||
var type = binding['event'],
|
||||
elt = binding['target'],
|
||||
callback = binding['callback'];
|
||||
|
||||
if(elt.detachEvent){
|
||||
elt.detachEvent('on' + type, callback);
|
||||
}else if(elt.removeEventListener){
|
||||
elt.removeEventListener(type, callback, false);
|
||||
}else{
|
||||
elt['on'+type] = false;
|
||||
}
|
||||
};
|
||||
//
|
||||
|
||||
return keyboardManagerService;
|
||||
}
|
||||
// This service was based on OpenJS library available in BSD License
|
||||
// http://www.openjs.com/scripts/events/keyboard_shortcuts/index.php
|
||||
|
||||
function keyboardService($window, $timeout) {
|
||||
|
||||
var keyboardManagerService = {};
|
||||
|
||||
var defaultOpt = {
|
||||
'type': 'keydown',
|
||||
'propagate': false,
|
||||
'inputDisabled': false,
|
||||
'target': $window.document,
|
||||
'keyCode': false
|
||||
};
|
||||
|
||||
// Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
|
||||
var shift_nums = {
|
||||
"`": "~",
|
||||
"1": "!",
|
||||
"2": "@",
|
||||
"3": "#",
|
||||
"4": "$",
|
||||
"5": "%",
|
||||
"6": "^",
|
||||
"7": "&",
|
||||
"8": "*",
|
||||
"9": "(",
|
||||
"0": ")",
|
||||
"-": "_",
|
||||
"=": "+",
|
||||
";": ":",
|
||||
"'": "\"",
|
||||
",": "<",
|
||||
".": ">",
|
||||
"/": "?",
|
||||
"\\": "|"
|
||||
};
|
||||
|
||||
// Special Keys - and their codes
|
||||
var special_keys = {
|
||||
'esc': 27,
|
||||
'escape': 27,
|
||||
'tab': 9,
|
||||
'space': 32,
|
||||
'return': 13,
|
||||
'enter': 13,
|
||||
'backspace': 8,
|
||||
|
||||
'scrolllock': 145,
|
||||
'scroll_lock': 145,
|
||||
'scroll': 145,
|
||||
'capslock': 20,
|
||||
'caps_lock': 20,
|
||||
'caps': 20,
|
||||
'numlock': 144,
|
||||
'num_lock': 144,
|
||||
'num': 144,
|
||||
|
||||
'pause': 19,
|
||||
'break': 19,
|
||||
|
||||
'insert': 45,
|
||||
'home': 36,
|
||||
'delete': 46,
|
||||
'end': 35,
|
||||
|
||||
'pageup': 33,
|
||||
'page_up': 33,
|
||||
'pu': 33,
|
||||
|
||||
'pagedown': 34,
|
||||
'page_down': 34,
|
||||
'pd': 34,
|
||||
|
||||
'left': 37,
|
||||
'up': 38,
|
||||
'right': 39,
|
||||
'down': 40,
|
||||
|
||||
'f1': 112,
|
||||
'f2': 113,
|
||||
'f3': 114,
|
||||
'f4': 115,
|
||||
'f5': 116,
|
||||
'f6': 117,
|
||||
'f7': 118,
|
||||
'f8': 119,
|
||||
'f9': 120,
|
||||
'f10': 121,
|
||||
'f11': 122,
|
||||
'f12': 123
|
||||
};
|
||||
|
||||
var isMac = navigator.platform.toUpperCase().indexOf('MAC')>=0;
|
||||
|
||||
// The event handler for bound element events
|
||||
function eventHandler(e) {
|
||||
e = e || $window.event;
|
||||
|
||||
var code, k;
|
||||
|
||||
// Find out which key is pressed
|
||||
if (e.keyCode)
|
||||
{
|
||||
code = e.keyCode;
|
||||
}
|
||||
else if (e.which) {
|
||||
code = e.which;
|
||||
}
|
||||
|
||||
var character = String.fromCharCode(code).toLowerCase();
|
||||
|
||||
if (code === 188){character = ",";} // If the user presses , when the type is onkeydown
|
||||
if (code === 190){character = ".";} // If the user presses , when the type is onkeydown
|
||||
|
||||
var propagate = true;
|
||||
|
||||
//Now we need to determine which shortcut this event is for, we'll do this by iterating over each
|
||||
//registered shortcut to find the match. We use Find here so that the loop exits as soon
|
||||
//as we've found the one we're looking for
|
||||
_.find(_.keys(keyboardManagerService.keyboardEvent), function(key) {
|
||||
|
||||
var shortcutLabel = key;
|
||||
var shortcutVal = keyboardManagerService.keyboardEvent[key];
|
||||
|
||||
// Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
|
||||
var kp = 0;
|
||||
|
||||
// Some modifiers key
|
||||
var modifiers = {
|
||||
shift: {
|
||||
wanted: false,
|
||||
pressed: e.shiftKey ? true : false
|
||||
},
|
||||
ctrl: {
|
||||
wanted: false,
|
||||
pressed: e.ctrlKey ? true : false
|
||||
},
|
||||
alt: {
|
||||
wanted: false,
|
||||
pressed: e.altKey ? true : false
|
||||
},
|
||||
meta: { //Meta is Mac specific
|
||||
wanted: false,
|
||||
pressed: e.metaKey ? true : false
|
||||
}
|
||||
};
|
||||
|
||||
var keys = shortcutLabel.split("+");
|
||||
var opt = shortcutVal.opt;
|
||||
var callback = shortcutVal.callback;
|
||||
|
||||
// Foreach keys in label (split on +)
|
||||
var l = keys.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
|
||||
var k = keys[i];
|
||||
switch (k) {
|
||||
case 'ctrl':
|
||||
case 'control':
|
||||
kp++;
|
||||
modifiers.ctrl.wanted = true;
|
||||
break;
|
||||
case 'shift':
|
||||
case 'alt':
|
||||
case 'meta':
|
||||
kp++;
|
||||
modifiers[k].wanted = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (k.length > 1) { // If it is a special key
|
||||
if (special_keys[k] === code) {
|
||||
kp++;
|
||||
}
|
||||
}
|
||||
else if (opt['keyCode']) { // If a specific key is set into the config
|
||||
if (opt['keyCode'] === code) {
|
||||
kp++;
|
||||
}
|
||||
}
|
||||
else { // The special keys did not match
|
||||
if (character === k) {
|
||||
kp++;
|
||||
}
|
||||
else {
|
||||
if (shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase
|
||||
character = shift_nums[character];
|
||||
if (character === k) {
|
||||
kp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //for end
|
||||
|
||||
if (kp === keys.length &&
|
||||
modifiers.ctrl.pressed === modifiers.ctrl.wanted &&
|
||||
modifiers.shift.pressed === modifiers.shift.wanted &&
|
||||
modifiers.alt.pressed === modifiers.alt.wanted &&
|
||||
modifiers.meta.pressed === modifiers.meta.wanted) {
|
||||
|
||||
//found the right callback!
|
||||
|
||||
// Disable event handler when focus input and textarea
|
||||
if (opt['inputDisabled']) {
|
||||
var elt;
|
||||
if (e.target) {
|
||||
elt = e.target;
|
||||
} else if (e.srcElement) {
|
||||
elt = e.srcElement;
|
||||
}
|
||||
|
||||
if (elt.nodeType === 3) { elt = elt.parentNode; }
|
||||
if (elt.tagName === 'INPUT' || elt.tagName === 'TEXTAREA' || elt.hasAttribute('disable-hotkeys')) {
|
||||
//This exits the Find loop
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$timeout(function () {
|
||||
callback(e);
|
||||
}, 1);
|
||||
|
||||
if (!opt['propagate']) { // Stop the event
|
||||
propagate = false;
|
||||
}
|
||||
|
||||
//This exits the Find loop
|
||||
return true;
|
||||
}
|
||||
|
||||
//we haven't found one so continue looking
|
||||
return false;
|
||||
|
||||
});
|
||||
|
||||
// Stop the event if required
|
||||
if (!propagate) {
|
||||
// e.cancelBubble is supported by IE - this will kill the bubbling process.
|
||||
e.cancelBubble = true;
|
||||
e.returnValue = false;
|
||||
|
||||
// e.stopPropagation works in Firefox.
|
||||
if (e.stopPropagation) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Store all keyboard combination shortcuts
|
||||
keyboardManagerService.keyboardEvent = {};
|
||||
|
||||
// Add a new keyboard combination shortcut
|
||||
keyboardManagerService.bind = function (label, callback, opt) {
|
||||
|
||||
//replace ctrl key with meta key
|
||||
if(isMac && label !== "ctrl+space"){
|
||||
label = label.replace("ctrl","meta");
|
||||
}
|
||||
|
||||
var elt;
|
||||
// Initialize opt object
|
||||
opt = angular.extend({}, defaultOpt, opt);
|
||||
label = label.toLowerCase();
|
||||
elt = opt.target;
|
||||
if(typeof opt.target === 'string'){
|
||||
elt = document.getElementById(opt.target);
|
||||
}
|
||||
|
||||
//Ensure we aren't double binding to the same element + type otherwise we'll end up multi-binding
|
||||
// and raising events for now reason. So here we'll check if the event is already registered for the element
|
||||
var boundValues = _.values(keyboardManagerService.keyboardEvent);
|
||||
var found = _.find(boundValues, function (i) {
|
||||
return i.target === elt && i.event === opt['type'];
|
||||
});
|
||||
|
||||
// Store shortcut
|
||||
keyboardManagerService.keyboardEvent[label] = {
|
||||
'callback': callback,
|
||||
'target': elt,
|
||||
'opt': opt
|
||||
};
|
||||
|
||||
if (!found) {
|
||||
//Attach the function with the event
|
||||
if (elt.addEventListener) {
|
||||
elt.addEventListener(opt['type'], eventHandler, false);
|
||||
} else if (elt.attachEvent) {
|
||||
elt.attachEvent('on' + opt['type'], eventHandler);
|
||||
} else {
|
||||
elt['on' + opt['type']] = eventHandler;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
// Remove the shortcut - just specify the shortcut and I will remove the binding
|
||||
keyboardManagerService.unbind = function (label) {
|
||||
label = label.toLowerCase();
|
||||
var binding = keyboardManagerService.keyboardEvent[label];
|
||||
delete(keyboardManagerService.keyboardEvent[label]);
|
||||
|
||||
if(!binding){return;}
|
||||
|
||||
var type = binding['event'],
|
||||
elt = binding['target'],
|
||||
callback = binding['callback'];
|
||||
|
||||
if(elt.detachEvent){
|
||||
elt.detachEvent('on' + type, callback);
|
||||
}else if(elt.removeEventListener){
|
||||
elt.removeEventListener(type, callback, false);
|
||||
}else{
|
||||
elt['on'+type] = false;
|
||||
}
|
||||
};
|
||||
//
|
||||
|
||||
return keyboardManagerService;
|
||||
}
|
||||
|
||||
angular.module('umbraco.services').factory('keyboardService', ['$window', '$timeout', keyboardService]);
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
</div>
|
||||
|
||||
<div class="controls" ng-if="installer.current.model.dbType == 0">
|
||||
<p>Great!, no need to configure anything then, you simply click the <strong>continue</strong> button below to continue to the next step</p>
|
||||
<p>Great! No need to configure anything, you can simply click the <strong>continue</strong> button below to continue to the next step</p>
|
||||
</div>
|
||||
|
||||
<div ng-if="installer.current.model.dbType < 0">
|
||||
<legend>What is the exact connectionstring we should use?</legend>
|
||||
<legend>What is the exact connection string we should use?</legend>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="server">Connection string</label>
|
||||
<div class="controls">
|
||||
@@ -64,7 +64,7 @@
|
||||
<label class="control-label" for="login">Login</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="login" name="login"
|
||||
placeholder="databaseuser"
|
||||
placeholder="umbraco-database-user"
|
||||
required ng-model="installer.current.model.login" />
|
||||
<small class="inline-help">Enter the database user name</small>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div>
|
||||
<h1>Your permission settings are not ready for umbraco</h1>
|
||||
<h1>Your permission settings are not ready for Umbraco</h1>
|
||||
<p>
|
||||
In order to run umbraco, you'll need to update your permission settings.
|
||||
Detailed information about the correct file & folder permissions for Umbraco can be found
|
||||
In order to run Umbraco, you'll need to update your permission settings.
|
||||
Detailed information about the correct file and folder permissions for Umbraco can be found
|
||||
<a href="https://our.umbraco.com/documentation/Installation/permissions"><strong>here</strong></a>.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<h1>Major version upgrade from {{installer.current.model.currentVersion}} to {{installer.current.model.newVersion}}</h1>
|
||||
<h2>There were {{installer.current.model.errors.length}} issues detected</h2>
|
||||
<p>
|
||||
The following compatibility issues were found. If you continue all non-compatible property editors will be converted to a Readonly/Label.
|
||||
The following compatibility issues were found. If you continue, all non-compatible property editors will be converted to a Readonly/Label.
|
||||
You will be able to change the property editor to a compatible type manually by editing the data type after installation.
|
||||
</p>
|
||||
<p>
|
||||
Otherwise if you choose not to proceed you will need to fix the errors listed below.
|
||||
Otherwise, if you choose not to proceed, you will need to fix the errors listed below.
|
||||
Refer to v{{installer.current.model.newVersion}} upgrade instructions for full details.
|
||||
</p>
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
<p>
|
||||
<button class="btn btn-success" ng-click="forward()">Continue</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
.umb-editors {
|
||||
.absolute();
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
|
||||
.umb-editor {
|
||||
box-shadow: 0px 0 30px 0 rgba(0,0,0,.3);
|
||||
@@ -16,7 +16,7 @@
|
||||
transform: none;
|
||||
will-change: transform;
|
||||
transition: transform 400ms ease-in-out;
|
||||
|
||||
|
||||
&.umb-editor--moveRight {
|
||||
transform: translateX(110%);
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
will-change: auto;
|
||||
transition: display 0s 320ms;
|
||||
}
|
||||
|
||||
|
||||
&--level0 {
|
||||
transform: none;
|
||||
}
|
||||
@@ -43,11 +43,11 @@
|
||||
.umb-editor--level@{i} {
|
||||
transform: translateX(@x);
|
||||
}
|
||||
|
||||
|
||||
.umb-editor--n@{i} {
|
||||
right:@x;
|
||||
}
|
||||
|
||||
|
||||
.level-loop(@i - 1);
|
||||
}
|
||||
|
||||
@@ -62,18 +62,18 @@
|
||||
.umb-editor {
|
||||
@size: extract(extract(@editorSizes, @iterator), 1);
|
||||
@value: extract(extract(@editorSizes, @iterator), 2);
|
||||
|
||||
|
||||
&--@{size} {
|
||||
width: @value;
|
||||
will-change: transform;
|
||||
left: auto;
|
||||
|
||||
|
||||
.umb-editor--container {
|
||||
max-width: @value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.create-editor-sizes(@iterator + 1);
|
||||
}
|
||||
|
||||
@@ -94,3 +94,14 @@
|
||||
opacity: 1;
|
||||
transition: opacity 320ms 20ms, visibility 0s;
|
||||
}
|
||||
|
||||
.umb-editor--trashed-message {
|
||||
background:@errorBackground;
|
||||
color:@errorText;
|
||||
padding:10px;
|
||||
margin-bottom:20px;
|
||||
|
||||
i {
|
||||
margin-right:5px;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
position: relative;
|
||||
padding: 20px;
|
||||
padding: 30px;
|
||||
background: @white;
|
||||
max-height: calc(100vh - 170px);
|
||||
overflow-y: auto;
|
||||
@@ -117,7 +117,7 @@
|
||||
.umb-overlay.umb-overlay-center .umb-overlay-drawer {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 0 20px 20px;
|
||||
padding: 0 30px 20px;
|
||||
}
|
||||
|
||||
/* ---------- OVERLAY TARGET ---------- */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
.umb-breadcrumbs__ancestor {
|
||||
display: flex;
|
||||
min-height: 25px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umb-breadcrumbs__action {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: 0 !important;
|
||||
padding: 0 0 0 26px !important;
|
||||
margin: 0;
|
||||
min-height: 22px;
|
||||
line-height: 22px;
|
||||
@@ -21,7 +21,6 @@
|
||||
}
|
||||
|
||||
&__text {
|
||||
margin: 0 0 0 26px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
user-select: none;
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
|
||||
.umb-media-grid__item.-selectable {
|
||||
cursor: pointer;
|
||||
|
||||
.tabbing-active &:focus {
|
||||
outline: 2px solid @inputBorderTabFocus;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-media-grid__item.-file {
|
||||
@@ -118,6 +122,7 @@
|
||||
|
||||
.umb-media-grid__item-overlay {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@@ -137,6 +142,10 @@
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.tabbing-active &:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-media-grid__info {
|
||||
|
||||
@@ -13,9 +13,15 @@
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__breadcrumb {
|
||||
.flex;
|
||||
margin-bottom: 10px;
|
||||
min-height: 25px;
|
||||
}
|
||||
|
||||
.umb-mini-list-view__back {
|
||||
font-size: 12px;
|
||||
margin-right: 5px;
|
||||
font-size: 13px;
|
||||
margin-right: 5px;
|
||||
color: @gray-4;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
border: 0 none;
|
||||
text-decoration: none !important;
|
||||
transition: border-color 100ms ease;
|
||||
background-color: @white;
|
||||
@@ -193,9 +194,8 @@
|
||||
color: @black;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
border-top: 1px solid @gray-8;
|
||||
border-bottom: 1px solid @gray-8;
|
||||
border-right: 1px solid @gray-8;
|
||||
border: 1px solid @gray-8;
|
||||
border-left: 0;
|
||||
padding: 10px 0;
|
||||
background: @white;
|
||||
}
|
||||
@@ -411,6 +411,7 @@
|
||||
}
|
||||
|
||||
.umb-gallery__thumbnail {
|
||||
background: transparent;
|
||||
flex: 0 1 100px;
|
||||
border: 1px solid @ui-action-discreet-border;
|
||||
border-radius: 3px;
|
||||
|
||||
@@ -232,6 +232,7 @@
|
||||
}
|
||||
.umb-mediapicker-multi > div {
|
||||
width:100%;
|
||||
.umb-property-editor--limit-width();
|
||||
}
|
||||
|
||||
|
||||
@@ -880,6 +881,21 @@
|
||||
.umb-datepicker p {margin-top:10px;}
|
||||
.umb-datepicker p a{color: @gray-3;}
|
||||
|
||||
//
|
||||
// Link picker
|
||||
// --------------------------------------------------
|
||||
.umb-linkpicker {
|
||||
.umb-linkpicker__url {
|
||||
width: 50%;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.umb-linkpicker__anchor {
|
||||
width: 50%;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Code mirror - even though this isn't a proprety editor right now, it could be so I'm putting the styles here
|
||||
// --------------------------------------------------
|
||||
|
||||
@@ -510,6 +510,14 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
closeTree();
|
||||
};
|
||||
|
||||
$scope.onOutsideClick = function() {
|
||||
closeTree();
|
||||
};
|
||||
|
||||
function closeTree() {
|
||||
if (!appState.getGlobalState("touchDevice")) {
|
||||
treeActive = false;
|
||||
$timeout(function () {
|
||||
@@ -518,7 +526,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$scope.toggleLanguageSelector = function () {
|
||||
$scope.page.languageSelectorIsOpen = !$scope.page.languageSelectorIsOpen;
|
||||
|
||||
@@ -7,6 +7,31 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
|
||||
.controller("previewController", function ($scope, $window, $location) {
|
||||
|
||||
$scope.currentCulture = {iso:'', title:'...', icon:'icon-loading'}
|
||||
var cultures = [];
|
||||
|
||||
$scope.tabbingActive = false;
|
||||
// There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution.
|
||||
// For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
||||
function handleFirstTab(evt) {
|
||||
if (evt.keyCode === 9) {
|
||||
$scope.tabbingActive = true;
|
||||
$scope.$digest();
|
||||
window.removeEventListener('keydown', handleFirstTab);
|
||||
window.addEventListener('mousedown', disableTabbingActive);
|
||||
}
|
||||
}
|
||||
|
||||
function disableTabbingActive(evt) {
|
||||
$scope.tabbingActive = false;
|
||||
$scope.$digest();
|
||||
window.removeEventListener('mousedown', disableTabbingActive);
|
||||
window.addEventListener("keydown", handleFirstTab);
|
||||
}
|
||||
|
||||
window.addEventListener("keydown", handleFirstTab);
|
||||
|
||||
|
||||
//gets a real query string value
|
||||
function getParameterByName(name, url) {
|
||||
if (!url) url = $window.location.href;
|
||||
@@ -75,15 +100,55 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
|
||||
$scope.valueAreLoaded = false;
|
||||
$scope.devices = [
|
||||
{ name: "desktop", css: "desktop", icon: "icon-display", title: "Desktop" },
|
||||
{ name: "laptop - 1366px", css: "laptop border", icon: "icon-laptop", title: "Laptop" },
|
||||
{ name: "iPad portrait - 768px", css: "iPad-portrait border", icon: "icon-ipad", title: "Tablet portrait" },
|
||||
{ name: "iPad landscape - 1024px", css: "iPad-landscape border", icon: "icon-ipad flip", title: "Tablet landscape" },
|
||||
{ name: "smartphone portrait - 480px", css: "smartphone-portrait border", icon: "icon-iphone", title: "Smartphone portrait" },
|
||||
{ name: "smartphone landscape - 320px", css: "smartphone-landscape border", icon: "icon-iphone flip", title: "Smartphone landscape" }
|
||||
{ name: "fullsize", css: "fullsize", icon: "icon-application-window-alt", title: "Browser" },
|
||||
{ name: "desktop", css: "desktop shadow", icon: "icon-display", title: "Desktop" },
|
||||
{ name: "laptop - 1366px", css: "laptop shadow", icon: "icon-laptop", title: "Laptop" },
|
||||
{ name: "iPad portrait - 768px", css: "iPad-portrait shadow", icon: "icon-ipad", title: "Tablet portrait" },
|
||||
{ name: "iPad landscape - 1024px", css: "iPad-landscape shadow", icon: "icon-ipad flip", title: "Tablet landscape" },
|
||||
{ name: "smartphone portrait - 480px", css: "smartphone-portrait shadow", icon: "icon-iphone", title: "Smartphone portrait" },
|
||||
{ name: "smartphone landscape - 320px", css: "smartphone-landscape shadow", icon: "icon-iphone flip", title: "Smartphone landscape" }
|
||||
];
|
||||
$scope.previewDevice = $scope.devices[0];
|
||||
|
||||
$scope.sizeOpen = false;
|
||||
$scope.cultureOpen = false;
|
||||
|
||||
$scope.toggleSizeOpen = function() {
|
||||
$scope.sizeOpen = toggleMenu($scope.sizeOpen);
|
||||
}
|
||||
$scope.toggleCultureOpen = function() {
|
||||
$scope.cultureOpen = toggleMenu($scope.cultureOpen);
|
||||
}
|
||||
|
||||
function toggleMenu(isCurrentlyOpen) {
|
||||
if (isCurrentlyOpen === false) {
|
||||
closeOthers();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function closeOthers() {
|
||||
$scope.sizeOpen = false;
|
||||
$scope.cultureOpen = false;
|
||||
}
|
||||
|
||||
$scope.windowClickHandler = function() {
|
||||
closeOthers();
|
||||
}
|
||||
function windowBlurHandler() {
|
||||
closeOthers();
|
||||
$scope.$digest();
|
||||
}
|
||||
|
||||
var win = angular.element($window);
|
||||
|
||||
win.on("blur", windowBlurHandler);
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
win.off("blur", handleBlwindowBlurHandlerur );
|
||||
});
|
||||
|
||||
|
||||
function setPageUrl(){
|
||||
$scope.pageId = $location.search().id || getParameterByName("id");
|
||||
@@ -123,6 +188,8 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
$scope.onFrameLoaded = function (iframe) {
|
||||
$scope.frameLoaded = true;
|
||||
configureSignalR(iframe);
|
||||
|
||||
$scope.currentCultureIso = $location.search().culture || null;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -136,17 +203,32 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
/*****************************************************************************/
|
||||
/* Change culture */
|
||||
/*****************************************************************************/
|
||||
$scope.changeCulture = function (culture) {
|
||||
if($location.search().culture !== culture){
|
||||
$scope.changeCulture = function (iso) {
|
||||
if($location.search().culture !== iso) {
|
||||
$scope.frameLoaded = false;
|
||||
$location.search("culture", culture);
|
||||
$scope.currentCultureIso = iso;
|
||||
$location.search("culture", iso);
|
||||
setPageUrl();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.isCurrentCulture = function(culture) {
|
||||
return $location.search().culture === culture;
|
||||
$scope.registerCulture = function(iso, title, isDefault) {
|
||||
var cultureObject = {iso: iso, title: title, isDefault: isDefault};
|
||||
cultures.push(cultureObject);
|
||||
}
|
||||
|
||||
$scope.$watch("currentCultureIso", function(oldIso, newIso) {
|
||||
// if no culture is selected, we will pick the default one:
|
||||
if ($scope.currentCultureIso === null) {
|
||||
$scope.currentCulture = cultures.find(function(culture) {
|
||||
return culture.isDefault === true;
|
||||
})
|
||||
return;
|
||||
}
|
||||
$scope.currentCulture = cultures.find(function(culture) {
|
||||
return culture.iso === $scope.currentCultureIso;
|
||||
})
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
+96
-88
@@ -1,98 +1,99 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function CopyController($scope, localizationService, eventsService, entityHelper) {
|
||||
function CopyController($scope, localizationService, eventsService, entityHelper) {
|
||||
|
||||
var vm = this;
|
||||
var vm = this;
|
||||
|
||||
vm.labels = {};
|
||||
vm.hideSearch = hideSearch;
|
||||
vm.selectResult = selectResult;
|
||||
vm.onSearchResults = onSearchResults;
|
||||
vm.submit = submit;
|
||||
vm.close = close;
|
||||
vm.labels = {};
|
||||
vm.hideSearch = hideSearch;
|
||||
vm.selectResult = selectResult;
|
||||
vm.onSearchResults = onSearchResults;
|
||||
vm.onToggle = toggleHandler;
|
||||
vm.submit = submit;
|
||||
vm.close = close;
|
||||
|
||||
var dialogOptions = $scope.model;
|
||||
var node = dialogOptions.currentNode;
|
||||
var dialogOptions = $scope.model;
|
||||
var node = dialogOptions.currentNode;
|
||||
|
||||
$scope.model.relateToOriginal = true;
|
||||
$scope.dialogTreeApi = {};
|
||||
$scope.model.relateToOriginal = true;
|
||||
$scope.dialogTreeApi = {};
|
||||
|
||||
vm.searchInfo = {
|
||||
searchFromId: null,
|
||||
searchFromName: null,
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
};
|
||||
vm.searchInfo = {
|
||||
searchFromId: null,
|
||||
searchFromName: null,
|
||||
showSearch: false,
|
||||
results: [],
|
||||
selectedSearchResults: []
|
||||
};
|
||||
|
||||
// get entity type based on the section
|
||||
$scope.entityType = entityHelper.getEntityTypeFromSection(dialogOptions.section);
|
||||
// get entity type based on the section
|
||||
$scope.entityType = entityHelper.getEntityTypeFromSection(dialogOptions.section);
|
||||
|
||||
function onInit() {
|
||||
function onInit() {
|
||||
|
||||
var labelKeys = [
|
||||
"general_copy",
|
||||
"defaultdialogs_relateToOriginalLabel"
|
||||
];
|
||||
var labelKeys = [
|
||||
"general_copy",
|
||||
"defaultdialogs_relateToOriginalLabel"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (data) {
|
||||
localizationService.localizeMany(labelKeys).then(function (data) {
|
||||
|
||||
vm.labels.title = data[0];
|
||||
vm.labels.relateToOriginal = data[1];
|
||||
vm.labels.title = data[0];
|
||||
vm.labels.relateToOriginal = data[1];
|
||||
|
||||
setTitle(vm.labels.title);
|
||||
});
|
||||
}
|
||||
setTitle(vm.labels.title);
|
||||
});
|
||||
}
|
||||
|
||||
function setTitle(value) {
|
||||
if (!$scope.model.title) {
|
||||
$scope.model.title = value;
|
||||
}
|
||||
}
|
||||
function setTitle(value) {
|
||||
if (!$scope.model.title) {
|
||||
$scope.model.title = value;
|
||||
}
|
||||
}
|
||||
|
||||
function nodeSelectHandler(args) {
|
||||
if (args && args.event) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
}
|
||||
function nodeSelectHandler(args) {
|
||||
if (args && args.event) {
|
||||
args.event.preventDefault();
|
||||
args.event.stopPropagation();
|
||||
}
|
||||
|
||||
//eventsService.emit("editors.content.copyController.select", args);
|
||||
//eventsService.emit("editors.content.copyController.select", args);
|
||||
|
||||
if ($scope.model.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.model.target.selected = false;
|
||||
}
|
||||
if ($scope.model.target) {
|
||||
//un-select if there's a current one selected
|
||||
$scope.model.target.selected = false;
|
||||
}
|
||||
|
||||
$scope.model.target = args.node;
|
||||
$scope.model.target.selected = true;
|
||||
}
|
||||
$scope.model.target = args.node;
|
||||
$scope.model.target.selected = true;
|
||||
}
|
||||
|
||||
function nodeExpandedHandler(args) {
|
||||
// open mini list view for list views
|
||||
if (args.node.metaData.isContainer) {
|
||||
openMiniListView(args.node);
|
||||
}
|
||||
}
|
||||
function nodeExpandedHandler(args) {
|
||||
// open mini list view for list views
|
||||
if (args.node.metaData.isContainer) {
|
||||
openMiniListView(args.node);
|
||||
}
|
||||
}
|
||||
|
||||
function hideSearch() {
|
||||
vm.searchInfo.showSearch = false;
|
||||
vm.searchInfo.searchFromId = null;
|
||||
vm.searchInfo.searchFromName = null;
|
||||
vm.searchInfo.results = [];
|
||||
}
|
||||
function hideSearch() {
|
||||
vm.searchInfo.showSearch = false;
|
||||
vm.searchInfo.searchFromId = null;
|
||||
vm.searchInfo.searchFromName = null;
|
||||
vm.searchInfo.results = [];
|
||||
}
|
||||
|
||||
// method to select a search result
|
||||
function selectResult(evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler({ event: evt, node: result });
|
||||
}
|
||||
// method to select a search result
|
||||
function selectResult(evt, result) {
|
||||
result.selected = result.selected === true ? false : true;
|
||||
nodeSelectHandler({ event: evt, node: result });
|
||||
}
|
||||
|
||||
//callback when there are search results
|
||||
function onSearchResults(results) {
|
||||
vm.searchInfo.results = results;
|
||||
vm.searchInfo.showSearch = true;
|
||||
}
|
||||
//callback when there are search results
|
||||
function onSearchResults(results) {
|
||||
vm.searchInfo.results = results;
|
||||
vm.searchInfo.showSearch = true;
|
||||
}
|
||||
|
||||
$scope.onTreeInit = function () {
|
||||
$scope.dialogTreeApi.callbacks.treeNodeSelect(nodeSelectHandler);
|
||||
@@ -100,19 +101,19 @@
|
||||
}
|
||||
|
||||
|
||||
// Mini list view
|
||||
$scope.selectListViewNode = function (node) {
|
||||
node.selected = node.selected === true ? false : true;
|
||||
nodeSelectHandler({ node: node });
|
||||
};
|
||||
// Mini list view
|
||||
$scope.selectListViewNode = function (node) {
|
||||
node.selected = node.selected === true ? false : true;
|
||||
nodeSelectHandler({ node: node });
|
||||
};
|
||||
|
||||
$scope.closeMiniListView = function () {
|
||||
$scope.miniListView = undefined;
|
||||
};
|
||||
$scope.closeMiniListView = function () {
|
||||
$scope.miniListView = undefined;
|
||||
};
|
||||
|
||||
function openMiniListView(node) {
|
||||
$scope.miniListView = node;
|
||||
}
|
||||
function openMiniListView(node) {
|
||||
$scope.miniListView = node;
|
||||
}
|
||||
|
||||
function submit() {
|
||||
if ($scope.model && $scope.model.submit) {
|
||||
@@ -126,9 +127,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
onInit();
|
||||
}
|
||||
function toggleHandler(type) {
|
||||
// If the relateToOriginal toggle is clicked
|
||||
if (type === "relate") {
|
||||
$scope.model.relateToOriginal = !$scope.model.relateToOriginal;
|
||||
}
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.CopyController", CopyController);
|
||||
onInit();
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.CopyController", CopyController);
|
||||
|
||||
})();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
<form novalidate name="dataTypeSettingsForm" val-form-manager>
|
||||
<form novalidate name="copyNodesForm" class="form-horizontal" val-form-manager>
|
||||
|
||||
<umb-editor-header
|
||||
name="model.title"
|
||||
@@ -59,11 +59,11 @@
|
||||
</umb-mini-list-view>
|
||||
</div>
|
||||
|
||||
<div class="umb-control-group -no-border">
|
||||
<div class="flex">
|
||||
<umb-checkbox input-id="relateToOriginal" model="model.relateToOriginal" text="{{vm.labels.relateToOriginal}}" />
|
||||
</div>
|
||||
</div>
|
||||
<umb-pane>
|
||||
<umb-control-group localize="label" label="@defaultdialogs_relateToOriginalLabel">
|
||||
<umb-toggle label-position="left" checked="model.relateToOriginal" on-click="vm.onToggle('relate')"></umb-toggle>
|
||||
</umb-control-group>
|
||||
</umb-pane>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
<div ng-controller="Umbraco.Editors.LinkPickerController as vm">
|
||||
<div ng-controller="Umbraco.Editors.LinkPickerController as vm" class="umb-linkpicker">
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<div class="flex">
|
||||
|
||||
<umb-control-group label="@defaultdialogs_urlLinkPicker">
|
||||
<umb-control-group label="@defaultdialogs_urlLinkPicker" class="umb-linkpicker__url">
|
||||
<input type="text"
|
||||
style="margin-right: 10px;"
|
||||
localize="placeholder"
|
||||
@@ -27,7 +27,7 @@
|
||||
ng-disabled="model.target.id || model.target.udi" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@defaultdialogs_anchorLinkPicker">
|
||||
<umb-control-group label="@defaultdialogs_anchorLinkPicker" class="umb-linkpicker__anchor">
|
||||
<input type="text"
|
||||
list="anchors"
|
||||
localize="placeholder"
|
||||
|
||||
+15
-8
@@ -1,7 +1,7 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.MediaPickerController",
|
||||
function ($scope, mediaResource, entityResource, userService, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService) {
|
||||
function ($scope, $timeout, mediaResource, entityResource, userService, mediaHelper, mediaTypeHelper, eventsService, treeService, localStorageService, localizationService, editorService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -292,13 +292,20 @@ angular.module("umbraco")
|
||||
|
||||
function onUploadComplete(files) {
|
||||
gotoFolder($scope.currentFolder).then(function () {
|
||||
if (files.length === 1 && $scope.model.selection.length === 0) {
|
||||
var image = $scope.images[$scope.images.length - 1];
|
||||
$scope.target = image;
|
||||
$scope.target.url = mediaHelper.resolveFile(image);
|
||||
selectMedia(image);
|
||||
}
|
||||
})
|
||||
$timeout(function () {
|
||||
if ($scope.multiPicker) {
|
||||
var images = _.rest($scope.images, $scope.images.length - files.length);
|
||||
_.each(images, function(image) {
|
||||
selectMedia(image);
|
||||
});
|
||||
} else {
|
||||
var image = $scope.images[$scope.images.length - 1];
|
||||
$scope.target = image;
|
||||
$scope.target.url = mediaHelper.resolveFile(image);
|
||||
selectMedia(image);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onFilesQueue() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div id="leftcolumn" ng-controller="Umbraco.NavigationController" ng-mouseleave="leaveTree($event)" ng-mouseenter="enterTree($event)">
|
||||
<div id="leftcolumn" ng-controller="Umbraco.NavigationController" ng-mouseleave="leaveTree($event)" ng-mouseenter="enterTree($event)" on-outside-click="onOutsideClick()">
|
||||
|
||||
<!-- navigation container -->
|
||||
<div id="navigation" ng-show="showNavigation" class="fill umb-modalcolumn" ng-animate="'slide'" nav-resize
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
type="text"
|
||||
ng-model="vm.searchQuery"
|
||||
ng-model-options="{ debounce: 200 }"
|
||||
ng-change="vm.search(vm.searchQuery)"
|
||||
placeholder="Search..."
|
||||
ng-change="vm.search(vm.searchQuery)"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
focus-when="{{vm.searchHasFocus}}" />
|
||||
<button ng-show="vm.searchQuery.length > 0" tabindex="-1" class="umb-search-input-clear umb-animated" ng-click="vm.clearSearch()">Clear</button>
|
||||
<button ng-show="vm.searchQuery.length > 0" tabindex="-1" class="umb-search-input-clear umb-animated" ng-click="vm.clearSearch()">
|
||||
<localize key="general_clear">Clear</localize>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="umb-search-results">
|
||||
|
||||
@@ -27,6 +27,12 @@
|
||||
</ng-form>
|
||||
|
||||
<umb-editor-container ng-if="vm.editor.content.apps.length > 0">
|
||||
|
||||
<!-- Deleted Context Message Bar (Displayed when viewing node in recycle bin) -->
|
||||
<div ng-show="vm.content.trashed" class="umb-editor--trashed-message">
|
||||
<i class="icon icon-trash"></i> <localize key="content_nodeIsInTrash">This item is in the Recycle Bin</localize>
|
||||
</div>
|
||||
|
||||
<div class="umb-editor-sub-views">
|
||||
<div ng-repeat="app in vm.editor.content.apps track by app.alias">
|
||||
<umb-editor-sub-view model="app" content="vm.content" />
|
||||
|
||||
@@ -16,5 +16,7 @@
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="umb-form-check__text">{{vm.text}}</span>
|
||||
<i ng-if="vm.iconClass.length" class="{{vm.iconClass}}" aria-hidden="true"></i>
|
||||
|
||||
<span ng-if="vm.text.length" class="umb-form-check__text">{{vm.text}}</span>
|
||||
</label>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<div class="umb-package-details">
|
||||
<div class="umb-package-details__main-content">
|
||||
|
||||
<umb-box data-element="node-info-membership" ng-repeat="group in node.tabs| filter: {properties:{view:'readonlyvalue'}} track by group.label">
|
||||
|
||||
<div class="umb-group-panel__header">
|
||||
<div>{{ group.label }}</div>
|
||||
</div>
|
||||
<div class="umb-group-panel__content">
|
||||
<umb-property data-element="property-{{group.alias}}" ng-repeat="property in group.properties | filter: {view:'readonlyvalue'} track by property.alias" property="property">
|
||||
<umb-property-editor model="property"></umb-property-editor>
|
||||
</umb-property>
|
||||
</div>
|
||||
</umb-box>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-package-details__sidebar">
|
||||
<umb-box data-element="node-info-general">
|
||||
<umb-box-header title-key="general_general"></umb-box-header>
|
||||
<umb-box-content class="block-form">
|
||||
|
||||
<umb-control-group ng-if="node.id !== 0" data-element="node-info-create-date" label="@content_createDate">
|
||||
{{node.createDateFormatted}} by {{ node.owner.name }}
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group ng-if="node.id !== 0" data-element="node-info-update-date" label="@content_updateDate">
|
||||
{{node.updateDateFormatted}}
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group data-element="node-info-document-type" label="@content_membertype">
|
||||
<umb-node-preview style="max-width: 100%; margin-bottom: 0px;"
|
||||
icon="node.icon"
|
||||
name="node.contentTypeName"
|
||||
alias="node.contentTypeAlias"
|
||||
allow-open="allowChangeMemberType"
|
||||
on-open="openMemberType(node)">
|
||||
</umb-node-preview>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group ng-if="node.id !== 0" data-element="node-info-id" label="Id">
|
||||
<div>{{ node.id }}</div>
|
||||
<small>{{ node.key }}</small>
|
||||
</umb-control-group>
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1 +1 @@
|
||||
<i class="icon-check umb-checkmark umb-checkmark--{{size}}" ng-class="{'umb-checkmark--checked': checked}"></i>
|
||||
<i class="icon-check umb-checkmark umb-checkmark--{{size}}" ng-class="{'umb-checkmark--checked': checked, 'cursor-auto': readonly}"></i>
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
<!--<i ng-show="item.selected" class="icon-check umb-media-grid__checkmark"></i>-->
|
||||
<a ng-if="allowOnClickEdit === 'true'" ng-click="clickEdit(item, $event)" ng-href="" class="icon-edit umb-media-grid__edit"></a>
|
||||
|
||||
<div data-element="media-grid-item-edit" class="umb-media-grid__item-overlay" ng-class="{'-locked': item.selected || !item.file || !item.thumbnail}" ng-click="clickItemName(item, $event, $index)">
|
||||
<button data-element="media-grid-item-edit" class="umb-media-grid__item-overlay btn-reset" ng-class="{'-locked': item.selected || !item.file || !item.thumbnail}" ng-click="clickItemName(item, $event, $index)" type="button">
|
||||
<i ng-if="onDetailsHover" class="icon-info umb-media-grid__info" ng-mouseover="hoverItemDetails(item, $event, true)" ng-mouseleave="hoverItemDetails(item, $event, false)"></i>
|
||||
<div class="umb-media-grid__item-name">{{item.name}}</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<!-- Check backgrund -->
|
||||
<div class="umb-media-grid__image-background" ng-if="item.thumbnail || item.extension === 'svg'"></div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<h4 class="umb-mini-list-view__title-text">{{ miniListView.node.name }}</h4>
|
||||
</div>
|
||||
|
||||
<div class="flex" style="margin-bottom: 10px;">
|
||||
<div class="umb-mini-list-view__breadcrumb">
|
||||
|
||||
<a ng-if="showBackButton()" href="" class="umb-mini-list-view__back" ng-click="exitMiniListView()">
|
||||
<i class="icon-arrow-left umb-mini-list-view__back-icon"></i>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
<!-- we need to show the old pass field when the provider cannot retrieve the password -->
|
||||
<umb-control-group alias="oldPassword" label="@user_oldPassword" ng-if="vm.showOldPass()" required="true">
|
||||
<input type="password" name="oldPassword" ng-model="vm.passwordValues.oldPassword"
|
||||
<input type="password" name="oldPassword" id="oldPassword" ng-model="vm.passwordValues.oldPassword"
|
||||
class="input-block-level umb-textstring textstring"
|
||||
required
|
||||
val-server-field="oldPassword"
|
||||
@@ -36,7 +36,7 @@
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="password" label="@user_newPassword" ng-if="!vm.showReset" required="true">
|
||||
<input type="password" name="password" ng-model="vm.passwordValues.newPassword"
|
||||
<input type="password" name="password" id="password" ng-model="vm.passwordValues.newPassword"
|
||||
class="input-block-level umb-textstring textstring"
|
||||
required
|
||||
val-server-field="password"
|
||||
@@ -50,7 +50,7 @@
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="confirmPassword" label="@user_confirmNewPassword" ng-if="!vm.showReset" required="true">
|
||||
<input type="password" name="confirmPassword" ng-model="vm.passwordValues.confirm"
|
||||
<input type="password" name="confirmPassword" id="confirmPassword" ng-model="vm.passwordValues.confirm"
|
||||
class="input-block-level umb-textstring textstring"
|
||||
val-compare="password"
|
||||
no-dirty-check />
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<tbody>
|
||||
<tr ng-repeat="domain in vm.domains">
|
||||
<td>
|
||||
<input style="width: 100%; margin-bottom: 0;" type="text" ng-model="domain.name" name="domain_name_{{$index}}" required />
|
||||
<input style="width: 100%; margin-bottom: 0;" type="text" ng-model="domain.name" name="domain_name_{{$index}}" required umb-auto-focus />
|
||||
<span ng-if="vm.domainForm.$submitted" ng-messages="vm.domainForm['domain_name_' + $index].$error">
|
||||
<span class="help-inline" ng-message="required"><localize key="validation_invalidEmpty"></localize></span>
|
||||
</span>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<h3>Start here</h3>
|
||||
|
||||
<h4>Get started with Members right now</h4>
|
||||
<p>Use the tool below to search for an existing member.</p>
|
||||
|
||||
<h4>More about members</h4>
|
||||
|
||||
<ul>
|
||||
<li>Learn about how to protect pages of your site from <a class="btn-link -underline" href="https://our.umbraco.com/wiki/reference/umbraco-client/context-menus/public-access" target="_blank">this Wiki entry</a></li>
|
||||
</ul>
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
<div class="mb4">
|
||||
<div class="flex items-center">
|
||||
<umb-toggle checked="vm.alwaysOn" id="profilerAlwaysOn" on-click="vm.toggle()"></umb-toggle>
|
||||
<umb-toggle checked="vm.alwaysOn" input-id="profilerAlwaysOn" on-click="vm.toggle()"></umb-toggle>
|
||||
<label for="profilerAlwaysOn" class="mb0 ml2">
|
||||
<localize key="profiling_activateByDefault">Activate the profiler by default</localize>
|
||||
</label>
|
||||
|
||||
@@ -10,7 +10,11 @@ function DataTypeEditController($scope, $routeParams, appState, navigationServic
|
||||
|
||||
var evts = [];
|
||||
var vm = this;
|
||||
|
||||
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "visuallyHiddenTexts_newDataType";
|
||||
vm.header.setPageTitle = true;
|
||||
|
||||
//setup scope vars
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
hide-icon="true"
|
||||
hide-description="true"
|
||||
hide-alias="true"
|
||||
navigation="vm.page.navigation">
|
||||
navigation="vm.page.navigation"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container class="form-horizontal">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div ng-switch-when="container">
|
||||
<umb-confirm
|
||||
on-confirm="performContainerDelete"
|
||||
on-cancel="cancel">
|
||||
on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
</div>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<umb-checkbox model="confirmed" text="{{labels.deleteConfirm}}">
|
||||
</umb-checkbox>
|
||||
|
||||
<umb-confirm ng-if="confirmed" on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm ng-if="confirmed" on-confirm="performDelete" on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
</div>
|
||||
</ng-switch>
|
||||
|
||||
@@ -64,7 +64,8 @@
|
||||
if (infiniteMode) {
|
||||
documentTypeId = $scope.model.id;
|
||||
create = $scope.model.create;
|
||||
noTemplate = $scope.model.notemplate;
|
||||
if (create && !documentTypeId) documentTypeId = -1;
|
||||
noTemplate = $scope.model.notemplate || $scope.model.noTemplate;
|
||||
isElement = $scope.model.isElement;
|
||||
allowVaryByCulture = $scope.model.allowVaryByCulture;
|
||||
vm.submitButtonKey = "buttons_saveAndClose";
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<form name="importDoctype">
|
||||
|
||||
<!-- Select files -->
|
||||
<button class="btn"
|
||||
<button class="btn btn-action"
|
||||
name="file"
|
||||
ngf-select
|
||||
ng-model="filesHolder"
|
||||
|
||||
@@ -159,11 +159,17 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-info dropdown-toggle" data-toggle="dropdown" ng-href="" ng-click="log.searchDropdownOpen = !log.searchDropdownOpen">
|
||||
<i class="icon-search"></i> <localize key="general_search">Search</localize>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<div class="btn-group" deep-blur="log.searchDropdownOpen = !log.searchDropdownOpen">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-info dropdown-toggle"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="{{log.searchDropdownOpen === undefined ? false : log.searchDropdownOpen}}"
|
||||
ng-click="log.searchDropdownOpen = !log.searchDropdownOpen">
|
||||
<i class="icon-search" aria-hidden="true"></i>
|
||||
<localize key="general_search">Search</localize>
|
||||
<span class="caret" aria-hidden="true"></span>
|
||||
</button>
|
||||
|
||||
<umb-dropdown ng-if="log.searchDropdownOpen" on-close="log.searchDropdownOpen = false">
|
||||
<umb-dropdown-item>
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{vm.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="vm.performDelete" on-cancel="vm.cancel"></umb-confirm>
|
||||
<umb-confirm on-confirm="vm.performDelete" on-cancel="vm.cancel" confirm-button-style="danger"></umb-confirm>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
alias="vm.macro.alias"
|
||||
hide-description="true"
|
||||
hide-icon="true"
|
||||
navigation="vm.page.navigation">
|
||||
navigation="vm.page.navigation"editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container class="form-horizontal">
|
||||
|
||||
@@ -11,7 +11,10 @@ function MacrosEditController($scope, $q, $routeParams, macroResource, editorSta
|
||||
var vm = this;
|
||||
|
||||
vm.promises = {};
|
||||
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "general_macro";
|
||||
vm.header.setPageTitle = true;
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.saveButtonState = "init";
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
<div class="umb-property-editor form-horizontal">
|
||||
<div ui-sortable="sortableOptions" ng-model="model.macro.parameters">
|
||||
<div class="control-group umb-prevalues-multivalues__listitem" ng-repeat="parameter in model.macro.parameters track by $id(parameter)">
|
||||
<i class="icon icon-navigation handle"></i>
|
||||
<i class="icon icon-navigation handle" aria-hidden="true"></i>
|
||||
<div class="umb-prevalues-multivalues__left">
|
||||
<span>{{parameter.label}}</span> <span class="muted">({{parameter.key}})</span>: <small>{{parameter.editor}}</small>
|
||||
</div>
|
||||
<div class="umb-prevalues-multivalues__right">
|
||||
<a class="umb-node-preview__action" ng-click="vm.edit(parameter, $event)"><localize key="general_edit">Edit</localize></a>
|
||||
<a class="umb-node-preview__action umb-node-preview__action--red" ng-click="vm.remove(parameter, $event)"><localize key="general_remove">Remove</localize></a>
|
||||
<button type="button" class="umb-node-preview__action" ng-click="vm.edit(parameter, $event)"><localize key="general_edit">Edit</localize></button>
|
||||
<button type="button" class="umb-node-preview__action umb-node-preview__action--red" ng-click="vm.remove(parameter, $event)"><localize key="general_remove">Remove</localize></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<umb-checkbox model="confirmed" text="{{labels.deleteConfirm}}">
|
||||
</umb-checkbox>
|
||||
|
||||
<umb-confirm ng-if="confirmed" on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm ng-if="confirmed" on-confirm="performDelete" on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
</div>
|
||||
</ng-switch>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function MemberAppContentController($scope) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Member.Apps.ContentController", MemberAppContentController);
|
||||
})();
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="form-horizontal" ng-controller="Umbraco.Editors.Member.Apps.ContentController as vm">
|
||||
|
||||
<div class="umb-group-panel" ng-repeat="group in content.tabs track by group.label">
|
||||
|
||||
<div class="umb-group-panel__header">
|
||||
<div>{{ group.label }}</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-group-panel__content">
|
||||
<umb-property data-element="property-{{group.alias}}" ng-repeat="property in group.properties | filter: {view:'!readonlyvalue'} | filter: {alias:'!_umb_id'} | filter: {alias:'!_umb_doctype'} track by property.alias" property="property">
|
||||
<umb-property-editor model="property"></umb-property-editor>
|
||||
</umb-property>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
<umb-member-node-info
|
||||
ng-if="content"
|
||||
node="content">
|
||||
</umb-member-node-info>
|
||||
@@ -14,29 +14,22 @@
|
||||
hide-icon="true"
|
||||
hide-description="true"
|
||||
hide-alias="true"
|
||||
navigation="content.apps"
|
||||
on-select-navigation-item="appChanged(item)"
|
||||
show-back-button="showBack()"
|
||||
on-back="onBack()"
|
||||
editorfor="header.editorfor"
|
||||
setpagetitle="header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container class="form-horizontal">
|
||||
|
||||
<div class="umb-group-panel" ng-repeat="group in content.tabs track by group.label">
|
||||
|
||||
<div class="umb-group-panel__header">
|
||||
<div>{{ group.label }}</div>
|
||||
|
||||
<umb-editor-container>
|
||||
<div class="umb-editor-sub-views" ng-if="!page.loading">
|
||||
<div id="sub-view-{{$index}}" ng-repeat="app in content.apps track by app.alias">
|
||||
<umb-editor-sub-view model="app" content="content" />
|
||||
</div>
|
||||
|
||||
<div class="umb-group-panel__content">
|
||||
<umb-property data-element="property-{{group.alias}}" ng-repeat="property in group.properties track by property.alias" property="property">
|
||||
<umb-property-editor model="property"></umb-property-editor>
|
||||
</umb-property>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</umb-editor-container>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
|
||||
@@ -45,9 +45,7 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
|
||||
|
||||
$scope.content = data;
|
||||
|
||||
setHeaderNameState($scope.content);
|
||||
|
||||
editorState.set($scope.content);
|
||||
init();
|
||||
|
||||
$scope.page.loading = false;
|
||||
|
||||
@@ -59,9 +57,7 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
|
||||
.then(function (data) {
|
||||
$scope.content = data;
|
||||
|
||||
setHeaderNameState($scope.content);
|
||||
|
||||
editorState.set($scope.content);
|
||||
init();
|
||||
|
||||
$scope.page.loading = false;
|
||||
|
||||
@@ -90,9 +86,7 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
|
||||
|
||||
$scope.content = data;
|
||||
|
||||
setHeaderNameState($scope.content);
|
||||
|
||||
editorState.set($scope.content);
|
||||
init();
|
||||
|
||||
if (!infiniteMode) {
|
||||
var path = buildTreePath(data);
|
||||
@@ -121,11 +115,48 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
|
||||
|
||||
}
|
||||
|
||||
function setHeaderNameState(content) {
|
||||
function init() {
|
||||
|
||||
var content = $scope.content;
|
||||
|
||||
// we need to check wether an app is present in the current data, if not we will present the default app.
|
||||
var isAppPresent = false;
|
||||
|
||||
// on first init, we dont have any apps. but if we are re-initializing, we do, but ...
|
||||
if ($scope.app) {
|
||||
|
||||
// lets check if it still exists as part of our apps array. (if not we have made a change to our docType, even just a re-save of the docType it will turn into new Apps.)
|
||||
_.forEach(content.apps, function (app) {
|
||||
if (app === $scope.app) {
|
||||
isAppPresent = true;
|
||||
}
|
||||
});
|
||||
|
||||
// if we did reload our DocType, but still have the same app we will try to find it by the alias.
|
||||
if (isAppPresent === false) {
|
||||
_.forEach(content.apps, function (app) {
|
||||
if (app.alias === $scope.app.alias) {
|
||||
isAppPresent = true;
|
||||
app.active = true;
|
||||
$scope.appChanged(app);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if we still dont have a app, lets show the first one:
|
||||
if (isAppPresent === false) {
|
||||
content.apps[0].active = true;
|
||||
$scope.appChanged(content.apps[0]);
|
||||
}
|
||||
|
||||
if (content.membershipScenario === 0) {
|
||||
$scope.page.nameLocked = true;
|
||||
}
|
||||
|
||||
editorState.set($scope.content);
|
||||
|
||||
if(content.membershipScenario === 0) {
|
||||
$scope.page.nameLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** Just shows a simple notification that there are client side validation issues to be fixed */
|
||||
@@ -194,6 +225,15 @@ function MemberEditController($scope, $routeParams, $location, appState, memberR
|
||||
|
||||
};
|
||||
|
||||
$scope.appChanged = function (app) {
|
||||
$scope.app = app;
|
||||
|
||||
// setup infinite mode
|
||||
if (infiniteMode) {
|
||||
$scope.page.submitButtonLabelKey = "buttons_saveAndClose";
|
||||
}
|
||||
}
|
||||
|
||||
$scope.showBack = function () {
|
||||
return !!listName;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<umb-checkbox model="confirmed" text="{{labels.deleteConfirm}}">
|
||||
</umb-checkbox>
|
||||
|
||||
<umb-confirm ng-if="confirmed" on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm ng-if="confirmed" on-confirm="performDelete" on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
|
||||
|
||||
|
||||
@@ -7,19 +7,31 @@
|
||||
|
||||
<div class="umb-packages-section">
|
||||
<div class="umb-packages-search">
|
||||
<input class="-full-width-input" type="text" name="query" localize="placeholder" placeholder="@packager_packageSearch" umb-auto-focus ng-model="vm.searchQuery" ng-change="vm.search()" no-dirty-check>
|
||||
<label for="package-query" class="sr-only">
|
||||
<localize key="packager_packageSearch">Search for packages</localize>
|
||||
</label>
|
||||
<input
|
||||
class="-full-width-input"
|
||||
type="text"
|
||||
name="query"
|
||||
id="package-query"
|
||||
localize="placeholder"
|
||||
placeholder="@packager_packageSearch"
|
||||
umb-auto-focus ng-model="vm.searchQuery"
|
||||
ng-change="vm.search()"
|
||||
no-dirty-check>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-packages-section" ng-if="vm.searchQuery == ''">
|
||||
<div class="umb-packages-categories">
|
||||
<a href=""
|
||||
<button type="button"
|
||||
class="umb-packages-category"
|
||||
ng-click="vm.selectCategory(category, vm.categories)"
|
||||
ng-repeat="category in vm.categories"
|
||||
ng-class="{'-active': category.active, '-first': $first, '-last': $last}">
|
||||
<div>{{category.name}}</div>
|
||||
</a>
|
||||
{{category.name}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +42,7 @@
|
||||
<div class="umb-packages">
|
||||
|
||||
<div class="umb-package" ng-repeat="package in vm.popular">
|
||||
<a class="umb-package-link" href="" ng-click="vm.showPackageDetails(package)">
|
||||
<button type="button" class="umb-package-link" ng-click="vm.showPackageDetails(package)">
|
||||
|
||||
<div class="umb-package-icon">
|
||||
<img ng-src="{{package.icon}}" alt="" />
|
||||
@@ -42,15 +54,17 @@
|
||||
|
||||
<div class="umb-package-numbers">
|
||||
<small class="umb-package-downloads">
|
||||
<i class="icon-download-alt"></i> <strong>{{package.downloads}}</strong>
|
||||
<i class="icon-download-alt" aria-hidden="true"></i>
|
||||
<strong>{{package.downloads}}</strong>
|
||||
</small>
|
||||
<small class="umb-package-likes">
|
||||
<i class="icon-hearts"></i> <strong>{{package.likes}}</strong>
|
||||
<i class="icon-hearts" aria-hidden="true"></i>
|
||||
<strong>{{package.likes}}</strong>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</button>
|
||||
</div> <!-- end package -->
|
||||
|
||||
</div> <!-- end packages -->
|
||||
@@ -64,7 +78,7 @@
|
||||
<div class="umb-packages">
|
||||
|
||||
<div class="umb-package" ng-repeat="package in vm.packages">
|
||||
<a class="umb-package-link" href="" ng-click="vm.showPackageDetails(package)">
|
||||
<button type="button" class="umb-package-link" ng-click="vm.showPackageDetails(package)">
|
||||
|
||||
<div class="umb-package-icon">
|
||||
<img ng-src="{{package.icon}}" alt="" />
|
||||
@@ -76,15 +90,17 @@
|
||||
|
||||
<div class="umb-package-numbers">
|
||||
<small class="umb-package-downloads">
|
||||
<i class="icon-download-alt"></i> <strong>{{ package.downloads }}</strong>
|
||||
<i class="icon-download-alt" aria-hidden="true"></i>
|
||||
<strong>{{ package.downloads }}</strong>
|
||||
</small>
|
||||
<small class="umb-package-likes">
|
||||
<i class="icon-hearts"></i> <strong>{{ package.likes }}</strong>
|
||||
<i class="icon-hearts" aria-hidden="true"></i>
|
||||
<strong>{{ package.likes }}</strong>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</button>
|
||||
</div> <!-- end package -->
|
||||
|
||||
</div> <!-- end packages -->
|
||||
@@ -140,9 +156,9 @@
|
||||
<div class="umb-package-details__description" ng-bind-html="vm.package.description"></div>
|
||||
<div class="umb-gallery">
|
||||
<div class="umb-gallery__thumbnails">
|
||||
<a class="umb-gallery__thumbnail" ng-repeat="image in vm.package.images" ng-click="vm.openLightbox($index, vm.package.images)">
|
||||
<img ng-src="{{ image.thumbnail }}" />
|
||||
</a>
|
||||
<button type="button" class="umb-gallery__thumbnail" ng-repeat="image in vm.package.images" ng-click="vm.openLightbox($index, vm.package.images)">
|
||||
<img ng-src="{{ image.thumbnail }}" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</umb-box-content>
|
||||
@@ -274,7 +290,7 @@
|
||||
<div>
|
||||
<div class="umb-package-details__information-item" ng-repeat="externalSource in vm.package.externalSources">
|
||||
<a class="umb-package-details__link" target="_blank" href="{{ externalSource.url }}">
|
||||
<i class="icon-out"></i>
|
||||
<i class="icon-out" aria-hidden="true"></i>
|
||||
{{ externalSource.name }}
|
||||
</a>
|
||||
</div>
|
||||
@@ -304,7 +320,7 @@
|
||||
|
||||
<form novalidate name="localPackageForm" class="w-100">
|
||||
<div class="umb-package-icon">
|
||||
<i ng-if="!vm.localPackage.icon" class="icon-box"></i>
|
||||
<i ng-if="!vm.localPackage.icon" class="icon-box" aria-hidden="true"></i>
|
||||
<img ng-if="vm.localPackage.icon" ng-src="{{vm.localPackage.icon}}" alt="" />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-prevalues-multivalues__right">
|
||||
<a class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></a>
|
||||
<button type="button" class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -53,7 +53,7 @@
|
||||
<div class="umb-cropsizes__controls">
|
||||
<button class="btn btn-info add" ng-hide="editMode" ng-click="add($event)"><localize key="general_add">Add</localize></button>
|
||||
<button class="btn btn-info add" ng-show="editMode" ng-click="add($event)"><localize key="general_update">Update</localize></button>
|
||||
<a href class="btn btn-link" ng-show="editMode" ng-click="cancel($event)"><localize key="general_cancel">Cancel</localize></a>
|
||||
<button type="button" class="btn btn-link" ng-show="editMode" ng-click="cancel($event)"><localize key="general_cancel">Cancel</localize></button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -65,8 +65,8 @@
|
||||
<p><span>{{item.alias}}</span> <small>({{item.width}}px × {{item.height}}px)</small></p>
|
||||
</div>
|
||||
<div class="umb-prevalues-multivalues__right">
|
||||
<a href="#" prevent-default class="umb-node-preview__action" ng-click="edit(item, $event)"><localize key="general_edit">Edit</localize></a>
|
||||
<a href="#" prevent-default class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></a>
|
||||
<button type="button" class="umb-node-preview__action" ng-click="edit(item, $event)"><localize key="general_edit">Edit</localize></button>
|
||||
<button type="button" class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(item, $event)"><localize key="general_remove">Remove</localize></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@
|
||||
<span class="help-inline" ng-bind="errorMsg"</span>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<table ng-show="model.value.length > 0">
|
||||
<table class="table" ng-show="model.value.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<td></td>
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="list-view-layout__name flex-column content-start">
|
||||
<span class="list-view-layout__name-text" ng-if="!val.isSystem" ng-bind="val.alias"></span>
|
||||
<span class="list-view-layout__name-text" ng-if="val.isSystem == 1" ng-bind="val.alias"></span>
|
||||
<span class="list-view-layout__system" ng-show="val.isSystem == 1">(system field)</span>
|
||||
<span class="list-view-layout__system" ng-show="val.isSystem == 1">(system field)</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
+1
-5
@@ -53,10 +53,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
$scope.canAdd = function () {
|
||||
return !$scope.model.docTypes || !$scope.model.value || $scope.model.value.length < $scope.model.docTypes.length;
|
||||
}
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.model.value.splice(index, 1);
|
||||
}
|
||||
@@ -112,6 +108,7 @@
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$scope.canAdd = function () {
|
||||
return !$scope.model.value || _.some($scope.model.elemTypes, function (elType) {
|
||||
return !_.find($scope.model.value, function (c) {
|
||||
@@ -120,7 +117,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$scope.openElemTypeModal = function ($event, config) {
|
||||
|
||||
//we have to add the alias to the objects (they are stored as ncAlias)
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
<div class="umb-rte-editor-con">
|
||||
<input type="text" id="{{model.alias}}" ng-focus="focus()" style="position:absolute;top:0;width:0;height:0;" />
|
||||
<div id="{{textAreaHtmlId}}" class="umb-rte-editor" ng-style="{ width: containerWidth, height: containerHeight, overflow: containerOverflow}"></div>
|
||||
<div disable-hotkeys id="{{textAreaHtmlId}}" class="umb-rte-editor" ng-style="{ width: containerWidth, height: containerHeight, overflow: containerOverflow}"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
|
||||
<umb-control-group label="Toolbar" description="Pick the toolbar options that should be available when editing">
|
||||
<div ng-repeat="cmd in tinyMceConfig.commands">
|
||||
<label>
|
||||
<umb-checkbox model="cmd.selected"
|
||||
on-change="selectCommand(cmd)"
|
||||
class="mce-cmd" />
|
||||
|
||||
<!--<img ng-src="{{cmd.icon}}" />-->
|
||||
<i class="mce-ico" ng-class="(cmd.isCustom ? ' mce-i-custom ' : ' mce-i-') + cmd.fontIcon"></i>
|
||||
|
||||
{{cmd.name}}
|
||||
</label>
|
||||
<umb-checkbox
|
||||
model="cmd.selected"
|
||||
on-change="selectCommand(cmd)"
|
||||
icon-class="mce-ico {{(cmd.isCustom ? ' mce-i-custom ' : ' mce-i-') + cmd.fontIcon}}"
|
||||
text="{{cmd.name}}"
|
||||
class="mce-cmd" />
|
||||
</div>
|
||||
</umb-control-group>
|
||||
|
||||
|
||||
+16
-1
@@ -15,7 +15,22 @@ function textAreaController($scope, validationMessageService) {
|
||||
if ($scope.model.config && $scope.model.config.maxChars) {
|
||||
$scope.model.maxlength = true;
|
||||
}
|
||||
|
||||
|
||||
$scope.$on("formSubmitting", function() {
|
||||
if ($scope.isLengthValid()) {
|
||||
$scope.textareaFieldForm.textarea.$setValidity("maxChars", true);
|
||||
} else {
|
||||
$scope.textareaFieldForm.textarea.$setValidity("maxChars", false);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.isLengthValid = function() {
|
||||
if (!$scope.model.maxlength) {
|
||||
return true;
|
||||
}
|
||||
return $scope.model.config.maxChars >= $scope.model.count;
|
||||
}
|
||||
|
||||
$scope.model.change = function () {
|
||||
if ($scope.model.value) {
|
||||
$scope.model.count = $scope.model.value.length;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="help" ng-if="model.maxlength === true && model.count >= (model.config.maxChars*.8) && model.count <= model.config.maxChars">
|
||||
<localize key="textbox_characters_left" tokens="[model.config.maxChars - model.count]" watch-tokens="true">%0% characters left.</localize>
|
||||
</div>
|
||||
<div class="help text-error" ng-if="model.maxlength === true && model.count > model.config.maxChars">
|
||||
<div class="help text-error" ng-if="!isLengthValid()">
|
||||
<localize key="textbox_characters_exceed" tokens="[model.config.maxChars, model.count - model.config.maxChars]" watch-tokens="true">Maximum %0% characters, <strong>%1%</strong> too many.</localize>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -11,7 +11,19 @@ function textboxController($scope, validationMessageService) {
|
||||
// if no max is specified in the config
|
||||
$scope.model.config.maxChars = 500;
|
||||
}
|
||||
|
||||
|
||||
$scope.$on("formSubmitting", function() {
|
||||
if ($scope.isLengthValid()) {
|
||||
$scope.textboxFieldForm.textbox.$setValidity("maxChars", true);
|
||||
} else {
|
||||
$scope.textboxFieldForm.textbox.$setValidity("maxChars", false);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.isLengthValid = function() {
|
||||
return $scope.model.config.maxChars >= $scope.model.count;
|
||||
}
|
||||
|
||||
$scope.model.change = function () {
|
||||
if ($scope.model.value) {
|
||||
$scope.model.count = $scope.model.value.length;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<p class="sr-only" tabindex="0">{{model.label}} <localize key="textbox_characters_left" tokens="[model.config.maxChars - model.count]" watch-tokens="true">%0% characters left.</localize></p>
|
||||
<p aria-hidden="True"><localize key="textbox_characters_left" tokens="[model.config.maxChars - model.count]" watch-tokens="true">%0% characters left.</localize></p>
|
||||
</div>
|
||||
<div class="help text-error" ng-if="model.count > model.config.maxChars">
|
||||
<div class="help text-error" ng-if="!isLengthValid()">
|
||||
<p class="sr-only" tabindex="0">{{model.label}} <localize key="textbox_characters_exceed" tokens="[model.config.maxChars, model.count - model.config.maxChars]" watch-tokens="true">Maximum %0% characters, <strong>%1%</strong> too many.</localize></p>
|
||||
<p aria-hidden="true"><localize key="textbox_characters_exceed" tokens="[model.config.maxChars, model.count - model.config.maxChars]" watch-tokens="true">Maximum %0% characters, <strong>%1%</strong> too many.</localize></p>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="vm.performDelete" on-cancel="vm.cancel">
|
||||
<umb-confirm on-confirm="vm.performDelete" on-cancel="vm.cancel" confirm-button-style="danger">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,10 @@ function RelationTypeEditController($scope, $routeParams, relationTypeResource,
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "relationType_tabRelationType";
|
||||
vm.header.setPageTitle = true;
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.saveButtonState = "init";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user