Замена текста внутри текстовой области без фокуса - PullRequest
6 голосов
/ 19 декабря 2010

Я хочу заменить выделенный текст (или вставить новый текст после позиции курсора, если ничего не выделено).Новый текст вводится из другого текстового поля.
Я хочу иметь возможность вставлять новый текст, не щелкая сначала (фокусируя) в текстовой области.
значение: сначала выберите текст для замены внутри текстовой области, затем введите новый текст в полетекстовое поле и нажмите кнопку.

<textarea id='text' cols="40" rows="20">
</textarea>

<div id="opt">
    <input id="input" type="text" size="35">
    <input type="button" onclick='pasteIntoInput(document.getElementById("input").value)' value="button"/>    
</div>


function pasteIntoInput(text) { 
  el=document.getElementById("text");
  el.focus();    
  if (typeof el.selectionStart == "number"&& typeof el.selectionEnd == "number") { 
    var val = el.value; 
    var selStart = el.selectionStart;
    el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);        
    el.selectionEnd = el.selectionStart = selStart + text.length;
  } 
  else if (typeof document.selection != "undefined") {
    var textRange = document.selection.createRange();        
    textRange.text = text;       
    textRange.collapse(false);        
    textRange.select();
  } 
}  

Онлайн пример: текст ссылки

Ответы [ 4 ]

5 голосов
/ 19 декабря 2010

Итак, вы хотите сохранить выделение, когда вы фокусируете текстовую область и фокусируете на теге ввода.

Вам нужно запомнить выделение (начальную и конечную точки, когда текстовая область теряет фокус) и принудительно выделить выделение, чтобы оно сохранялось.

Чтобы запомнить выборку, вы можете сохранить el.selectionStart и el.selectionEnd в двух глобальных переменных внутри функции, которая вызывается при onblur() событии тега textarea.

Тогда внутри вашего pasteIntoInput() вы можете рассмотреть эти две точки для замены.

Для принудительного выбора - проверьте это решение для сохранения выбора. Однако здесь используется jquery, а не простой javascript.

Однако я не уверен, действительно ли решение работает. Я попробовал это здесь http://jsfiddle.net/sandeepan_nits/qpZdJ/1/, но это не работает, как ожидалось.

Обновление

Сомневаюсь, можно ли сохранить выбор после того, как фокус исчезнет Вероятно, для выбора необходим фокус, и ссылка на ответ, которую я дал, пытается сфокусироваться, а затем выбрать. В этом случае это не решит вашу проблему. Таким образом, альтернативы могут быть -

  • подделка текстовой области с помощью html div. Вы можете определить некоторые стили, чтобы создать эффект выделения и применить его onblur() или использовать простой готовый редактор, если он доступен.

  • Отображение выделения динамически в отдельной области. Проверьте это демо jquery fieldSelection plugin . Помните, что вы уже сохраняете выделение в глобальных переменных для фактической замены. Вам нужно только отобразить пользователю выбор, который будет заменен. Я думаю, что отображение выбора отдельно, как эта демонстрация, экономит ваше время, и это тоже выглядит круто.

Но, конечно, зависит от ваших требований.

Дальнейшее обновление

Проверьте http://jsfiddle.net/sandeepan_nits/qpZdJ/2/ для работающей «Замена текста внутри текстовой области без фокуса» (как вы хотите), но без выделения на размытие. Я до сих пор не знаю, можно ли оставить выделение размытым.

Другое обновление (21 декабря)

Рабочее решение для IE, а также других браузеров http://jsfiddle.net/sandeepan_nits/qpZdJ/24/

Вот тот же код: -

HTML -

<textarea id='text' cols="40" rows="20" onbeforedeactivate="storeSelectionIeCase();" onblur="storeSelectionOthersCase();">
</textarea>

<div id="opt">
    <input id="input" type="text" size="35">
    <input type="button" onclick='pasteIntoInput(document.getElementById("input").value)' value="button"/>

</div>

и все JS

var storedSelectionStart = null;
var storedSelectionEnd = null;

function pasteIntoInput(text)
{

    el=document.getElementById("text");

    el.focus();    
    if((storedSelectionStart != null) && (storedSelectionEnd != null))
    {
        start = storedSelectionStart;
        end = storedSelectionEnd;
    }
    else
    {
        start = el.selectionStart;
        end = el.selectionEnd;
    }
    if (typeof start  == "number"&& typeof end == "number")
    {
        var val = el.value;
        var selStart = start;
        var end  = selStart + text.length;
        el.value = val.slice(0, selStart) + text + val.slice(end );        
    }
    else if (typeof document.selection != "undefined")
    {
       var textRange = document.selection.createRange();        
       textRange.text = text;       
       textRange.collapse(false);        
       textRange.select();
    }
}  

function storeSelectionOthersCase()
{
    if(!(isBrowserIE6() || isBrowserIE7()))
    {
        storeSelection();
    }
    else
    {
        return false;
    }
}


function storeSelectionIeCase()
{
    if((isBrowserIE6() || isBrowserIE7()))
    {
        storeSelection();
    }
    else
    {
        return false;
    }
}


function storeSelection()
{
    //get selection
    el=document.getElementById("text");

    var el = document.getElementById("text");
    var sel = getInputSelection(el);
    //alert("check"+sel.start + ", " + sel.end);


    storedSelectionStart  = sel.start;
    storedSelectionEnd = sel.end;

   //alert("see"+storedSelectionStart  +" - "+storedSelectionEnd );
}

function getInputSelection(el)
{
    var start = 0, end = 0, normalizedValue, range,
        textInputRange, len, endRange;

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        start = el.selectionStart;
        end = el.selectionEnd;
    } else {
        range = document.selection.createRange();

        if (range && range.parentElement() == el) {
            len = el.value.length;
            normalizedValue = el.value.replace(/\r\n/g, "\n");

            // Create a working TextRange that lives only in the input
            textInputRange = el.createTextRange();
            textInputRange.moveToBookmark(range.getBookmark());

            // Check if the start and end of the selection are at the very end
            // of the input, since moveStart/moveEnd doesn't return what we want
            // in those cases
            endRange = el.createTextRange();
            endRange.collapse(false);

            if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
                start = end = len;
            } else {
                start = -textInputRange.moveStart("character", -len);
                start += normalizedValue.slice(0, start).split("\n").length - 1;

                if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
                    end = len;
                } else {
                    end = -textInputRange.moveEnd("character", -len);
                    end += normalizedValue.slice(0, end).split("\n").length - 1;
                }
            }
        }
    }

    return {
        start: start,
        end: end
    };
}

function isBrowserIE6()
{
    var ret = false;
    if(($.browser.msie) && (parseInt($.browser.version) == 6) && (!this.XMLHttpRequest))
    {
        ret = true;
    }
    return ret;
}

function isBrowserIE7()
{
    var ret = false;
    if(($.browser.msie) && ((parseInt($.browser.version) == 7) && (this.XMLHttpRequest)))
    { //Modification because of IE tester IE7 being detected as IE6
        ret = true;
    }
    return ret;
}

Предыдущая скрипта не работала в IE, потому что к моменту возникновения события onblur() выбор в IE был уничтожен. Я применил некоторые браузерные условия для IE 6 и 7, но еще не тестировал в IE 8.

Спасибо Тиму Дауну , который помог мне выявить проблему с предыдущей скрипкой.

0 голосов
/ 31 августа 2012

Плагин jquery для начала и конца индекса выделения в текстовой области.Приведенные выше коды javascript не работали для IE7 и IE8 и дали очень противоречивые результаты, поэтому я написал этот небольшой плагин jquery.Позволяет временно сохранить начальный и конечный индексы выбора и выделить его позднее.

Рабочий пример и краткая версия здесь: http://jsfiddle.net/hYuzk/3/

Более подробная версия с комментариямии т.д. здесь: http://jsfiddle.net/hYuzk/4/

        // Cross browser plugins to set or get selection/caret position in textarea, input fields etc for IE7,IE8,IE9, FF, Chrome, Safari etc
        $.fn.extend({
            // Gets or sets a selection or caret position in textarea, input field etc.
            // Usage Example: select text from index 2 to 5 --> $('#myTextArea').caretSelection({start: 2, end: 5});
            //                get selected text or caret position --> $('#myTextArea').caretSelection();
            //                if start and end positions are the same, caret position will be set instead o fmaking a selection
            caretSelection : function(options)
            {
            if(options && !isNaN(options.start) && !isNaN(options.end))
            {
                this.setCaretSelection(options);
            }
            else
            {
                return this.getCaretSelection();
            }
            },
            setCaretSelection : function(options)
            {
            var inp = this[0];
            if(inp.createTextRange)
            {
                var selRange = inp.createTextRange();
                selRange.collapse(true);
                selRange.moveStart('character', options.start);
                selRange.moveEnd('character',options.end - options.start);
                selRange.select();
            }
            else if(inp.setSelectionRange)
            {
                inp.focus();
                inp.setSelectionRange(options.start, options.end);
            }
            },
            getCaretSelection: function()
            {
            var inp = this[0], start = 0, end = 0;
            if(!isNaN(inp.selectionStart))
            {
                start = inp.selectionStart;
                end = inp.selectionEnd;
            }
            else if( inp.createTextRange )
            {
                var inpTxtLen = inp.value.length, jqueryTxtLen = this.val().length;
                var inpRange = inp.createTextRange(), collapsedRange = inp.createTextRange();

                inpRange.moveToBookmark(document.selection.createRange().getBookmark());
                collapsedRange.collapse(false);

                start = inpRange.compareEndPoints('StartToEnd', collapsedRange) > -1 ? jqueryTxtLen : inpRange.moveStart('character', -inpTxtLen);
                end = inpRange.compareEndPoints('EndToEnd', collapsedRange) > -1 ? jqueryTxtLen : inpRange.moveEnd('character', -inpTxtLen);
            }
            return {start: Math.abs(start), end: Math.abs(end)};

            },
            // Usage: $('#txtArea').replaceCaretSelection({start: startIndex, end: endIndex, text: 'text to replace with', insPos: 'before|after|select'})
            // Options     start: start index of the text to be replaced
            //               end: end index of the text to be replaced
            //              text: text to replace the selection with
            //            insPos: indicates whether to place the caret 'before' or 'after' the replacement text, 'select' will select the replacement text

            replaceCaretSelection: function(options)
            {
            var pos = this.caretSelection();
            this.val( this.val().substring(0,pos.start) + options.text + this.val().substring(pos.end) );
            if(options.insPos == 'before')
            {
                this.caretSelection({start: pos.start, end: pos.start});
            }
            else if( options.insPos == 'after' )
            {
                this.caretSelection({start: pos.start + options.text.length, end: pos.start + options.text.length});
            }
            else if( options.insPos == 'select' )
            {
                this.caretSelection({start: pos.start, end: pos.start + options.text.length});
            }
            }
        });
0 голосов
/ 23 декабря 2010

Это альтернативное решение, основанное на ответах сверху и дополнительных идеях.
Только для IE (другие браузеры поддерживают эту функцию по умолчанию).

Требуется дополнительное тестирование (я проверял это только в IE8)

<script type="text/javascript">
    var pos = 0;
    var len = 0;

    function pasteIntoInput(text) {
       var el = document.getElementById("text");

        el.focus();
        if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
            var val = el.value;
            var selStart = el.selectionStart;
            el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);
            el.selectionEnd = el.selectionStart = selStart + text.length;
        }
        else if (typeof document.selection != "undefined") {
        //var textRange = document.selection.createRange();
        var textRange  = el.createTextRange();
            //  el.focus();
            if (len > 0) { //something selected, so replace
                textRange.collapse(true);
                textRange.moveEnd('character', pos+len);
                textRange.moveStart('character', pos);
                textRange.select();
                textRange.text = text;

            }
            else {
                textRange.collapse(true);                   
                textRange.moveEnd('character', pos);
                textRange.moveStart('character', pos);                    
                textRange.text = text;
                textRange.select();

            }
            el.focus();
        }
    }


    function GetCaretPosition(txtarea) {

        pos = 0;
        if (document.selection) {

            // get current selection
            var range = document.selection.createRange();
            if (range.text.length>0)
             len=range.text.length;

            // get full range
            var rangeFull = document.body.createTextRange();
            rangeFull.moveToElementText(txtarea);

            var sel_start;
            for (sel_start = 0; rangeFull.compareEndPoints('StartToStart', range) < 0; sel_start++) {
                rangeFull.moveStart('character', 1);
            }                


            pos = sel_start;                


        }  

    }

</script>
0 голосов
/ 21 декабря 2010

Хорошо, поправьте меня, где я не прав.

1) При выделении текста в текстовой области, при нажатии кнопки выбранный текст заменяется текстом на входе.
2) Если текст не выделен, независимо от положения курсора, текст автоматически добавляется в самый конец текстовой области.

Если это единственные условия, то этого javascript будет достаточно, в противном случае мне потребуется дополнительная информация о том, что вы хотите, чтобы он делал.

function pasteIntoInput(text) { 
  el=document.getElementById("text");
  el.focus();    
  if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number" && el.selectionStart != el.selectionEnd) { 
    var val = el.value; 
    var selStart = el.selectionStart;
    el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);        
    el.selectionEnd = el.selectionStart = selStart + text.length;
  }
  else
    el.value += text;
}

Извините, что я не могу помочь, было бы полезно понять использование этой функции, чтобы я мог выполнить желаемое действие.

...