Вставить текст в текущую позицию курсора в раскрывающемся списке, измененном внутри iframe

Я использую текстовый редактор, предоставленный Microsoft ajax-toolkit.
Он отображает iframe в браузере. Я добавил раскрывающийся список в этом редакторе, и я хочу, чтобы при изменении индекса раскрывающегося списка значение должно быть добавлено в текущую позицию курсора в редакторе.

У меня есть код на SO, который дает мне текущий выделенный текст внутри редактора следующим образом

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;
        }
 }

Но я хочу добавить текст в текущую позицию. Html отображается как ниже

<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>

Я стараюсь следовать

$("#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));
        });

функция вставки текста не работает с iframe, как следует

$.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();
            }
        }
    })

Ответ 1

Легко, вам просто нужно использовать.

$( "# Editor1_ctl02_ctl00" ) содержание() найти ( 'текстовое поле') insertAtCaret ( 'значение');...

Обновление

Извините, я думал, что функция insertAtCaret работает для вас, вам просто нужно работать внутри iFrame. Вы можете использовать эту версию 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);
                }
            }
        )
    }
});

и назовите его так:

$( "# Editor1_ctl02_ctl00" ) содержание() найти ( 'тело') insertAtCaret ($ Вэл)...

Функция, адаптированная из здесь

Счастливое кодирование!

Ответ 2

Здесь, кажется, несколько проблем.

  • В редакторе Microsoft ajax-toolkit создается iframe, где включено свойство designMode, и почему оно редактируется, он не имеет значения, а textNodes добавляются прямо к телу, что делает его немного сложнее.

  • Когда вы выбираете что-то из выпадающего списка, основное внимание уделяется выпадающему меню, и нет позиции каретки, так как фокус смещается от iFrame.
    Я предполагаю, что выпадающий список находится в верхней строке редактора или где-либо еще, что находится за пределами iFrame.

Кроме того, в редакторе Microsoft ajax-toolkit есть рекомендуемое обновление, HTMLEditorExtender.

Код, который вы должны зафиксировать в позиции каретки, кажется, предназначен для обычного ввода /textarea, и вам придется адаптировать этот код для работы с любым Node внутри iframe, который находится в designMode, с его собственным окном и документ и т.д.

Учитывая приведенные выше соображения, это то, что я придумал для этого.

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