Merge branch 'v8/dev' into temp8-server-content-validation-fixes-4884

This commit is contained in:
Stephan
2019-04-02 14:03:02 +02:00
47 changed files with 257 additions and 307 deletions

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Compose
private static void ContentService_Moved(IContentService sender, MoveEventArgs<IContent> e)
{
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContent.ToInvariantString())))
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinContentString)))
{
var relationService = Current.Services.RelationService;
const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias;
@@ -37,7 +37,7 @@ namespace Umbraco.Core.Compose
private static void MediaService_Moved(IMediaService sender, MoveEventArgs<IMedia> e)
{
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinMedia.ToInvariantString())))
foreach (var item in e.MoveInfoCollection.Where(x => x.OriginalPath.Contains(Constants.System.RecycleBinMediaString)))
{
var relationService = Current.Services.RelationService;
const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias;

View File

@@ -93,7 +93,6 @@ namespace Umbraco.Core
/// </summary>
public const string DisableElectionForSingleServer = "Umbraco.Core.DisableElectionForSingleServer";
/// <summary>
/// Debug specific web.config AppSetting keys for Umbraco
/// </summary>

View File

@@ -145,11 +145,11 @@
public const string PartialViewMacros = "partialViewMacros";
public const string LogViewer = "logViewer";
public const string LogViewer = "logViewer";
public static class Groups
{
public const string Settings = "settingsGroup";
public const string Settings = "settingsGroup";
public const string Templating = "templatingGroup";

View File

@@ -92,10 +92,10 @@ namespace Umbraco.Core
/// </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>
/// 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>
@@ -209,71 +209,71 @@ namespace Umbraco.Core
public static Dictionary<string, PropertyType> GetStandardPropertyTypeStubs()
{
return new Dictionary<string, PropertyType>
{
{
Comments,
new PropertyType(PropertyEditors.Aliases.TextArea, ValueStorageType.Ntext, true, Comments)
{
Comments,
new PropertyType(PropertyEditors.Aliases.TextArea, ValueStorageType.Ntext, true, Comments)
{
Name = CommentsLabel
}
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
}
},
{
IsApproved,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsApproved)
{
Name = IsApprovedLabel
}
},
{
IsLockedOut,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsLockedOut)
{
Name = IsLockedOutLabel
}
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
Name = CommentsLabel
}
};
},
{
FailedPasswordAttempts,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
{
Name = FailedPasswordAttemptsLabel
}
},
{
IsApproved,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsApproved)
{
Name = IsApprovedLabel
}
},
{
IsLockedOut,
new PropertyType(PropertyEditors.Aliases.Boolean, ValueStorageType.Integer, true, IsLockedOut)
{
Name = IsLockedOutLabel
}
},
{
LastLockoutDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
{
Name = LastLockoutDateLabel
}
},
{
LastLoginDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
{
Name = LastLoginDateLabel
}
},
{
LastPasswordChangeDate,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
{
Name = LastPasswordChangeDateLabel
}
},
{
PasswordAnswer,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
{
Name = PasswordAnswerLabel
}
},
{
PasswordQuestion,
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
{
Name = PasswordQuestionLabel
}
}
};
}
}

View File

@@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{
public static class Icons
{
/// <summary>
/// System contenttype icon
/// </summary>
@@ -42,12 +34,10 @@ namespace Umbraco.Core
/// </summary>
public const string MemberType = "icon-users";
/// <summary>
/// System member icon
/// </summary>
public const string Template = "icon-layout";
}
}
}

View File

@@ -1,7 +1,4 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{

View File

@@ -123,7 +123,6 @@ namespace Umbraco.Core
public static readonly Guid Template = new Guid(Strings.Template);
public static readonly Guid ContentItem = new Guid(Strings.ContentItem);
}
}
}

View File

@@ -3,7 +3,7 @@
public static partial class Constants
{
/// <summary>
/// Defines the constants used for the Umbraco package repository
/// Defines the constants used for the Umbraco package repository
/// </summary>
public static class PackageRepository
{

View File

@@ -34,7 +34,6 @@ namespace Umbraco.Core
/// </summary>
public const string ContentPicker = "Umbraco.ContentPicker";
/// <summary>
/// DateTime.
/// </summary>

View File

@@ -1,7 +1,4 @@
using System;
using System.ComponentModel;
namespace Umbraco.Core
namespace Umbraco.Core
{
public static partial class Constants
{
@@ -22,7 +19,6 @@ namespace Umbraco.Core
public const string PreviewCookieName = "UMB_PREVIEW";
public const string InstallerCookieName = "umb_installId";
}
}
}

View File

@@ -151,22 +151,22 @@ namespace Umbraco.Core.Models
internal static bool HasContentRootAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasContentBinAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContent.ToInvariantString(), user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinContentString, user.CalculateContentStartNodeIds(entityService), Constants.System.RecycleBinContent);
}
internal static bool HasMediaRootAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.Root.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RootString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasMediaBinAccess(this IUser user, IEntityService entityService)
{
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMedia.ToInvariantString(), user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
return ContentPermissionsHelper.HasPathAccess(Constants.System.RecycleBinMediaString, user.CalculateMediaStartNodeIds(entityService), Constants.System.RecycleBinMedia);
}
internal static bool HasPathAccess(this IUser user, IContent content, IEntityService entityService)
@@ -327,7 +327,7 @@ namespace Umbraco.Core.Models
? entityService.GetAllPaths(objectType, asn).ToDictionary(x => x.Id, x => x.Path)
: new Dictionary<int, string>();
paths[Constants.System.Root] = Constants.System.Root.ToString(); // entityService does not get that one
paths[Constants.System.Root] = Constants.System.RootString; // entityService does not get that one
var binPath = GetBinPath(objectType);

View File

@@ -69,7 +69,7 @@ namespace Umbraco.Core
public const string Tag = /*TableNamePrefix*/ "cms" + "Tags";
public const string TagRelationship = /*TableNamePrefix*/ "cms" + "TagRelationship";
public const string KeyValue = TableNamePrefix + "KeyValue";
public const string AuditEntry = TableNamePrefix + "Audit";

View File

@@ -61,7 +61,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
// move to parent (or -1), update path, save
moving.ParentId = parentId;
var movingPath = moving.Path + ","; // save before changing
moving.Path = (container == null ? Constants.System.Root.ToString() : container.Path) + "," + moving.Id;
moving.Path = (container == null ? Constants.System.RootString : container.Path) + "," + moving.Id;
moving.Level = container == null ? 1 : container.Level + 1;
Save(moving);

View File

@@ -534,7 +534,7 @@ namespace Umbraco.Core.Services.Implement
//null check otherwise we get exceptions
if (content.Path.IsNullOrWhiteSpace()) return Enumerable.Empty<IContent>();
var rootId = Constants.System.Root.ToInvariantString();
var rootId = Constants.System.RootString;
var ids = content.Path.Split(',')
.Where(x => x != rootId && x != content.Id.ToString(CultureInfo.InvariantCulture)).Select(int.Parse).ToArray();
if (ids.Any() == false)
@@ -1909,7 +1909,7 @@ namespace Umbraco.Core.Services.Implement
// if uow is not immediate, content.Path will be updated only when the UOW commits,
// and because we want it now, we have to calculate it by ourselves
//paths[content.Id] = content.Path;
paths[content.Id] = (parent == null ? (parentId == Constants.System.RecycleBinContent ? "-1,-20" : "-1") : parent.Path) + "," + content.Id;
paths[content.Id] = (parent == null ? (parentId == Constants.System.RecycleBinContent ? "-1,-20" : Constants.System.RootString) : parent.Path) + "," + content.Id;
const int pageSize = 500;
var page = 0;

View File

@@ -995,7 +995,7 @@ namespace Umbraco.Core.Services.Implement
// if uow is not immediate, content.Path will be updated only when the UOW commits,
// and because we want it now, we have to calculate it by ourselves
//paths[media.Id] = media.Path;
paths[media.Id] = (parent == null ? (parentId == Constants.System.RecycleBinMedia ? "-1,-21" : "-1") : parent.Path) + "," + media.Id;
paths[media.Id] = (parent == null ? (parentId == Constants.System.RecycleBinMedia ? "-1,-21" : Constants.System.RootString) : parent.Path) + "," + media.Id;
const int pageSize = 500;
var page = 0;

View File

@@ -20,7 +20,7 @@ namespace Umbraco.Core
internal static Dictionary<string, UdiType> GetTypes()
{
return new Dictionary<string,UdiType>
return new Dictionary<string, UdiType>
{
{ Unknown, UdiType.Unknown },

View File

@@ -13,7 +13,12 @@ angular.module("umbraco.directives")
// TODO: A lot of the code below should be shared between the grid rte and the normal rte
var promises = [];
//To id the html textarea we need to use the datetime ticks because we can have multiple rte's per a single property alias
// because now we have to support having 2x (maybe more at some stage) content editors being displayed at once. This is because
// we have this mini content editor panel that can be launched with MNTP.
scope.textAreaHtmlId = scope.uniqueId + "_" + String.CreateGuid();
//queue file loading
if (typeof (tinymce) === "undefined") {
promises.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", scope));
@@ -34,7 +39,7 @@ angular.module("umbraco.directives")
var tinyMceEditor = null;
promises.push(tinyMceService.getTinyMceEditorConfig({
htmlId: scope.uniqueId,
htmlId: scope.textAreaHtmlId,
stylesheets: editorConfig.stylesheets,
toolbar: editorConfig.toolbar,
mode: editorConfig.mode
@@ -145,17 +150,11 @@ angular.module("umbraco.directives")
}
});
//listen for formSubmitting event (the result is callback used to remove the event subscription)
var formSubmittingListener = scope.$on("formSubmitting", function () {
scope.value = tinyMceEditor ? tinyMceEditor.getContent() : null;
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise if this is part of a modal, the listener still exists because the dom
// element might still be there even after the modal has been hidden.
scope.$on('$destroy', function () {
formSubmittingListener();
eventsService.unsubscribe(tabShownListener);
//ensure we unbind this in case the blur doesn't fire above
$('.umb-panel-body').off('scroll', pinToolbar);

View File

@@ -128,9 +128,10 @@
position: relative;
margin-bottom: 40px;
padding-top: 10px;
border: 1px solid @grayLighter;
&:hover {
background-color: @grayLighter;
border-color: @grayLight;
}
&[ng-click],
@@ -161,15 +162,16 @@
}
.umb-grid .umb-row .umb-cell-placeholder {
min-height: 130px;
background-color: @gray-10;
border-width: 2px;
min-height: 88px;
border-width: 1px;
border-style: dashed;
border-color: @gray-8;
border-color: @ui-action-discreet-border;
color: @ui-action-discreet-type;
transition: border-color 100ms linear;
&:hover {
border-color: @blueMid;
border-color: @ui-action-discreet-border-hover;
color: @ui-action-discreet-type-hover;
cursor: pointer;
}
}
@@ -207,9 +209,9 @@
}
.umb-grid .cell-tools-add {
color: @ui-action-type;
color: @ui-action-discreet-type;
&:focus, &:hover {
color: @ui-action-type-hover;
color: @ui-action-discreet-type-hover;
text-decoration: none;
}
}
@@ -219,16 +221,18 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: @ui-action-type;
color: @ui-action-discreet-type;
}
.umb-grid .cell-tools-add.-bar {
display: block;
background: @gray-10;
text-align: center;
padding: 5px;
border: 1px dashed @gray-7;
border: 1px dashed @ui-action-discreet-border;
margin: 10px;
&:focus, &:hover {
border-color: @ui-action-discreet-border-hover;
}
}
@@ -249,7 +253,6 @@
.umb-grid .cell-tools-edit {
display: inline-block;
color: @white;
}
.umb-grid .drop-overlay {
@@ -412,36 +415,17 @@
// Row states
.umb-grid .umb-row.-active {
background-color: @ui-action-type;
border-color: @ui-action-type;
.umb-row-title-bar {
cursor: move;
}
.row-tool,
.umb-row-title {
color: @white;
}
.umb-grid-has-config {
color: fade(@white, 66);
}
.umb-cell {
.umb-grid-has-config {
color: fade(@black, 44);
}
}
.umb-cell .umb-cell-content {
border-color: transparent;
}
}
.umb-grid .umb-row.-active-child {
background-color: @gray-10;
.umb-row-title-bar {
cursor: inherit;
}
@@ -449,22 +433,7 @@
.umb-row-title {
color: @gray-3;
}
.row-tool {
color: fade(@black, 23);
}
.umb-grid-has-config {
color: fade(@black, 44);
}
.umb-cell-content.-placeholder {
border-color: @gray-8;
&:hover {
border-color: fade(@gray, 44);
}
}
}
@@ -573,14 +542,13 @@
display: inline-block;
cursor: pointer;
border-radius: 200px;
background: @gray-10;
border: 1px solid @gray-7;
border: 1px solid @ui-action-discreet-border;
margin: 2px;
&:hover, &:hover * {
background: @ui-action-type-hover !important;
background: @ui-action-discreet-type-hover !important;
color: @white !important;
border-color: @ui-action-type-hover !important;
border-color: @ui-action-discreet-border-hover !important;
text-decoration: none;
}
}

View File

@@ -113,12 +113,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
$scope.exitPreview = function () {
var culture = $location.search().culture || getParameterByName("culture");
var relativeUrl = "/" + $scope.pageId;
if(culture){
relativeUrl +='?culture='+ culture;
}
var relativeUrl = "/" + $scope.pageId +'?culture='+ culture;
window.top.location.href = "../preview/end?redir=" + encodeURIComponent(relativeUrl);
};

View File

@@ -6,6 +6,6 @@
<p>
<strong>Name:</strong><br/>
<input ng-model="model.name" type="text" name="queryName" ng-change="model.disableSubmitButton = model.name.length === 0"/>
<input style="width: 100%" ng-model="model.name" type="text" name="queryName" ng-change="model.disableSubmitButton = model.name.length === 0"/>
</p>
</div>
</div>

View File

@@ -1,3 +1,3 @@
<div class="umb-rte"
id="{{uniqueId}}">
id="{{textAreaHtmlId}}">
</div>

View File

@@ -51,18 +51,19 @@
<div style="position:relative; width:100%;">
<!-- Search/expression filter -->
<input class="form-control search-input" type="text" ng-model="vm.logOptions.filterExpression" style="width:100%;" placeholder="Search logs&hellip;" />
<input class="form-control search-input" type="text" ng-model="vm.logOptions.filterExpression" style="width:100%; padding-right: 160px;" placeholder="Search logs&hellip;" />
<!-- Save Search & Clear Search icon buttons -->
<ins class="icon-rate" ng-if="vm.checkForSavedSearch()" ng-click="vm.addToSavedSearches()" style="float: left; position: absolute; top: 0; line-height: 32px; right: 160px; color: #fdb45c; cursor: pointer;">&nbsp;</ins>
<ins class="icon-wrong" ng-if="vm.logOptions.filterExpression" ng-click="vm.resetSearch()" style="float: left; position: absolute; top: 0; line-height: 32px; right: 140px; color: #bbbabf; cursor: pointer;">&nbsp;</ins>
<ins class="icon-rate" ng-show="vm.checkForSavedSearch()" ng-click="vm.addToSavedSearches()" style="position: absolute; top: 0; line-height: 32px; right: 140px; color: #fdb45c; cursor: pointer;">&nbsp;</ins>
<ins class="icon-wrong" ng-show="vm.logOptions.filterExpression" ng-click="vm.resetSearch()" style="position: absolute; top: 0; line-height: 32px; right: 120px; color: #bbbabf; cursor: pointer;">&nbsp;</ins>
<a class="umb-variant-switcher__toggle ng-scope" href="" ng-click="vm.dropdownOpen = !vm.dropdownOpen" style="top:0;">
<span class="ng-binding">Example Searches</span>
<ins class="umb-variant-switcher__expand icon-navigation-down" ng-class="{'icon-navigation-down': !vm.dropdownOpen, 'icon-navigation-up': vm.dropdownOpen}">&nbsp;</ins>
<!-- Saved Searches -->
<a class="umb-variant-switcher__toggle ng-scope" href="" ng-click="vm.dropdownOpen = !vm.dropdownOpen" style="top: 1px; right: 0; position: absolute;">
<span class="ng-binding">Saved Searches</span>
<ins class="umb-variant-switcher__expand icon-navigation-down" ng-class="{'icon-navigation-down': !vm.dropdownOpen, 'icon-navigation-up': vm.dropdownOpen}" style="margin-top: 0;"></ins>
</a>
<!-- Common Searches Dropdown -->
<!-- Saved Searches Dropdown -->
<umb-dropdown ng-if="vm.dropdownOpen" style="width: 100%; max-height: 250px; overflow-y: scroll; margin-top: -10px;" on-close="vm.dropdownOpen = false" umb-keyboard-list>
<umb-dropdown-item class="umb-variant-switcher__item" ng-class="{'umb-variant-switcher_item--current': variant.active}" ng-repeat="search in vm.searches">
<a href="" class="umb-variant-switcher__name-wrapper" ng-click="vm.selectSearch(search)" prevent-default>

View File

@@ -1,25 +1,26 @@
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.Grid.EmbedController",
function ($scope, $timeout, $sce, editorService) {
function onInit() {
$scope.trustedValue = null;
$scope.trustedValue = $sce.trustAsHtml($scope.control.value);
if(!$scope.control.value) {
$timeout(function(){
if($scope.control.$initializing){
$scope.setEmbed();
}
}, 200);
}
function getEmbed() {
return $sce.trustAsHtml($scope.control.value);
}
$scope.setEmbed = function(){
$scope.embedHtml = getEmbed();
$scope.$watch('control.value', function(newValue, oldValue) {
if(angular.equals(newValue, oldValue)){
return; // simply skip that
}
$scope.embedHtml = getEmbed();
}, false);
$scope.setEmbed = function() {
var embed = {
submit: function(model) {
$scope.control.value = model.embed.preview;
$scope.trustedValue = $sce.trustAsHtml(model.embed.preview);
editorService.close();
},
close: function() {
@@ -28,6 +29,5 @@ angular.module("umbraco")
};
editorService.embed(embed);
};
onInit();
});

View File

@@ -1,10 +1,10 @@
<div ng-controller="Umbraco.PropertyEditors.Grid.EmbedController">
<div class="umb-editor-placeholder" ng-click="setEmbed()" ng-if="trustedValue === null">
<div class="umb-editor-placeholder" ng-click="setEmbed()" ng-if="control.value === null">
<i class="icon icon-movie-alt"></i>
<div class="help-text"><localize key="grid_clickToEmbed">Click to embed</localize></div>
</div>
<div ng-if="control.value" ng-bind-html="trustedValue"></div>
<div ng-if="control.value" ng-bind-html="embedHtml"></div>
</div>

View File

@@ -1,20 +1,18 @@
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.Grid.MediaController",
function ($scope, $timeout, userService, editorService) {
$scope.thumbnailUrl = getThumbnailUrl();
if (!$scope.model.config.startNodeId) {
userService.getCurrentUser().then(function (userData) {
$scope.model.config.startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
$scope.model.config.startNodeIsVirtual = userData.startMediaIds.length !== 1;
});
}
function onInit() {
if($scope.control.value){
$scope.setUrl();
}
}
$scope.setImage = function(){
var startNodeId = $scope.model.config && $scope.model.config.startNodeId ? $scope.model.config.startNodeId : undefined;
var startNodeIsVirtual = startNodeId ? $scope.model.config.startNodeIsVirtual : undefined;
@@ -34,10 +32,8 @@ angular.module("umbraco")
id: selectedImage.id,
udi: selectedImage.udi,
image: selectedImage.image,
altText: selectedImage.altText
};
$scope.setUrl();
caption: selectedImage.altText
};
editorService.close();
},
@@ -48,10 +44,18 @@ angular.module("umbraco")
editorService.mediaPicker(mediaPicker);
};
$scope.$watch('control.value', function(newValue, oldValue) {
if(angular.equals(newValue, oldValue)){
return; // simply skip that
}
$scope.thumbnailUrl = getThumbnailUrl();
}, true);
function getThumbnailUrl() {
$scope.setUrl = function(){
if($scope.control.value.image){
if($scope.control.value && $scope.control.value.image) {
var url = $scope.control.value.image;
if($scope.control.editor.config && $scope.control.editor.config.size){
@@ -70,10 +74,10 @@ angular.module("umbraco")
{
url += "?width=800&upscale=false&animationprocessmode=false"
}
$scope.url = url;
return url;
}
return null;
};
onInit();
});

View File

@@ -5,11 +5,10 @@
<div ng-id="!control.$inserted" class="help-text"><localize key="grid_clickToInsertImage">Click to insert image</localize></div>
</div>
<div ng-if="control.value">
<div ng-if="thumbnailUrl !== null">
<img
ng-if="url"
ng-click="setImage()"
ng-src="{{url}}"
ng-src="{{thumbnailUrl}}"
class="fullSizeImage" />
<input type="text" class="caption" ng-model="control.value.caption" localize="placeholder" placeholder="@grid_placeholderImageCaption" />
</div>

View File

@@ -13,11 +13,16 @@ angular.module("umbraco")
// Grid status variables
var placeHolder = "";
var currentForm = angularHelper.getCurrentForm($scope);
$scope.currentRowWithActiveChild = null;
$scope.currentCellWithActiveChild = null;
$scope.active = null;
$scope.currentRow = null;
$scope.currentCell = null;
$scope.currentToolsControl = null;
$scope.currentControl = null;
$scope.openRTEToolbarId = null;
$scope.hasSettings = false;
$scope.showRowConfigurations = true;
@@ -237,10 +242,13 @@ angular.module("umbraco")
});
$scope.$apply(function () {
var cell = event.target.getScope_HackForSortable().area;
cell.hasActiveChild = hasActiveChild(cell, cell.controls);
cell.active = false;
if(hasActiveChild(cell, cell.controls)) {
$scope.currentCellWithActiveChild = cell;
}
$scope.active = cell;
});
}
@@ -309,12 +317,12 @@ angular.module("umbraco")
// Row management function
// *********************************************
$scope.clickRow = function (index, rows) {
rows[index].active = true;
};
$scope.clickOutsideRow = function (index, rows) {
rows[index].active = false;
$scope.clickRow = function(index, rows, $event) {
$scope.currentRowWithActiveChild = null;
$scope.active = rows[index];
$event.stopPropagation();
};
function getAllowedLayouts(section) {
@@ -361,6 +369,7 @@ angular.module("umbraco")
if (section.rows.length > 0) {
section.rows.splice($index, 1);
$scope.currentRow = null;
$scope.currentRowWithActiveChild = null;
$scope.openRTEToolbarId = null;
currentForm.$setDirty();
}
@@ -515,14 +524,13 @@ angular.module("umbraco")
// Area management functions
// *********************************************
$scope.clickCell = function (index, cells, row) {
cells[index].active = true;
row.hasActiveChild = true;
};
$scope.clickOutsideCell = function (index, cells, row) {
cells[index].active = false;
row.hasActiveChild = hasActiveChild(row, cells);
$scope.clickCell = function(index, cells, row, $event) {
$scope.currentCellWithActiveChild = null;
$scope.active = cells[index];
$scope.currentRowWithActiveChild = row;
$event.stopPropagation();
};
$scope.cellPreview = function (cell) {
@@ -538,14 +546,12 @@ angular.module("umbraco")
// *********************************************
// Control management functions
// *********************************************
$scope.clickControl = function (index, controls, cell) {
controls[index].active = true;
cell.hasActiveChild = true;
};
$scope.clickOutsideControl = function (index, controls, cell) {
controls[index].active = false;
cell.hasActiveChild = hasActiveChild(cell, controls);
$scope.clickControl = function (index, controls, cell, $event) {
$scope.active = controls[index];
$scope.currentCellWithActiveChild = cell;
$event.stopPropagation();
};
function hasActiveChild(item, children) {
@@ -596,8 +602,8 @@ angular.module("umbraco")
if (index === undefined) {
index = cell.controls.length;
}
newControl.active = true;
$scope.active = newControl;
//populate control
$scope.initControl(newControl, index + 1);

View File

@@ -68,13 +68,13 @@
<!-- ng-mouseleave="disableCurrentRow()" -->
<div class="umb-row"
ng-repeat="row in section.rows"
ng-click="clickRow($index, section.rows)"
ng-click="clickRow($index, section.rows, $event)"
ng-class="{
'-has-config': row.hasConfig,
'-active': row.active,
'-active-child': row.hasActiveChild}"
on-outside-click="clickOutsideRow($index, section.rows)"
bind-click-on="{{row.active}}"
'-active': row === active,
'-active-child': row === currentRowWithActiveChild}"
bind-click-on="{{row === active || row === currentRowWithActiveChild}}"
data-rowid="{{row.$uniqueId}}">
<div class="umb-row-title-bar">
@@ -88,7 +88,7 @@
</div>
<!-- Row tool -->
<div class="umb-tools row-tools" ng-show="row.active && !sortMode">
<div class="umb-tools row-tools" ng-show="(row === active || row === currentRowWithActiveChild) && !sortMode">
<div class="cell-tools-edit row-tool" ng-if="hasSettings">
<i class="icon icon-settings" title="@grid_settings" localize="title" ng-click="editGridItemSettings(row, 'row')"></i>
@@ -122,17 +122,17 @@
ng-style="{width: area.$percentage + '%'}"
ng-class="{
'-has-config': area.hasConfig,
'-active': area.active,
'-active-child': area.hasActiveChild}"
'-active': area === active,
'-active-child': area === currentCellWithActiveChild}"
ng-model="area.controls"
ng-click="clickCell($index, row.areas, row)"
on-outside-click="clickOutsideCell($index, row.areas, row)"
bind-click-on="{{area.active}}">
ng-click="clickCell($index, row.areas, row, $event)"
bind-click-on="{{area === active}}">
<!-- Cell -->
<div class="umb-cell-content"
ng-class="
{'-active': area.active,
{'-active': area === active,
'-has-editors': area.controls.length > 0,
'-collapsed': sortMode}">
@@ -152,7 +152,7 @@
<localize key="grid_settingsApplied" />
</div>
<div class="cell-tools" ng-if="area.active && !sortMode">
<div class="cell-tools" ng-if="(area === active || area === currentCellWithActiveChild) && !sortMode">
<div class="cell-tool" ng-click="editGridItemSettings(area, 'cell')">
<i class="icon-settings"></i>
</div>
@@ -172,14 +172,14 @@
<div class="umb-control"
umb-grid-hack-scope
ng-repeat="control in area.controls"
ng-click="clickControl($index, area.controls, area)"
ng-class="{'-active': control.active}"
on-outside-click="clickOutsideControl($index, area.controls, area)"
bind-click-on="{{control.active}}"
ng-click="clickControl($index, area.controls, area, $event)"
ng-class="{'-active': control === active}"
bind-click-on="{{control === active}}"
umb-set-dirty-on-change="{{control.value}}"
data-itemid="{{control.$uniqueId}}">
<div class="umb-control-click-overlay" ng-show="!control.active && !sortMode"></div>
<div class="umb-control-click-overlay" ng-show="control !== active && !sortMode"></div>
<div class="umb-control-collapsed umb-control-handle" ng-show="sortMode">
{{control.editor.name}}
@@ -189,11 +189,11 @@
<div class="umb-control-bar umb-control-handle">
<div class="umb-control-title" ng-if="control.active">
<div class="umb-control-title" ng-if="control === active">
{{control.editor.name}}
</div>
<div class="umb-tools" ng-if="control.active">
<div class="umb-tools" ng-if="control === active">
<div class="umb-control-tool" ng-if="control.editor.config.settings">
<i class="umb-control-tool-icon icon-settings" ng-click="editGridItemSettings(control, 'control')"></i>

View File

@@ -9,9 +9,7 @@ angular.module("umbraco")
//To id the html textarea we need to use the datetime ticks because we can have multiple rte's per a single property alias
// because now we have to support having 2x (maybe more at some stage) content editors being displayed at once. This is because
// we have this mini content editor panel that can be launched with MNTP.
var d = new Date();
var n = d.getTime();
$scope.textAreaHtmlId = $scope.model.alias + "_" + n + "_rte";
$scope.textAreaHtmlId = $scope.model.alias + "_" + String.CreateGuid();
var editorConfig = $scope.model.config ? $scope.model.config.editor : null;
if (!editorConfig || angular.isString(editorConfig)) {

View File

@@ -94,7 +94,7 @@ namespace Umbraco.Web.Editors
// if the parentId is root (-1) then we just need an empty string as we are
// creating the path below and we don't want -1 in the path
if (parentId == Core.Constants.System.Root.ToInvariantString())
if (parentId == Core.Constants.System.RootString)
{
parentId = string.Empty;
}
@@ -276,7 +276,7 @@ namespace Umbraco.Web.Editors
// Make sure that the root virtual path ends with '/'
codeFileDisplay.VirtualPath = codeFileDisplay.VirtualPath.EnsureEndsWith("/");
if (id != Core.Constants.System.Root.ToInvariantString())
if (id != Core.Constants.System.RootString)
{
codeFileDisplay.VirtualPath += id.TrimStart("/").EnsureEndsWith("/");
//if it's not new then it will have a path, otherwise it won't

View File

@@ -26,7 +26,7 @@ namespace Umbraco.Web.Models.Trees
[DataContract(Name = "node", Namespace = "")]
public sealed class TreeRootNode : TreeNode
{
private static readonly string RootId = Core.Constants.System.Root.ToString(CultureInfo.InvariantCulture);
private static readonly string RootId = Core.Constants.System.RootString;
private bool _isGroup;
private bool _isSingleNodeTree;

View File

@@ -71,7 +71,7 @@ namespace Umbraco.Web.Trees
//if there are no trees defined for this section but the section is defined then we can have a simple
//full screen section without trees
var name = Services.TextService.Localize("sections/" + application);
return TreeRootNode.CreateSingleTreeRoot(Constants.System.Root.ToInvariantString(), null, null, name, TreeNodeCollection.Empty, true);
return TreeRootNode.CreateSingleTreeRoot(Constants.System.RootString, null, null, name, TreeNodeCollection.Empty, true);
}
// handle request for a specific tree / or when there is only one tree
@@ -114,7 +114,7 @@ namespace Umbraco.Web.Trees
// otherwise it's a section with all empty trees, aka a fullscreen section
// todo is this true? what if we just failed to TryGetRootNode on all of them? SD: Yes it's true but we should check the result of TryGetRootNode and throw?
return TreeRootNode.CreateSingleTreeRoot(Constants.System.Root.ToInvariantString(), null, null, name, TreeNodeCollection.Empty, true);
return TreeRootNode.CreateSingleTreeRoot(Constants.System.RootString, null, null, name, TreeNodeCollection.Empty, true);
}
// for many groups
@@ -180,7 +180,7 @@ namespace Umbraco.Web.Trees
var rootNode = await GetRootNode(tree, querystring);
var sectionRoot = TreeRootNode.CreateSingleTreeRoot(
Constants.System.Root.ToInvariantString(),
Constants.System.RootString,
rootNode.ChildNodesUrl,
rootNode.MenuUrl,
rootNode.Name,

View File

@@ -44,7 +44,7 @@ namespace Umbraco.Web.Trees
var entities = Services.EntityService.GetChildren(Constants.System.Root, UmbracoObjectTypes.DocumentBlueprint).ToArray();
//check if we're rendering the root in which case we'll render the content types that have blueprints
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
//get all blueprint content types
var contentTypeAliases = entities.Select(x => ((ContentEntitySlim) x).ContentTypeAlias).Distinct();
@@ -91,7 +91,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
// root actions
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);

View File

@@ -109,7 +109,7 @@ namespace Umbraco.Web.Trees
protected override MenuItemCollection PerformGetMenuForNode(string id, FormDataCollection queryStrings)
{
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
var menu = new MenuItemCollection();

View File

@@ -120,7 +120,7 @@ namespace Umbraco.Web.Trees
{
var nodes = new TreeNodeCollection();
var rootIdString = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
var rootIdString = Constants.System.RootString;
var hasAccessToRoot = UserStartNodes.Contains(Constants.System.Root);
var startNodeId = queryStrings.HasKey(TreeQueryStringParameters.StartNodeId)
@@ -256,7 +256,7 @@ namespace Umbraco.Web.Trees
protected sealed override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
//check if we're rendering the root
if (id == Constants.System.Root.ToInvariantString() && UserStartNodes.Contains(Constants.System.Root))
if (id == Constants.System.RootString && UserStartNodes.Contains(Constants.System.Root))
{
var altStartId = string.Empty;
@@ -264,7 +264,7 @@ namespace Umbraco.Web.Trees
altStartId = queryStrings.GetValue<string>(TreeQueryStringParameters.StartNodeId);
//check if a request has been made to render from a specific start node
if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.Root.ToString(CultureInfo.InvariantCulture))
if (string.IsNullOrEmpty(altStartId) == false && altStartId != "undefined" && altStartId != Constants.System.RootString)
{
id = altStartId;
}
@@ -272,7 +272,7 @@ namespace Umbraco.Web.Trees
var nodes = GetTreeNodesInternal(id, queryStrings);
//only render the recycle bin if we are not in dialog and the start id id still the root
if (IsDialog(queryStrings) == false && id == Constants.System.Root.ToInvariantString())
if (IsDialog(queryStrings) == false && id == Constants.System.RootString)
{
nodes.Add(CreateTreeNode(
RecycleBinId.ToInvariantString(),

View File

@@ -72,7 +72,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.ActionAlias;

View File

@@ -96,7 +96,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
//set the default to create
menu.DefaultMenuAlias = ActionNew.ActionAlias;

View File

@@ -58,7 +58,7 @@ namespace Umbraco.Web.Trees
Func<IDictionaryItem, string> ItemSort() => item => item.ItemKey;
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
nodes.AddRange(
Services.LocalizationService.GetRootDictionaryItems().OrderBy(ItemSort()).Select(
@@ -104,7 +104,7 @@ namespace Umbraco.Web.Trees
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
if (id != Constants.System.Root.ToInvariantString())
if (id != Constants.System.RootString)
menu.Items.Add<ActionDelete>(Services.TextService, true, opensDialog: true);
menu.Items.Add(new RefreshNode(Services.TextService, true));

View File

@@ -35,7 +35,7 @@ namespace Umbraco.Web.Trees
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.RootString
? HttpUtility.UrlDecode(id).TrimStart("/")
: "";
@@ -84,7 +84,7 @@ namespace Umbraco.Web.Trees
{
var root = base.CreateRootNode(queryStrings);
//check if there are any children
root.HasChildren = GetTreeNodes(Constants.System.Root.ToInvariantString(), queryStrings).Any();
root.HasChildren = GetTreeNodes(Constants.System.RootString, queryStrings).Any();
return root;
}
@@ -139,14 +139,14 @@ namespace Umbraco.Web.Trees
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
{
//if root node no need to visit the filesystem so lets just create the menu and return it
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
return GetMenuForRootNode(queryStrings);
}
var menu = new MenuItemCollection();
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.Root.ToInvariantString()
var path = string.IsNullOrEmpty(id) == false && id != Constants.System.RootString
? HttpUtility.UrlDecode(id).TrimStart("/")
: "";

View File

@@ -29,7 +29,7 @@ namespace Umbraco.Web.Trees
{
var nodes = new TreeNodeCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
foreach (var macro in Services.MacroService.GetAll())
{
@@ -50,7 +50,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
//Create the normal create action
menu.Items.Add<ActionNew>(Services.TextService);

View File

@@ -86,7 +86,7 @@ namespace Umbraco.Web.Trees
//set the default
menu.DefaultMenuAlias = ActionNew.ActionAlias;
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
// if the user's start node is not the root then the only menu item to display is refresh
if (UserStartNodes.Contains(Constants.System.Root) == false)

View File

@@ -65,7 +65,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
// set the default to create
menu.DefaultMenuAlias = ActionNew.ActionAlias;

View File

@@ -121,7 +121,7 @@ namespace Umbraco.Web.Trees
{
var nodes = new TreeNodeCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
nodes.Add(
CreateTreeNode(Constants.Conventions.MemberTypes.AllMembersListId, id, queryStrings, Services.TextService.Localize("member/allMembers"), "icon-users", true,
@@ -148,7 +148,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
// root actions
if (_provider.IsUmbracoMembershipProvider())

View File

@@ -21,7 +21,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
// root actions
menu.Items.Add(new CreateChildEntity(Services.TextService));

View File

@@ -18,7 +18,7 @@ namespace Umbraco.Web.Trees
{
var menu = new MenuItemCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
//Create the normal create action
menu.Items.Add<ActionNew>(Services.TextService.Localize("actions", ActionNew.ActionAlias));
@@ -41,7 +41,7 @@ namespace Umbraco.Web.Trees
{
var nodes = new TreeNodeCollection();
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
nodes.AddRange(Services.RelationService.GetAllRelationTypes()
.Select(rt => CreateTreeNode(rt.Id.ToString(), id, queryStrings, rt.Name,

View File

@@ -44,7 +44,7 @@ namespace Umbraco.Web.Trees
{
var nodes = new TreeNodeCollection();
var found = id == Constants.System.Root.ToInvariantString()
var found = id == Constants.System.RootString
? Services.FileService.GetTemplates(-1)
: Services.FileService.GetTemplates(int.Parse(id));
@@ -77,7 +77,7 @@ namespace Umbraco.Web.Trees
var item = menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true);
item.NavigateToRoute($"{queryStrings.GetRequiredValue<string>("application")}/templates/edit/{id}?create=true");
if (id == Constants.System.Root.ToInvariantString())
if (id == Constants.System.RootString)
{
//refresh action
menu.Items.Add(new RefreshNode(Services.TextService, true));

View File

@@ -173,7 +173,7 @@ namespace Umbraco.Web.Trees
/// <returns></returns>
protected virtual TreeNode CreateRootNode(FormDataCollection queryStrings)
{
var rootNodeAsString = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
var rootNodeAsString = Constants.System.RootString;
var currApp = queryStrings.GetValue<string>(TreeQueryStringParameters.Application);
var node = new TreeNode(