Merge branch temp8 into temp8-11502
This commit is contained in:
+2
-1
@@ -48,4 +48,5 @@ Umbraco is contribution focused and community driven. If you want to contribute
|
||||
|
||||
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](CONTRIBUTING_DETAILED.md#reporting-bugs).
|
||||
|
||||
To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
You can comment and report issues on the [github issue tracker](https://github.com/umbraco/Umbraco-CMS/issues).
|
||||
Since [September 2018](https://umbraco.com/blog/a-second-take-on-umbraco-issue-tracker-hello-github-issues/) the old issue tracker is in read only mode, but can still be found at [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
|
||||
@@ -21,6 +21,6 @@ The following items will now be automatically included when creating a deploy pa
|
||||
system: umbraco, config\splashes and global.asax.
|
||||
|
||||
Please read the release notes on our.umbraco.com:
|
||||
http://our.umbraco.com/contribute/releases
|
||||
https://our.umbraco.com/download/releases
|
||||
|
||||
- Umbraco
|
||||
|
||||
@@ -81,6 +81,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
[ConfigurationProperty("loginBackgroundImage")]
|
||||
internal InnerTextConfigurationElement<string> LoginBackgroundImage => GetOptionalTextElement("loginBackgroundImage", string.Empty);
|
||||
[ConfigurationProperty("StripUdiAttributes")]
|
||||
internal InnerTextConfigurationElement<bool> StripUdiAttributes
|
||||
{
|
||||
get { return GetOptionalTextElement("StripUdiAttributes", true); }
|
||||
}
|
||||
|
||||
|
||||
string IContentSection.NotificationEmailAddress => Notifications.NotificationEmailAddress;
|
||||
|
||||
@@ -136,6 +142,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
bool IContentSection.EnableInheritedMediaTypes => EnableInheritedMediaTypes;
|
||||
|
||||
bool IContentSection.StripUdiAttributes => StripUdiAttributes;
|
||||
|
||||
string IContentSection.LoginBackgroundImage => LoginBackgroundImage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
IEnumerable<string> ImageTagAllowedAttributes { get; }
|
||||
|
||||
IEnumerable<IImagingAutoFillUploadField> ImageAutoFillProperties { get; }
|
||||
|
||||
|
||||
string ScriptFolderPath { get; }
|
||||
|
||||
IEnumerable<string> ScriptFileTypes { get; }
|
||||
@@ -66,5 +66,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
bool EnableInheritedMediaTypes { get; }
|
||||
|
||||
string LoginBackgroundImage { get; }
|
||||
bool StripUdiAttributes { get; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,11 @@ namespace Umbraco.Core
|
||||
/// Property alias for the Media's file extension.
|
||||
/// </summary>
|
||||
public const string Extension = "umbracoExtension";
|
||||
|
||||
/// <summary>
|
||||
/// The default height/width of an image file if the size can't be determined from the metadata
|
||||
/// </summary>
|
||||
public const int DefaultSize = 200;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
/// </remarks>
|
||||
public const string RecycleBinMediaPathPrefix = "-1,-21,";
|
||||
|
||||
public const int DefaultLabelDataTypeId = -92;
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";
|
||||
public const string UmbracoUpgradePlanName = "Umbraco.Core";
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ namespace Umbraco.Core.Events
|
||||
|
||||
// fixme see notes above
|
||||
// delete event args does NOT superceedes 'unpublished' event
|
||||
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "UnPublished")
|
||||
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "Unpublished")
|
||||
return false;
|
||||
|
||||
// found occurences, need to determine if this event args is superceded
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
/// <summary>
|
||||
/// Used when nodes are unpublished
|
||||
/// </summary>
|
||||
UnPublish,
|
||||
Unpublish,
|
||||
/// <summary>
|
||||
/// Used when nodes are moved
|
||||
/// </summary>
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A set of tag changes.
|
||||
/// </summary>
|
||||
internal class PropertyTagChange
|
||||
{
|
||||
public ChangeType Type { get; set; }
|
||||
|
||||
public IEnumerable<(string Type, string Tags)> Tags { get; set; }
|
||||
|
||||
public enum ChangeType
|
||||
{
|
||||
Replace,
|
||||
Remove,
|
||||
Merge
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -748,7 +748,7 @@ ORDER BY colName";
|
||||
|
||||
if (excludeUserGroups != null && excludeUserGroups.Length > 0)
|
||||
{
|
||||
var subQuery = @"AND (umbracoUser.id NOT IN (SELECT DISTINCT umbracoUser.id
|
||||
const string subQuery = @"AND (umbracoUser.id NOT IN (SELECT DISTINCT umbracoUser.id
|
||||
FROM umbracoUser
|
||||
INNER JOIN umbracoUser2UserGroup ON umbracoUser2UserGroup.userId = umbracoUser.id
|
||||
INNER JOIN umbracoUserGroup ON umbracoUserGroup.id = umbracoUser2UserGroup.userGroupId
|
||||
@@ -809,7 +809,7 @@ ORDER BY colName";
|
||||
sql = new SqlTranslator<IUser>(sql, query).Translate();
|
||||
|
||||
// get sorted and filtered sql
|
||||
var sqlNodeIdsWithSort = ApplySort(ApplyFilter(sql, filterSql), orderDirection, orderBy);
|
||||
var sqlNodeIdsWithSort = ApplySort(ApplyFilter(sql, filterSql, query != null), orderDirection, orderBy);
|
||||
|
||||
// get a page of results and total count
|
||||
var pagedResult = Database.Page<UserDto>(pageIndex + 1, pageSize, sqlNodeIdsWithSort);
|
||||
@@ -820,11 +820,17 @@ ORDER BY colName";
|
||||
return pagedResult.Items.Select(UserFactory.BuildEntity);
|
||||
}
|
||||
|
||||
private Sql<ISqlContext> ApplyFilter(Sql<ISqlContext> sql, Sql<ISqlContext> filterSql)
|
||||
private Sql<ISqlContext> ApplyFilter(Sql<ISqlContext> sql, Sql<ISqlContext> filterSql, bool hasWhereClause)
|
||||
{
|
||||
if (filterSql == null) return sql;
|
||||
|
||||
sql.Append(SqlContext.Sql(" WHERE " + filterSql.SQL.TrimStart("AND "), filterSql.Arguments));
|
||||
//ensure we don't append a WHERE if there is already one
|
||||
var args = filterSql.Arguments;
|
||||
var sqlFilter = hasWhereClause
|
||||
? filterSql.SQL
|
||||
: " WHERE " + filterSql.SQL.TrimStart("AND ");
|
||||
|
||||
sql.Append(SqlContext.Sql(sqlFilter, args));
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
@@ -63,5 +65,6 @@ namespace Umbraco.Core.Security
|
||||
/// Used so that we aren't creating a new CultureInfo object for every single request
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<string, CultureInfo> UserCultures = new ConcurrentDictionary<string, CultureInfo>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,7 +635,9 @@ namespace Umbraco.Core.Security
|
||||
|| identityUser.LastLoginDateUtc.HasValue && user.LastLoginDate.ToUniversalTime() != identityUser.LastLoginDateUtc.Value)
|
||||
{
|
||||
anythingChanged = true;
|
||||
user.LastLoginDate = identityUser.LastLoginDateUtc.Value.ToLocalTime();
|
||||
//if the LastLoginDate is being set to MinValue, don't convert it ToLocalTime
|
||||
var dt = identityUser.LastLoginDateUtc == DateTime.MinValue ? DateTime.MinValue : identityUser.LastLoginDateUtc.Value.ToLocalTime();
|
||||
user.LastLoginDate = dt;
|
||||
}
|
||||
if (identityUser.IsPropertyDirty("LastPasswordChangeDateUtc")
|
||||
|| (user.LastPasswordChangeDate != default(DateTime) && identityUser.LastPasswordChangeDateUtc.HasValue == false)
|
||||
|
||||
@@ -988,14 +988,14 @@ namespace Umbraco.Core.Services.Implement
|
||||
UnpublishResultType result;
|
||||
if (culture == "*" || culture == null)
|
||||
{
|
||||
Audit(AuditType.UnPublish, "Unpublished by user", userId, content.Id);
|
||||
Audit(AuditType.Unpublish, "Unpublished by user", userId, content.Id);
|
||||
result = UnpublishResultType.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
Audit(AuditType.UnPublish, $"Culture \"{culture}\" unpublished by user", userId, content.Id);
|
||||
Audit(AuditType.Unpublish, $"Culture \"{culture}\" unpublished by user", userId, content.Id);
|
||||
if (!content.Published)
|
||||
Audit(AuditType.UnPublish, $"Unpublished (culture \"{culture}\" is mandatory) by user", userId, content.Id);
|
||||
Audit(AuditType.Unpublish, $"Unpublished (culture \"{culture}\" is mandatory) by user", userId, content.Id);
|
||||
result = content.Published ? UnpublishResultType.SuccessCulture : UnpublishResultType.SuccessMandatoryCulture;
|
||||
}
|
||||
scope.Complete();
|
||||
@@ -1120,9 +1120,9 @@ namespace Umbraco.Core.Services.Implement
|
||||
if (unpublishResult.Success) // and succeeded, trigger events
|
||||
{
|
||||
// events and audit
|
||||
scope.Events.Dispatch(UnPublished, this, new PublishEventArgs<IContent>(content, false, false), "UnPublished");
|
||||
scope.Events.Dispatch(Unpublished, this, new PublishEventArgs<IContent>(content, false, false), "Unpublished");
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.RefreshBranch).ToEventArgs());
|
||||
Audit(AuditType.UnPublish, "Unpublished by user", userId, content.Id);
|
||||
Audit(AuditType.Unpublish, "Unpublished by user", userId, content.Id);
|
||||
scope.Complete();
|
||||
return new PublishResult(PublishResultType.Success, evtMsgs, content);
|
||||
}
|
||||
@@ -1348,10 +1348,10 @@ namespace Umbraco.Core.Services.Implement
|
||||
scope.WriteLock(Constants.Locks.ContentTree);
|
||||
|
||||
// if it's not trashed yet, and published, we should unpublish
|
||||
// but... UnPublishing event makes no sense (not going to cancel?) and no need to save
|
||||
// but... Unpublishing event makes no sense (not going to cancel?) and no need to save
|
||||
// just raise the event
|
||||
if (content.Trashed == false && content.Published)
|
||||
scope.Events.Dispatch(UnPublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(UnPublished));
|
||||
scope.Events.Dispatch(Unpublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(Unpublished));
|
||||
|
||||
DeleteLocked(scope, content);
|
||||
|
||||
@@ -2098,12 +2098,12 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <summary>
|
||||
/// Occurs before unpublish
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> UnPublishing;
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Unpublishing;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after unpublish
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> UnPublished;
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Unpublished;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after change.
|
||||
@@ -2197,8 +2197,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
// ensures that a document can be unpublished
|
||||
internal UnpublishResult StrategyCanUnpublish(IScope scope, IContent content, int userId, EventMessages evtMsgs)
|
||||
{
|
||||
// raise UnPublishing event
|
||||
if (scope.Events.DispatchCancelable(UnPublishing, this, new PublishEventArgs<IContent>(content, evtMsgs)))
|
||||
// raise Unpublishing event
|
||||
if (scope.Events.DispatchCancelable(Unpublishing, this, new PublishEventArgs<IContent>(content, evtMsgs)))
|
||||
{
|
||||
Logger.Info<ContentService>("Document {ContentName} (id={ContentId}) cannot be unpublished: unpublishing was cancelled.", content.Name, content.Id);
|
||||
return new UnpublishResult(UnpublishResultType.FailedCancelledByEvent, evtMsgs, content);
|
||||
@@ -2282,10 +2282,10 @@ namespace Umbraco.Core.Services.Implement
|
||||
foreach (var content in contents.OrderByDescending(x => x.ParentId))
|
||||
{
|
||||
// if it's not trashed yet, and published, we should unpublish
|
||||
// but... UnPublishing event makes no sense (not going to cancel?) and no need to save
|
||||
// but... Unpublishing event makes no sense (not going to cancel?) and no need to save
|
||||
// just raise the event
|
||||
if (content.Trashed == false && content.Published)
|
||||
scope.Events.Dispatch(UnPublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(UnPublished));
|
||||
scope.Events.Dispatch(Unpublished, this, new PublishEventArgs<IContent>(content, false, false), nameof(Unpublished));
|
||||
|
||||
// if current content has children, move them to trash
|
||||
var c = content;
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
private readonly IAuditRepository _auditRepository;
|
||||
private readonly IContentTypeRepository _contentTypeRepository;
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private static HttpClient _httpClient;
|
||||
|
||||
public PackagingService(
|
||||
ILogger logger,
|
||||
@@ -1441,7 +1442,6 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <returns></returns>
|
||||
public string FetchPackageFile(Guid packageId, Version umbracoVersion, int userId)
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
//includeHidden = true because we don't care if it's hidden we want to get the file regardless
|
||||
@@ -1449,7 +1449,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
byte[] bytes;
|
||||
try
|
||||
{
|
||||
bytes = httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult();
|
||||
if (_httpClient == null)
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
}
|
||||
bytes = _httpClient.GetByteArrayAsync(url).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
|
||||
@@ -76,11 +76,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
// reload - cheap, cached
|
||||
|
||||
// default role is single server, but if registrations contain more
|
||||
// than one active server, then role is master or slave
|
||||
// than one active server, then role is master or replica
|
||||
regs = _serverRegistrationRepository.GetMany().ToArray();
|
||||
|
||||
// default role is single server, but if registrations contain more
|
||||
// than one active server, then role is master or slave
|
||||
// than one active server, then role is master or replica
|
||||
_currentServerRole = regs.Count(x => x.IsActive) > 1
|
||||
? (server.IsMaster ? ServerRole.Master : ServerRole.Replica)
|
||||
: ServerRole.Single;
|
||||
|
||||
@@ -1384,6 +1384,30 @@ namespace Umbraco.Core
|
||||
return idCheckList.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a file name to a friendly name for a content item
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToFriendlyName(this string fileName)
|
||||
{
|
||||
// strip the file extension
|
||||
fileName = fileName.StripFileExtension();
|
||||
|
||||
// underscores and dashes to spaces
|
||||
fileName = fileName.ReplaceMany(new[] { '_', '-' }, ' ');
|
||||
|
||||
// any other conversions ?
|
||||
|
||||
// Pascalcase (to be done last)
|
||||
fileName = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(fileName);
|
||||
|
||||
// Replace multiple consecutive spaces with a single space
|
||||
fileName = string.Join(" ", fileName.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
// From: http://stackoverflow.com/a/961504/5018
|
||||
// filters control characters but allows only properly-formed surrogate sequences
|
||||
private static readonly Lazy<Regex> InvalidXmlChars = new Lazy<Regex>(() =>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
Single = 1,
|
||||
|
||||
/// <summary>
|
||||
/// In a multi-servers environment, the server is a slave server.
|
||||
/// In a multi-servers environment, the server is a replica server.
|
||||
/// </summary>
|
||||
Replica = 2,
|
||||
|
||||
|
||||
@@ -729,7 +729,6 @@
|
||||
<Compile Include="Models\PropertyCollection.cs" />
|
||||
<Compile Include="Models\PropertyGroup.cs" />
|
||||
<Compile Include="Models\PropertyGroupCollection.cs" />
|
||||
<Compile Include="Models\PropertyTagChange.cs" />
|
||||
<Compile Include="Models\PropertyType.cs" />
|
||||
<Compile Include="Models\PropertyTypeCollection.cs" />
|
||||
<Compile Include="Models\PublicAccessEntry.cs" />
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace Umbraco.Tests.Cache
|
||||
new EventDefinition<IContentService, MoveEventArgs<IContent>>(null, serviceContext.ContentService, new MoveEventArgs<IContent>(new MoveEventInfo<IContent>(null, "", -1)), "Trashed"),
|
||||
new EventDefinition<IContentService, RecycleBinEventArgs>(null, serviceContext.ContentService, new RecycleBinEventArgs(Guid.NewGuid())),
|
||||
new EventDefinition<IContentService, PublishEventArgs<IContent>>(null, serviceContext.ContentService, new PublishEventArgs<IContent>(Enumerable.Empty<IContent>()), "Published"),
|
||||
new EventDefinition<IContentService, PublishEventArgs<IContent>>(null, serviceContext.ContentService, new PublishEventArgs<IContent>(Enumerable.Empty<IContent>()), "UnPublished"),
|
||||
new EventDefinition<IContentService, PublishEventArgs<IContent>>(null, serviceContext.ContentService, new PublishEventArgs<IContent>(Enumerable.Empty<IContent>()), "Unpublished"),
|
||||
|
||||
new EventDefinition<IPublicAccessService, SaveEventArgs<PublicAccessEntry>>(null, serviceContext.PublicAccessService, new SaveEventArgs<PublicAccessEntry>(Enumerable.Empty<PublicAccessEntry>())),
|
||||
new EventDefinition<IPublicAccessService, DeleteEventArgs<PublicAccessEntry>>(null, serviceContext.PublicAccessService, new DeleteEventArgs<PublicAccessEntry>(Enumerable.Empty<PublicAccessEntry>())),
|
||||
|
||||
@@ -463,7 +463,7 @@ namespace Umbraco.Tests.Integration
|
||||
|
||||
#endregion
|
||||
|
||||
#region Save, Publish & UnPublish single content
|
||||
#region Save, Publish & Unpublish single content
|
||||
|
||||
[Test]
|
||||
public void SaveUnpublishedContent()
|
||||
@@ -721,7 +721,7 @@ namespace Umbraco.Tests.Integration
|
||||
|
||||
#endregion
|
||||
|
||||
#region Publish & UnPublish branch
|
||||
#region Publish & Unpublish branch
|
||||
|
||||
[Test]
|
||||
public void UnpublishContentBranch()
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)]
|
||||
public class AuditRepositoryTest : TestWithDatabaseBase
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void Can_Add_Audit_Entry()
|
||||
{
|
||||
@@ -23,7 +27,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
using (var scope = sp.CreateScope())
|
||||
{
|
||||
var repo = new AuditRepository((IScopeAccessor) sp, CacheHelper, Logger);
|
||||
repo.Save(new AuditItem(-1, "This is a System audit trail", AuditType.System, 0));
|
||||
repo.Save(new AuditItem(-1, "This is a System audit trail", AuditType.System, -1));
|
||||
|
||||
var dtos = scope.Database.Fetch<LogDto>("WHERE id > -1");
|
||||
|
||||
@@ -42,8 +46,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
repo.Save(new AuditItem(i, $"Content {i} created", AuditType.New, 0));
|
||||
repo.Save(new AuditItem(i, $"Content {i} published", AuditType.Publish, 0));
|
||||
repo.Save(new AuditItem(i, $"Content {i} created", AuditType.New, -1));
|
||||
repo.Save(new AuditItem(i, $"Content {i} published", AuditType.Publish, -1));
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
@@ -60,6 +64,49 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Items_By_User_Id_With_Query_And_Filter()
|
||||
{
|
||||
var sp = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = sp.CreateScope())
|
||||
{
|
||||
var repo = new AuditRepository((IScopeAccessor)sp, CacheHelper, Logger);
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
repo.Save(new AuditItem(i, $"Content {i} created", AuditType.New, -1));
|
||||
repo.Save(new AuditItem(i, $"Content {i} published", AuditType.Publish, -1));
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
using (var scope = sp.CreateScope())
|
||||
{
|
||||
var repo = new AuditRepository((IScopeAccessor)sp, CacheHelper, Logger);
|
||||
|
||||
var query = sp.SqlContext.Query<IAuditItem>().Where(x => x.UserId == -1);
|
||||
|
||||
try
|
||||
{
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
|
||||
|
||||
var page = repo.GetPagedResultsByQuery(query, 0, 10, out var total, Direction.Descending,
|
||||
new[] { AuditType.Publish },
|
||||
sp.SqlContext.Query<IAuditItem>().Where(x => x.UserId > -2));
|
||||
|
||||
Assert.AreEqual(10, page.Count());
|
||||
Assert.AreEqual(100, total);
|
||||
}
|
||||
finally
|
||||
{
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlTrace = false;
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlCount = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Paged_Items_With_AuditType_Filter()
|
||||
{
|
||||
@@ -70,8 +117,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
repo.Save(new AuditItem(i, $"Content {i} created", AuditType.New, 0));
|
||||
repo.Save(new AuditItem(i, $"Content {i} published", AuditType.Publish, 0));
|
||||
repo.Save(new AuditItem(i, $"Content {i} created", AuditType.New, -1));
|
||||
repo.Save(new AuditItem(i, $"Content {i} published", AuditType.Publish, -1));
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
@@ -101,8 +148,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
repo.Save(new AuditItem(i, "Content created", AuditType.New, 0));
|
||||
repo.Save(new AuditItem(i, "Content published", AuditType.Publish, 0));
|
||||
repo.Save(new AuditItem(i, "Content created", AuditType.New, -1));
|
||||
repo.Save(new AuditItem(i, "Content published", AuditType.Publish, -1));
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
|
||||
@@ -8,17 +8,19 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true)]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, WithApplication = true, Logger = UmbracoTestOptions.Logger.Console)]
|
||||
public class UserRepositoryTest : TestWithDatabaseBase
|
||||
{
|
||||
private MediaRepository CreateMediaRepository(IScopeProvider provider, out IMediaTypeRepository mediaTypeRepository)
|
||||
@@ -50,14 +52,14 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
private UserRepository CreateRepository(IScopeProvider provider)
|
||||
{
|
||||
var accessor = (IScopeAccessor) provider;
|
||||
var repository = new UserRepository(accessor, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), Mock.Of<IMapperCollection>(), TestObjects.GetGlobalSettings());
|
||||
var repository = new UserRepository(accessor, CacheHelper.CreateDisabledCacheHelper(), Logger, Mappers, TestObjects.GetGlobalSettings());
|
||||
return repository;
|
||||
}
|
||||
|
||||
private UserGroupRepository CreateUserGroupRepository(IScopeProvider provider)
|
||||
{
|
||||
var accessor = (IScopeAccessor) provider;
|
||||
return new UserGroupRepository(accessor, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>());
|
||||
return new UserGroupRepository(accessor, CacheHelper.CreateDisabledCacheHelper(), Logger);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -338,7 +340,72 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var result = repository.Count(query);
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.GreaterThanOrEqualTo(2));
|
||||
Assert.AreEqual(2, result);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Paged_Results_By_Query_And_Filter_And_Groups()
|
||||
{
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider);
|
||||
|
||||
var users = CreateAndCommitMultipleUsers(repository);
|
||||
var query = provider.SqlContext.Query<IUser>().Where(x => x.Username == "TestUser1" || x.Username == "TestUser2");
|
||||
|
||||
try
|
||||
{
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
|
||||
|
||||
// Act
|
||||
var result = repository.GetPagedResultsByQuery(query, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending,
|
||||
excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias },
|
||||
filter: provider.SqlContext.Query<IUser>().Where(x => x.Id > -1));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(2, totalRecs);
|
||||
}
|
||||
finally
|
||||
{
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlTrace = false;
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlCount = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Get_Paged_Results_With_Filter_And_Groups()
|
||||
{
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider);
|
||||
|
||||
var users = CreateAndCommitMultipleUsers(repository);
|
||||
|
||||
try
|
||||
{
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
|
||||
|
||||
// Act
|
||||
var result = repository.GetPagedResultsByQuery(null, 0, 10, out var totalRecs, user => user.Id, Direction.Ascending,
|
||||
includeUserGroups: new[] { Constants.Security.AdminGroupAlias, Constants.Security.SensitiveDataGroupAlias },
|
||||
excludeUserGroups: new[] { Constants.Security.TranslatorGroupAlias },
|
||||
filter: provider.SqlContext.Query<IUser>().Where(x => x.Id == -1));
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, totalRecs);
|
||||
}
|
||||
finally
|
||||
{
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlTrace = false;
|
||||
scope.Database.AsUmbracoDatabase().EnableSqlCount = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace Umbraco.Tests.Scoping
|
||||
[Test]
|
||||
public void SupersededEvents2()
|
||||
{
|
||||
Test_UnPublished += OnDoThingFail;
|
||||
Test_Unpublished += OnDoThingFail;
|
||||
Test_Deleted += OnDoThingFail;
|
||||
|
||||
var contentService = Mock.Of<IContentService>();
|
||||
@@ -178,7 +178,7 @@ namespace Umbraco.Tests.Scoping
|
||||
var scopeProvider = _testObjects.GetScopeProvider(Mock.Of<ILogger>());
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
|
||||
{
|
||||
scope.Events.Dispatch(Test_UnPublished, contentService, new PublishEventArgs<IContent>(new [] { content }), "UnPublished");
|
||||
scope.Events.Dispatch(Test_Unpublished, contentService, new PublishEventArgs<IContent>(new [] { content }), "Unpublished");
|
||||
scope.Events.Dispatch(Test_Deleted, contentService, new DeleteEventArgs<IContent>(new [] { content }), "Deleted");
|
||||
|
||||
// see U4-10764
|
||||
@@ -395,7 +395,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
public static event TypedEventHandler<ScopeEventDispatcherTests, SaveEventArgs<decimal>> DoThing3;
|
||||
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Test_UnPublished;
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Test_Unpublished;
|
||||
public static event TypedEventHandler<IContentService, DeleteEventArgs<IContent>> Test_Deleted;
|
||||
|
||||
public class TestEventArgs : CancellableObjectEventArgs
|
||||
|
||||
@@ -1208,7 +1208,7 @@ namespace Umbraco.Tests.Services
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_UnPublish_Content()
|
||||
public void Can_Unpublish_Content()
|
||||
{
|
||||
// Arrange
|
||||
var contentService = ServiceContext.ContentService;
|
||||
|
||||
@@ -3,9 +3,11 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
@@ -30,6 +32,14 @@ namespace Umbraco.Tests.Strings
|
||||
Assert.IsInstanceOf<MockShortStringHelper>(helper);
|
||||
}
|
||||
|
||||
[TestCase("hello-world.png", "Hello World")]
|
||||
[TestCase("hello-world .png", "Hello World")]
|
||||
[TestCase("_hello-world __1.png", "Hello World 1")]
|
||||
public void To_Friendly_Name(string first, string second)
|
||||
{
|
||||
Assert.AreEqual(first.ToFriendlyName(), second);
|
||||
}
|
||||
|
||||
[TestCase("hello", "world", false)]
|
||||
[TestCase("hello", "hello", true)]
|
||||
[TestCase("hellohellohellohellohellohellohello", "hellohellohellohellohellohellohelloo", false)]
|
||||
|
||||
@@ -172,6 +172,11 @@ namespace Umbraco.Tests.Testing
|
||||
Container.RegisterSingleton<ILogger>(f => new SerilogLogger(new FileInfo(TestHelper.MapPathForTest("~/unit-test.config"))));
|
||||
Container.RegisterSingleton<IProfiler>(f => new LogProfiler(f.GetInstance<ILogger>()));
|
||||
}
|
||||
else if (option == UmbracoTestOptions.Logger.Console)
|
||||
{
|
||||
Container.RegisterSingleton<ILogger>(f => new ConsoleLogger());
|
||||
Container.RegisterSingleton<IProfiler>(f => new LogProfiler(f.GetInstance<ILogger>()));
|
||||
}
|
||||
|
||||
Container.RegisterSingleton(f => new ProfilingLogger(f.GetInstance<ILogger>(), f.GetInstance<IProfiler>()));
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
// pure mocks
|
||||
Mock,
|
||||
// Serilog for tests
|
||||
Serilog
|
||||
Serilog,
|
||||
// console logger
|
||||
Console
|
||||
}
|
||||
|
||||
public enum Database
|
||||
|
||||
@@ -78,6 +78,9 @@
|
||||
<PackageReference Include="AutoMapper" Version="7.0.1" />
|
||||
<PackageReference Include="Castle.Core" Version="4.2.1" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta025" />
|
||||
<PackageReference Include="HtmlAgilityPack">
|
||||
<Version>1.8.9</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="LightInject" Version="5.1.2" />
|
||||
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
|
||||
<PackageReference Include="Lucene.Net" Version="3.0.3" />
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using LightInject;
|
||||
using HtmlAgilityPack;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
@@ -12,7 +12,6 @@ using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Stubs;
|
||||
using Umbraco.Tests.Testing.Objects.Accessors;
|
||||
@@ -21,6 +20,8 @@ using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Templates;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Tests.Web
|
||||
{
|
||||
@@ -62,6 +63,14 @@ namespace Umbraco.Tests.Web
|
||||
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
|
||||
//this one has an invalid char so won't match
|
||||
[TestCase("hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
|
||||
// with a-tag with data-udi attribute, that needs to be stripped
|
||||
[TestCase("hello <a data-udi=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\"> world</a> ", "hello <a href=\"/my-test-url\"> world</a> ")]
|
||||
// with a-tag with data-udi attribute spelled wrong, so don't need stripping
|
||||
[TestCase("hello <a data-uid=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\"> world</a> ", "hello <a data-uid=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" href=\"/my-test-url\"> world</a> ")]
|
||||
// with a img-tag with data-udi id, that needs to be strippde
|
||||
[TestCase("hello <img data-udi=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" src=\"imageofcats.jpg\"> world ", "hello <img src=\"imageofcats.jpg\"> world ")]
|
||||
// with a img-tag with data-udi id spelled wrong, so don't need stripping
|
||||
[TestCase("hello <img data-uid=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" src=\"imageofcats.jpg\"> world ", "hello <img data-uid=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" src=\"imageofcats.jpg\"> world ")]
|
||||
public void ParseLocalLinks(string input, string result)
|
||||
{
|
||||
var serviceCtxMock = new TestObjects(null).GetServiceContextMock();
|
||||
@@ -102,7 +111,7 @@ namespace Umbraco.Tests.Web
|
||||
//setup a quick mock of the WebRouting section
|
||||
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "AutoLegacy")),
|
||||
//pass in the custom url provider
|
||||
new[]{ testUrlProvider.Object },
|
||||
new[] { testUrlProvider.Object },
|
||||
globalSettings,
|
||||
new TestVariationContextAccessor(),
|
||||
true))
|
||||
@@ -112,5 +121,27 @@ namespace Umbraco.Tests.Web
|
||||
Assert.AreEqual(result, output);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripDataUdiAttributesUsingSrtringOnLinks()
|
||||
{
|
||||
var input = "hello <a data-udi=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" href=\"/my-test-url\"> world</a> ";
|
||||
var expected = "hello <a href=\"/my-test-url\"> world</a> ";
|
||||
|
||||
var result = TemplateUtilities.StripUdiDataAttributes(input);
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StripDataUdiAttributesUsingStringOnImages()
|
||||
{
|
||||
var input = "hello <img data-udi=\"umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570\" src=\"imageofcats.jpg\"> world ";
|
||||
var expected = "hello <img src=\"imageofcats.jpg\"> world ";
|
||||
|
||||
var result = TemplateUtilities.StripUdiDataAttributes(input);
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6012
-3181
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,12 @@
|
||||
{
|
||||
"author": "Umbraco HQ",
|
||||
"name": "umbraco",
|
||||
"homepage": "https://github.com/umbraco/umbraco-cms/",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/umbraco/Umbraco-CMS.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://issues.umbraco.org"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.4"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "bower-installer",
|
||||
"test": "karma start test/config/karma.conf.js --singlerun",
|
||||
"build": "gulp"
|
||||
},
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"npm": "^6.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^6.5.0",
|
||||
"bower-installer": "^1.2.0",
|
||||
|
||||
+82
-65
@@ -157,10 +157,19 @@
|
||||
if(app && app.alias !== "umbContent" && app.alias !== "umbInfo") {
|
||||
$scope.defaultButton = null;
|
||||
$scope.subButtons = null;
|
||||
$scope.page.showSaveButton = false;
|
||||
$scope.page.showPreviewButton = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// create the save button
|
||||
if(_.contains($scope.content.allowedActions, "A")) {
|
||||
$scope.page.showSaveButton = true;
|
||||
// add ellipsis to the save button if it opens the variant overlay
|
||||
$scope.page.saveButtonEllipsis = content.variants && content.variants.length > 1 ? "true" : "false";
|
||||
}
|
||||
|
||||
// create the pubish combo button
|
||||
$scope.page.buttonGroupState = "init";
|
||||
var buttons = contentEditingHelper.configureContentEditorButtons({
|
||||
create: $scope.page.isNew,
|
||||
@@ -168,8 +177,7 @@
|
||||
methods: {
|
||||
saveAndPublish: $scope.saveAndPublish,
|
||||
sendToPublish: $scope.sendToPublish,
|
||||
save: $scope.save,
|
||||
unPublish: $scope.unPublish
|
||||
unpublish: $scope.unpublish
|
||||
}
|
||||
});
|
||||
|
||||
@@ -225,9 +233,7 @@
|
||||
|
||||
// This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish
|
||||
function performSave(args) {
|
||||
|
||||
$scope.page.buttonGroupState = "busy";
|
||||
|
||||
|
||||
eventsService.emit("content.saving", { content: $scope.content, action: args.action });
|
||||
|
||||
return contentEditingHelper.contentEditorPerformSave({
|
||||
@@ -242,8 +248,6 @@
|
||||
|
||||
syncTreeNode($scope.content, data.path);
|
||||
|
||||
$scope.page.buttonGroupState = "success";
|
||||
|
||||
eventsService.emit("content.saved", { content: $scope.content, action: args.action });
|
||||
|
||||
return $q.when(data);
|
||||
@@ -257,8 +261,6 @@
|
||||
editorState.set($scope.content);
|
||||
}
|
||||
|
||||
$scope.page.buttonGroupState = "error";
|
||||
|
||||
return $q.reject(err);
|
||||
});
|
||||
}
|
||||
@@ -332,52 +334,45 @@
|
||||
});
|
||||
}
|
||||
|
||||
$scope.unPublish = function () {
|
||||
$scope.unpublish = function() {
|
||||
clearNotifications($scope.content);
|
||||
if (formHelper.submitForm({ scope: $scope, action: "unpublish", skipValidation: true })) {
|
||||
var dialog = {
|
||||
parentScope: $scope,
|
||||
view: "views/content/overlays/unpublish.html",
|
||||
variants: $scope.content.variants, //set a model property for the dialog
|
||||
skipFormValidation: true, //when submitting the overlay form, skip any client side validation
|
||||
submitButtonLabelKey: "content_unpublish",
|
||||
submit: function (model) {
|
||||
|
||||
//if there's any variants than we need to set the language and include the variants to publish
|
||||
var culture = null;
|
||||
if ($scope.content.variants.length > 0) {
|
||||
_.each($scope.content.variants,
|
||||
function (d) {
|
||||
//set the culture if this is active
|
||||
if (d.active === true) {
|
||||
culture = d.language.culture;
|
||||
}
|
||||
});
|
||||
model.submitButtonState = "busy";
|
||||
|
||||
var selectedVariants = _.filter(model.variants, function(variant) { return variant.save; });
|
||||
var culturesForUnpublishing = _.map(selectedVariants, function(variant) { return variant.language.culture; });
|
||||
|
||||
contentResource.unpublish($scope.content.id, culturesForUnpublishing)
|
||||
.then(function (data) {
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
contentEditingHelper.reBindChangedProperties($scope.content, data);
|
||||
init($scope.content);
|
||||
syncTreeNode($scope.content, data.path);
|
||||
$scope.page.buttonGroupState = "success";
|
||||
eventsService.emit("content.unpublished", { content: $scope.content });
|
||||
overlayService.close();
|
||||
}, function (err) {
|
||||
$scope.page.buttonGroupState = 'error';
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
close: function () {
|
||||
overlayService.close();
|
||||
}
|
||||
};
|
||||
overlayService.open(dialog);
|
||||
}
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope, skipValidation: true })) {
|
||||
|
||||
$scope.page.buttonGroupState = "busy";
|
||||
|
||||
eventsService.emit("content.unpublishing", { content: $scope.content });
|
||||
|
||||
contentResource.unPublish($scope.content.id, culture)
|
||||
.then(function (data) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
scope: $scope,
|
||||
savedContent: data,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
|
||||
});
|
||||
|
||||
init($scope.content);
|
||||
|
||||
syncTreeNode($scope.content, data.path);
|
||||
|
||||
$scope.page.buttonGroupState = "success";
|
||||
|
||||
eventsService.emit("content.unpublished", { content: $scope.content });
|
||||
|
||||
}, function (err) {
|
||||
$scope.page.buttonGroupState = 'error';
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
$scope.sendToPublish = function () {
|
||||
clearNotifications($scope.content);
|
||||
if (showSaveOrPublishDialog()) {
|
||||
@@ -405,13 +400,20 @@
|
||||
}
|
||||
}
|
||||
else {
|
||||
return performSave({ saveMethod: contentResource.sendToPublish, action: "sendToPublish" });
|
||||
$scope.page.buttonGroupState = "busy";
|
||||
return performSave({
|
||||
saveMethod: contentResource.sendToPublish,
|
||||
action: "sendToPublish"
|
||||
}).then(function(){
|
||||
$scope.page.buttonGroupState = "success";
|
||||
}, function () {
|
||||
$scope.page.buttonGroupState = "error";
|
||||
});;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.saveAndPublish = function () {
|
||||
clearNotifications($scope.content);
|
||||
// TODO: Add "..." to publish button label if there are more than one variant to publish - currently it just adds the elipses if there's more than 1 variant
|
||||
if (showSaveOrPublishDialog()) {
|
||||
//before we launch the dialog we want to execute all client side validations first
|
||||
if (formHelper.submitForm({ scope: $scope, action: "publish" })) {
|
||||
@@ -457,7 +459,15 @@
|
||||
else {
|
||||
//ensure the publish flag is set
|
||||
$scope.content.variants[0].publish = true;
|
||||
return performSave({ saveMethod: contentResource.publish, action: "publish" });
|
||||
$scope.page.buttonGroupState = "busy";
|
||||
return performSave({
|
||||
saveMethod: contentResource.publish,
|
||||
action: "publish"
|
||||
}).then(function(){
|
||||
$scope.page.buttonGroupState = "success";
|
||||
}, function () {
|
||||
$scope.page.buttonGroupState = "error";
|
||||
});;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -488,15 +498,14 @@
|
||||
clearNotifications($scope.content);
|
||||
overlayService.close();
|
||||
return $q.when(data);
|
||||
},
|
||||
function (err) {
|
||||
clearDirtyState($scope.content.variants);
|
||||
model.submitButtonState = "error";
|
||||
//re-map the dialog model since we've re-bound the properties
|
||||
dialog.variants = $scope.content.variants;
|
||||
//don't reject, we've handled the error
|
||||
return $q.when(err);
|
||||
});
|
||||
}, function (err) {
|
||||
clearDirtyState($scope.content.variants);
|
||||
model.submitButtonState = "error";
|
||||
//re-map the dialog model since we've re-bound the properties
|
||||
dialog.variants = $scope.content.variants;
|
||||
//don't reject, we've handled the error
|
||||
return $q.when(err);
|
||||
});
|
||||
},
|
||||
close: function (oldModel) {
|
||||
overlayService.close();
|
||||
@@ -507,7 +516,15 @@
|
||||
}
|
||||
}
|
||||
else {
|
||||
return performSave({ saveMethod: $scope.saveMethod(), action: "save" });
|
||||
$scope.page.saveButtonState = "busy";
|
||||
return performSave({
|
||||
saveMethod: $scope.saveMethod(),
|
||||
action: "save"
|
||||
}).then(function(){
|
||||
$scope.page.saveButtonState = "success";
|
||||
}, function () {
|
||||
$scope.page.saveButtonState = "error";
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
+32
-8
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService, dateHelper, editorService) {
|
||||
function ContentNodeInfoDirective($timeout, $location, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource) {
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
// make sure dates are formatted to the user's locale
|
||||
formatDatesToLocal();
|
||||
|
||||
//default setting for redirect url management
|
||||
scope.urlTrackerDisabled = false;
|
||||
|
||||
// Declare a fallback URL for the <umb-node-preview/> directive
|
||||
if (scope.documentType !== null) {
|
||||
scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id;
|
||||
@@ -139,7 +142,7 @@
|
||||
|
||||
// get current backoffice user and format dates
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
angular.forEach(data.items, function(item) {
|
||||
angular.forEach(data.items, function (item) {
|
||||
item.timestampFormatted = dateHelper.getLocalDate(item.timestamp, currentUser.locale, 'LLL');
|
||||
});
|
||||
});
|
||||
@@ -156,6 +159,25 @@
|
||||
});
|
||||
|
||||
}
|
||||
function loadRedirectUrls() {
|
||||
scope.loadingRedirectUrls = true;
|
||||
//check if Redirect Url Management is enabled
|
||||
redirectUrlsResource.getEnableState().then(function (response) {
|
||||
scope.urlTrackerDisabled = response.enabled !== true;
|
||||
if (scope.urlTrackerDisabled === false) {
|
||||
|
||||
redirectUrlsResource.getRedirectsForContentItem(scope.node.udi)
|
||||
.then(function (data) {
|
||||
scope.redirectUrls = data.searchResults;
|
||||
scope.hasRedirects = (typeof data.searchResults !== 'undefined' && data.searchResults.length > 0);
|
||||
scope.loadingRedirectUrls = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
scope.loadingRedirectUrls = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setAuditTrailLogTypeColor(auditTrail) {
|
||||
angular.forEach(auditTrail, function (item) {
|
||||
@@ -164,7 +186,7 @@
|
||||
case "Publish":
|
||||
item.logTypeColor = "success";
|
||||
break;
|
||||
case "UnPublish":
|
||||
case "Unpublish":
|
||||
case "Delete":
|
||||
item.logTypeColor = "danger";
|
||||
break;
|
||||
@@ -312,12 +334,13 @@
|
||||
});
|
||||
}
|
||||
|
||||
// load audit trail when on the info tab
|
||||
// load audit trail and redirects when on the info tab
|
||||
evts.push(eventsService.on("app.tabChange", function (event, args) {
|
||||
$timeout(function(){
|
||||
$timeout(function () {
|
||||
if (args.alias === "umbInfo") {
|
||||
isInfoTab = true;
|
||||
loadAuditTrail();
|
||||
loadRedirectUrls();
|
||||
} else {
|
||||
isInfoTab = false;
|
||||
}
|
||||
@@ -325,13 +348,14 @@
|
||||
}));
|
||||
|
||||
// watch for content state updates
|
||||
scope.$watch('node.updateDate', function(newValue, oldValue){
|
||||
scope.$watch('node.updateDate', function (newValue, oldValue) {
|
||||
|
||||
if(!newValue) { return; }
|
||||
if(newValue === oldValue) { return; }
|
||||
if (!newValue) { return; }
|
||||
if (newValue === oldValue) { return; }
|
||||
|
||||
if(isInfoTab) {
|
||||
loadAuditTrail();
|
||||
loadRedirectUrls();
|
||||
formatDatesToLocal();
|
||||
setNodePublishStatus(scope.node);
|
||||
}
|
||||
|
||||
+29
-25
@@ -11,32 +11,36 @@ function hexBgColor() {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
var origColor = null;
|
||||
if (attr.hexBgOrig) {
|
||||
//set the orig based on the attribute if there is one
|
||||
origColor = attr.hexBgOrig;
|
||||
}
|
||||
|
||||
attr.$observe("hexBgColor", function (newVal) {
|
||||
if (newVal) {
|
||||
if (!origColor) {
|
||||
//get the orig color before changing it
|
||||
origColor = element.css("border-color");
|
||||
}
|
||||
//validate it - test with and without the leading hash.
|
||||
if (/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", "#" + newVal);
|
||||
return;
|
||||
}
|
||||
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", newVal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
element.css("background-color", origColor);
|
||||
});
|
||||
// Only add inline hex background color if defined and not "true".
|
||||
if (attr.hexBgInline === undefined || (attr.hexBgInline !== undefined && attr.hexBgInline === "true")) {
|
||||
|
||||
var origColor = null;
|
||||
if (attr.hexBgOrig) {
|
||||
// Set the orig based on the attribute if there is one.
|
||||
origColor = attr.hexBgOrig;
|
||||
}
|
||||
|
||||
attr.$observe("hexBgColor", function (newVal) {
|
||||
if (newVal) {
|
||||
if (!origColor) {
|
||||
// Get the orig color before changing it.
|
||||
origColor = element.css("border-color");
|
||||
}
|
||||
// Validate it - test with and without the leading hash.
|
||||
if (/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", "#" + newVal);
|
||||
return;
|
||||
}
|
||||
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", newVal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
element.css("background-color", origColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives').directive("hexBgColor", hexBgColor);
|
||||
angular.module('umbraco.directives').directive("hexBgColor", hexBgColor);
|
||||
|
||||
+15
-3
@@ -41,7 +41,6 @@
|
||||
};
|
||||
|
||||
function setFocalPoint (event) {
|
||||
|
||||
$scope.$emit("imageFocalPointStart");
|
||||
|
||||
var offsetX = event.offsetX - 10;
|
||||
@@ -50,7 +49,6 @@
|
||||
calculateGravity(offsetX, offsetY);
|
||||
|
||||
lazyEndEvent();
|
||||
|
||||
};
|
||||
|
||||
/** Initializes the component */
|
||||
@@ -148,12 +146,26 @@
|
||||
|
||||
/** Sets the width/height/left/top dimentions based on the image size and the "center" value */
|
||||
function setDimensions() {
|
||||
if (htmlImage && vm.center) {
|
||||
|
||||
if (vm.src.endsWith(".svg")) {
|
||||
// svg files don't automatically get a size by
|
||||
// loading them set a default size for now
|
||||
vm.dimensions.width = 200;
|
||||
vm.dimensions.height = 200;
|
||||
vm.dimensions.left = vm.center.left * vm.dimensions.width - 10;
|
||||
vm.dimensions.top = vm.center.top * vm.dimensions.height - 10;
|
||||
// can't crop an svg file, don't show the focal point
|
||||
if (htmlOverlay) {
|
||||
htmlOverlay.remove();
|
||||
}
|
||||
}
|
||||
else if (htmlImage && vm.center) {
|
||||
vm.dimensions.width = htmlImage.width();
|
||||
vm.dimensions.height = htmlImage.height();
|
||||
vm.dimensions.left = vm.center.left * vm.dimensions.width - 10;
|
||||
vm.dimensions.top = vm.center.top * vm.dimensions.height - 10;
|
||||
}
|
||||
|
||||
return vm.dimensions.width;
|
||||
};
|
||||
|
||||
|
||||
+9
-1
@@ -73,7 +73,15 @@ angular.module("umbraco.directives")
|
||||
if (node.selected) {
|
||||
css.push("umb-tree-node-checked");
|
||||
}
|
||||
|
||||
|
||||
//is this the current action node (this is not the same as the current selected node!)
|
||||
var actionNode = appState.getMenuState("currentNode");
|
||||
if (actionNode) {
|
||||
if (actionNode.id === node.id) {
|
||||
css.push("active");
|
||||
}
|
||||
}
|
||||
|
||||
return css.join(" ");
|
||||
};
|
||||
|
||||
|
||||
+11
-4
@@ -1,5 +1,4 @@
|
||||
|
||||
/**
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbColorSwatches
|
||||
@restrict E
|
||||
@@ -15,9 +14,10 @@ Use this directive to generate color swatches to pick from.
|
||||
</umb-color-swatches>
|
||||
</pre>
|
||||
@param {array} colors (<code>attribute</code>): The array of colors.
|
||||
@param {string} colors (<code>attribute</code>): The array of colors.
|
||||
@param {string} selectedColor (<code>attribute</code>): The selected color.
|
||||
@param {string} size (<code>attribute</code>): The size (s, m).
|
||||
@param {string} useLabel (<code>attribute</code>): Specify if labels should be used.
|
||||
@param {string} useColorClass (<code>attribute</code>): Specify if color values are css classes.
|
||||
@param {function} onSelect (<code>expression</code>): Callback function when the item is selected.
|
||||
**/
|
||||
|
||||
@@ -28,6 +28,11 @@ Use this directive to generate color swatches to pick from.
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
// Set default to true if not defined
|
||||
if (angular.isUndefined(scope.useColorClass)) {
|
||||
scope.useColorClass = false;
|
||||
}
|
||||
|
||||
scope.setColor = function (color) {
|
||||
scope.selectedColor = color;
|
||||
if (scope.onSelect) {
|
||||
@@ -45,7 +50,9 @@ Use this directive to generate color swatches to pick from.
|
||||
colors: '=?',
|
||||
size: '@',
|
||||
selectedColor: '=',
|
||||
onSelect: '&'
|
||||
onSelect: '&',
|
||||
useLabel: '=',
|
||||
useColorClass: '=?'
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
+11
-1
@@ -125,6 +125,14 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
i--;
|
||||
}
|
||||
|
||||
if (scope.includeSubFolders !== 'true') {
|
||||
if (item.parentId !== parseInt(scope.currentFolderId)) {
|
||||
scope.items.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (scope.items.length > 0) {
|
||||
@@ -316,7 +324,9 @@ Use this directive to generate a thumbnail grid of media items.
|
||||
itemMaxHeight: "@",
|
||||
itemMinWidth: "@",
|
||||
itemMinHeight: "@",
|
||||
onlyImages: "@"
|
||||
onlyImages: "@",
|
||||
includeSubFolders: "@",
|
||||
currentFolderId: "@"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
+2
-1
@@ -221,7 +221,8 @@
|
||||
isClientSide: true
|
||||
});
|
||||
|
||||
newVal += files[i].name + ",";
|
||||
//special check for a comma in the name
|
||||
newVal += files[i].name.replace(',', '-') + ",";
|
||||
|
||||
if (isImage) {
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ angular.module('umbraco.mocks').
|
||||
"content_statistics": "Statistics",
|
||||
"content_titleOptional": "Title (optional)",
|
||||
"content_type": "Type",
|
||||
"content_unPublish": "Unpublish",
|
||||
"content_unpublish": "Unpublish",
|
||||
"content_updateDate": "Last edited",
|
||||
"content_updateDateDesc": "Date/time this document was created",
|
||||
"content_uploadClear": "Remove file",
|
||||
|
||||
@@ -206,7 +206,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.contentResource#unPublish
|
||||
* @name umbraco.resources.contentResource#unpublish
|
||||
* @methodOf umbraco.resources.contentResource
|
||||
*
|
||||
* @description
|
||||
@@ -214,7 +214,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* contentResource.unPublish(1234)
|
||||
* contentResource.unpublish(1234)
|
||||
* .then(function() {
|
||||
* alert("node was unpulished");
|
||||
* }, function(err){
|
||||
@@ -225,21 +225,20 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
unPublish: function (id, culture) {
|
||||
unpublish: function (id, cultures) {
|
||||
if (!id) {
|
||||
throw "id cannot be null";
|
||||
}
|
||||
|
||||
if (!culture) {
|
||||
culture = null;
|
||||
if (!cultures) {
|
||||
cultures = [];
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"contentApiBaseUrl",
|
||||
"PostUnPublish",
|
||||
{ id: id, culture: culture })),
|
||||
"PostUnpublish"), { id: id, cultures: cultures }),
|
||||
'Failed to publish content with id ' + id);
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -7,10 +7,60 @@
|
||||
**/
|
||||
function logResource($q, $http, umbRequestHelper) {
|
||||
|
||||
function isValidDate(input) {
|
||||
if (input) {
|
||||
if (Object.prototype.toString.call(input) === "[object Date]" && !isNaN(input.getTime())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
function dateToValidIsoString(input) {
|
||||
if (isValidDate(input)) {
|
||||
return input.toISOString();
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
//the factory object returned
|
||||
return {
|
||||
|
||||
getPagedEntityLog: function (options) {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.logResource#getPagedEntityLog
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* Gets a paginated log history for a entity
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* var options = {
|
||||
* id : 1234
|
||||
* pageSize : 10,
|
||||
* pageNumber : 1,
|
||||
* orderDirection : "Descending",
|
||||
* sinceDate : new Date(2018,0,1)
|
||||
* };
|
||||
* logResource.getPagedEntityLog(options)
|
||||
* .then(function(log) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Object} options options object
|
||||
* @param {Int} options.id the id of the entity
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 1
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
|
||||
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getPagedEntityLog: function(options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 10,
|
||||
@@ -24,11 +74,15 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
if (options.hasOwnProperty('sinceDate')) {
|
||||
options.sinceDate = dateToValidIsoString(options.sinceDate);
|
||||
}
|
||||
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
} else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
@@ -45,7 +99,37 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
'Failed to retrieve log data for id');
|
||||
},
|
||||
|
||||
getPagedUserLog: function (options) {
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.logResource#getPagedUserLog
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* Gets a paginated log history for the current user
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* var options = {
|
||||
* pageSize : 10,
|
||||
* pageNumber : 1,
|
||||
* orderDirection : "Descending",
|
||||
* sinceDate : new Date(2018,0,1)
|
||||
* };
|
||||
* logResource.getPagedUserLog(options)
|
||||
* .then(function(log) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Object} options options object
|
||||
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
|
||||
* @param {Int} options.pageNumber if paging data, current page index, default = 1
|
||||
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
|
||||
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getPagedUserLog: function(options) {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 10,
|
||||
@@ -59,11 +143,15 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
angular.extend(defaults, options);
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
if (options.hasOwnProperty('sinceDate')) {
|
||||
options.sinceDate = dateToValidIsoString(options.sinceDate);
|
||||
}
|
||||
|
||||
//change asc/desct
|
||||
if (options.orderDirection === "asc") {
|
||||
options.orderDirection = "Ascending";
|
||||
}
|
||||
else if (options.orderDirection === "desc") {
|
||||
} else if (options.orderDirection === "desc") {
|
||||
options.orderDirection = "Descending";
|
||||
}
|
||||
|
||||
@@ -71,7 +159,7 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetPagedEntityLog",
|
||||
"GetPagedCurrentUserLog",
|
||||
options)),
|
||||
'Failed to retrieve log data for id');
|
||||
},
|
||||
@@ -82,6 +170,7 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* <strong>[OBSOLETE] use getPagedEntityLog instead</strong><br />
|
||||
* Gets the log history for a give entity id
|
||||
*
|
||||
* ##usage
|
||||
@@ -96,23 +185,24 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getEntityLog: function (id) {
|
||||
getEntityLog: function(id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetEntityLog",
|
||||
[{ id: id }])),
|
||||
'Failed to retrieve user data for id ' + id);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetEntityLog",
|
||||
[{ id: id }])),
|
||||
'Failed to retrieve user data for id ' + id);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.logResource#getUserLog
|
||||
* @methodOf umbraco.resources.logResource
|
||||
*
|
||||
* @description
|
||||
* Gets the current users' log history for a given type of log entry
|
||||
* <strong>[OBSOLETE] use getPagedUserLog instead</strong><br />
|
||||
* Gets the current user's log history for a given type of log entry
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
@@ -127,14 +217,14 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getUserLog: function (type, since) {
|
||||
getUserLog: function(type, since) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetCurrentUserLog",
|
||||
[{ logtype: type}, {sinceDate: since }])),
|
||||
'Failed to retrieve log data for current user of type ' + type + ' since ' + since);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetCurrentUserLog",
|
||||
[{ logtype: type }, { sinceDate: dateToValidIsoString(since) }])),
|
||||
'Failed to retrieve log data for current user of type ' + type + ' since ' + since);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -158,16 +248,16 @@ function logResource($q, $http, umbRequestHelper) {
|
||||
* @returns {Promise} resourcePromise object containing the log.
|
||||
*
|
||||
*/
|
||||
getLog: function (type, since) {
|
||||
getLog: function(type, since) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetLog",
|
||||
[{ logtype: type}, {sinceDate: since }])),
|
||||
'Failed to retrieve log data of type ' + type + ' since ' + since);
|
||||
}
|
||||
};
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logApiBaseUrl",
|
||||
"GetLog",
|
||||
[{ logtype: type }, { sinceDate: dateToValidIsoString(since) }])),
|
||||
'Failed to retrieve log data of type ' + type + ' since ' + since);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.resources').factory('logResource', logResource);
|
||||
|
||||
@@ -40,6 +40,32 @@
|
||||
{ searchTerm: searchTerm, page: pageIndex, pageSize: pageSize })),
|
||||
'Failed to retrieve data for searching redirect urls');
|
||||
}
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.resources.redirectUrlResource#getRedirectsForContentItem
|
||||
* @methodOf umbraco.resources.redirectUrlResource
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Used to retrieve RedirectUrls for a specific item of content for Information tab
|
||||
* ##usage
|
||||
* <pre>
|
||||
* redirectUrlsResource.getRedirectsForContentItem("udi:123456")
|
||||
* .then(function(response) {
|
||||
*
|
||||
* });
|
||||
* </pre>
|
||||
* @param {String} contentUdi identifier for the content item to retrieve redirects for
|
||||
*/
|
||||
function getRedirectsForContentItem(contentUdi) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"redirectUrlManagementApiBaseUrl",
|
||||
"RedirectUrlsForContentItem",
|
||||
{ contentUdi: contentUdi })),
|
||||
'Failed to retrieve redirects for content: ' + contentUdi);
|
||||
}
|
||||
|
||||
function getEnableState() {
|
||||
|
||||
@@ -50,7 +76,7 @@
|
||||
"GetEnableState")),
|
||||
'Failed to retrieve data to check if the 301 redirect is enabled');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.resources.redirectUrlResource#deleteRedirectUrl
|
||||
@@ -107,7 +133,8 @@
|
||||
searchRedirectUrls: searchRedirectUrls,
|
||||
deleteRedirectUrl: deleteRedirectUrl,
|
||||
toggleUrlTracker: toggleUrlTracker,
|
||||
getEnableState: getEnableState
|
||||
getEnableState: getEnableState,
|
||||
getRedirectsForContentItem: getRedirectsForContentItem
|
||||
};
|
||||
|
||||
return resource;
|
||||
|
||||
@@ -65,17 +65,14 @@ angular.module('umbraco.services')
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads in moment.js requirements during the _loadInitAssets call
|
||||
*/
|
||||
function loadMomentLocaleForCurrentUser() {
|
||||
function getMomentLocales(locales, supportedLocales) {
|
||||
|
||||
var self = this;
|
||||
|
||||
function loadLocales(currentUser, supportedLocales) {
|
||||
var locale = currentUser.locale.toLowerCase();
|
||||
var localeUrls = [];
|
||||
var locales = locales.split(',');
|
||||
for (var i = 0; i < locales.length; i++) {
|
||||
var locale = locales[i].toString().toLowerCase();
|
||||
if (locale !== 'en-us') {
|
||||
var localeUrls = [];
|
||||
|
||||
if (supportedLocales.indexOf(locale + '.js') > -1) {
|
||||
localeUrls.push('lib/moment/' + locale + '.js');
|
||||
}
|
||||
@@ -85,16 +82,35 @@ angular.module('umbraco.services')
|
||||
localeUrls.push('lib/moment/' + majorLocale);
|
||||
}
|
||||
}
|
||||
return self.load(localeUrls, $rootScope);
|
||||
}
|
||||
else {
|
||||
$q.when(true);
|
||||
}
|
||||
}
|
||||
|
||||
return localeUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads specific Moment.js Locales.
|
||||
* @param {any} locales
|
||||
* @param {any} supportedLocales
|
||||
*/
|
||||
function loadLocales(locales, supportedLocales) {
|
||||
var localeUrls = getMomentLocales(locales, supportedLocales);
|
||||
if (localeUrls.length >= 1) {
|
||||
return assetsService.load(localeUrls, $rootScope);
|
||||
}
|
||||
else {
|
||||
$q.when(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads in moment.js requirements during the _loadInitAssets call
|
||||
*/
|
||||
function loadMomentLocaleForCurrentUser() {
|
||||
|
||||
userService.getCurrentUser().then(function (currentUser) {
|
||||
return javascriptLibraryResource.getSupportedLocalesForMoment().then(function (supportedLocales) {
|
||||
return loadLocales(currentUser, supportedLocales);
|
||||
return loadLocales(currentUser.locale, supportedLocales);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -136,7 +152,9 @@ angular.module('umbraco.services')
|
||||
return $q.when(true);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
loadLocales: loadLocales,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.assetsService#loadCss
|
||||
|
||||
@@ -146,7 +146,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
if (!args.methods) {
|
||||
throw "args.methods is not defined";
|
||||
}
|
||||
if (!args.methods.saveAndPublish || !args.methods.sendToPublish || !args.methods.save || !args.methods.unPublish) {
|
||||
if (!args.methods.saveAndPublish || !args.methods.sendToPublish || !args.methods.unpublish) {
|
||||
throw "args.methods does not contain all required defined methods";
|
||||
}
|
||||
|
||||
@@ -179,26 +179,16 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
alias: "sendToPublish",
|
||||
addEllipsis: args.content.variants && args.content.variants.length > 1 ? "true" : "false"
|
||||
};
|
||||
case "A":
|
||||
//save
|
||||
return {
|
||||
letter: ch,
|
||||
labelKey: "buttons_save",
|
||||
handler: args.methods.save,
|
||||
hotKey: "ctrl+s",
|
||||
hotKeyWhenHidden: true,
|
||||
alias: "save",
|
||||
addEllipsis: args.content.variants && args.content.variants.length > 1 ? "true" : "false"
|
||||
};
|
||||
case "Z":
|
||||
//unpublish
|
||||
return {
|
||||
letter: ch,
|
||||
labelKey: "content_unPublish",
|
||||
handler: args.methods.unPublish,
|
||||
labelKey: "content_unpublish",
|
||||
handler: args.methods.unpublish,
|
||||
hotKey: "ctrl+u",
|
||||
hotKeyWhenHidden: true,
|
||||
alias: "unpublish"
|
||||
alias: "unpublish",
|
||||
addEllipsis: args.content.variants && args.content.variants.length > 1 ? "true" : "false"
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
@@ -209,8 +199,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
buttons.subButtons = [];
|
||||
|
||||
//This is the ideal button order but depends on circumstance, we'll use this array to create the button list
|
||||
// Publish, SendToPublish, Save
|
||||
var buttonOrder = ["U", "H", "A"];
|
||||
// Publish, SendToPublish
|
||||
var buttonOrder = ["U", "H"];
|
||||
|
||||
//Create the first button (primary button)
|
||||
//We cannot have the Save or SaveAndPublish buttons if they don't have create permissions when we are creating a new item.
|
||||
@@ -252,7 +242,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
// so long as it's already published and if the user has access to publish
|
||||
// and the user has access to unpublish (may have been removed via Event)
|
||||
if (!args.create) {
|
||||
if (args.content.publishDate && _.contains(args.content.allowedActions, "U") && _.contains(args.content.allowedActions, "Z")) {
|
||||
var hasPublishedVariant = args.content.variants.filter(function(variant) { return (variant.state === "Published" || variant.state === "PublishedPendingChanges"); }).length > 0;
|
||||
if (hasPublishedVariant && _.contains(args.content.allowedActions, "U") && _.contains(args.content.allowedActions, "Z")) {
|
||||
buttons.subButtons.push(createButtonDefinition("Z"));
|
||||
}
|
||||
}
|
||||
@@ -412,8 +403,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
case "Z":
|
||||
return {
|
||||
letter: ch,
|
||||
labelKey: "content_unPublish",
|
||||
handler: "unPublish"
|
||||
labelKey: "content_unpublish",
|
||||
handler: "unpublish"
|
||||
};
|
||||
|
||||
default:
|
||||
|
||||
@@ -85,6 +85,7 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q
|
||||
appState.setSectionState("showSearchResults", false);
|
||||
appState.setGlobalState("stickyNavigation", false);
|
||||
appState.setGlobalState("showTray", false);
|
||||
appState.setMenuState("currentNode", null);
|
||||
|
||||
if (appState.getGlobalState("isTablet") === true) {
|
||||
appState.setGlobalState("showNavigation", false);
|
||||
@@ -365,7 +366,8 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q
|
||||
|
||||
if (appState.getGlobalState("isTablet") === true && !appState.getGlobalState("stickyNavigation")) {
|
||||
//reset it to whatever is in the url
|
||||
appState.setSectionState("currentSection", $routeParams.section);
|
||||
appState.setSectionState("currentSection", $routeParams.section);
|
||||
|
||||
setMode("default-hidesectiontree");
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,6 @@ angular.module('umbraco.services')
|
||||
/** Called to update the current user's timeout */
|
||||
function setUserTimeoutInternal(newTimeout) {
|
||||
|
||||
|
||||
var asNumber = parseFloat(newTimeout);
|
||||
if (!isNaN(asNumber) && currentUser && angular.isNumber(asNumber)) {
|
||||
currentUser.remainingAuthSeconds = newTimeout;
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
@import "components/umb-querybuilder.less";
|
||||
@import "components/umb-pagination.less";
|
||||
@import "components/umb-mini-list-view.less";
|
||||
@import "components/umb-multiple-textbox.less";
|
||||
@import "components/umb-badge.less";
|
||||
@import "components/umb-nested-content.less";
|
||||
@import "components/umb-checkmark.less";
|
||||
|
||||
@@ -227,13 +227,29 @@ input[type="button"] {
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
background: @green;
|
||||
color: white;
|
||||
color: @white;
|
||||
font-weight: bold;
|
||||
&:hover {
|
||||
background: @green-d1;
|
||||
}
|
||||
}
|
||||
|
||||
// outlined
|
||||
.btn-outline {
|
||||
border: 1px solid @gray-8;
|
||||
background: @white;
|
||||
color: @black;
|
||||
padding: 5px 13px;
|
||||
}
|
||||
|
||||
.btn-outline:hover,
|
||||
.btn-outline:focus,
|
||||
.btn-outline:active {
|
||||
border-color: @gray-7;
|
||||
background: transparent;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
// Cross-browser Jank
|
||||
// --------------------------------------------------
|
||||
|
||||
|
||||
@@ -790,13 +790,13 @@ h4.panel-title {
|
||||
}
|
||||
|
||||
.smartphone-portrait {
|
||||
width: 320px;
|
||||
height: 504px;
|
||||
width: 360px;
|
||||
height: 640px;
|
||||
}
|
||||
|
||||
.smartphone-landscape {
|
||||
width: 480px;
|
||||
height: 256px;
|
||||
width: 640px;
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
.border {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
.umb-dashboard__content {
|
||||
padding: 30px 20px;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
.umb-button-group {
|
||||
|
||||
.umb-button__button {
|
||||
border-radius: 3px 0px 0px 3px;
|
||||
border-radius: @baseBorderRadius;
|
||||
}
|
||||
|
||||
.umb-button-group__toggle {
|
||||
border-radius: 0px 3px 3px 0;
|
||||
border-radius: 0px @baseBorderRadius @baseBorderRadius 0;
|
||||
border-left: 1px solid rgba(0,0,0,0.09);
|
||||
margin-left: -2px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
height: 105px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
@@ -114,6 +113,7 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 3px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
background: @gray-10;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: -20px;
|
||||
margin-top: -10px;
|
||||
position: relative;
|
||||
top: 0;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
.umb-prevalues-multivalues__left {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.umb-prevalues-multivalues__right {
|
||||
|
||||
@@ -94,6 +94,10 @@ body.touch .umb-tree {
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
|
||||
&.active {
|
||||
background: @gray-10;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: @gray-10;
|
||||
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
.umb-color-swatches {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
|
||||
.umb-color-box {
|
||||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
padding: 1px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
margin: 5px;
|
||||
border-radius: 3px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
transition: box-shadow .3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover, &:focus {
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
@@ -28,4 +32,55 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.with-labels {
|
||||
|
||||
.umb-color-box {
|
||||
width: 120px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
|
||||
.umb-color-box-inner {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
min-height: 80px;
|
||||
padding-top: 10px;
|
||||
|
||||
.umb-color-box__label {
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
flex: 0 0 100%;
|
||||
padding: 1px 5px;
|
||||
max-width: 100%;
|
||||
margin-top: auto;
|
||||
margin-bottom: -3px;
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
text-indent: 0;
|
||||
text-align: left;
|
||||
border: 1px solid @gray-8;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
overflow: hidden;
|
||||
|
||||
.umb-color-box__name {
|
||||
color: @black;
|
||||
font-weight: bold;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.umb-color-box__description {
|
||||
font-size: 12px;
|
||||
line-height: 1.5em;
|
||||
color: @gray-3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,18 @@
|
||||
background-color: @white;
|
||||
}
|
||||
|
||||
.umb-media-grid__item-file-icon > span {
|
||||
color: @white;
|
||||
background: @gray-4;
|
||||
padding: 1px 3px;
|
||||
font-size: 10px;
|
||||
line-height: 130%;
|
||||
display: block;
|
||||
margin-top: -30px;
|
||||
margin-left: -10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-media-grid__item.-selected {
|
||||
box-shadow: 0 2px 8px 0 rgba(0,0,0,.35);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
.umb-multiple-textbox .textbox-wrapper {
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.umb-multiple-textbox .textbox-wrapper .umb-editor {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.umb-multiple-textbox .textbox-wrapper i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.umb-multiple-textbox .textbox-wrapper i.handle {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.umb-multiple-textbox .textbox-wrapper a.remove {
|
||||
margin-left: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-multiple-textbox .add-link {
|
||||
&:extend(.umb-node-preview-add);
|
||||
}
|
||||
|
||||
.umb-editor-wrapper .umb-multiple-textbox .add-link {
|
||||
&:extend(.umb-editor-wrapper .umb-node-preview);
|
||||
}
|
||||
|
||||
.umb-modal .umb-multiple-textbox .textbox-wrapper .umb-editor {
|
||||
flex: 1 1 auto;
|
||||
width: auto;
|
||||
}
|
||||
@@ -166,7 +166,7 @@ input.umb-table__input {
|
||||
|
||||
}
|
||||
|
||||
.-content .-unpublished {
|
||||
.-content :not(.with-unpublished-version).-unpublished {
|
||||
.umb-table__name > * {
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
@@ -27,5 +27,5 @@
|
||||
|
||||
.umb-permission__description {
|
||||
font-size: 13px;
|
||||
color: @gray-5;
|
||||
color: @gray-4;
|
||||
}
|
||||
|
||||
@@ -133,27 +133,6 @@ div.umb-codeeditor .umb-btn-toolbar {
|
||||
//
|
||||
// Color picker
|
||||
// --------------------------------------------------
|
||||
ul.color-picker li {
|
||||
padding: 2px;
|
||||
margin: 3px;
|
||||
border: 2px solid transparent;
|
||||
width: 60px;
|
||||
|
||||
.thumbnail{
|
||||
min-width: auto;
|
||||
width: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
height: 50px;
|
||||
display:flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor:pointer;
|
||||
margin: 0 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/* pre-value editor */
|
||||
.control-group.color-picker-preval {
|
||||
@@ -174,7 +153,7 @@ ul.color-picker li {
|
||||
div.color-picker-prediv {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
max-width: 80%;
|
||||
max-width: 85%;
|
||||
|
||||
pre {
|
||||
display: inline-flex;
|
||||
@@ -357,13 +336,30 @@ ul.color-picker li {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-icon-holder .icon{
|
||||
.umb-sortable-thumbnails .umb-icon-holder .icon {
|
||||
font-size: 40px;
|
||||
line-height: 50px;
|
||||
color: @gray-3;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-icon-holder .file-icon > span {
|
||||
color: @white;
|
||||
background: @gray-4;
|
||||
padding: 1px 3px;
|
||||
font-size: 10px;
|
||||
line-height: 130%;
|
||||
display: block;
|
||||
margin-top: -30px;
|
||||
width: 2em;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-icon-holder .file-icon + small {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__wrapper {
|
||||
width: 124px;
|
||||
height: 124px;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
function init() {
|
||||
// Check if it is a new user
|
||||
var inviteVal = $location.search().invite;
|
||||
//1 = enter password, 2 = password set, 3 = invalid token
|
||||
if (inviteVal && (inviteVal === "1" || inviteVal === "2")) {
|
||||
|
||||
$q.all([
|
||||
@@ -58,6 +59,8 @@
|
||||
$scope.inviteStep = Number(inviteVal);
|
||||
|
||||
});
|
||||
} else if (inviteVal && inviteVal === "3") {
|
||||
$scope.inviteStep = Number(inviteVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,10 +104,18 @@
|
||||
</umb-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div ng-show="invitedUser == null && inviteStep === 3" ng-if="inviteStep === 3" class="umb-login-container">
|
||||
<div class="form">
|
||||
<h1 style="margin-bottom: 10px; text-align: left;">Hi there</h1>
|
||||
<p style="line-height: 1.6; margin-bottom: 25px;">
|
||||
<localize key="user_userinviteExpiredMessage">Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it.</localize>
|
||||
</p>
|
||||
|
||||
<div ng-show="invitedUser == null" class="umb-login-container">
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="invitedUser == null && !inviteStep" class="umb-login-container">
|
||||
|
||||
<div class="form">
|
||||
<h1>{{greeting}}</h1>
|
||||
|
||||
+1
-1
@@ -313,7 +313,7 @@ angular.module("umbraco")
|
||||
|
||||
function searchMedia() {
|
||||
$scope.loading = true;
|
||||
entityResource.getPagedDescendants($scope.startNodeId, "Media", $scope.searchOptions)
|
||||
entityResource.getPagedDescendants($scope.currentFolder.id, "Media", $scope.searchOptions)
|
||||
.then(function(data) {
|
||||
// update image data to work with image grid
|
||||
angular.forEach(data.items, function(mediaItem) {
|
||||
|
||||
+26
-18
@@ -23,13 +23,19 @@
|
||||
|
||||
<div class="form-search">
|
||||
<i class="icon-search"></i>
|
||||
<input class="umb-search-field search-query -full-width-input"
|
||||
ng-model="searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="changeSearch()"
|
||||
type="text"
|
||||
no-dirty-check />
|
||||
<input class="umb-search-field search-query -full-width-input"
|
||||
ng-model="searchOptions.filter"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_search"
|
||||
ng-change="changeSearch()"
|
||||
type="text"
|
||||
no-dirty-check />
|
||||
<br />
|
||||
<label>
|
||||
<localize key="general_includeFromsubFolders">Include subfolders in search</localize>
|
||||
<input type="checkbox" ng-model="showChilds"
|
||||
ng-change="changeSearch()">
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="upload-button">
|
||||
@@ -81,17 +87,19 @@
|
||||
</umb-file-dropzone>
|
||||
|
||||
<umb-media-grid
|
||||
ng-if="!loading"
|
||||
items="images"
|
||||
on-click="clickHandler"
|
||||
on-click-name="clickItemName"
|
||||
on-click-edit="editMediaItem(item)"
|
||||
allow-on-click-edit="{{allowMediaEdit}}"
|
||||
item-max-width="150"
|
||||
item-max-height="150"
|
||||
item-min-width="100"
|
||||
item-min-height="100"
|
||||
only-images={{onlyImages}}>
|
||||
ng-if="!loading"
|
||||
items="images"
|
||||
on-click="clickHandler"
|
||||
on-click-name="clickItemName"
|
||||
on-click-edit="editMediaItem(item)"
|
||||
allow-on-click-edit="{{allowMediaEdit}}"
|
||||
item-max-width="150"
|
||||
item-max-height="150"
|
||||
item-min-width="100"
|
||||
item-min-height="100"
|
||||
only-images={{onlyImages}}
|
||||
include-sub-folders={{showChilds}}
|
||||
current-Folder-id="{{currentFolder.id}}">
|
||||
</umb-media-grid>
|
||||
|
||||
<div class="flex justify-center">
|
||||
|
||||
@@ -39,12 +39,23 @@
|
||||
<umb-button
|
||||
alias="preview"
|
||||
ng-if="!page.isNew && content.allowPreview && page.showPreviewButton"
|
||||
type="button"
|
||||
button-style="info"
|
||||
type="button"
|
||||
button-style="outline"
|
||||
action="preview(content)"
|
||||
label="Preview page"
|
||||
label-key="buttons_showPage">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
ng-if="page.showSaveButton"
|
||||
alias="save"
|
||||
type="button"
|
||||
button-style="info"
|
||||
state="page.saveButtonState"
|
||||
action="save(content)"
|
||||
label-key="buttons_save"
|
||||
shortcut="ctrl+s"
|
||||
add-ellipsis="{{page.saveButtonEllipsis}}">
|
||||
</umb-button>
|
||||
|
||||
<umb-button-group
|
||||
ng-if="defaultButton && !content.trashed && !infiniteModel.infiniteMode"
|
||||
|
||||
@@ -22,6 +22,23 @@
|
||||
</ul>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
<umb-box data-element="node-info-redirects" style="display:none;" ng-cloak ng-show="!urlTrackerDisabled && hasRedirects">
|
||||
<umb-box-header title-key="redirectUrls_redirectUrlManagement"></umb-box-header>
|
||||
<umb-box-content class="block-form">
|
||||
<div style="position: relative;">
|
||||
<div ng-if="loadingRedirectUrls" style="background: rgba(255, 255, 255, 0.8); position: absolute; top: 0; left: 0; right: 0; bottom: 0;"></div>
|
||||
<umb-load-indicator ng-if="loadingRedirectUrls"></umb-load-indicator>
|
||||
<div ng-show="hasRedirects">
|
||||
<p><localize key="redirectUrls_panelInformation" class="ng-isolate-scope ng-scope">The following URLs redirect to this content item:</localize></p>
|
||||
<ul class="nav nav-stacked" style="margin-bottom: 0;">
|
||||
<li ng-repeat="redirectUrl in redirectUrls">
|
||||
<a href="{{redirectUrl.originalUrl}}" target="_blank"><i ng-class="value.icon" class="icon-out"></i> {{redirectUrl.originalUrl}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
<umb-box data-element="node-info-history">
|
||||
<umb-box-header title-key="general_history"></umb-box-header>
|
||||
@@ -67,6 +84,7 @@
|
||||
class="history-item__badge"
|
||||
size="xs"
|
||||
color="{{item.logTypeColor}}">
|
||||
|
||||
<localize key="auditTrails_small{{ item.logType }}">{{ item.logType }}</localize>
|
||||
</umb-badge>
|
||||
<span>
|
||||
@@ -179,7 +197,7 @@
|
||||
</div>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group data-element="node-info-create-date" label="@template_createdDate">
|
||||
<umb-control-group ng-if="node.id !== 0" data-element="node-info-create-date" label="@template_createdDate">
|
||||
{{node.createDateFormatted}} <localize key="general_by">by</localize> {{ node.owner.name }}
|
||||
</umb-control-group>
|
||||
|
||||
@@ -209,7 +227,7 @@
|
||||
</div>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group data-element="node-info-id" label="Id">
|
||||
<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>
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
<div ng-if="notification.view">
|
||||
<div ng-include="notification.view"></div>
|
||||
</div>
|
||||
|
||||
<div ng-if="notification.headline">
|
||||
<a ng-href="{{notification.url}}" target="_blank">
|
||||
<div ng-if="notification.headline" ng-switch on="{{notification}}">
|
||||
<a ng-href="{{notification.url}}" ng-switch-when="{{notification.url && notification.url.trim() != ''}}" target="_blank">
|
||||
<strong>{{notification.headline}}</strong>
|
||||
<span ng-bind-html="notification.message"></span>
|
||||
</a>
|
||||
<div ng-switch-default>
|
||||
<strong>{{notification.headline}}</strong>
|
||||
<span ng-bind-html="notification.message"></span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<div class="umb-color-swatches">
|
||||
<div class="umb-color-swatches" ng-class="{ 'with-labels': useLabel }">
|
||||
|
||||
<button class="umb-color-box umb-color-box--{{size}} btn-{{color.value}}" ng-repeat="color in colors" title="{{color.name}}" ng-click="setColor(color.value)">
|
||||
<div class="check_circle" ng-if="color.value === selectedColor">
|
||||
<i class="icon icon-check small"></i>
|
||||
<button type="button" class="umb-color-box umb-color-box--{{size}} btn-{{color.value}}" ng-repeat="color in colors" title="{{color.label}}" hex-bg-inline="{{useColorClass === false}}" hex-bg-color="{{color.value}}" ng-class="{ 'active': color.value === selectedColor }" ng-click="setColor(color.value)">
|
||||
<div class="umb-color-box-inner">
|
||||
<div class="check_circle" ng-if="color.value === selectedColor">
|
||||
<i class="icon icon-check small"></i>
|
||||
</div>
|
||||
<div class="umb-color-box__label" ng-if="useLabel">
|
||||
<div class="umb-color-box__name truncate">{{ color.label }}</div>
|
||||
<div class="umb-color-box__description">#{{ color.value }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,23 +5,26 @@
|
||||
<umb-editor-sub-header-content-right>
|
||||
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
alias="compositions"
|
||||
ng-if="compositions !== false"
|
||||
type="button"
|
||||
button-style="link"
|
||||
button-style="outline"
|
||||
label-key="contentTypeEditor_compositions"
|
||||
icon="icon-merge"
|
||||
action="openCompositionsDialog()">
|
||||
action="openCompositionsDialog()"
|
||||
size="xs">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
alias="reorder"
|
||||
ng-if="sorting !== false"
|
||||
type="button"
|
||||
button-style="link"
|
||||
button-style="outline"
|
||||
label-key="{{sortingButtonKey}}"
|
||||
icon="icon-navigation"
|
||||
action="toggleSortingMode();">
|
||||
action="toggleSortingMode();"
|
||||
size="xs">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-sub-header-content-right>
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
<img class="umb-media-grid__item-image-placeholder" ng-if="!item.thumbnail && item.extension != 'svg'" src="assets/img/transparent.png" alt="{{item.name}}" draggable="false" />
|
||||
|
||||
<!-- Icon for files -->
|
||||
<i class="umb-media-grid__item-icon {{item.icon}}" ng-if="!item.thumbnail && item.extension != 'svg'"></i>
|
||||
|
||||
<span class="umb-media-grid__item-file-icon" ng-if="!item.thumbnail && item.extension != 'svg'">
|
||||
<i class="umb-media-grid__item-icon {{item.icon}}"></i>
|
||||
<span>.{{item.extension}}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
ng-class="{
|
||||
'-selected':item.selected,
|
||||
'-published':item.published,
|
||||
'-unpublished':!item.published
|
||||
'-unpublished':!item.published,
|
||||
'with-unpublished-version':!item.published && item.hasPublishedVersion
|
||||
}"
|
||||
ng-click="vm.selectItem(item, $index, $event)">
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}">
|
||||
<span style="margin-bottom: 2px;">{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
</label>
|
||||
|
||||
<div ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</div>
|
||||
|
||||
<div ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}">
|
||||
<span style="margin-bottom: 2px;">{{ variant.language.name }}</span>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
</label>
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}">
|
||||
<span style="margin-bottom: 2px;">{{ variant.language.name }}</span>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
</label>
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function UnpublishController($scope, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
var autoSelectedVariants = [];
|
||||
|
||||
vm.changeSelection = changeSelection;
|
||||
vm.publishedVariantFilter = publishedVariantFilter;
|
||||
vm.unpublishedVariantFilter = unpublishedVariantFilter;
|
||||
|
||||
function onInit() {
|
||||
|
||||
vm.variants = $scope.model.variants;
|
||||
|
||||
// set dialog title
|
||||
if (!$scope.model.title) {
|
||||
localizationService.localize("content_unpublish").then(function (value) {
|
||||
$scope.model.title = value;
|
||||
});
|
||||
}
|
||||
|
||||
// node has variants
|
||||
if (vm.variants.length !== 1) {
|
||||
//now sort it so that the current one is at the top
|
||||
vm.variants = _.sortBy(vm.variants, function (v) {
|
||||
return v.active ? 0 : 1;
|
||||
});
|
||||
|
||||
var active = _.find(vm.variants, function (v) {
|
||||
return v.active;
|
||||
});
|
||||
|
||||
if (active) {
|
||||
//ensure that the current one is selected
|
||||
active.save = true;
|
||||
}
|
||||
|
||||
// autoselect other variants if needed
|
||||
changeSelection(active);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function changeSelection(selectedVariant) {
|
||||
|
||||
// disable submit button if nothing is selected
|
||||
var firstSelected = _.find(vm.variants, function (v) {
|
||||
return v.save;
|
||||
});
|
||||
$scope.model.disableSubmitButton = !firstSelected; //disable submit button if there is none selected
|
||||
|
||||
// if a mandatory variant is selected we want to selet all other variants
|
||||
// and disable selection for the others
|
||||
if(selectedVariant.save && selectedVariant.language.isMandatory) {
|
||||
|
||||
angular.forEach(vm.variants, function(variant){
|
||||
if(!variant.save && publishedVariantFilter(variant)) {
|
||||
// keep track of the variants we automaically select
|
||||
// so we can remove the selection again
|
||||
autoSelectedVariants.push(variant.language.culture);
|
||||
variant.save = true;
|
||||
}
|
||||
variant.disabled = true;
|
||||
});
|
||||
|
||||
// make sure the mandatory isn't disabled so we can deselect again
|
||||
selectedVariant.disabled = false;
|
||||
|
||||
}
|
||||
|
||||
// if a mandatory variant is deselected we want to deselet all the variants
|
||||
// that was automatically selected so it goes back to the state before the mandatory language was selected.
|
||||
// We also want to enable all checkboxes again
|
||||
if(!selectedVariant.save && selectedVariant.language.isMandatory) {
|
||||
|
||||
angular.forEach(vm.variants, function(variant){
|
||||
|
||||
// check if variant was auto selected, then deselect
|
||||
if(_.contains(autoSelectedVariants, variant.language.culture)) {
|
||||
variant.save = false;
|
||||
};
|
||||
|
||||
variant.disabled = false;
|
||||
});
|
||||
autoSelectedVariants = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function publishedVariantFilter(variant) {
|
||||
//determine a variant is 'published' (meaning it will show up as able unpublish)
|
||||
// * it has been published
|
||||
// * it has been published with pending changes
|
||||
return (variant.state === "Published" || variant.state === "PublishedPendingChanges");
|
||||
}
|
||||
|
||||
function unpublishedVariantFilter(variant) {
|
||||
//determine a variant is 'modified' (meaning it will NOT show up as able to unpublish)
|
||||
// * it's editor is in a $dirty state
|
||||
// * it is published with pending changes
|
||||
return (variant.state !== "Published" && variant.state !== "PublishedPendingChanges");
|
||||
}
|
||||
|
||||
//when this dialog is closed, remove all unpublish and disabled flags
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var i = 0; i < vm.variants.length; i++) {
|
||||
vm.variants[i].save = false;
|
||||
vm.variants[i].disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
onInit();
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Overlays.UnpublishController", UnpublishController);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,66 @@
|
||||
<div ng-controller="Umbraco.Overlays.UnpublishController as vm">
|
||||
|
||||
<!-- 1 language -->
|
||||
<div ng-if="vm.variants.length === 1">
|
||||
<p><localize key="prompt_confirmUnpublish"></localize></p>
|
||||
</div>
|
||||
|
||||
<!-- Multiple languages -->
|
||||
<div ng-if="vm.variants.length > 1">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<p><localize key="content_languagesToUnpublish"></localize></p>
|
||||
</div>
|
||||
|
||||
<div class="umb-list umb-list--condensed">
|
||||
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.publishedVariantFilter">
|
||||
<ng-form name="unpublishVariantSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{variant.htmlId}}"
|
||||
name="unpublishVariantSelector"
|
||||
type="checkbox"
|
||||
ng-model="variant.save"
|
||||
ng-change="vm.changeSelection(variant)"
|
||||
ng-disabled="variant.disabled"
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
</label>
|
||||
|
||||
<div class="umb-permission__description">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div class="umb-list umb-list--condensed" ng-if="!vm.loading && (vm.variants | filter:vm.unpublishedVariantFilter).length > 0">
|
||||
<div style="margin-bottom: 15px; font-weight: bold;">
|
||||
<p><localize key="content_unpublishedLanguages"></localize></p>
|
||||
</div>
|
||||
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.unpublishedVariantFilter">
|
||||
<div>
|
||||
<div style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,20 +1,15 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.ColorPickerController">
|
||||
|
||||
<div ng-if="!isConfigured" >
|
||||
<localize key="colorpicker_noColors">You haven't defined any colors</localize>
|
||||
</div>
|
||||
<div ng-if="!isConfigured">
|
||||
<localize key="colorpicker_noColors">You haven't defined any colors</localize>
|
||||
</div>
|
||||
|
||||
<ul class="thumbnails color-picker">
|
||||
<li ng-repeat="(key, val) in model.config.items">
|
||||
<a ng-click="toggleItem(val)" class="thumbnail" hex-bg-color="{{val.value}}">
|
||||
<div class="check_circle" ng-if="isActiveColor(val)">
|
||||
<i class="icon icon-check small"></i>
|
||||
</div>
|
||||
</a>
|
||||
<span class="color-label" ng-if="model.useLabel" ng-bind="val.label"></span>
|
||||
</li>
|
||||
</ul>
|
||||
<umb-color-swatches colors="model.config.items"
|
||||
selected-color="model.value.value"
|
||||
size="m"
|
||||
use-label="model.useLabel">
|
||||
</umb-color-swatches>
|
||||
|
||||
<input type="hidden" name="modelValue" ng-model="model.value" val-property-validator="validateMandatory"/>
|
||||
<input type="hidden" name="modelValue" ng-model="model.value" val-property-validator="validateMandatory" />
|
||||
|
||||
</div>
|
||||
|
||||
+2
@@ -33,6 +33,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
|
||||
/** Performs validation based on the renderModel data */
|
||||
function validate() {
|
||||
if ($scope.contentPickerForm) {
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
//Validate!
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
|
||||
@@ -199,6 +200,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
|
||||
_.each(model.selection, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
}
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
editorService.close();
|
||||
|
||||
@@ -42,8 +42,9 @@
|
||||
</umb-image-gravity>
|
||||
<a href class="btn btn-link btn-crop-delete" ng-click="clear()"><i class="icon-delete red"></i> <localize key="content_uploadClear">Remove file</localize></a>
|
||||
</div>
|
||||
|
||||
<ul class="umb-sortable-thumbnails cropList clearfix">
|
||||
|
||||
|
||||
<ul ng-if="!imageSrc.endsWith('.svg')" class="umb-sortable-thumbnails cropList clearfix">
|
||||
<li ng-repeat=" (key,value) in model.value.crops" ng-class="{'current':currentCrop.alias === value.alias}" ng-click="crop(value)">
|
||||
|
||||
<umb-image-thumbnail center="model.value.focalPoint"
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
</umb-empty-state>
|
||||
|
||||
<umb-empty-state
|
||||
ng-if="vm.itemsWithoutFolders.length === 0 && options.filter.length > 0"
|
||||
ng-if="vm.itemsWithoutFolders.length === 0 && folders.length === 0 && options.filter.length > 0"
|
||||
position="center">
|
||||
<localize key="general_searchNoResult"></localize>
|
||||
</umb-empty-state>
|
||||
|
||||
+12
-22
@@ -227,10 +227,6 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
},
|
||||
500);
|
||||
|
||||
if (reload === true) {
|
||||
$scope.reloadView($scope.contentId, true);
|
||||
}
|
||||
|
||||
if (successMsg) {
|
||||
localizationService.localize("bulk_done")
|
||||
.then(function (v) {
|
||||
@@ -260,12 +256,13 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
with simple values */
|
||||
|
||||
$scope.getContent = function (contentId) {
|
||||
$scope.reloadView($scope.contentId, true);
|
||||
|
||||
$scope.reloadView($scope.contentId);
|
||||
}
|
||||
|
||||
$scope.reloadView = function (id, reloadFolders) {
|
||||
|
||||
$scope.reloadView = function (id) {
|
||||
$scope.viewLoaded = false;
|
||||
$scope.folders = [];
|
||||
|
||||
listViewHelper.clearSelection($scope.listViewResultSet.items, $scope.folders, $scope.selection);
|
||||
|
||||
@@ -278,20 +275,13 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
if ($scope.listViewResultSet.items) {
|
||||
_.each($scope.listViewResultSet.items, function (e, index) {
|
||||
setPropertyValues(e);
|
||||
});
|
||||
}
|
||||
if (e.contentTypeAlias === 'Folder') {
|
||||
$scope.folders.push(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (reloadFolders && $scope.entityType === 'media') {
|
||||
//The folders aren't loaded - we only need to do this once since we're never changing node ids
|
||||
mediaResource.getChildFolders($scope.contentId)
|
||||
.then(function (page) {
|
||||
$scope.folders = page.items;
|
||||
$scope.viewLoaded = true;
|
||||
});
|
||||
|
||||
} else {
|
||||
$scope.viewLoaded = true;
|
||||
}
|
||||
$scope.viewLoaded = true;
|
||||
|
||||
//NOTE: This might occur if we are requesting a higher page number than what is actually available, for example
|
||||
// if you have more than one page and you delete all items on the last page. In this case, we need to reset to the last
|
||||
@@ -421,7 +411,7 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
|
||||
$scope.unpublish = function () {
|
||||
applySelected(
|
||||
function (selected, index) { return contentResource.unPublish(getIdCallback(selected[index])); },
|
||||
function (selected, index) { return contentResource.unpublish(getIdCallback(selected[index])); },
|
||||
function (count, total) {
|
||||
var key = (total === 1 ? "bulk_unpublishedItemOfItem" : "bulk_unpublishedItemOfItems");
|
||||
return localizationService.localize(key, [count, total]);
|
||||
@@ -609,7 +599,7 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
$scope.options.allowBulkMove ||
|
||||
$scope.options.allowBulkDelete;
|
||||
|
||||
$scope.reloadView($scope.contentId, true);
|
||||
$scope.reloadView($scope.contentId);
|
||||
}
|
||||
|
||||
function getLocalizedKey(alias) {
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
|
||||
<!-- FILE -->
|
||||
<span class="umb-icon-holder" ng-hide="image.thumbnail || image.metaData.umbracoExtension.Value === 'svg' || image.extension === 'svg'">
|
||||
<i class="icon {{image.icon}} large"></i>
|
||||
<span class="file-icon">
|
||||
<i class="icon {{image.icon}} large"></i>
|
||||
<span>.{{image.extension}}</span>
|
||||
</span>
|
||||
<small>{{image.name}}</small>
|
||||
</span>
|
||||
|
||||
|
||||
@@ -395,7 +395,9 @@ angular.module("umbraco")
|
||||
var unsubscribe = $scope.$on("formSubmitting", function () {
|
||||
//TODO: Here we should parse out the macro rendered content so we can save on a lot of bytes in data xfer
|
||||
// we do parse it out on the server side but would be nice to do that on the client side before as well.
|
||||
$scope.model.value = tinyMceEditor ? tinyMceEditor.getContent() : null;
|
||||
if (tinyMceEditor !== undefined && tinyMceEditor != null && !$scope.isLoading) {
|
||||
$scope.model.value = tinyMceEditor.getContent();
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.textAreaController">
|
||||
<ng-form name="textareaFieldForm">
|
||||
<textarea ng-model="model.value" id="{{model.alias}}" name="textarea" rows="10" class="umb-property-editor umb-textarea textstring" val-server="value" ng-keyup="model.change()"></textarea>
|
||||
<textarea ng-model="model.value" id="{{model.alias}}" name="textarea" rows="{{model.config.rows || 10}}" class="umb-property-editor umb-textarea textstring" val-server="value" ng-keyup="model.change()"></textarea>
|
||||
|
||||
<span ng-messages="textareaFieldForm.textarea.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
<umb-editor-sub-header-section>
|
||||
<umb-button
|
||||
type="button"
|
||||
label="Clear selection"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
label-key="buttons_clearSelection"
|
||||
action="vm.clearSelection()"
|
||||
disabled="actionInProgress">
|
||||
@@ -62,48 +62,52 @@
|
||||
</umb-editor-sub-header-content-left>
|
||||
|
||||
<umb-editor-sub-header-content-right ng-if="vm.selection.length > 0">
|
||||
<div style="margin-right: 5px;">
|
||||
<umb-button
|
||||
ng-if="vm.allowSetUserGroup"
|
||||
type="button" size="xs"
|
||||
label-key="actions_setGroup"
|
||||
icon="icon-users"
|
||||
action="vm.openBulkUserGroupPicker()">
|
||||
</umb-button>
|
||||
</div>
|
||||
<div style="margin-right: 5px;">
|
||||
<umb-button
|
||||
ng-if="vm.allowEnableUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
state="vm.enableUserButtonState"
|
||||
label-key="actions_enable"
|
||||
icon="icon-check"
|
||||
action="vm.enableUsers()">
|
||||
</umb-button>
|
||||
</div>
|
||||
<div style="margin-right: 5px;">
|
||||
<umb-button
|
||||
ng-if="vm.allowUnlockUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
state="vm.unlockUserButtonState"
|
||||
label-key="actions_unlock"
|
||||
icon="icon-unlocked"
|
||||
action="vm.unlockUsers()">
|
||||
</umb-button>
|
||||
</div>
|
||||
<div>
|
||||
<umb-button
|
||||
ng-if="vm.allowDisableUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
state="vm.disableUserButtonState"
|
||||
label-key="actions_disable"
|
||||
icon="icon-block"
|
||||
action="vm.disableUsers()">
|
||||
</umb-button>
|
||||
</div>
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
ng-if="vm.allowSetUserGroup"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
label-key="actions_setGroup"
|
||||
icon="icon-users"
|
||||
action="vm.openBulkUserGroupPicker()">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
ng-if="vm.allowEnableUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
state="vm.enableUserButtonState"
|
||||
label-key="actions_enable"
|
||||
icon="icon-check"
|
||||
action="vm.enableUsers()">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
ng-if="vm.allowUnlockUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
state="vm.unlockUserButtonState"
|
||||
label-key="actions_unlock"
|
||||
icon="icon-unlocked"
|
||||
action="vm.unlockUsers()">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
ng-if="vm.allowDisableUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
state="vm.disableUserButtonState"
|
||||
label-key="actions_disable"
|
||||
icon="icon-block"
|
||||
action="vm.disableUsers()">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-sub-header-content-right>
|
||||
|
||||
</umb-editor-sub-header>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="7.0.1" />
|
||||
<PackageReference Include="CSharpTest.Net.Collections" Version="14.906.1403.1082" />
|
||||
<PackageReference Include="ClientDependency" Version="1.9.6" />
|
||||
<PackageReference Include="ClientDependency" Version="1.9.7" />
|
||||
<PackageReference Include="ClientDependency-Mvc5" Version="1.8.0.0" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta025" />
|
||||
<PackageReference Include="ImageProcessor.Web" Version="4.9.3.25" />
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
<key alias="statistics">Statistika</key>
|
||||
<key alias="titleOptional">Titulek (volitelně)</key>
|
||||
<key alias="type">Typ</key>
|
||||
<key alias="unPublish">Nepublikovat</key>
|
||||
<key alias="unpublish">Nepublikovat</key>
|
||||
<key alias="updateDate">Naposledy změněno</key>
|
||||
<key alias="updateDateDesc" version="7.0">Datum/čas poslední změny dokumentu</key>
|
||||
<key alias="uploadClear">Odebrat soubor(y)</key>
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
<key alias="smallMove">Flyttet</key>
|
||||
<key alias="smallSave">Gemt</key>
|
||||
<key alias="smallDelete">Slettet</key>
|
||||
<key alias="smallUnPublish">Afpubliceret</key>
|
||||
<key alias="smallUnpublish">Afpubliceret</key>
|
||||
<key alias="smallRollBack">Indhold tilbagerullet</key>
|
||||
<key alias="smallSendToPublish">Sendt til udgivelse</key>
|
||||
<key alias="smallSendToTranslate">Sendt til oversættelse</key>
|
||||
@@ -229,7 +229,7 @@
|
||||
<key alias="titleOptional">Titel (valgfri)</key>
|
||||
<key alias="altTextOptional">Alternativ tekst (valgfri)</key>
|
||||
<key alias="type">Type</key>
|
||||
<key alias="unPublish">Afpublicér</key>
|
||||
<key alias="unpublish">Afpublicér</key>
|
||||
<key alias="unpublished">Afpubliceret</key>
|
||||
<key alias="updateDate">Sidst redigeret</key>
|
||||
<key alias="updateDateDesc" version="7.0">Tidspunkt for seneste redigering</key>
|
||||
@@ -1619,4 +1619,4 @@ Mange hilsner fra Umbraco robotten
|
||||
<key alias="noRestoreRelation">Der findes ikke nogen "Genopret" relation for dette dokument/medie. Brug "Flyt" muligheden fra menuen for at flytte det manuelt.</key>
|
||||
<key alias="restoreUnderRecycled">Det dokument/medie du ønsker at genoprette under ('%0%') er i skraldespanden. Brug "Flyt" muligheden fra menuen for at flytte det manuelt.</key>
|
||||
</area>
|
||||
</language>
|
||||
</language>
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
<key alias="titleOptional">Titel (optional)</key>
|
||||
<key alias="altTextOptional">Alternativtext (optional)</key>
|
||||
<key alias="type">Typ</key>
|
||||
<key alias="unPublish">Veröffentlichung widerrufen</key>
|
||||
<key alias="unpublish">Veröffentlichung widerrufen</key>
|
||||
<key alias="updateDate">Zuletzt bearbeitet am</key>
|
||||
<key alias="updateDateDesc" version="7.0">Letzter Änderungszeitpunkt des Dokuments</key>
|
||||
<key alias="uploadClear">Datei entfernen</key>
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
<area alias="auditTrails">
|
||||
<key alias="atViewingFor">Viewing for</key>
|
||||
<key alias="delete">Delete Content performed by user</key>
|
||||
<key alias="unpublish">UnPublish performed by user</key>
|
||||
<key alias="unpublish">Unpublish performed by user</key>
|
||||
<key alias="publish">Save and Publish performed by user</key>
|
||||
<key alias="save">Save Content performed by user</key>
|
||||
<key alias="move">Move Content performed by user</key>
|
||||
@@ -159,7 +159,7 @@
|
||||
<key alias="smallMove">Move</key>
|
||||
<key alias="smallSave">Save</key>
|
||||
<key alias="smallDelete">Delete</key>
|
||||
<key alias="smallUnPublish">Unpublish</key>
|
||||
<key alias="smallUnpublish">Unpublish</key>
|
||||
<key alias="smallRollBack">Rollback</key>
|
||||
<key alias="smallSendToPublish">Send To Publish</key>
|
||||
<key alias="smallSendToTranslate">Send To Translation</key>
|
||||
@@ -238,7 +238,7 @@
|
||||
<key alias="titleOptional">Title (optional)</key>
|
||||
<key alias="altTextOptional">Alternative text (optional)</key>
|
||||
<key alias="type">Type</key>
|
||||
<key alias="unPublish">Unpublish</key>
|
||||
<key alias="unpublish">Unpublish</key>
|
||||
<key alias="unpublished">Unpublished</key>
|
||||
<key alias="updateDate">Last edited</key>
|
||||
<key alias="updateDateDesc" version="7.0">Date/time this document was edited</key>
|
||||
@@ -687,6 +687,7 @@
|
||||
<key alias="embed">Embed</key>
|
||||
<key alias="retrieve">Retrieve</key>
|
||||
<key alias="selected">selected</key>
|
||||
<key alias="includeFromsubFolders">Include subfolders in search</key>
|
||||
</area>
|
||||
|
||||
<area alias="colors">
|
||||
@@ -1688,8 +1689,8 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
|
||||
<key alias="tabHasNoSortOrder">tab has no sort order</key>
|
||||
|
||||
<key alias="compositionUsageHeading">Where is this composition used?</key>
|
||||
<key alias="compositionUsageSpecification">This composition is currently used in the composition of the following content types:</key>
|
||||
<key alias="compositionUsageHeading">Where is this composition used?</key>
|
||||
<key alias="compositionUsageSpecification">This composition is currently used in the composition of the following content types:</key>
|
||||
</area>
|
||||
|
||||
<area alias="modelsBuilder">
|
||||
@@ -1863,7 +1864,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="goToProfile">Go to user profile</key>
|
||||
<key alias="groupsHelp">Add groups to assign access and permissions</key>
|
||||
<key alias="inviteAnotherUser">Invite another user</key>
|
||||
<key alias="inviteUserHelp">Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco.</key>
|
||||
<key alias="inviteUserHelp">Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. Invites last for 72 hours.</key>
|
||||
<key alias="language">Language</key>
|
||||
<key alias="languageHelp">Set the language you will see in menus and dialogs</key>
|
||||
<key alias="lastLockoutDate">Last lockout date</key>
|
||||
@@ -1927,6 +1928,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="userInvited">has been invited</key>
|
||||
<key alias="userInvitedSuccessHelp">An invitation has been sent to the new user with details about how to log in to Umbraco.</key>
|
||||
<key alias="userinviteWelcomeMessage">Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we just need you to setup a password and add a picture for your avatar.</key>
|
||||
<key alias="userinviteExpiredMessage">Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it.</key>
|
||||
<key alias="userinviteAvatarMessage">Upload a picture to make it easy for other users to recognize you.</key>
|
||||
<key alias="writer">Writer</key>
|
||||
<key alias="translator">Translator</key>
|
||||
@@ -2185,6 +2187,8 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="enableUrlTracker">Enable URL tracker</key>
|
||||
<key alias="originalUrl">Original URL</key>
|
||||
<key alias="redirectedTo">Redirected To</key>
|
||||
<key alias="redirectUrlManagement">Redirect Url Management</key>
|
||||
<key alias="panelInformation">The following URLs redirect to this content item:</key>
|
||||
<key alias="noRedirects">No redirects have been made</key>
|
||||
<key alias="noRedirectsDescription">When a published page gets renamed or moved a redirect will automatically be made to the new page.</key>
|
||||
<key alias="removeButton">Remove</key>
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
<area alias="auditTrails">
|
||||
<key alias="atViewingFor">Viewing for</key>
|
||||
<key alias="delete">Delete Content performed by user</key>
|
||||
<key alias="unpublish">UnPublish performed by user</key>
|
||||
<key alias="unpublish">Unpublish performed by user</key>
|
||||
<key alias="publish">Save and Publish performed by user</key>
|
||||
<key alias="save">Save Content performed by user</key>
|
||||
<key alias="move">Move Content performed by user</key>
|
||||
@@ -162,7 +162,7 @@
|
||||
<key alias="smallMove">Move</key>
|
||||
<key alias="smallSave">Save</key>
|
||||
<key alias="smallDelete">Delete</key>
|
||||
<key alias="smallUnPublish">Unpublish</key>
|
||||
<key alias="smallUnpublish">Unpublish</key>
|
||||
<key alias="smallRollBack">Rollback</key>
|
||||
<key alias="smallSendToPublish">Send To Publish</key>
|
||||
<key alias="smallSendToTranslate">Send To Translation</key>
|
||||
@@ -243,7 +243,7 @@
|
||||
<key alias="titleOptional">Title (optional)</key>
|
||||
<key alias="altTextOptional">Alternative text (optional)</key>
|
||||
<key alias="type">Type</key>
|
||||
<key alias="unPublish">Unpublish</key>
|
||||
<key alias="unpublish">Unpublish</key>
|
||||
<key alias="unpublished">Draft</key>
|
||||
<key alias="notCreated">Not created</key>
|
||||
<key alias="updateDate">Last edited</key>
|
||||
@@ -266,7 +266,9 @@
|
||||
<key alias="languagesToPublish">What languages would you like to publish?</key>
|
||||
<key alias="languagesToSave">What languages would you like to save?</key>
|
||||
<key alias="languagesToSendForApproval">What languages would you like to send for approval?</key>
|
||||
<key alias="languagesToUnpublish">Select the languages to unpublish. Unpublishing a mandatory language will unpublish all languages.</key>
|
||||
<key alias="publishedLanguages">Published Languages</key>
|
||||
<key alias="unpublishedLanguages">Unpublished Languages</key>
|
||||
<key alias="unmodifiedLanguages">Unmodified Languages</key>
|
||||
<key alias="readyToPublish">Ready to Publish?</key>
|
||||
<key alias="readyToSave">Ready to Save?</key>
|
||||
@@ -700,6 +702,7 @@
|
||||
<key alias="embed">Embed</key>
|
||||
<key alias="retrieve">Retrieve</key>
|
||||
<key alias="selected">selected</key>
|
||||
<key alias="includeFromsubFolders">Include subfolders in search</key>
|
||||
</area>
|
||||
<area alias="colors">
|
||||
<key alias="black">Black</key>
|
||||
@@ -1435,7 +1438,8 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="templateSavedHeader">Template saved</key>
|
||||
<key alias="templateSavedText">Template saved without any errors!</key>
|
||||
<key alias="contentUnpublished">Content unpublished</key>
|
||||
<key alias="contentVariationUnpublished">Content variation %0% unpublished</key>
|
||||
<key alias="contentCultureUnpublished">Content variation %0% unpublished</key>
|
||||
<key alias="contentMandatoryCultureUnpublished">The mandatory language '%0%' was unpublished. All languages for this content item are now unpublished.</key>
|
||||
<key alias="partialViewSavedHeader">Partial view saved</key>
|
||||
<key alias="partialViewSavedText">Partial view saved without any errors!</key>
|
||||
<key alias="partialViewErrorHeader">Partial view not saved</key>
|
||||
@@ -1700,13 +1704,13 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
|
||||
<key alias="tabHasNoSortOrder">tab has no sort order</key>
|
||||
|
||||
<key alias="compositionUsageHeading">Where is this composition used?</key>
|
||||
<key alias="compositionUsageSpecification">This composition is currently used in the composition of the following content types:</key>
|
||||
<key alias="compositionUsageHeading">Where is this composition used?</key>
|
||||
<key alias="compositionUsageSpecification">This composition is currently used in the composition of the following content types:</key>
|
||||
</area>
|
||||
|
||||
<area alias="languages">
|
||||
<key alias="addLanguage">Add language</key>
|
||||
<key alias="mandatoryLanguage">Mandatory</key>
|
||||
<key alias="mandatoryLanguage">Mandatory language</key>
|
||||
<key alias="mandatoryLanguageHelp">Properties on this language have to be filled out before the node can be published.</key>
|
||||
<key alias="defaultLanguage">Default language</key>
|
||||
<key alias="defaultLanguageHelp">An Umbraco site can only have one default language set.</key>
|
||||
@@ -1888,7 +1892,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="goToProfile">Go to user profile</key>
|
||||
<key alias="groupsHelp">Add groups to assign access and permissions</key>
|
||||
<key alias="inviteAnotherUser">Invite another user</key>
|
||||
<key alias="inviteUserHelp">Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco.</key>
|
||||
<key alias="inviteUserHelp">Invite new users to give them access to Umbraco. An invite email will be sent to the user with information on how to log in to Umbraco. Invites last for 72 hours.</key>
|
||||
<key alias="language">Language</key>
|
||||
<key alias="languageHelp">Set the language you will see in menus and dialogs</key>
|
||||
<key alias="lastLockoutDate">Last lockout date</key>
|
||||
@@ -1952,6 +1956,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="userInvited">has been invited</key>
|
||||
<key alias="userInvitedSuccessHelp">An invitation has been sent to the new user with details about how to log in to Umbraco.</key>
|
||||
<key alias="userinviteWelcomeMessage">Hello there and welcome to Umbraco! In just 1 minute you’ll be good to go, we just need you to setup a password and add a picture for your avatar.</key>
|
||||
<key alias="userinviteExpiredMessage">Welcome to Umbraco! Unfortunately your invite has expired. Please contact your administrator and ask them to resend it.</key>
|
||||
<key alias="userinviteAvatarMessage">Upload a picture to make it easy for other users to recognize you.</key>
|
||||
<key alias="writer">Writer</key>
|
||||
<key alias="translator">Translator</key>
|
||||
@@ -2212,6 +2217,8 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="enableUrlTracker">Enable URL tracker</key>
|
||||
<key alias="originalUrl">Original URL</key>
|
||||
<key alias="redirectedTo">Redirected To</key>
|
||||
<key alias="redirectUrlManagement">Redirect Url Management</key>
|
||||
<key alias="panelInformation">The following URLs redirect to this content item:</key>
|
||||
<key alias="noRedirects">No redirects have been made</key>
|
||||
<key alias="noRedirectsDescription">When a published page gets renamed or moved a redirect will automatically be made to the new page.</key>
|
||||
<key alias="removeButton">Remove</key>
|
||||
|
||||
@@ -203,7 +203,7 @@
|
||||
<key alias="titleOptional">Título (opcional)</key>
|
||||
<key alias="altTextOptional">Texto alternativo (opcional)</key>
|
||||
<key alias="type">Tipo</key>
|
||||
<key alias="unPublish">Ocultar</key>
|
||||
<key alias="unpublish">Ocultar</key>
|
||||
<key alias="updateDate">Última actualización</key>
|
||||
<key alias="updateDateDesc" version="7.0">Fecha/hora este documento fue modificado</key>
|
||||
<key alias="uploadClear">Eliminar archivo</key>
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
<key alias="smallMove">Déplacement</key>
|
||||
<key alias="smallSave">Sauvegarde</key>
|
||||
<key alias="smallDelete">Suppression</key>
|
||||
<key alias="smallUnPublish">Dépublication</key>
|
||||
<key alias="smallUnpublish">Dépublication</key>
|
||||
<key alias="smallRollBack">Récupération</key>
|
||||
<key alias="smallSendToPublish">Envoi pour publication</key>
|
||||
<key alias="smallSendToTranslate">Envoi pour traduction</key>
|
||||
@@ -234,7 +234,7 @@
|
||||
<key alias="titleOptional">Titre (optionnel)</key>
|
||||
<key alias="altTextOptional">Texte alternatif (optionnel)</key>
|
||||
<key alias="type">Type</key>
|
||||
<key alias="unPublish">Dépublier</key>
|
||||
<key alias="unpublish">Dépublier</key>
|
||||
<key alias="unpublished">Dépublié</key>
|
||||
<key alias="updateDate">Dernière édition</key>
|
||||
<key alias="updateDateDesc" version="7.0">Date/heure à laquelle ce document a été édité</key>
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
<key alias="statistics">סטטיסטיקות</key>
|
||||
<key alias="titleOptional">כותרת (לא חובה)</key>
|
||||
<key alias="type">סוג</key>
|
||||
<key alias="unPublish">ממתין לפירסום</key>
|
||||
<key alias="unpublish">ממתין לפירסום</key>
|
||||
<key alias="updateDate">נערך לאחרונה</key>
|
||||
<key alias="uploadClear">הסר קובץ</key>
|
||||
<key alias="urls">קשר למסמך</key>
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<key alias="statistics">Statistiche</key>
|
||||
<key alias="titleOptional">Titolo (opzionale)</key>
|
||||
<key alias="type">Tipo</key>
|
||||
<key alias="unPublish">Non pubblicare</key>
|
||||
<key alias="unpublish">Non pubblicare</key>
|
||||
<key alias="updateDate">Ultima modifica</key>
|
||||
<key alias="uploadClear">Rimuovi il file</key>
|
||||
<key alias="urls">Link al documento</key>
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
<key alias="titleOptional">タイトル (オプション)</key>
|
||||
<key alias="altTextOptional">代替テキスト (オプション)</key>
|
||||
<key alias="type">型</key>
|
||||
<key alias="unPublish">非公開</key>
|
||||
<key alias="unpublish">非公開</key>
|
||||
<key alias="updateDate">最終更新日時</key>
|
||||
<key alias="updateDateDesc" version="7.0">このドキュメントが最後に更新された日時</key>
|
||||
<key alias="uploadClear">ファイルの消去</key>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<key alias="statistics">통계</key>
|
||||
<key alias="titleOptional">제목(옵션)</key>
|
||||
<key alias="type">유형</key>
|
||||
<key alias="unPublish">발행취소</key>
|
||||
<key alias="unpublish">발행취소</key>
|
||||
<key alias="updateDate">마지막 수정일</key>
|
||||
<key alias="uploadClear">파일 삭제</key>
|
||||
<key alias="urls">문서에 링크</key>
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
<key alias="titleOptional">Tittel (valgfri)</key>
|
||||
<key alias="altTextOptional">Alternativ tekst (valgfri)</key>
|
||||
<key alias="type">Type</key>
|
||||
<key alias="unPublish">Avpubliser</key>
|
||||
<key alias="unpublish">Avpubliser</key>
|
||||
<key alias="updateDate">Sist endret</key>
|
||||
<key alias="updateDateDesc" version="7.0">Tidspunkt for siste endring</key>
|
||||
<key alias="uploadClear">Fjern fil</key>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user