RadEditor.getSelectedElement() does not return a svg-element in Chrome & Edge

4 Answers 187 Views
Editor
Matthias
Top achievements
Rank 2
Iron
Matthias asked on 28 Jul 2021, 09:45 AM | edited on 28 Jul 2021, 02:40 PM

As for the context:
We're using telerik:RadEditor to e.g. edit and display html-contents including SVGs (scalable vector graphics). In this editor we have declared multiple EditorContextMenu containing EditorTools, which call custom js-functions which in turn perform the intended actions.

This is an extract of our code:

<script type="text/javascript">
    Telerik.Web.UI.Editor.CommandList["ChangeDiagramm"] = function (commandName, editor, args) {
        var elem = editor.getSelectedElement();
        /* Issue: Depending on the browser, "elem" is or is not a SVG, although the EditorContextMenu, mentioned below, is the only one calling this js-function! */
        if (elem.tagName.toUpperCase() == "SVG") {
            StartModalDialog('EditHtmliagramRedirect.aspx?ID=' + elem.attributes.name.value, 500, 600, 1);
        }
    };
</script>

<telerik:RadEditor ExternalDialogsPath="~/Documentation/Documentation/Dialogs/Editor/Controls" EnableTrackChanges="false" 
    EnableComments="false" ID="ReHtml" EnableResize="False" NewLineMode="P" runat="server" OnClientLoad="OnClientLoaded" 
    OnClientSubmit="OnClientSubmit" OnClientPasteHtml="OnClientPasteHtml" OnClientCommandExecuting="OnClientCommandExecuting" 
    OnClientCommandExecuted="OnClientCommandExecuted" OnClientSelectionChange="OnClientSelectionChanged" UseRadContextMenu="False">

    <ContextMenus>
        <telerik:EditorContextMenu TagName="svg">
            <telerik:EditorTool Name="ChangeDiagramm" ShowIcon="true" Text="Edit SVG" ShowText="false" />
        </telerik:EditorContextMenu>
        <%--                         
		More EditorContextMenus each of which for different html-tags; none of them related to SVGs (img, a, li, span, ...)
        --%>
    </ContextMenus>
    
</telerik:RadEditor>

 

Example-editor-content:

<p>before</p><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="391px" height="221px" viewBox="-0.5 -0.5 391 221" name="c26facdc-b9af-46d3-8de6-7afc86696afa"><defs style=""></defs><g style=""><rect x="0" y="0" width="80" height="80" fill="#ffffff" stroke="#000000" pointer-events="all"></rect>
<path d="M 110 0 L 210 0 L 230 40 L 210 80 L 110 80 L 130 40 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
<path d="M 270 0 L 370 0 L 390 20 L 390 80 L 290 80 L 270 60 L 270 0 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
<path d="M 270 0 L 370 0 L 390 20 L 290 20 Z" fill-opacity="0.05" fill="#000000" stroke="none" pointer-events="all"></path>
<path d="M 270 0 L 290 20 L 290 80 L 270 60 Z" fill-opacity="0.1" fill="#000000" stroke="none" pointer-events="all"></path>
<path d="M 290 80 L 290 20 L 270 0 M 290 20 L 390 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
<path d="M 40 80 Q 80 220 205 220 Q 330 220 339.55 86.35" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"></path>
<path d="M 339.92 81.12 L 342.91 88.35 L 339.55 86.35 L 335.93 87.85 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
</g></svg><p>after</p>

For a long time, this code was working as intended in Firefox, Chrome and Microsoft Edge (the new one, based on the chromium engine). I.e. if someone right-clicks the svg-graphic in "Design"-mode of the editor, the corresponding js-function is being called and the "elem"-variable within the js-function has been set to the svg-element of the "Example-editor-content", hence fulfilling the if-statement and opening the modal dialog.

As of recent Edge and Chrome now show "elem" to be the "p"-tag containing the text "after", whereas Firefox still works as intended and sets "elem" to the "svg"-tag. Unfortunately I don't know the exact date, when it broke.

I suspect, the issue might be due to changes in Chrome/Edge/chromium, because the same issue also arises in older versions of our web-application. But since the editor.getSelectedElement-js-function is a black-box to me, I'm not able to confirm this.

Could you please investigate this issue?

4 Answers, 1 is accepted

Sort by
0
Accepted
Matthias
Top achievements
Rank 2
Iron
answered on 31 Mar 2022, 10:23 AM

Hi,

unfortunately, we still encounter the same issue. Therefore I was wondering if you could take a look at this paragraph from my previous answer.

What I'm curious about is this: The following code works properly for and only for right-clicks on svg-tags (in Chrome/Edge and Firefox). How do you manage to detect/figure out that the right-click is being performed on an svg-element (in Edge/Chrome)? If I can adopt this mechanism, my issue would be resolved.

<telerik:EditorContextMenu TagName="svg">
    <telerik:EditorTool Name="ChangeDiagramm" ShowIcon="true" Text="Edit SVG" ShowText="false" />
</telerik:EditorContextMenu>

Kind Regards,
Matthias

Rumen
Telerik team
commented on 04 Apr 2022, 02:43 PM

Hi Matthias,

I examined the code of the context menu functionality and found out that it relies on this line var node = e.srcElement || e.target to detect the returned by the browser node:

_getContextElement: function (e) {
		
		var editor = this.get_editor();
		var node = e.srcElement || e.target;
		var isTag = function(name) { return EditorUtils.isTag(node, name); };
		var map2img = function(map) { return editor.findContent("img[usemap='#" + map.id + "']")[0]; };

		if(isTag("area")) {
			node = map2img(node.parentNode);
		}
		else if(isTag("map")) {
			node = map2img(node);
		}

		return node;
	},

So please try the following code to get the node type being svg, rect, g or another custom tag:

            <script>
                var node = null;
                function OnClientSelectionChange(editor, args) {
                    var element = editor.get_contentArea();
                    $telerik.addExternalHandler(element, "click", function (e) {
                        node = e.srcElement || e.target;

                        console.log(node.tagName);
                    });
                    $telerik.addExternalHandler(element, "contextmenu", function (e) {
                        node = e.srcElement || e.target;

                        console.log(node.tagName);
                    });
                }
            </script>
            <telerik:RadEditor OnClientSelectionChange="OnClientSelectionChange" ContentAreaMode="div" runat="server" ID="RadEditor1">
                <Content>
                   <p>before</p><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="391px" height="221px" viewBox="-0.5 -0.5 391 221" name="c26facdc-b9af-46d3-8de6-7afc86696afa"><defs style=""></defs><g style=""><rect x="0" y="0" width="80" height="80" fill="#ffffff" stroke="#000000" pointer-events="all"></rect>
<path d="M 110 0 L 210 0 L 230 40 L 210 80 L 110 80 L 130 40 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
<path d="M 270 0 L 370 0 L 390 20 L 390 80 L 290 80 L 270 60 L 270 0 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
<path d="M 270 0 L 370 0 L 390 20 L 290 20 Z" fill-opacity="0.05" fill="#000000" stroke="none" pointer-events="all"></path>
<path d="M 270 0 L 290 20 L 290 80 L 270 60 Z" fill-opacity="0.1" fill="#000000" stroke="none" pointer-events="all"></path>
<path d="M 290 80 L 290 20 L 270 0 M 290 20 L 390 20" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
<path d="M 40 80 Q 80 220 205 220 Q 330 220 339.55 86.35" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"></path>
<path d="M 339.92 81.12 L 342.91 88.35 L 339.55 86.35 L 335.93 87.85 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"></path>
</g></svg><p>after</p>
                    <hr/>
                    <p>before</p><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="241px" height="81px" viewBox="-0.5 -0.5 241 81" name="e02f6c85-f392-452f-965e-0c0f8eeeb0e2"><defs style=""></defs><g style=""><rect x="0" y="0" width="80" height="80" fill="#ffffff" stroke="#000000" pointer-events="all"></rect><rect x="200" y="30" width="40" height="20" fill="none" stroke="none" pointer-events="all"></rect><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 40px; margin-left: 201px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">my text</div>
</div>
</div>
</foreignObject><text x="220" y="44" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">my text</text></switch></g></g></svg><p>after</p>
                </Content>
                <Modules>
                    <telerik:EditorModule Name="RadEditorDomInspector" />
                </Modules>
                <ContextMenus>
                    <telerik:EditorContextMenu TagName="svg">
                        <telerik:EditorTool Name="ChangeDiagramm" ShowIcon="true" Text="Edit SVG" ShowText="false" />
                    </telerik:EditorContextMenu>
                    <telerik:EditorContextMenu TagName="rect">
                        <telerik:EditorTool Name="ChangeDiagramm" ShowIcon="true" Text="Edit SVG" ShowText="false" />
                    </telerik:EditorContextMenu>
                    <telerik:EditorContextMenu TagName="path">
                        <telerik:EditorTool Name="ChangeDiagramm" ShowIcon="true" Text="Edit SVG" ShowText="false" />
                    </telerik:EditorContextMenu>
                    <%--                         
		More EditorContextMenus each of which for different html-tags; none of them related to SVGs (img, a, li, span, ...)
                    --%>
                </ContextMenus>
                <Tools>
                    <telerik:EditorToolGroup>
                        <telerik:EditorTool Name="ChangeDiagramm" />
                    </telerik:EditorToolGroup>
                </Tools>
            </telerik:RadEditor>
            <script type="text/javascript">
                Telerik.Web.UI.Editor.CommandList["ChangeDiagramm"] = function (commandName, editor, args) {
                    
                    
                    /* Issue: Depending on the browser, "elem" is or is not a SVG, although the EditorContextMenu, mentioned below, is the only one calling this js-function! */
                    if (node.tagName.toLowerCase() == "svg" || node.tagName.toLowerCase() == "rect" || node.tagName.toLowerCase() == "g") {
                        console.log("svg selected")
                    }
                };
            </script>

0
Rumen
Telerik team
answered on 30 Jul 2021, 12:19 PM

Hi Matthias,

Thank you for reporting this browser behavior!

The selection support of SVG elements in the editable HTML elements is limited and there are different glitches related to them.

The content area of RadEditor is an editable iframe/div element that uses the underlying rich text editing engine of the browser under which it operates.

I tested the provided svg content in an editable iframe (a sample HTML page is attached) under IE, Chrome and Firefox and noticed that the SVG content is not selectable in Firefox and Chrome and selectable only in IE.

Since there is no reliable selection the context menu for SVG tag also works strangely and shows only when right-clicking outside of the shapes -

If you right-click over an svg shape the context menu does not show:

The next step was to debug the getSelectedElement method which showed me that the latest version of Chrome now doesn't return a tagName in Chrome when the SVG is clicked but a text (text node). I am not sure whether this is going to be changed in the future versions of the browser, but it will be hard to be fixed since no tag is returned. 

What you can try is to obtain the selection with another library https://github.com/timdown/rangy / https://github.com/timdown/rangy/wiki or the API provided by the browser. 

You can also check this SO item for more ideas: https://stackoverflow.com/questions/5676737/access-an-selected-image-within-a-contenteditable-field-in-an-iframe

Last but not least, if we find a solution for this browser issue, we will apply to the getSelectedElement function source code and notify you right away.

Best Regards,
Rumen
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Matthias
Top achievements
Rank 2
Iron
commented on 02 Aug 2021, 06:59 AM

Hi Rumen,
unfortunately I am not able to find the sample-page you've tried to attach. Could you please send me a direct link to it? Thanks in advance.
Best Regards,
Matthias
0
Matthias
Top achievements
Rank 2
Iron
answered on 02 Aug 2021, 08:11 AM | edited on 02 Aug 2021, 08:39 AM

Hi Rumen,

I've also noticed, that right-clicking any svg-element vs right-clicking in between the elements does make a difference. For our use-case I'd wish for it to be the same behavior in both cases (resulting in the "edit svg"-context), but I can also see why it wouldn't be that way by default - besides, that's not the scope of this question.

I've tried the document.geSelection() of the SO item you mentioned, but to no avail. In Edge/Chrome this just returns the node after the svg-element; the same as editor.getSelectedElement(); from my original question. And although I did not try Rangy myself, I would imagine, that this js-library would run into the same restrictions as we've already discussed: Having a different behavior in Edge/Chrome than in Firefox.

What I'm curious about is this: The following code properly works for and only for right-clicks on svg-tags (in Chrome/Edge and Firefox). How do you manage to detect/figure out that the right-click is being performed on an svg-element (in Edge/Chrome)? If I can adopt this mechanism, my issue would be resolved.

<telerik:EditorContextMenu TagName="svg">
    <telerik:EditorTool Name="ChangeDiagramm" ShowIcon="true" Text="Edit SVG" ShowText="false" />
</telerik:EditorContextMenu>

Best regards,
Matthias

P.S.: I just realized, when using a different but similar content (modified svg), the editor.getSelectedElement() method works as expected; unfortunately, this does not resolve my issue.

Modified svg/content:
<p>before</p><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="241px" height="81px" viewBox="-0.5 -0.5 241 81" name="e02f6c85-f392-452f-965e-0c0f8eeeb0e2"><defs style=""></defs><g style=""><rect x="0" y="0" width="80" height="80" fill="#ffffff" stroke="#000000" pointer-events="all"></rect><rect x="200" y="30" width="40" height="20" fill="none" stroke="none" pointer-events="all"></rect><g transform="translate(-0.5 -0.5)"><switch><foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 40px; margin-left: 201px;">
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">my text</div>
</div>
</div>
</foreignObject><text x="220" y="44" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">my text</text></switch></g></g></svg><p>after</p>

0
Matthias
Top achievements
Rank 2
Iron
answered on 07 Apr 2022, 03:48 PM

Hi Rumen,

thank you very much for your insights and the sample code. As a proof of concept, your code works beautifully and I've managed to adapt it to our needs in no time!

To anyone trying to do the same thing, please bare in mind that the following javascript will add an additional handler for each click you perform, because those handler's do currently NOT get removed at all!

var node = null;
function OnClientSelectionChange(editor, args) {
    var element = editor.get_contentArea();
    $telerik.addExternalHandler(element, "click", function (e) {
        node = e.srcElement || e.target;

        console.log(node.tagName);
    });
    $telerik.addExternalHandler(element, "contextmenu", function (e) {
        node = e.srcElement || e.target;

        console.log(node.tagName);
    });
}

To work around this issue, one can simply keep track of the current handler and remove it before adding a new one; e.g.:

// remove old handler, if it exists
if (clickHandler)
    $telerik.removeExternalHandler(element, "click", clickHandler);
// declare new handler (overriding the old one)
clickHandler = function (e) {
    node = e.srcElement || e.target;
    //console.log("click" + node.tagName);
};
// add new handler
$telerik.addExternalHandler(element, "click", clickHandler);

 

Thank you again very much!

Kind regards,
Matthias

Rumen
Telerik team
commented on 08 Apr 2022, 08:34 AM

Awesome, I used your example to update the attachEventHandler article in the help.

Keep up the great work!

Matthias
Top achievements
Rank 2
Iron
commented on 08 Apr 2022, 08:46 AM

Thanks for the hint; glad, I could return the favor.
Tags
Editor
Asked by
Matthias
Top achievements
Rank 2
Iron
Answers by
Matthias
Top achievements
Rank 2
Iron
Rumen
Telerik team
Share this question
or