From e6d6dce3a8e6b00c97676b920e6ede2f02c27741 Mon Sep 17 00:00:00 2001
From: Mehmet <36473707+ustadstar@users.noreply.github.com>
Date: Mon, 28 Feb 2022 13:17:17 +0100
Subject: [PATCH] Fix mssing image caption in RTE (#11807)
---
.../Models/RichTextEditorSettings.cs | 2 +-
.../src/common/services/tinymce.service.js | 146 +++++++++---------
2 files changed, 70 insertions(+), 78 deletions(-)
diff --git a/src/Umbraco.Core/Configuration/Models/RichTextEditorSettings.cs b/src/Umbraco.Core/Configuration/Models/RichTextEditorSettings.cs
index 6ea563c741..de8215a51b 100644
--- a/src/Umbraco.Core/Configuration/Models/RichTextEditorSettings.cs
+++ b/src/Umbraco.Core/Configuration/Models/RichTextEditorSettings.cs
@@ -7,7 +7,7 @@ namespace Umbraco.Cms.Core.Configuration.Models
[UmbracoOptions(Constants.Configuration.ConfigRichTextEditor)]
public class RichTextEditorSettings
{
- internal const string StaticValidElements = "+a[id|style|rel|data-id|data-udi|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|reversed|start|style|type],-ul[class|style],-li[class|style],br[class],img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel|data-id],-sub[style|class],-sup[style|class],-blockquote[dir|style|class],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*]";
+ internal const string StaticValidElements = "+a[id|style|rel|data-id|data-udi|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|reversed|start|style|type],-ul[class|style],-li[class|style],br[class],img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel|data-id],-sub[style|class],-sup[style|class],-blockquote[dir|style|class],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*],figure,figcaption";
internal const string StaticInvalidElements = "font";
private static readonly string[] s_default_plugins = new[]
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 e6eb430201..98543a7c68 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
@@ -11,7 +11,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
//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
- var extendedValidElements = "@[id|class|style],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align],span[id|class|style|lang]";
+ var extendedValidElements = "@[id|class|style],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align],span[id|class|style|lang],figure,figcaption";
var fallbackStyles = [{ title: "Page header", block: "h2" }, { title: "Section header", block: "h3" }, { title: "Paragraph header", block: "h4" }, { title: "Normal", block: "p" }, { title: "Quote", block: "blockquote" }, { title: "Code", block: "code" }];
// these languages are available for localization
var availableLanguages = [
@@ -292,7 +292,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
}
function sizeImageInEditor(editor, imageDomElement, imgUrl) {
-
var size = editor.dom.getSize(imageDomElement);
if (editor.settings.maxImageSize && editor.settings.maxImageSize !== 0) {
@@ -656,21 +655,19 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
stateSelector: 'img[data-udi]',
onclick: function () {
-
- var selectedElm = editor.selection.getNode(),
- currentTarget,
- imgDomElement;
+ var selectedElm = editor.selection.getNode(),
+ currentTarget;
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"),
- url: img.attr("src")
+ url: img.attr("src"),
+ caption: img.attr('data-caption')
};
if (hasUdi) {
@@ -687,85 +684,80 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
userService.getCurrentUser().then(function (userData) {
if (callback) {
angularHelper.safeApply($rootScope, function() {
- callback(currentTarget, userData, imgDomElement);
+ callback(currentTarget, userData);
});
}
});
}
});
},
-
- insertMediaInEditor: function (editor, img, imgDomElement) {
+ /**
+ * @ngdoc method
+ * @name umbraco.services.tinyMceService#insetMediaInEditor
+ * @methodOf umbraco.services.tinyMceService
+ *
+ * @description
+ * Inserts the image element in tinymce plugin
+ *
+ * @param {Object} editor the TinyMCE editor instance
+ */
+ insertMediaInEditor: function (editor, img) {
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;
-
- if(img.url !== editor.dom.getAttrib(imgDomElement, "src")){
- hasImageSrcChanged = true;
+ // 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,
+ "data-caption": img.caption
+ };
+ var newImage = editor.dom.createHTML('img', data);
+ var parentElement = editor.selection.getNode().parentElement;
+
+ if (img.caption) {
+ var figCaption = editor.dom.createHTML('figcaption', {}, img.caption);
+ var combined = newImage + figCaption;
+
+ if (parentElement.nodeName !== 'FIGURE') {
+ var fragment = editor.dom.createHTML('figure', {}, combined);
+ editor.selection.setContent(fragment);
}
-
- // If null/undefinied it will remove the attribute
- editor.dom.setAttrib(imgDomElement, "alt", img.altText);
-
- // 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);
+ else {
+ parentElement.innerHTML = combined;
}
-
- // 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;
- }
-
- });
-
}
+ else {
+ //if caption is removed, remove the figure element
+ if (parentElement.nodeName === 'FIGURE') {
+ parentElement.parentElement.innerHTML = newImage;
+ }
+ else {
+ editor.selection.setContent(newImage);
+ }
+ }
+
+ // 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;
+ }
+
+ });
+
}
},