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 23104b99f5..07aa4d57b7 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
@@ -158,10 +158,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
}
function uploadImageHandler(blobInfo, success, failure, progress){
-
- //TODO: Worth refactoring to Angular $http calls
- //Rather than XHR??
-
let xhr, formData;
xhr = new XMLHttpRequest();
@@ -185,24 +181,20 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
json = JSON.parse(xhr.responseText);
- if (!json || typeof json.location !== 'string') {
+ if (!json || typeof json.tmpLocation !== 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
- // Put UDI into localstorage (used to update the img with data-udi later on)
- localStorageService.set(`tinymce__${json.location}`, json.udi);
+ // Put temp location into localstorage (used to update the img with data-tmpimg later on)
+ localStorage.setItem(`tinymce__${blobInfo.blobUri()}`, json.tmpLocation);
- success(json.location);
+ success();
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.blob().name);
- //TODO: Send Media Parent ID from config
- //TODO: How will each RTE pass in this value to this function?!
- formData.append('mediaParent', -1);
-
xhr.send(formData);
}
@@ -215,21 +207,22 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
if(content.indexOf('
data attribute
+ File.Move(currentFile, newFilePath);
}
+ catch (Exception ex)
+ {
+ // Could be a file permission ex
+ throw;
+ }
- _mediaService.Save(f, Security.CurrentUser.Id);
-
- // Need to get URL to the media item and its UDI
- var udi = f.GetUdi();
-
-
- // TODO: Check this is the BEST way to get the URL
- // Ensuring if they use some CDN & blob storage?!
- var mediaTyped = Umbraco.Media(f.Id);
- var location = mediaTyped.Url;
-
- return Request.CreateResponse(HttpStatusCode.OK, new { location = location, udi = udi });
+ return Request.CreateResponse(HttpStatusCode.OK, new { tmpLocation = relativeNewFilePath });
}
}
}
diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
index 3ced379604..911defcd17 100644
--- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs
@@ -1,12 +1,15 @@
-using System;
+using HtmlAgilityPack;
+using System;
using System.Collections.Generic;
+using System.IO;
using Umbraco.Core;
+using Umbraco.Core.IO;
using Umbraco.Core.Logging;
-using Umbraco.Core.Macros;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Examine;
+using Umbraco.Web.Composing;
using Umbraco.Web.Macros;
using Umbraco.Web.Templates;
@@ -25,18 +28,23 @@ namespace Umbraco.Web.PropertyEditors
Icon = "icon-browser-window")]
public class RichTextPropertyEditor : DataEditor
{
+ private IMediaService _mediaService;
+ private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
+
///
/// The constructor will setup the property editor based on the attribute if one is found
///
- public RichTextPropertyEditor(ILogger logger) : base(logger)
+ public RichTextPropertyEditor(ILogger logger, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) : base(logger)
{
+ _mediaService = mediaService;
+ _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
}
///
/// Create a custom value editor
///
///
- protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute);
+ protected override IDataValueEditor CreateValueEditor() => new RichTextPropertyValueEditor(Attribute, _mediaService, _contentTypeBaseServiceProvider);
protected override IConfigurationEditor CreateConfigurationEditor() => new RichTextConfigurationEditor();
@@ -47,9 +55,15 @@ namespace Umbraco.Web.PropertyEditors
///
internal class RichTextPropertyValueEditor : DataValueEditor
{
- public RichTextPropertyValueEditor(DataEditorAttribute attribute)
+ private IMediaService _mediaService;
+ private IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
+
+ public RichTextPropertyValueEditor(DataEditorAttribute attribute, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider)
: base(attribute)
- { }
+ {
+ _mediaService = mediaService;
+ _contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
+ }
///
public override object Configuration
@@ -71,10 +85,9 @@ namespace Umbraco.Web.PropertyEditors
/// Format the data for the editor
///
///
- ///
+ /// Rte
///
- ///
- ///
+ /// te
public override object ToEditor(Property property, IDataTypeService dataTypeService, string culture = null, string segment = null)
{
var val = property.GetValue(culture, segment);
@@ -99,8 +112,66 @@ namespace Umbraco.Web.PropertyEditors
var editorValueWithMediaUrlsRemoved = TemplateUtilities.RemoveMediaUrlsFromTextString(editorValue.Value.ToString());
var parsed = MacroTagParser.FormatRichTextContentForPersistence(editorValueWithMediaUrlsRemoved);
+
+ // HTML content when being persisted may j
+ parsed = FindPastedTempImages(parsed);
+
return parsed;
}
+
+ private string FindPastedTempImages(string html)
+ {
+ // Find all img's that has data-tmpimg attribute
+ // Use HTML Agility Pack - https://html-agility-pack.net
+ var htmlDoc = new HtmlDocument();
+ htmlDoc.LoadHtml(html);
+
+ var tmpImages = htmlDoc.DocumentNode.SelectNodes("//img[@data-tmpimg]");
+ if (tmpImages == null || tmpImages.Count == 0)
+ return html;
+
+ var userId = Current.UmbracoContext.Security.CurrentUser.Id;
+
+ foreach (var img in tmpImages)
+ {
+ // The data attribute contains the path to the tmp img to persist as a media item
+ var tmpImgPath = img.GetAttributeValue("data-tmpimg", string.Empty);
+
+ if (string.IsNullOrEmpty(tmpImgPath))
+ continue;
+
+ var absTmpImgPath = IOHelper.MapPath(tmpImgPath);
+ var fileName = Path.GetFileName(absTmpImgPath);
+ var safeFileName = fileName.ToSafeFileName();
+
+ // TODO: In future task (get the parent folder from this config) to save the media into
+ var mediaItemName = safeFileName.ToFriendlyName();
+ var f = _mediaService.CreateMedia(mediaItemName, -1, Constants.Conventions.MediaTypes.Image, userId);
+ var fileInfo = new FileInfo(absTmpImgPath);
+
+ var fs = fileInfo.OpenReadWithRetry();
+ if (fs == null) throw new InvalidOperationException("Could not acquire file stream");
+ using (fs)
+ {
+ f.SetValue(_contentTypeBaseServiceProvider, Constants.Conventions.Media.File, safeFileName, fs);
+ }
+
+ _mediaService.Save(f, userId);
+
+ // Add the UDI to the img element as new data attribute
+ var udi = f.GetUdi();
+ img.SetAttributeValue("data-udi", udi.ToString());
+
+ //Get the new persisted image url
+ var mediaTyped = Current.UmbracoHelper.Media(f.Id);
+ var location = mediaTyped.Url;
+
+ // Remove the data attribute (so we do not re-process this)
+ img.Attributes.Remove("data-tmpimg");
+ }
+
+ return htmlDoc.DocumentNode.OuterHtml;
+ }
}
internal class RichTextPropertyIndexValueFactory : IPropertyIndexValueFactory