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 da013d88ee..387b206514 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
@@ -588,12 +588,15 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
var selectedElm = editor.selection.getNode(),
- currentTarget;
+ currentTarget,
+ imgDomElement;
if (selectedElm.nodeName === 'IMG') {
var img = $(selectedElm);
+ imgDomElement = selectedElm;
var hasUdi = img.attr("data-udi") ? true : false;
+ var hasDataTmpImg = img.attr("data-tmpimg") ? true : false;
currentTarget = {
altText: img.attr("alt"),
@@ -605,12 +608,16 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
} else {
currentTarget["id"] = img.attr("rel");
}
+
+ if(hasDataTmpImg){
+ currentTarget["tmpimg"] = img.attr("data-tmpimg");
+ }
}
userService.getCurrentUser().then(function (userData) {
if (callback) {
angularHelper.safeApply($rootScope, function() {
- callback(currentTarget, userData);
+ callback(currentTarget, userData, imgDomElement);
});
}
});
@@ -618,25 +625,77 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
});
},
- insertMediaInEditor: function (editor, img) {
+ insertMediaInEditor: function (editor, img, imgDomElement) {
if (img) {
+ // imgElement is only definied if updating an image
+ // if null/undefinied then its a BRAND new image
+ if(imgDomElement){
+ // Check if the img src has changed
+ // If it has we will need to do some resizing/recalc again
+ var hasImageSrcChanged = false;
- var data = {
- alt: img.altText || "",
- src: (img.url) ? img.url : "nothing.jpg",
- id: '__mcenew',
- 'data-udi': img.udi
- };
+ if(img.url !== editor.dom.getAttrib(imgDomElement, "src")){
+ hasImageSrcChanged = true;
+ }
- editor.selection.setContent(editor.dom.createHTML('img', data));
+ // If null/undefinied it will remove the attribute
+ editor.dom.setAttrib(imgDomElement, "alt", img.altText);
- $timeout(function () {
- var imgElm = editor.dom.get('__mcenew');
- sizeImageInEditor(editor, imgElm, img.url);
- editor.dom.setAttrib(imgElm, 'id', null);
- editor.fire('Change');
+ // It's possible to pick a NEW image - so need to ensure this gets updated
+ if(img.udi){
+ editor.dom.setAttrib(imgDomElement, "data-udi", img.udi);
+ }
- }, 500);
+ // It's possible to pick a NEW image - so need to ensure this gets updated
+ if(img.url){
+ editor.dom.setAttrib(imgDomElement, "src", img.url);
+ }
+
+ // Remove width & height attributes (ONLY if imgSrc changed)
+ // So native image size is used as this needed to re-calc width & height
+ // For the function sizeImageInEditor() & apply the image resizing querystrings etc..
+ if(hasImageSrcChanged){
+ editor.dom.setAttrib(imgDomElement, "width", null);
+ editor.dom.setAttrib(imgDomElement, "height", null);
+
+ //Re-calc the image dimensions
+ sizeImageInEditor(editor, imgDomElement, img.url);
+ }
+
+ } else{
+ // We need to create a NEW DOM
element to insert
+ // setting an attribute of ID to __mcenew, so we can gather a reference to the node, to be able to update its size accordingly to the size of the image.
+ var data = {
+ alt: img.altText || "",
+ src: (img.url) ? img.url : "nothing.jpg",
+ 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 () {
+
+ var imgElm = editor.dom.get("__mcenew");
+ editor.dom.setAttrib(imgElm, "id", null);
+
+ // When image is loaded we are ready to call sizeImageInEditor.
+ var onImageLoaded = function() {
+ sizeImageInEditor(editor, imgElm, img.url);
+ editor.fire("Change");
+ }
+
+ // Check if image already is loaded.
+ if(imgElm.complete === true) {
+ onImageLoaded();
+ } else {
+ imgElm.onload = onImageLoaded;
+ }
+
+ });
+
+ }
}
},
@@ -1402,7 +1461,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
});
//Create the insert media plugin
- self.createMediaPicker(args.editor, function (currentTarget, userData) {
+ self.createMediaPicker(args.editor, function (currentTarget, userData, imgDomElement) {
var startNodeId, startNodeIsVirtual;
if (!args.model.config.startNodeId) {
@@ -1425,7 +1484,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
startNodeIsVirtual: startNodeIsVirtual,
dataTypeKey: args.model.dataTypeKey,
submit: function (model) {
- self.insertMediaInEditor(args.editor, model.selection[0]);
+ self.insertMediaInEditor(args.editor, model.selection[0], imgDomElement);
editorService.close();
},
close: function () {
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
index 837c0ebc9d..24b8b999fa 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
@@ -98,11 +98,15 @@ angular.module("umbraco")
gotoStartNode();
}
} else {
- //if a target is specified, go look it up - generally this target will just contain ids not the actual full
- //media object so we need to look it up
+ // if a target is specified, go look it up - generally this target will just contain ids not the actual full
+ // media object so we need to look it up
var id = $scope.target.udi ? $scope.target.udi : $scope.target.id;
var altText = $scope.target.altText;
- entityResource.getById(id, "Media")
+
+ // ID of a UDI or legacy int ID still could be null/undefinied here
+ // As user may dragged in an image that has not been saved to media section yet
+ if(id){
+ entityResource.getById(id, "Media")
.then(function (node) {
$scope.target = node;
if (ensureWithinStartNode(node)) {
@@ -113,6 +117,12 @@ angular.module("umbraco")
}
},
gotoStartNode);
+ }
+ else {
+ // No ID set - then this is going to be a tmpimg that has not been uploaded
+ // User editing this will want to be changing the ALT text
+ $scope.openDetailsDialog();
+ }
}
}
@@ -508,4 +518,4 @@ angular.module("umbraco")
onInit();
- });
\ No newline at end of file
+ });
diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.controller.js
index ddfca295d4..1f39c2423e 100644
--- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/mediafolderpicker.controller.js
@@ -27,7 +27,7 @@ function mediaFolderPickerController($scope, editorService, entityResource) {
$scope.add = function() {
var mediaPickerOptions = {
view: "mediapicker",
- multiPicker: true,
+ multiPicker: false, // We only want to allow you to pick one folder at a given time
disableFolderSelect: false,
onlyImages: false,
onlyFolders: true,
diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
index 0b37638afd..2c2c69d181 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;
@@ -86,26 +87,63 @@ namespace Umbraco.Web.PropertyEditors
if (rawJson.IsNullOrWhiteSpace())
return null;
- 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;
}
}