Merge remote-tracking branch 'origin/v8/dev' into v9/dev
# Conflicts: # src/SolutionInfo.cs # src/Umbraco.Core/Cache/DataTypeCacheRefresher.cs # src/Umbraco.Core/Extensions/PublishedContentExtensions.cs # src/Umbraco.Core/Extensions/PublishedPropertyExtension.cs # src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs # src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs
This commit is contained in:
@@ -3,6 +3,7 @@ using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
@@ -62,6 +63,11 @@ namespace Umbraco.Cms.Core.Cache
|
||||
foreach (var payload in payloads)
|
||||
{
|
||||
_idKeyMap.ClearCache(payload.Id);
|
||||
|
||||
if (dataTypeCache.Success)
|
||||
{
|
||||
dataTypeCache.Result.Clear(RepositoryCacheKeys.GetKey<IDataType, int>(payload.Id));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: not sure I like these?
|
||||
|
||||
@@ -262,7 +262,7 @@ namespace Umbraco.Extensions
|
||||
|
||||
// else... if we have a property, at least let the converter return its own
|
||||
// vision of 'no value' (could be an empty enumerable) - otherwise, default
|
||||
return property == null ? default : property.Value<T>(publishedValueFallback, culture, segment, fallback, defaultValue);
|
||||
return property == null ? default : property.Value<T>(publishedValueFallback, culture, segment);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -32,16 +32,9 @@ namespace Umbraco.Extensions
|
||||
// we have a value
|
||||
// try to cast or convert it
|
||||
var value = property.GetValue(culture, segment);
|
||||
if (value is T valueAsT)
|
||||
{
|
||||
return valueAsT;
|
||||
}
|
||||
|
||||
if (value is T valueAsT) return valueAsT;
|
||||
var valueConverted = value.TryConvertTo<T>();
|
||||
if (valueConverted)
|
||||
{
|
||||
return valueConverted.Result;
|
||||
}
|
||||
if (valueConverted) return valueConverted.Result;
|
||||
|
||||
// cannot cast nor convert the value, nothing we can return but 'default'
|
||||
// note: we don't want to fallback in that case - would make little sense
|
||||
@@ -50,28 +43,14 @@ namespace Umbraco.Extensions
|
||||
|
||||
// we don't have a value, try fallback
|
||||
if (publishedValueFallback.TryGetValue(property, culture, segment, fallback, defaultValue, out var fallbackValue))
|
||||
{
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
// we don't have a value - neither direct nor fallback
|
||||
// give a chance to the converter to return something (eg empty enumerable)
|
||||
var noValue = property.GetValue(culture, segment);
|
||||
if (noValue == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
if (noValue is T noValueAsT)
|
||||
{
|
||||
return noValueAsT;
|
||||
}
|
||||
|
||||
if (noValue is T noValueAsT) return noValueAsT;
|
||||
var noValueConverted = noValue.TryConvertTo<T>();
|
||||
if (noValueConverted)
|
||||
{
|
||||
return noValueConverted.Result;
|
||||
}
|
||||
if (noValueConverted) return noValueConverted.Result;
|
||||
|
||||
// cannot cast noValue nor convert it, nothing we can return but 'default'
|
||||
return default;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
/// </summary>
|
||||
public class MediaPickerConfiguration : IIgnoreUserStartNodesConfig
|
||||
{
|
||||
[ConfigurationField("notice", "You can NOT change the property editor", "obsoletemediapickernotice")]
|
||||
public bool Notice { get; set; }
|
||||
|
||||
[ConfigurationField("multiPicker", "Pick multiple items", "boolean")]
|
||||
public bool Multiple { get; set; }
|
||||
|
||||
|
||||
@@ -151,14 +151,14 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
|
||||
//New UDI pickers with newer Ids
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1046, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1046", SortOrder = 2, UniqueId = new Guid("FD1E0DA5-5606-4862-B679-5D0CF3A52A59"), Text = "Content Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker (old)", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Multi URL Picker (old)", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "(Obsolete) Media Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "(Obsolete) Multiple Media Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Multi URL Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1051, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1051", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3Guid, Text = "Media Picker 3", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1052, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1052", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3MultipleGuid, Text = "Multiple Media Picker 3", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1053, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1053", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3SingleImageGuid, Text = "Image Media Picker 3", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1054, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1054", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3MultipleImagesGuid, Text = "Multiple Image Media Picker 3", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1051, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1051", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3Guid, Text = "Media Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1052, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1052", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3MultipleGuid, Text = "Multiple Media Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1053, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1053", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3SingleImageGuid, Text = "Image Media Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1054, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1054", SortOrder = 2, UniqueId = Cms.Core.Constants.DataTypes.Guids.MediaPicker3MultipleImagesGuid, Text = "Multiple Image Media Picker", NodeObjectType = Cms.Core.Constants.ObjectTypes.DataType, CreateDate = DateTime.Now });
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MediaPicker3,
|
||||
EditorType.PropertyValue,
|
||||
"Media Picker v3",
|
||||
"Media Picker",
|
||||
"mediapicker3",
|
||||
ValueType = ValueTypes.Json,
|
||||
Group = Constants.PropertyEditors.Groups.Media,
|
||||
|
||||
@@ -19,11 +19,12 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MediaPicker,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Media Picker",
|
||||
"(Obsolete)Media Picker",
|
||||
"mediapicker",
|
||||
ValueType = ValueTypes.Text,
|
||||
Group = Constants.PropertyEditors.Groups.Media,
|
||||
Icon = Constants.Icons.MediaImage)]
|
||||
Icon = Constants.Icons.MediaImage,
|
||||
IsDeprecated = true)]
|
||||
public class MediaPickerPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly IIOHelper _ioHelper;
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
content.SetValue("ddl", "1234");
|
||||
content.SetValue("chklist", "randomc");
|
||||
content.SetValue("contentPicker", Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")).ToString());
|
||||
content.SetValue("mediaPicker", Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")).ToString());
|
||||
content.SetValue("mediaPicker3", "[{\"key\": \"8f78ce9e-8fe0-4500-a52d-4c4f35566ba9\",\"mediaKey\": \"44CB39C8-01E5-45EB-9CF8-E70AAF2D1691\",\"crops\": [],\"focalPoint\": {\"left\": 0.5,\"top\": 0.5}}]");
|
||||
content.SetValue("memberPicker", Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")).ToString());
|
||||
content.SetValue("multiUrlPicker", "[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]");
|
||||
content.SetValue("tags", "this,is,tags");
|
||||
|
||||
@@ -355,7 +355,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.DropDownListFlexible, ValueStorageType.Integer) { Alias = "ddl", Name = "Dropdown List", Mandatory = false, SortOrder = 14, DataTypeId = -42 });
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.CheckBoxList, ValueStorageType.Nvarchar) { Alias = "chklist", Name = "Checkbox List", Mandatory = false, SortOrder = 15, DataTypeId = -43 });
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.ContentPicker, ValueStorageType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeId = 1046 });
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.MediaPicker, ValueStorageType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeId = 1048 });
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.MediaPicker3, ValueStorageType.Integer) { Alias = "mediapicker3", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeId = 1051 });
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.MemberPicker, ValueStorageType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeId = 1047 });
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.MultiUrlPicker, ValueStorageType.Nvarchar) { Alias = "multiUrlPicker", Name = "Multi URL Picker", Mandatory = false, SortOrder = 21, DataTypeId = 1050 });
|
||||
contentCollection.Add(new PropertyType(ShortStringHelper, Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeId = 1041 });
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
var isLeftColumnAbove = false;
|
||||
scope.editors = [];
|
||||
|
||||
/* we need to keep a count of open editors because the length of the editors array is first changed when animations are done
|
||||
we do this because some infinite editors close more than one editor at the time and we get the wrong count from editors.length
|
||||
because of the animation */
|
||||
let editorCount = 0;
|
||||
|
||||
function addEditor(editor) {
|
||||
editor.inFront = true;
|
||||
editor.moveRight = true;
|
||||
@@ -51,13 +56,16 @@
|
||||
|
||||
updateEditors(-1);
|
||||
|
||||
if(scope.editors.length === 1){
|
||||
if(scope.editors.length === 1) {
|
||||
if(isLeftColumnAbove){
|
||||
$('#leftcolumn').addClass(aboveBackDropCssClass);
|
||||
}
|
||||
|
||||
isLeftColumnAbove = false;
|
||||
}
|
||||
|
||||
// when the last editor is closed remove the focus lock
|
||||
if (editorCount === 0) {
|
||||
// Remove the inert attribute from the #mainwrapper
|
||||
focusLockService.removeInertAttribute();
|
||||
}
|
||||
@@ -105,16 +113,19 @@
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("appState.editors.open", function (name, args) {
|
||||
editorCount = editorCount + 1;
|
||||
addEditor(args.editor);
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("appState.editors.close", function (name, args) {
|
||||
// remove the closed editor
|
||||
if (args && args.editor) {
|
||||
editorCount = editorCount - 1;
|
||||
removeEditor(args.editor);
|
||||
}
|
||||
// close all editors
|
||||
if (args && !args.editor && args.editors.length === 0) {
|
||||
editorCount = 0;
|
||||
scope.editors = [];
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
|
||||
function getDomNodes(){
|
||||
infiniteEditorsWrapper = document.querySelector('.umb-editors');
|
||||
infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor'));
|
||||
if(infiniteEditorsWrapper) {
|
||||
infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor') || []);
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusableElements(targetElm) {
|
||||
@@ -84,22 +86,24 @@
|
||||
var defaultFocusedElement = getAutoFocusElement(focusableElements);
|
||||
var lastKnownElement;
|
||||
|
||||
// If an inifite editor is being closed then we reset the focus to the element that triggered the the overlay
|
||||
// If an infinite editor is being closed then we reset the focus to the element that triggered the the overlay
|
||||
if(closingEditor){
|
||||
var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1;
|
||||
var editorInfo = infiniteEditors[0].querySelector('.editor-info');
|
||||
|
||||
// If there is only one editor open, search for the "editor-info" inside it and set focus on it
|
||||
// This is relevant when a property editor has been selected and the editor where we selected it from
|
||||
// is closed taking us back to the first layer
|
||||
// Otherwise set it to the last element in the lastKnownFocusedElements array
|
||||
if(infiniteEditors.length === 1 && editorInfo !== null){
|
||||
lastKnownElement = editorInfo;
|
||||
if(infiniteEditors && infiniteEditors.length === 1){
|
||||
var editorInfo = infiniteEditors[0].querySelector('.editor-info');
|
||||
if(infiniteEditors && infiniteEditors.length === 1 && editorInfo !== null) {
|
||||
lastKnownElement = editorInfo;
|
||||
|
||||
// Clear the array
|
||||
clearLastKnownFocusedElements();
|
||||
// Clear the array
|
||||
clearLastKnownFocusedElements();
|
||||
}
|
||||
}
|
||||
else {
|
||||
var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1;
|
||||
lastKnownElement = $rootScope.lastKnownFocusableElements[lastItemIndex];
|
||||
|
||||
// Remove the last item from the array so we always set the correct lastKnowFocus for each layer
|
||||
@@ -149,20 +153,24 @@
|
||||
}
|
||||
|
||||
function cleanupEventHandlers() {
|
||||
var activeEditor = infiniteEditors[infiniteEditors.length - 1];
|
||||
var inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
|
||||
//if we're in infinite editing mode
|
||||
if(infiniteEditors.length > 0) {
|
||||
var activeEditor = infiniteEditors[infiniteEditors.length - 1];
|
||||
var inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
|
||||
|
||||
if(inactiveEditors.length > 0) {
|
||||
for (var index = 0; index < inactiveEditors.length; index++) {
|
||||
var inactiveEditor = inactiveEditors[index];
|
||||
if(inactiveEditors.length > 0) {
|
||||
for (var index = 0; index < inactiveEditors.length; index++) {
|
||||
var inactiveEditor = inactiveEditors[index];
|
||||
|
||||
// Remove event handlers from inactive editors
|
||||
inactiveEditor.removeEventListener('keydown', handleKeydown);
|
||||
// Remove event handlers from inactive editors
|
||||
inactiveEditor.removeEventListener('keydown', handleKeydown);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Why is this one only begin called if there is no other infinite editors, wouldn't it make sense always to clean this up?
|
||||
// Remove event handlers from the active editor
|
||||
activeEditor.removeEventListener('keydown', handleKeydown);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Remove event handlers from the active editor
|
||||
activeEditor.removeEventListener('keydown', handleKeydown);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,10 +181,7 @@
|
||||
// Fetch the DOM nodes we need
|
||||
getDomNodes();
|
||||
|
||||
// Cleanup event handlers if we're in infinite editing mode
|
||||
if(infiniteEditors.length > 0){
|
||||
cleanupEventHandlers();
|
||||
}
|
||||
cleanupEventHandlers();
|
||||
|
||||
getFocusableElements(targetElm);
|
||||
|
||||
@@ -204,17 +209,19 @@
|
||||
// Make sure to disconnect the observer so we potentially don't end up with having many active ones
|
||||
disconnectObserver = true;
|
||||
|
||||
// Pass the correct editor in order to find the focusable elements
|
||||
var newTarget = infiniteEditors[infiniteEditors.length - 2];
|
||||
if(infiniteEditors && infiniteEditors.length > 1) {
|
||||
// Pass the correct editor in order to find the focusable elements
|
||||
var newTarget = infiniteEditors[infiniteEditors.length - 2];
|
||||
|
||||
if(infiniteEditors.length > 1){
|
||||
// Setting closing till true will let us re-apply the last known focus to then opened layer that then becomes
|
||||
// active
|
||||
closingEditor = true;
|
||||
if(infiniteEditors.length > 1) {
|
||||
// Setting closing till true will let us re-apply the last known focus to then opened layer that then becomes
|
||||
// active
|
||||
closingEditor = true;
|
||||
|
||||
onInit(newTarget);
|
||||
onInit(newTarget);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear lastKnownFocusableElements
|
||||
|
||||
@@ -26,7 +26,7 @@ angular.module("umbraco.directives")
|
||||
forceUpdate: '@?'
|
||||
},
|
||||
|
||||
link: function (scope, element, attrs) {
|
||||
link: function (scope, element, attrs, windowResizeListener) {
|
||||
|
||||
var unsubscribe = [];
|
||||
let sliderRef = null;
|
||||
|
||||
@@ -48,8 +48,6 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
});
|
||||
}
|
||||
else if (value[0]) {
|
||||
//notificationsService.error("Validation", value[0]);
|
||||
console.log({type:messageType, header:"Validation", message:value[0]})
|
||||
notificationsService.showNotification({type:messageType, header:"Validation", message:value[0]})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
// We are not ready to limit the pasted elements further than default, we will return to this feature. ( TODO: Make this feature an option. )
|
||||
// We keep spans here, cause removing spans here also removes b-tags inside of them, instead we strip them out later. (TODO: move this definition to the config file... )
|
||||
var validPasteElements = "-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody,img[src|alt|width|height],ul,ol,li,hr,pre,dl,dt,figure,figcaption,wbr"
|
||||
|
||||
|
||||
// add elements from user configurated styleFormats to our list of validPasteElements.
|
||||
// (This means that we only allow H3-element if its configured as a styleFormat on this specific propertyEditor.)
|
||||
var style, i = 0;
|
||||
@@ -610,7 +610,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
'contenteditable': false
|
||||
},
|
||||
embed.preview);
|
||||
|
||||
|
||||
// Only replace if activeElement is an Embed element.
|
||||
if (activeElement && activeElement.nodeName.toUpperCase() === "DIV" && activeElement.classList.contains("embeditem")){
|
||||
activeElement.replaceWith(wrapper); // directly replaces the html node
|
||||
@@ -738,9 +738,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
id: "__mcenew",
|
||||
"data-udi": img.udi
|
||||
};
|
||||
|
||||
|
||||
editor.selection.setContent(editor.dom.createHTML('img', data));
|
||||
|
||||
|
||||
// Using settimeout to wait for a DoM-render, so we can find the new element by ID.
|
||||
$timeout(function () {
|
||||
|
||||
@@ -761,7 +761,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1401,11 +1401,26 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
function syncContent() {
|
||||
|
||||
if(args.model.value === args.editor.getContent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//stop watching before we update the value
|
||||
stopWatch();
|
||||
angularHelper.safeApply($rootScope, function () {
|
||||
args.model.value = args.editor.getContent();
|
||||
|
||||
//make the form dirty manually so that the track changes works, setting our model doesn't trigger
|
||||
// the angular bits because tinymce replaces the textarea.
|
||||
if (args.currentForm) {
|
||||
args.currentForm.$setDirty();
|
||||
}
|
||||
// With complex validation we need to set a input field to dirty, not the form. but we will keep the old code for backwards compatibility.
|
||||
if (args.currentFormInput) {
|
||||
args.currentFormInput.$setDirty();
|
||||
}
|
||||
});
|
||||
|
||||
//re-watch the value
|
||||
startWatch();
|
||||
}
|
||||
@@ -1430,7 +1445,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
// Upload BLOB images (dragged/pasted ones)
|
||||
// find src attribute where value starts with `blob:`
|
||||
// search is case-insensitive and allows single or double quotes
|
||||
// search is case-insensitive and allows single or double quotes
|
||||
if(content.search(/src=["']blob:.*?["']/gi) !== -1){
|
||||
args.editor.uploadImages(function(data) {
|
||||
// Once all images have been uploaded
|
||||
@@ -1496,6 +1511,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
args.editor.on('Change', function (e) {
|
||||
syncContent();
|
||||
});
|
||||
args.editor.on('Keyup', function (e) {
|
||||
syncContent();
|
||||
});
|
||||
|
||||
//when we leave the editor (maybe)
|
||||
args.editor.on('blur', function (e) {
|
||||
@@ -1520,12 +1538,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
args.editor.on('Dirty', function (e) {
|
||||
syncContent(); // Set model.value to the RTE's content
|
||||
|
||||
//make the form dirty manually so that the track changes works, setting our model doesn't trigger
|
||||
// the angular bits because tinymce replaces the textarea.
|
||||
if (args.currentForm) {
|
||||
args.currentForm.$setDirty();
|
||||
}
|
||||
});
|
||||
|
||||
let self = this;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
padding: 2px 6px;
|
||||
}
|
||||
.umb-range-slider .noUi-handle {
|
||||
outline: none;
|
||||
cursor: grab;
|
||||
border-radius: 100px;
|
||||
border: none;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
width="{{crop.width}}"
|
||||
max-size="75">
|
||||
</umb-image-thumbnail>
|
||||
<span class="__text">{{crop.alias}}</span>
|
||||
<span class="__text">{{crop.label}}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<p style="background-color: #fee4e1; padding: 8px;"><strong>Important:</strong> switching from the (Obsolete) Media Picker to Media Picker will mean all data (references to previously selected media items) will be deleted and no longer available.</p>
|
||||
@@ -5,12 +5,12 @@ angular.module("umbraco")
|
||||
// TODO: A lot of the code below should be shared between the grid rte and the normal rte
|
||||
|
||||
$scope.isLoading = true;
|
||||
|
||||
|
||||
//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.model.alias + "_" + String.CreateGuid();
|
||||
|
||||
|
||||
var editorConfig = $scope.model.config ? $scope.model.config.editor : null;
|
||||
if (!editorConfig || Utilities.isString(editorConfig)) {
|
||||
editorConfig = tinyMceService.defaultPrevalues();
|
||||
@@ -28,14 +28,14 @@ angular.module("umbraco")
|
||||
$scope.containerOverflow = editorConfig.mode === "distraction-free" ? (height ? "auto" : "inherit") : "inherit";
|
||||
|
||||
var promises = [];
|
||||
|
||||
|
||||
// we need to make sure that the element is initialized before we can init TinyMCE, because we find the placeholder by ID, so it needs to be appended to document before.
|
||||
var initPromise = $q((resolve, reject) => {
|
||||
this.$onInit = resolve;
|
||||
});
|
||||
|
||||
|
||||
promises.push(initPromise);
|
||||
|
||||
|
||||
//queue file loading
|
||||
tinyMceAssets.forEach(function (tinyJsAsset) {
|
||||
promises.push(assetsService.loadJs(tinyJsAsset, $scope));
|
||||
@@ -50,50 +50,50 @@ angular.module("umbraco")
|
||||
toolbar: editorConfig.toolbar,
|
||||
mode: editorConfig.mode
|
||||
}));
|
||||
|
||||
|
||||
//wait for queue to end
|
||||
$q.all(promises).then(function (result) {
|
||||
|
||||
|
||||
var standardConfig = result[promises.length - 1];
|
||||
|
||||
|
||||
if (height !== null) {
|
||||
standardConfig.plugins.splice(standardConfig.plugins.indexOf("autoresize"), 1);
|
||||
}
|
||||
|
||||
|
||||
//create a baseline Config to extend upon
|
||||
var baseLineConfigObj = {
|
||||
maxImageSize: editorConfig.maxImageSize,
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
|
||||
|
||||
baseLineConfigObj.setup = function (editor) {
|
||||
|
||||
|
||||
//set the reference
|
||||
tinyMceEditor = editor;
|
||||
|
||||
|
||||
tinyMceEditor.on('init', function (e) {
|
||||
$timeout(function () {
|
||||
$scope.isLoading = false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//initialize the standard editor functionality for Umbraco
|
||||
tinyMceService.initializeEditor({
|
||||
editor: editor,
|
||||
model: $scope.model,
|
||||
currentForm: angularHelper.getCurrentForm($scope)
|
||||
currentFormInput: $scope.rteForm.modelValue
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
angular.extend(baseLineConfigObj, standardConfig);
|
||||
|
||||
|
||||
// We need to wait for DOM to have rendered before we can find the element by ID.
|
||||
$timeout(function () {
|
||||
tinymce.init(baseLineConfigObj);
|
||||
}, 150);
|
||||
|
||||
|
||||
//listen for formSubmitting event (the result is callback used to remove the event subscription)
|
||||
var unsubscribe = $scope.$on("formSubmitting", function () {
|
||||
if (tinyMceEditor !== undefined && tinyMceEditor != null && !$scope.isLoading) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.RTEController" class="umb-property-editor umb-rte" ng-class="{'--initialized': !isLoading}">
|
||||
<umb-load-indicator ng-if="isLoading"></umb-load-indicator>
|
||||
|
||||
<div class="umb-rte-editor-con">
|
||||
<input type="text" id="{{model.alias}}" ng-focus="focus()" style="position:absolute;top:0;width:0;height:0;" />
|
||||
<div disable-hotkeys id="{{textAreaHtmlId}}" class="umb-rte-editor" ng-style="{ width: containerWidth, height: containerHeight, overflow: containerOverflow}"></div>
|
||||
</div>
|
||||
<ng-form name="rteForm">
|
||||
<div class="umb-rte-editor-con">
|
||||
<input type="text" id="{{model.alias}}" ng-focus="focus()" name="modelValue" ng-model="model.value" style="position:absolute;top:0;width:0;height:0;" />
|
||||
<div disable-hotkeys id="{{textAreaHtmlId}}" class="umb-rte-editor" ng-style="{ width: containerWidth, height: containerHeight, overflow: containerOverflow}"></div>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
@@ -235,8 +235,12 @@
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:8121</IISUrl>
|
||||
<DevelopmentServerPort>8130</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>8140</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:8130</IISUrl>
|
||||
<IISUrl>http://localhost:8140</IISUrl>
|
||||
<DevelopmentServerPort>8131</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:8131</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EdotCover_002EIde_002ECore_002EFilterManagement_002EModel_002ESolutionFilterSettingsManagerMigrateSettings/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue"><data><IncludeFilters /><ExcludeFilters /></data></s:String>
|
||||
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue"><data /></s:String>
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=2DA32DA040A7D74599ABE288C7224CF0/Comment/@EntryValue">Disposable construction</s:String>
|
||||
|
||||
Reference in New Issue
Block a user