Merge pull request #6396 from umbraco/v8/bugfix/AB2734-Image-Deletion-Bug
Bug: RTE Image deletion error for images that has not been saved as media items
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
function ContentEditController($rootScope, $scope, $routeParams, $q, $window,
|
||||
appState, contentResource, entityResource, navigationService, notificationsService,
|
||||
serverValidationManager, contentEditingHelper, localizationService, formHelper, umbRequestHelper,
|
||||
editorState, $http, eventsService, overlayService, $location) {
|
||||
editorState, $http, eventsService, overlayService, $location, localStorageService) {
|
||||
|
||||
var evts = [];
|
||||
var infiniteMode = $scope.infiniteModel && $scope.infiniteModel.infiniteMode;
|
||||
@@ -189,6 +189,13 @@
|
||||
$scope.page.saveButtonState = "success";
|
||||
$scope.page.buttonGroupState = "success";
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("content.saved", function(){
|
||||
// Clear out localstorage keys that start with tinymce__
|
||||
// When we save/perist a content node
|
||||
// NOTE: clearAll supports a RegEx pattern of items to remove
|
||||
localStorageService.clearAll(/^tinymce__/);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* A service containing all logic for all of the Umbraco TinyMCE plugins
|
||||
*/
|
||||
function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, stylesheetResource, macroResource, macroService,
|
||||
$routeParams, umbRequestHelper, angularHelper, userService, editorService, entityResource, eventsService) {
|
||||
$routeParams, umbRequestHelper, angularHelper, userService, editorService, entityResource, eventsService, localStorageService) {
|
||||
|
||||
//These are absolutely required in order for the macros to render inline
|
||||
//we put these as extended elements because they get merged on top of the normal allowed elements by tiny mce
|
||||
@@ -203,7 +203,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
}
|
||||
|
||||
// Put temp location into localstorage (used to update the img with data-tmpimg later on)
|
||||
localStorage.setItem(`tinymce__${blobInfo.blobUri()}`, json.tmpLocation);
|
||||
localStorageService.set(`tinymce__${blobInfo.blobUri()}`, json.tmpLocation);
|
||||
|
||||
// We set the img src url to be the same as we started
|
||||
// The Blob URI is stored in TinyMce's cache
|
||||
@@ -234,23 +234,43 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
// Get img src
|
||||
var imgSrc = img.getAttribute("src");
|
||||
var tmpLocation = localStorage.getItem(`tinymce__${imgSrc}`);
|
||||
var tmpLocation = localStorageService.get(`tinymce__${imgSrc}`)
|
||||
|
||||
// Select the img & add new attr which we can search for
|
||||
// When its being persisted in RTE property editor
|
||||
// To create a media item & delete this tmp one etc
|
||||
tinymce.activeEditor.$(img).attr({ "data-tmpimg": tmpLocation });
|
||||
|
||||
|
||||
// Resize the image to the max size configured
|
||||
// NOTE: no imagesrc passed into func as the src is blob://...
|
||||
// We will append ImageResizing Querystrings on perist to DB with node save
|
||||
sizeImageInEditor(editor, img);
|
||||
|
||||
// We need to remove the image from the cache, otherwise we can't handle if we upload the exactly
|
||||
// same image twice
|
||||
tinymce.activeEditor.editorUpload.blobCache.removeByUri(imgSrc);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
// Get all img where src starts with blob: AND does NOT have a data=tmpimg attribute
|
||||
// This is most likely seen as a duplicate image that has already been uploaded
|
||||
// editor.uploadImages() does not give us any indiciation that the image been uploaded already
|
||||
var blobImageWithNoTmpImgAttribute = editor.dom.select("img[src^='blob:']:not([data-tmpimg])");
|
||||
|
||||
//For each of these selected items
|
||||
blobImageWithNoTmpImgAttribute.forEach(imageElement => {
|
||||
var blobSrcUri = editor.dom.getAttrib(imageElement, "src");
|
||||
|
||||
// Find the same image uploaded (Should be in LocalStorage)
|
||||
// May already exist in the editor as duplicate image
|
||||
// OR added to the RTE, deleted & re-added again
|
||||
// So lets fetch the tempurl out of localstorage for that blob URI item
|
||||
var tmpLocation = localStorageService.get(`tinymce__${blobSrcUri}`)
|
||||
|
||||
if(tmpLocation){
|
||||
sizeImageInEditor(editor, imageElement);
|
||||
editor.dom.setAttrib(imageElement, "data-tmpimg", tmpLocation);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ describe('RTE controller tests', function () {
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(module('LocalStorageModule'));
|
||||
|
||||
beforeEach(module('umbraco', function ($provide) {
|
||||
$provide.value('tinyMceAssets', []);
|
||||
}));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using HtmlAgilityPack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core;
|
||||
@@ -201,7 +202,11 @@ namespace Umbraco.Web.Templates
|
||||
var tmpImages = htmlDoc.DocumentNode.SelectNodes($"//img[@{TemporaryImageDataAttribute}]");
|
||||
if (tmpImages == null || tmpImages.Count == 0)
|
||||
return html;
|
||||
|
||||
|
||||
// An array to contain a list of URLs that
|
||||
// we have already processed to avoid dupes
|
||||
var uploadedImages = new Dictionary<string, GuidUdi>();
|
||||
|
||||
foreach (var img in tmpImages)
|
||||
{
|
||||
// The data attribute contains the path to the tmp img to persist as a media item
|
||||
@@ -209,36 +214,46 @@ namespace Umbraco.Web.Templates
|
||||
|
||||
if (string.IsNullOrEmpty(tmpImgPath))
|
||||
continue;
|
||||
|
||||
|
||||
var absoluteTempImagePath = IOHelper.MapPath(tmpImgPath);
|
||||
var fileName = Path.GetFileName(absoluteTempImagePath);
|
||||
var safeFileName = fileName.ToSafeFileName();
|
||||
|
||||
var mediaItemName = safeFileName.ToFriendlyName();
|
||||
IMedia mediaFile;
|
||||
GuidUdi udi;
|
||||
|
||||
if(mediaParentFolder == Guid.Empty)
|
||||
mediaFile = mediaService.CreateMedia(mediaItemName, Constants.System.Root, Constants.Conventions.MediaTypes.Image, userId);
|
||||
else
|
||||
mediaFile = mediaService.CreateMedia(mediaItemName, mediaParentFolder, Constants.Conventions.MediaTypes.Image, userId);
|
||||
|
||||
var fileInfo = new FileInfo(absoluteTempImagePath);
|
||||
|
||||
var fileStream = fileInfo.OpenReadWithRetry();
|
||||
if (fileStream == null) throw new InvalidOperationException("Could not acquire file stream");
|
||||
using (fileStream)
|
||||
if (uploadedImages.ContainsKey(tmpImgPath) == false)
|
||||
{
|
||||
mediaFile.SetValue(contentTypeBaseServiceProvider, Constants.Conventions.Media.File, safeFileName, fileStream);
|
||||
}
|
||||
if (mediaParentFolder == Guid.Empty)
|
||||
mediaFile = mediaService.CreateMedia(mediaItemName, Constants.System.Root, Constants.Conventions.MediaTypes.Image, userId);
|
||||
else
|
||||
mediaFile = mediaService.CreateMedia(mediaItemName, mediaParentFolder, Constants.Conventions.MediaTypes.Image, userId);
|
||||
|
||||
mediaService.Save(mediaFile, userId);
|
||||
var fileInfo = new FileInfo(absoluteTempImagePath);
|
||||
|
||||
var fileStream = fileInfo.OpenReadWithRetry();
|
||||
if (fileStream == null) throw new InvalidOperationException("Could not acquire file stream");
|
||||
using (fileStream)
|
||||
{
|
||||
mediaFile.SetValue(contentTypeBaseServiceProvider, Constants.Conventions.Media.File, safeFileName, fileStream);
|
||||
}
|
||||
|
||||
mediaService.Save(mediaFile, userId);
|
||||
|
||||
udi = mediaFile.GetUdi();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Already been uploaded & we have it's UDI
|
||||
udi = uploadedImages[tmpImgPath];
|
||||
}
|
||||
|
||||
// Add the UDI to the img element as new data attribute
|
||||
var udi = mediaFile.GetUdi();
|
||||
img.SetAttributeValue("data-udi", udi.ToString());
|
||||
|
||||
// Get the new persisted image url
|
||||
var mediaTyped = Current.UmbracoHelper.Media(mediaFile.Id);
|
||||
var mediaTyped = Current.UmbracoHelper.Media(udi.Guid);
|
||||
var location = mediaTyped.Url;
|
||||
|
||||
// Find the width & height attributes as we need to set the imageprocessor QueryString
|
||||
@@ -255,19 +270,24 @@ namespace Umbraco.Web.Templates
|
||||
// Remove the data attribute (so we do not re-process this)
|
||||
img.Attributes.Remove(TemporaryImageDataAttribute);
|
||||
|
||||
// Delete folder & image now its saved in media
|
||||
// The folder should contain one image - as a unique guid folder created
|
||||
// for each image uploaded from TinyMceController
|
||||
var folderName = Path.GetDirectoryName(absoluteTempImagePath);
|
||||
try
|
||||
{
|
||||
Directory.Delete(folderName, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
// Add to the dictionary to avoid dupes
|
||||
if(uploadedImages.ContainsKey(tmpImgPath) == false)
|
||||
{
|
||||
logger.Error(typeof(TemplateUtilities), ex, "Could not delete temp file or folder {FileName}", absoluteTempImagePath);
|
||||
uploadedImages.Add(tmpImgPath, udi);
|
||||
|
||||
// Delete folder & image now its saved in media
|
||||
// The folder should contain one image - as a unique guid folder created
|
||||
// for each image uploaded from TinyMceController
|
||||
var folderName = Path.GetDirectoryName(absoluteTempImagePath);
|
||||
try
|
||||
{
|
||||
Directory.Delete(folderName, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(typeof(TemplateUtilities), ex, "Could not delete temp file or folder {FileName}", absoluteTempImagePath);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return htmlDoc.DocumentNode.OuterHtml;
|
||||
|
||||
Reference in New Issue
Block a user