diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index 8fee11dbc9..da013d88ee 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -1188,6 +1188,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s var tinyMceRect = editor.editorContainer.getBoundingClientRect(); var tinyMceTop = tinyMceRect.top; var tinyMceBottom = tinyMceRect.bottom; + var tinyMceWidth = tinyMceRect.width; var tinyMceEditArea = tinyMce.find(".mce-edit-area"); @@ -1196,16 +1197,18 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s if (tinyMceTop < 177 && ((177 + toolbarHeight) < tinyMceBottom)) { toolbar - .css("visibility", "visible") .css("position", "fixed") .css("top", "177px") - .css("margin-top", "0"); + .css("left", "auto") + .css("right", "auto") + .css("width", tinyMceWidth); } else { toolbar - .css("visibility", "visible") .css("position", "absolute") - .css("top", "auto") - .css("margin-top", "0"); + .css("left", "") + .css("right", "") + .css("top", "") + .css("width", ""); } }, diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less index b3e729dfdd..277c2bcbe8 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-grid.less @@ -638,7 +638,11 @@ .umb-grid .mce-toolbar { border-bottom: 1px solid @gray-7; + background-color: white; display: none; + + left: 0; + right: 0; } .umb-grid .umb-control.-active .mce-toolbar { diff --git a/src/Umbraco.Web.UI.Client/src/less/rte.less b/src/Umbraco.Web.UI.Client/src/less/rte.less index f33617d03f..60065ee1d2 100644 --- a/src/Umbraco.Web.UI.Client/src/less/rte.less +++ b/src/Umbraco.Web.UI.Client/src/less/rte.less @@ -63,8 +63,9 @@ } /* Special case to support helviticons for the tiny mce button controls */ -.umb-rte .mce-ico.mce-i-custom[class^="icon-"], -.umb-rte .mce-ico.mce-i-custom[class*=" icon-"] { +// Also used in Prevalue editor. +.mce-ico.mce-i-custom[class^="icon-"], +.mce-ico.mce-i-custom[class*=" icon-"] { font-family: icomoon; font-size: 16px !important; } @@ -162,4 +163,5 @@ .umb-grid .umb-rte { border: 1px solid #d8d7d9; + max-width: none; } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 8ca698060a..c2bf5d0336 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -89,7 +89,10 @@ angular.module("umbraco") angular.extend(baseLineConfigObj, standardConfig); - tinymce.init(baseLineConfigObj); + // 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 () { diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index f940ed5c15..41f38a33e1 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System; +using System.Collections.Generic; using System.Linq; using Umbraco.Core; using Umbraco.Core.Logging; @@ -83,26 +84,63 @@ namespace Umbraco.Web.PropertyEditors // editorValue.Value is a JSON string of the grid var rawJson = editorValue.Value.ToString(); - var grid = JsonConvert.DeserializeObject(rawJson); + var grid = DeserializeGridValue(rawJson, out var rtes); - // Find all controls that use the RTE editor - var controls = grid.Sections.SelectMany(x => x.Rows.SelectMany(r => r.Areas).SelectMany(a => a.Controls)); - var rtes = controls.Where(x => x.Editor.Alias.ToLowerInvariant() == "rte"); + var userId = _umbracoContextAccessor.UmbracoContext?.Security.CurrentUser.Id ?? Constants.Security.SuperUserId; - foreach(var rte in rtes) + //process the rte values + foreach (var rte in rtes) { // Parse the HTML var html = rte.Value?.ToString(); - var userId = _umbracoContextAccessor.UmbracoContext?.Security.CurrentUser.Id ?? Constants.Security.SuperUserId; + var parseAndSavedTempImages = TemplateUtilities.FindAndPersistPastedTempImages(html, mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider, _logger); + var editorValueWithMediaUrlsRemoved = TemplateUtilities.RemoveMediaUrlsFromTextString(parseAndSavedTempImages); - var parsedHtml = TemplateUtilities.FindAndPersistPastedTempImages(html, mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider, _logger); - rte.Value = parsedHtml; + rte.Value = editorValueWithMediaUrlsRemoved; } // Convert back to raw JSON for persisting return JsonConvert.SerializeObject(grid); } + + /// + /// Ensures that the rich text editor values are processed within the grid + /// + /// + /// + /// + /// + /// + public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null) + { + var val = property.GetValue(culture, segment); + if (val == null) return string.Empty; + + var grid = DeserializeGridValue(val.ToString(), out var rtes); + + //process the rte values + foreach (var rte in rtes.ToList()) + { + var html = rte.Value?.ToString(); + + var propertyValueWithMediaResolved = TemplateUtilities.ResolveMediaFromTextString(html); + rte.Value = propertyValueWithMediaResolved; + } + + return grid; + } + + private GridValue DeserializeGridValue(string rawJson, out IEnumerable richTextValues) + { + var grid = JsonConvert.DeserializeObject(rawJson); + + // Find all controls that use the RTE editor + var controls = grid.Sections.SelectMany(x => x.Rows.SelectMany(r => r.Areas).SelectMany(a => a.Controls)); + richTextValues = controls.Where(x => x.Editor.Alias.ToLowerInvariant() == "rte"); + + return grid; + } } } } diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs index d29b96c1db..3eed40c8bf 100644 --- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs @@ -114,16 +114,16 @@ namespace Umbraco.Web.PropertyEditors if (editorValue.Value == null) return null; - var editorValueWithMediaUrlsRemoved = TemplateUtilities.RemoveMediaUrlsFromTextString(editorValue.Value.ToString()); - var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved); - var userId = _umbracoContextAccessor.UmbracoContext?.Security.CurrentUser.Id ?? Constants.Security.SuperUserId; var config = editorValue.DataTypeConfiguration as RichTextConfiguration; var mediaParent = config?.MediaParentId; var mediaParentId = mediaParent == null ? Guid.Empty : mediaParent.Guid; - parsed = TemplateUtilities.FindAndPersistPastedTempImages(parsed, mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider, _logger); + var parseAndSavedTempImages = TemplateUtilities.FindAndPersistPastedTempImages(editorValue.Value.ToString(), mediaParentId, userId, _mediaService, _contentTypeBaseServiceProvider, _logger); + var editorValueWithMediaUrlsRemoved = TemplateUtilities.RemoveMediaUrlsFromTextString(parseAndSavedTempImages); + var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved); + return parsed; } }