Merge branch 'temp8' into temp8-ui-cleanup
This commit is contained in:
+9
-8
@@ -179,6 +179,15 @@
|
||||
variant.variants[i].active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// keep track of the open variants across the different split views
|
||||
// push the first variant then update the variant index based on the editor index
|
||||
if(vm.openVariants && vm.openVariants.length === 0) {
|
||||
vm.openVariants.push(variant.language.culture);
|
||||
} else {
|
||||
vm.openVariants[editorIndex] = variant.language.culture;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//then assign the variant to a view model to the content app
|
||||
@@ -186,14 +195,6 @@
|
||||
return a.alias === "content";
|
||||
});
|
||||
contentApp.viewModel = variant;
|
||||
|
||||
// keep track of the open variants across the different split views
|
||||
// push the first variant then update the variant index based on the editor index
|
||||
if(vm.openVariants && vm.openVariants.length === 0) {
|
||||
vm.openVariants.push(variant.language.culture);
|
||||
} else {
|
||||
vm.openVariants[editorIndex] = variant.language.culture;
|
||||
}
|
||||
|
||||
// make sure the same app it set to active in the new variant
|
||||
if(activeAppAlias) {
|
||||
|
||||
@@ -204,6 +204,29 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.navigationService#retainQueryStrings
|
||||
* @methodOf umbraco.services.navigationService
|
||||
*
|
||||
* @description
|
||||
* Will check the next route parameters to see if any of the query strings that should be retained from the previous route are missing,
|
||||
* if they are they will be merged and an object containing all route parameters is returned. If nothing should be changed, then null is returned.
|
||||
* @param {Object} currRouteParams The current route parameters
|
||||
* @param {Object} nextRouteParams The next route parameters
|
||||
*/
|
||||
retainQueryStrings: function (currRouteParams, nextRouteParams) {
|
||||
var toRetain = angular.copy(nextRouteParams);
|
||||
var updated = false;
|
||||
_.each(retainedQueryStrings, function (r) {
|
||||
if (currRouteParams[r] && !nextRouteParams[r]) {
|
||||
toRetain[r] = currRouteParams[r];
|
||||
updated = true;
|
||||
}
|
||||
});
|
||||
return updated ? toRetain : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.navigationService#load
|
||||
|
||||
@@ -122,12 +122,25 @@ app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlH
|
||||
$route.reload();
|
||||
}
|
||||
else {
|
||||
//check if the location being changed is only the mculture query string, if so, cancel the routing since this is just
|
||||
//used as a global persistent query string that does not change routes.
|
||||
|
||||
|
||||
//check if the location being changed is only due to global/state query strings which means the location change
|
||||
//isn't actually going to cause a route change.
|
||||
if (navigationService.isRouteChangingNavigation(currentRouteParams, next.params)) {
|
||||
//continue the route
|
||||
$route.reload();
|
||||
//The location change will cause a route change. We need to ensure that the global/state
|
||||
//query strings have not been stripped out. If they have, we'll re-add them and re-route.
|
||||
|
||||
var toRetain = navigationService.retainQueryStrings(currentRouteParams, next.params);
|
||||
if (toRetain) {
|
||||
$route.updateParams(toRetain);
|
||||
}
|
||||
else {
|
||||
//continue the route
|
||||
$route.reload();
|
||||
}
|
||||
}
|
||||
else {
|
||||
//navigation is not changing but we should update the currentRouteParams to include all current parameters
|
||||
currentRouteParams = angular.copy(next.params);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
}
|
||||
|
||||
.umb-content-grid__icon.-light {
|
||||
color: @gray-8;
|
||||
color: @gray-5;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
}
|
||||
|
||||
.umb-content-grid__item-name.-light {
|
||||
color: @gray-8;
|
||||
color: @gray-5;
|
||||
}
|
||||
|
||||
.umb-content-grid__details-list {
|
||||
@@ -69,7 +69,7 @@
|
||||
}
|
||||
|
||||
.umb-content-grid__details-list.-light {
|
||||
color: @gray-8;
|
||||
color: @gray-5;
|
||||
}
|
||||
|
||||
.umb-content-grid__details-label {
|
||||
|
||||
@@ -15,12 +15,16 @@
|
||||
{{ item.name }}
|
||||
</div>
|
||||
|
||||
<ul class="umb-content-grid__details-list" ng-class="{'-light': !item.published&& item.updater != null}">
|
||||
<li class="umb-content-grid__details-item" ng-repeat="property in contentProperties">
|
||||
<div class="umb-content-grid__details-label">{{ property.header }}:</div>
|
||||
<div class="umb-content-grid__details-value">{{ item[property.alias] }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="umb-content-grid__details-list" ng-class="{'-light': !item.published && item.updater != null}">
|
||||
<li class="umb-content-grid__details-item" ng-if="item.state">
|
||||
<div class="umb-content-grid__details-label"><localize key="general_status"></localize>:</div>
|
||||
<div class="umb-content-grid__details-value"><umb-variant-state variant="item"></umb-variant-state></div>
|
||||
</li>
|
||||
<li class="umb-content-grid__details-item" ng-repeat="property in contentProperties">
|
||||
<div class="umb-content-grid__details-label">{{ property.header }}:</div>
|
||||
<div class="umb-content-grid__details-value">{{ item[property.alias] }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -32,4 +36,4 @@
|
||||
<localize key="content_noItemsToShow">There are no items to show</localize>
|
||||
</umb-empty-state>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
<i class="umb-table-head__icon icon" ng-class="{'icon-navigation-up': isSortDirection('Name', 'asc'), 'icon-navigation-down': isSortDirection('Name', 'desc')}"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="umb-table-cell" ng-if="items[0].state">
|
||||
<localize key="general_status">Status</localize>
|
||||
</div>
|
||||
<div class="umb-table-cell" ng-repeat="column in itemProperties">
|
||||
<a class="umb-table-head__link" title="Sort by {{ column.header }}" href="#"
|
||||
ng-click="sort(column.alias, column.allowSorting, column.isSystem)"
|
||||
@@ -46,6 +49,11 @@
|
||||
ng-bind="item.name">
|
||||
</a>
|
||||
</div>
|
||||
<div class="umb-table-cell" ng-if="item.state">
|
||||
<umb-variant-state
|
||||
variant="item">
|
||||
</umb-variant-state>
|
||||
</div>
|
||||
<div class="umb-table-cell" ng-repeat="column in itemProperties">
|
||||
<span title="{{column.header}}: {{item[column.alias]}}">
|
||||
|
||||
|
||||
+454
-446
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Validation;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
@@ -22,8 +20,11 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "createDate")]
|
||||
public DateTime CreateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating if this item is published or not based on it's <see cref="State"/>
|
||||
/// </summary>
|
||||
[DataMember(Name = "published")]
|
||||
public bool Published { get; set; }
|
||||
public bool Published => State == ContentSavedState.Published || State == ContentSavedState.PublishedPendingChanges;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the content item is a draft
|
||||
@@ -44,6 +45,16 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "sortOrder")]
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The saved/published state of an item
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is nullable since it's only relevant for content (non-content like media + members will be null)
|
||||
/// </remarks>
|
||||
[DataMember(Name = "state")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public ContentSavedState? State { get; set; }
|
||||
|
||||
protected bool Equals(ContentItemBasic other)
|
||||
{
|
||||
return Id == other.Id;
|
||||
|
||||
@@ -8,21 +8,21 @@
|
||||
/// <summary>
|
||||
/// The item isn't created yet
|
||||
/// </summary>
|
||||
NotCreated,
|
||||
NotCreated = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The item is saved but isn't published
|
||||
/// </summary>
|
||||
Draft,
|
||||
Draft = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The item is published and there are no pending changes
|
||||
/// </summary>
|
||||
Published,
|
||||
Published = 3,
|
||||
|
||||
/// <summary>
|
||||
/// The item is published and there are pending changes
|
||||
/// </summary>
|
||||
PublishedPendingChanges
|
||||
PublishedPendingChanges = 4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace Umbraco.Web.Models.Mapping
|
||||
var contentTypeBasicResolver = new ContentTypeBasicResolver<IContent, ContentItemDisplay>();
|
||||
var defaultTemplateResolver = new DefaultTemplateResolver();
|
||||
var variantResolver = new ContentVariantResolver(localizationService);
|
||||
var contentSavedStateResolver = new ContentSavedStateResolver();
|
||||
|
||||
//FROM IContent TO ContentItemDisplay
|
||||
CreateMap<IContent, ContentItemDisplay>()
|
||||
@@ -67,7 +66,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Segment, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Language, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.State, opt => opt.ResolveUsing(contentSavedStateResolver))
|
||||
.ForMember(dest => dest.State, opt => opt.ResolveUsing<ContentSavedStateResolver<ContentPropertyDisplay>>())
|
||||
.ForMember(dest => dest.Tabs, opt => opt.ResolveUsing(tabsAndPropertiesResolver));
|
||||
|
||||
//FROM IContent TO ContentItemBasic<ContentPropertyBasic, IContent>
|
||||
@@ -81,63 +80,76 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias))
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.UpdateDate, opt => opt.ResolveUsing<CultureUpdateDateResolver>())
|
||||
.ForMember(dest => dest.Published, opt => opt.ResolveUsing<CulturePublishedResolver>())
|
||||
.ForMember(dest => dest.Name, opt => opt.ResolveUsing<CultureNameResolver>());
|
||||
.ForMember(dest => dest.UpdateDate, opt => opt.ResolveUsing<UpdateDateResolver>())
|
||||
.ForMember(dest => dest.Name, opt => opt.ResolveUsing<NameResolver>())
|
||||
.ForMember(dest => dest.State, opt => opt.ResolveUsing<ContentBasicSavedStateResolver<ContentPropertyBasic>>());
|
||||
|
||||
//FROM IContent TO ContentPropertyCollectionDto
|
||||
//NOTE: the property mapping for cultures relies on a culture being set in the mapping context
|
||||
CreateMap<IContent, ContentPropertyCollectionDto>();
|
||||
}
|
||||
}
|
||||
|
||||
internal class CultureUpdateDateResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, DateTime>
|
||||
{
|
||||
public DateTime Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, DateTime destMember, ResolutionContext context)
|
||||
/// <summary>
|
||||
/// Resolves the update date for a content item/content variant
|
||||
/// </summary>
|
||||
private class UpdateDateResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, DateTime>
|
||||
{
|
||||
var culture = context.GetCulture();
|
||||
|
||||
//a culture needs to be in the context for a variant content item
|
||||
if (culture == null || source.ContentType.VariesByCulture() == false)
|
||||
return source.UpdateDate;
|
||||
|
||||
var pubDate = source.GetPublishDate(culture);
|
||||
return pubDate.HasValue ? pubDate.Value : source.UpdateDate;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CulturePublishedResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, bool>
|
||||
{
|
||||
public bool Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, bool destMember, ResolutionContext context)
|
||||
{
|
||||
var culture = context.GetCulture();
|
||||
|
||||
//a culture needs to be in the context for a variant content item
|
||||
if (culture == null || source.ContentType.VariesByCulture() == false)
|
||||
return source.Published;
|
||||
|
||||
return source.IsCulturePublished(culture);
|
||||
}
|
||||
}
|
||||
|
||||
internal class CultureNameResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, string>
|
||||
{
|
||||
public string Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, string destMember, ResolutionContext context)
|
||||
{
|
||||
var culture = context.GetCulture();
|
||||
|
||||
//a culture needs to be in the context for a variant content item
|
||||
if (culture == null || source.ContentType.VariesByCulture() == false)
|
||||
return source.Name;
|
||||
|
||||
if (source.CultureNames.TryGetValue(culture, out var name) && !string.IsNullOrWhiteSpace(name))
|
||||
public DateTime Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, DateTime destMember, ResolutionContext context)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"({ source.Name })";
|
||||
var culture = context.GetCulture();
|
||||
|
||||
//a culture needs to be in the context for a variant content item
|
||||
if (culture == null || source.ContentType.VariesByCulture() == false)
|
||||
return source.UpdateDate;
|
||||
|
||||
var pubDate = source.GetPublishDate(culture);
|
||||
return pubDate.HasValue ? pubDate.Value : source.UpdateDate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the published flag for a content item/content variant
|
||||
/// </summary>
|
||||
private class PublishedResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, bool>
|
||||
{
|
||||
public bool Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, bool destMember, ResolutionContext context)
|
||||
{
|
||||
var culture = context.GetCulture();
|
||||
|
||||
//a culture needs to be in the context for a variant content item
|
||||
if (culture == null || source.ContentType.VariesByCulture() == false)
|
||||
return source.Published;
|
||||
|
||||
return source.IsCulturePublished(culture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the name for a content item/content variant
|
||||
/// </summary>
|
||||
private class NameResolver : IValueResolver<IContent, ContentItemBasic<ContentPropertyBasic>, string>
|
||||
{
|
||||
public string Resolve(IContent source, ContentItemBasic<ContentPropertyBasic> destination, string destMember, ResolutionContext context)
|
||||
{
|
||||
var culture = context.GetCulture();
|
||||
|
||||
//a culture needs to be in the context for a variant content item
|
||||
if (culture == null || source.ContentType.VariesByCulture() == false)
|
||||
return source.Name;
|
||||
|
||||
if (source.CultureNames.TryGetValue(culture, out var name) && !string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"({ source.Name })";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,9 +6,30 @@ using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class ContentSavedStateResolver : IValueResolver<IContent, ContentVariantDisplay, ContentSavedState>
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="ContentSavedState?"/> for an <see cref="IContent"/> item
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class ContentBasicSavedStateResolver<T> : IValueResolver<IContent, IContentProperties<T>, ContentSavedState?>
|
||||
where T : ContentPropertyBasic
|
||||
{
|
||||
public ContentSavedState Resolve(IContent source, ContentVariantDisplay destination, ContentSavedState destMember, ResolutionContext context)
|
||||
private readonly ContentSavedStateResolver<T> _inner = new ContentSavedStateResolver<T>();
|
||||
|
||||
public ContentSavedState? Resolve(IContent source, IContentProperties<T> destination, ContentSavedState? destMember, ResolutionContext context)
|
||||
{
|
||||
return _inner.Resolve(source, destination, default, context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="ContentSavedState"/> for an <see cref="IContent"/> item
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class ContentSavedStateResolver<T> : IValueResolver<IContent, IContentProperties<T>, ContentSavedState>
|
||||
where T : ContentPropertyBasic
|
||||
{
|
||||
public ContentSavedState Resolve(IContent source, IContentProperties<T> destination, ContentSavedState destMember, ResolutionContext context)
|
||||
{
|
||||
PublishedState publishedState;
|
||||
bool isEdited;
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.TreeNodeUrl, opt => opt.ResolveUsing(contentTreeNodeUrlResolver))
|
||||
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Errors, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Published, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.State, opt => opt.UseValue<ContentSavedState?>(null))
|
||||
.ForMember(dest => dest.Edited, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
@@ -62,7 +62,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
|
||||
.ForMember(dest => dest.Trashed, opt => opt.MapFrom(src => src.Trashed))
|
||||
.ForMember(dest => dest.ContentTypeAlias, opt => opt.MapFrom(src => src.ContentType.Alias))
|
||||
.ForMember(dest => dest.Published, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.State, opt => opt.UseValue<ContentSavedState?>(null))
|
||||
.ForMember(dest => dest.Edited, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.MembershipScenario, opt => opt.ResolveUsing(src => membershipScenarioMappingResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Notifications, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Errors, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Published, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.State, opt => opt.UseValue<ContentSavedState?>(null))
|
||||
.ForMember(dest => dest.Edited, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
@@ -91,7 +91,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
|
||||
.ForMember(dest => dest.Username, opt => opt.MapFrom(src => src.Username))
|
||||
.ForMember(dest => dest.Trashed, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Published, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.State, opt => opt.UseValue<ContentSavedState?>(null))
|
||||
.ForMember(dest => dest.Edited, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
@@ -115,7 +115,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.Path, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.SortOrder, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Published, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.State, opt => opt.UseValue(ContentSavedState.Draft))
|
||||
.ForMember(dest => dest.Edited, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Trashed, opt => opt.Ignore())
|
||||
|
||||
Reference in New Issue
Block a user