Insert text at current cursor position on dropdown list changed inside iframe
Asked Answered
K

2

11

I am using a text editor provided by Microsoft ajax-toolkit.
It renders iframe on browser. I have added a dropdown in that editor and I want that when user changes the drop-down index the value should be added in the editor current cursor position.

I got a code on SO which gives me the current selected text inside editor is as follows

function getIframeSelectionText(iframe) {
        var win = iframe.contentWindow;
        var doc = iframe.contentDocument || win.document;

        if (win.getSelection) {
            return win.getSelection().toString();

        } else if (doc.selection && doc.selection.createRange) {
            return doc.selection.createRange().text;
        }
 }

But I want to add some text at the current position. The html is rendering as below

<td class="ajax__htmleditor_editor_editpanel"><div id="Editor1_ctl02" style="height:100%;width:100%;">
            <iframe id="Editor1_ctl02_ctl00" name="Editor1_ctl02_ctl00" marginheight="0" marginwidth="0" frameborder="0" style="height:100%;width:100%;display:none;border-width:0px;">

            </iframe><textarea id="Editor1_ctl02_ctl01" class="ajax__htmleditor_htmlpanel_default" style="height:100%;width:100%;display:none;"></textarea><iframe id="Editor1_ctl02_ctl02" name="Editor1_ctl02_ctl02" marginheight="0" marginwidth="0" frameborder="0" style="height:100%;width:100%;display:none;border-width:0px;">

            </iframe>
        </div></td>

I am trying as follow

$("#imgDropdown").change(function () {
            //var iframeBody =    $(window.Editor1_ctl02_ctl00.document.getElementsByTagName("body")[0]);
            var iframe = document.getElementById("Editor1_ctl02_ctl00");
            $("#Editor1_ctl02_ctl00").find("body").insertAtCaret("value");
            //alert(getIframeSelectionText(iframe));
        });

the function for inserting text is not working with iframe is as follow

$.fn.extend({
        insertAtCaret: function (myValue) {
            if (document.selection) {
                this.focus();
                sel = document.selection.createRange();
                sel.text = myValue;
                this.focus();
            }
            else if (this.selectionStart || this.selectionStart == '0') {
                var startPos = this.selectionStart;
                var endPos = this.selectionEnd;
                var scrollTop = this.scrollTop;
                this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos, this.value.length);
                this.focus();
                this.selectionStart = startPos + myValue.length;
                this.selectionEnd = startPos + myValue.length;
                this.scrollTop = scrollTop;
            } else {
                this.value += myValue;
                this.focus();
            }
        }
    })
Kalmick answered 29/3, 2014 at 12:45 Comment(5)
Any console errors (for example, security problems)?Toper
What specifically is not working? Can you test that the function is being called correctly with the correct parameters, etc. for us?Message
The $("#Editor1_ctl02_ctl00").find("body").insertAtCaret("value"); is not working it should insert the values in the body where the current pointer is.Shilashilha
Could you provide a jsfiddle?Taishataisho
Is the code even correctly entering into the .insertAtCaret() function? Can you successfully place an alert in there to test it gets inside that function?Message
O
8

Easy, you just have to use.

$("#Editor1_ctl02_ctl00").contents().find('textarea').insertAtCaret('value');

Updated

Sorry, I thought the insertAtCaret function is working for you, you just needed to work inside iFrame. You can use this version of insertAtCaret:

jQuery.fn.extend({
    insertAtCaret: function (html) {
        var winObject = function (el){
            var doc = el.ownerDocument;
            return doc.defaultView || doc.parentWindow
        };
        return this.each(function (i) {
                var sel, range, w = this;
                w = winObject(w);
                if (w.getSelection) {
                    // IE9 and non-IE
                    sel = w.getSelection();
                    if (sel.getRangeAt && sel.rangeCount) {
                        range = sel.getRangeAt(0);
                        range.deleteContents();

                        // Range.createContextualFragment() would be useful here but is
                        // only relatively recently standardized and is not supported in
                        // some browsers (IE9, for one)
                        var el = w.document.createElement("div");
                        el.innerHTML = html;
                        var frag = w.document.createDocumentFragment(), node, lastNode;
                        while ((node = el.firstChild)) {
                            lastNode = frag.appendChild(node);
                        }
                        range.insertNode(frag);

                        // Preserve the selection
                        if (lastNode) {
                            range = range.cloneRange();
                            range.setStartAfter(lastNode);
                            range.collapse(true);
                            sel.removeAllRanges();
                            sel.addRange(range);
                        }
                    }
                } else if (w.document.selection && w.document.selection.type != "Control") {
                    // IE < 9
                    w.document.selection.createRange().pasteHTML(html);
                }
            }
        )
    }
});

and call it like:

$("#Editor1_ctl02_ctl00").contents().find('body').insertAtCaret($val);

Function adapted from here

Happy coding!

Orlantha answered 4/4, 2014 at 3:10 Comment(3)
thank for you response but there is no textarea inside my editor.Shilashilha
thank it's is working in Mozilla but not working in ie.Shilashilha
Which version of ie? Working on my IE 10.Orlantha
T
0

There seem to be a few issues here.

  1. The Microsoft ajax-toolkit editor creates an iframe where the designMode property is turned on, and that's why it's editable, it has no value, and textNodes are added straight to the body, which makes it a little more difficult.

  2. When you're selecting something from a dropdown, the focus is on the dropdown, and there is no caret position, as the focus is shifted away from the iFrame.
    I'm assuming that the dropdown is in the top menubar for the editor or anywhere else that is outside the iFrame.

Also, the Microsoft ajax-toolkit editor has a recommended update, the HTMLEditorExtender.

The code you have to capture the caret position seems to be for a regular input / textarea, and you'd have to adapt that code to work with any Node inside an iframe that is in designMode, with it's own window and document etc.

Given the above considerations, this is what I came up with to do this

var frameID  = 'Editor1_ctl02_ctl00',
    selectID = 'imgDropdown',
    iframe   = document.getElementById(frameID),
    iWin     = iframe.contentWindow ? iframe.contentWindow : window.frames[frameID];

$(iWin).on('blur', function() {
    $(iframe).data('range', getRange(iWin));
});

$('#' + selectID).on('change', function() {
    var range = $(iframe).data('range');
    addText(iWin, range, this.value);
});


function getRange(win) {
    var sel, range, html;
    if (win.getSelection) {
        sel = win.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();
        }
    } else if (win.document.selection && win.document.selection.createRange) {
        range = win.document.selection.createRange();
    }
    return range;
}

function addText(win, range, text) {
    if (win.getSelection) {
       range.insertNode(win.document.createTextNode(text));
    } else if (win.document.selection && win.document.selection.createRange) {
        range.text = text;
    }
}

FIDDLE

Tagalog answered 8/4, 2014 at 0:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.