设置光标/插入位置的最佳方法是什么?

时间:2022-09-15 03:14:37

If I'm inserting content into a textarea that TinyMCE has co-opted, what's the best way to set the position of the cursor/caret?

如果我将内容插入到TinyMCE已经选择的textarea中,那么设置光标/插入符号位置的最佳方法是什么?

I'm using tinyMCE.execCommand("mceInsertRawHTML", false, content); to insert the content, and I'd like set the cursor position to the end of the content.

我正在使用tinyMCE.execCommand(“mceInsertRawHTML”,false,content);插入内容,我想将光标位置设置为内容的结尾。

Both document.selection and myField.selectionStart won't work for this, and I feel as though this is going to be supported by TinyMCE (through something I can't find on their forum) or it's going to be a really ugly hack.

document.selection和myField.selectionStart都不适用于此,我觉得TinyMCE将支持这一点(通过我们在论坛上找不到的东西)或者它将是一个非常丑陋的黑客。

Later: It gets better; I just figured out that, when you load TinyMCE in WordPress, it loads the entire editor in an embedded iframe.

后来:它变得更好;我只是想通了,当你在WordPress中加载TinyMCE时,它会在嵌入式iframe中加载整个编辑器。

Later (2): I can use document.getElementById('content_ifr').contentDocument.getSelection(); to get the selection as a string, but not a Selection Object that I can use getRangeAt(0) on. Making progress little by little.

稍后(2):我可以使用document.getElementById('content_ifr')。contentDocument.getSelection();将选择作为字符串,但不是我可以使用getRangeAt(0)的选择对象。一点一点地进步。

10 个解决方案

#1


26  

First what you should do is add a span at the end of the content you want to create.

首先,您应该在要创建的内容的末尾添加一个范围。

var ed = tinyMCE.activeEditor;

//add an empty span with a unique id
var endId = tinymce.DOM.uniqueId();
ed.dom.add(ed.getBody(), 'span', {'id': endId}, '');

//select that span
var newNode = ed.dom.select('span#' + endId);
ed.selection.select(newNode[0]);

This is a strategy used by the TinyMCE developers themselves in writing Selection.js. Reading the underlying source can be massively helpful for this kind of problem.

这是TinyMCE开发人员在编写Selection.js时使用的策略。阅读基础资源可以极大地帮助解决这类问题。

#2


20  

After spending over 15 hours on this issue (dedication, I know), I found a partial solution that works in FF and Safari, but not in IE. For the moment, this is good enough for me although I might continue working on it in the future.

在这个问题上花了超过15个小时(奉献,我知道),我找到了一个部分解决方案,适用于FF和Safari,但不适用于IE。目前,这对我来说已经足够了,尽管我将来可能继续努力。

The solution: When inserting HTML at the current caret position, the best function to use is:

解决方案:在当前插入位置插入HTML时,最好使用的函数是:

tinyMCE.activeEditor.selection.setContent(htmlcontent);

In Firefox and Safari, this function will insert the content at the current caret position within the iframe that WordPress uses as a TinyMCE editor. The issue with IE 7 and 8 is that the function seems to add the content to the top of the page, not the iframe (i.e. it completely misses the text editor). To address this issue, I added a conditional statement based on this code that will use this function instead for IE:

在Firefox和Safari中,此函数会将内容插入到WordPress用作TinyMCE编辑器的iframe中的当前插入位置。 IE 7和8的问题在于该函数似乎将内容添加到页面顶部,而不是iframe(即它完全错过了文本编辑器)。为了解决这个问题,我添加了一个基于此代码的条件语句,它将使用此函数代替IE:

tinyMCE.activeEditor.execCommand("mceInsertRawHTML", false, htmlcontent);

tinyMCE.activeEditor.execCommand(“mceInsertRawHTML”,false,htmlcontent);

The issue for this second function, however, is that the caret position is set to the beginning of the post area after it has been called (with no hope of recalling it based on the browser range, etc.). Somewhere near the end I discovered that this function works to restore the caret position at the end of the inserted content with the first function:

然而,第二个函数的问题在于,在调用后,插入位置设置为后期区域的开头(根据浏览器范围等,无法调用它)。在接近结尾的地方,我发现这个函数可以用第一个函数恢复插入内容末尾的插入位置:

tinyMCE.activeEditor.focus();

In addition, it restores the caret position to the end of the inserted content without having to calculate the length of the inserted text. The downside is that it only works with the first insertion function which seems to cause problems in IE 7 and IE 8 (which might be more of a WordPress fault than TinyMCE).

此外,它将插入符号位置恢复到插入内容的末尾,而不必计算插入文本的长度。缺点是它只适用于第一个插入功能,它似乎在IE 7和IE 8中引起问题(可能比TinyMCE更多的是WordPress故障)。

A wordy answer, I know. Feel free to ask questions for clarification.

一个罗嗦的答案,我知道。随意提出问题以便澄清。

#3


14  

It is so simple to move the cursor to the end that I can't believe the awful kludges that have been posted elsewhere online to do this. Mr. Spocke's answer wasn't initially helpful but in the end the API docs provided me with the answer. "Select all content and then collapse the selection":

将光标移动到最终是如此简单,以至于我无法相信已经在网上其他地方发布的可怕的kludges来做到这一点。 Spocke先生的回答最初没有帮助,但最终API文档为我提供了答案。 “选择所有内容,然后折叠选择”:

ed.selection.select(ed.getBody(), true); // ed is the editor instance

ed.selection.collapse(false);

I hope this helps someone else as this thread is one of the first to come up in Google.

我希望这可以帮助其他人,因为这个帖子是第一个出现在谷歌中的人之一。

#4


6  

The correct solution is to use the tinyMCE api tinymce.dom.Selection

正确的解决方案是使用tinyMCE api tinymce.dom.Selection

http://www.tinymce.com/wiki.php/API3:class.tinymce.dom.Selection

the syntaxe is something like :

语法是这样的:

var rng = tinymce.DOM.createRng();  // the range obj
var newNode = editor.dom.select(...    // find the correct selector so that newNode is the element of your editor text
rng.setStart(newNode.firstChild, 0); // 0 is the offset : here it will be at the beginning of the line.
rng.setEnd(newNode.firstChild, 0);
editor.selection.setRng(rng);

it works I use this myself.

它有效我自己用它。

#5


4  

The best way that I have found is to insert the content with a temp id and then give that focus using some trickery I found in the advlink plugin.

我找到的最好的方法是插入带有temp id的内容,然后使用我在advlink插件中找到的一些技巧来提供焦点。

Hope this helps.

希望这可以帮助。

            var ed = tinyMCE.activeEditor;

            ed.execCommand('mceInsertContent', false, '<a id="_mce_temp_rob" href="http://robubu.com">robubu.com</a>');

            //horrible hack to put the cursor in the right spot
            ed.focus(); //give the editor focus
            ed.selection.select(ed.dom.select('#_mce_temp_rob')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.setAttrib('_mce_temp_rob', 'id', ''); //remove the temp id

If you're doing this from a popup I think you also need to add

如果您从弹出窗口执行此操作,我认为您还需要添加

        tinyMCEPopup.storeSelection();

before closing the popup.

在关闭弹出窗口之前。

For anyone trying to insert content from a Wordpress custom meta box into the TinyMCE editor, this is the solution that works. I tried a ton of other scripts, including another on this page, the answer above by Gary Tan, which worked for me when installing custom TinyMCE buttons but didnt work out in this scenario.

对于任何试图将Wordpress自定义元框中的内容插入TinyMCE编辑器的人来说,这是可行的解决方案。我尝试了大量的其他脚本,包括本页面上的另一个脚本,上面的回答是Gary Tan,在安装自定义TinyMCE按钮时对我有用但在这种情况下没有用。

#6


1  

Insert a DOM node at the current selection/caret location.

在当前选择/插入位置插入DOM节点。

tinyMCE.activeEditor.selection.setNode(tinyMCE.activeEditor.dom.create('img', {src : 'some.gif', title : 'some title'}));

#7


1  

Just throwing in my own 2 cents here. None of these answered my question. I was not putting in an HTML element, but a block of text ([code][/code] for example) and needed the cursor to go between the two.

在这里扔我自己的2美分。这些都没有回答我的问题。我没有放入一个HTML元素,而是一个文本块(例如[code] [/ code]),并且需要光标在两者之间。

Using part of @robyates answer, what I did was put a temporary HTML element in between the 2 [code] tags, focus on it, then removed the HTML element completely. Here is my code:

使用@robyates答案的一部分,我所做的是在2 [code]标签之间放置一个临时HTML元素,专注于它,然后完全删除HTML元素。这是我的代码:

setup : function(ed) {
    // Add a custom button
    ed.addButton('codeblock', {
        title : 'Code Block',
        text : '[code/]',
        icon: false,
        onclick : function() {
            // Add you own code to execute something on click
            ed.focus();
            //ed.selection.setContent('[code][/code]');
            ed.execCommand('mceInsertContent', false, '[code]<span id="_cursor" />[/code]');

            ed.selection.select(ed.dom.select('#_cursor')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.remove('_cursor'); //remove the element
        }
    });
}

#8


1  

I've plagiarized this from here.

我从这里抄袭了这个。

function setCaretTo(obj, pos) { 
    if(obj.createTextRange) { 
        /* Create a TextRange, set the internal pointer to
           a specified position and show the cursor at this
           position
        */ 
        var range = obj.createTextRange(); 
        range.move("character", pos); 
        range.select(); 
    } else if(obj.selectionStart) { 
        /* Gecko is a little bit shorter on that. Simply
           focus the element and set the selection to a
           specified position
        */ 
        obj.focus(); 
        obj.setSelectionRange(pos, pos); 
    } 
} 

#9


1  

So, here is solution from the our project. Our objective was to change (+)/(-)/(?) strings to the appropriate images "on the fly" while user is typing.

所以,这是我们项目的解决方案。我们的目标是在用户输入时将“+”/( - )/(?)字符串“动态”更改为适当的图像。

There was a problem: every time after changing string to image, cursor went the beginning of the image, not to the end as was expected.

出现了一个问题:每次将字符串更改为图像后,光标都会出现在图像的开头,而不是预期的结束。

We added bulk of the code which moves cursor to the end of the image, so user can type continuously w/o interrupting on "jumpy" cursor.

我们添加了大量的代码,将光标移动到图像的末尾,因此用户可以连续输入w / o中断“jumpy”光标。

Key part: Instead of using editor.getBody, there is a more elegant way to create the temporary span and furthermore, delete it immediately after the necessary actions.

关键部分:不是使用editor.getBody,而是使用更优雅的方式创建临时跨度,并在必要的操作后立即删除它。

if (value.match(/\([+?-]\)/)) {
        // set current cursor via span
        editor.selection.setContent('<span id="temp-span"/>');

        // refresh Content with new span
        value = editor.getContent();

        // changing (+)/(-)/(?) to the appropriate image "on the fly"
        value = value.replace('(+)', ' <img src="https://url_here/static/task_manager/img/add.png">&nbsp;');
        value = value.replace('(-)', ' <img src="https://url_here/static/task_manager/img/forbidden.png">&nbsp;');
        value = value.replace('(?)', ' <img src="https://url_here/static/task_manager/img/help_16.png">&nbsp;');
        if (this.state.editor) {
            editor.setContent(value);

            // move cursor to the latter span
            var newNode = editor.dom.select('span#temp-span');
            editor.selection.select(newNode[0]);
            editor.selection.setContent('');
        }
        // and refreshing content again w/o span
        value = editor.getContent();
    }

#10


0  

This is the solution that works for me:

这是适合我的解决方案:

// params: 
//   $node: jquery node with tinymce loaded 
//   text: text to set at then before caret
function setTextAndCaretToEnd($node, text) {
     var ed = window.tinyMCE.get($node.attr("id"));
     ed.focus();
     ed.selection.setContent(text);
}

#1


26  

First what you should do is add a span at the end of the content you want to create.

首先,您应该在要创建的内容的末尾添加一个范围。

var ed = tinyMCE.activeEditor;

//add an empty span with a unique id
var endId = tinymce.DOM.uniqueId();
ed.dom.add(ed.getBody(), 'span', {'id': endId}, '');

//select that span
var newNode = ed.dom.select('span#' + endId);
ed.selection.select(newNode[0]);

This is a strategy used by the TinyMCE developers themselves in writing Selection.js. Reading the underlying source can be massively helpful for this kind of problem.

这是TinyMCE开发人员在编写Selection.js时使用的策略。阅读基础资源可以极大地帮助解决这类问题。

#2


20  

After spending over 15 hours on this issue (dedication, I know), I found a partial solution that works in FF and Safari, but not in IE. For the moment, this is good enough for me although I might continue working on it in the future.

在这个问题上花了超过15个小时(奉献,我知道),我找到了一个部分解决方案,适用于FF和Safari,但不适用于IE。目前,这对我来说已经足够了,尽管我将来可能继续努力。

The solution: When inserting HTML at the current caret position, the best function to use is:

解决方案:在当前插入位置插入HTML时,最好使用的函数是:

tinyMCE.activeEditor.selection.setContent(htmlcontent);

In Firefox and Safari, this function will insert the content at the current caret position within the iframe that WordPress uses as a TinyMCE editor. The issue with IE 7 and 8 is that the function seems to add the content to the top of the page, not the iframe (i.e. it completely misses the text editor). To address this issue, I added a conditional statement based on this code that will use this function instead for IE:

在Firefox和Safari中,此函数会将内容插入到WordPress用作TinyMCE编辑器的iframe中的当前插入位置。 IE 7和8的问题在于该函数似乎将内容添加到页面顶部,而不是iframe(即它完全错过了文本编辑器)。为了解决这个问题,我添加了一个基于此代码的条件语句,它将使用此函数代替IE:

tinyMCE.activeEditor.execCommand("mceInsertRawHTML", false, htmlcontent);

tinyMCE.activeEditor.execCommand(“mceInsertRawHTML”,false,htmlcontent);

The issue for this second function, however, is that the caret position is set to the beginning of the post area after it has been called (with no hope of recalling it based on the browser range, etc.). Somewhere near the end I discovered that this function works to restore the caret position at the end of the inserted content with the first function:

然而,第二个函数的问题在于,在调用后,插入位置设置为后期区域的开头(根据浏览器范围等,无法调用它)。在接近结尾的地方,我发现这个函数可以用第一个函数恢复插入内容末尾的插入位置:

tinyMCE.activeEditor.focus();

In addition, it restores the caret position to the end of the inserted content without having to calculate the length of the inserted text. The downside is that it only works with the first insertion function which seems to cause problems in IE 7 and IE 8 (which might be more of a WordPress fault than TinyMCE).

此外,它将插入符号位置恢复到插入内容的末尾,而不必计算插入文本的长度。缺点是它只适用于第一个插入功能,它似乎在IE 7和IE 8中引起问题(可能比TinyMCE更多的是WordPress故障)。

A wordy answer, I know. Feel free to ask questions for clarification.

一个罗嗦的答案,我知道。随意提出问题以便澄清。

#3


14  

It is so simple to move the cursor to the end that I can't believe the awful kludges that have been posted elsewhere online to do this. Mr. Spocke's answer wasn't initially helpful but in the end the API docs provided me with the answer. "Select all content and then collapse the selection":

将光标移动到最终是如此简单,以至于我无法相信已经在网上其他地方发布的可怕的kludges来做到这一点。 Spocke先生的回答最初没有帮助,但最终API文档为我提供了答案。 “选择所有内容,然后折叠选择”:

ed.selection.select(ed.getBody(), true); // ed is the editor instance

ed.selection.collapse(false);

I hope this helps someone else as this thread is one of the first to come up in Google.

我希望这可以帮助其他人,因为这个帖子是第一个出现在谷歌中的人之一。

#4


6  

The correct solution is to use the tinyMCE api tinymce.dom.Selection

正确的解决方案是使用tinyMCE api tinymce.dom.Selection

http://www.tinymce.com/wiki.php/API3:class.tinymce.dom.Selection

the syntaxe is something like :

语法是这样的:

var rng = tinymce.DOM.createRng();  // the range obj
var newNode = editor.dom.select(...    // find the correct selector so that newNode is the element of your editor text
rng.setStart(newNode.firstChild, 0); // 0 is the offset : here it will be at the beginning of the line.
rng.setEnd(newNode.firstChild, 0);
editor.selection.setRng(rng);

it works I use this myself.

它有效我自己用它。

#5


4  

The best way that I have found is to insert the content with a temp id and then give that focus using some trickery I found in the advlink plugin.

我找到的最好的方法是插入带有temp id的内容,然后使用我在advlink插件中找到的一些技巧来提供焦点。

Hope this helps.

希望这可以帮助。

            var ed = tinyMCE.activeEditor;

            ed.execCommand('mceInsertContent', false, '<a id="_mce_temp_rob" href="http://robubu.com">robubu.com</a>');

            //horrible hack to put the cursor in the right spot
            ed.focus(); //give the editor focus
            ed.selection.select(ed.dom.select('#_mce_temp_rob')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.setAttrib('_mce_temp_rob', 'id', ''); //remove the temp id

If you're doing this from a popup I think you also need to add

如果您从弹出窗口执行此操作,我认为您还需要添加

        tinyMCEPopup.storeSelection();

before closing the popup.

在关闭弹出窗口之前。

For anyone trying to insert content from a Wordpress custom meta box into the TinyMCE editor, this is the solution that works. I tried a ton of other scripts, including another on this page, the answer above by Gary Tan, which worked for me when installing custom TinyMCE buttons but didnt work out in this scenario.

对于任何试图将Wordpress自定义元框中的内容插入TinyMCE编辑器的人来说,这是可行的解决方案。我尝试了大量的其他脚本,包括本页面上的另一个脚本,上面的回答是Gary Tan,在安装自定义TinyMCE按钮时对我有用但在这种情况下没有用。

#6


1  

Insert a DOM node at the current selection/caret location.

在当前选择/插入位置插入DOM节点。

tinyMCE.activeEditor.selection.setNode(tinyMCE.activeEditor.dom.create('img', {src : 'some.gif', title : 'some title'}));

#7


1  

Just throwing in my own 2 cents here. None of these answered my question. I was not putting in an HTML element, but a block of text ([code][/code] for example) and needed the cursor to go between the two.

在这里扔我自己的2美分。这些都没有回答我的问题。我没有放入一个HTML元素,而是一个文本块(例如[code] [/ code]),并且需要光标在两者之间。

Using part of @robyates answer, what I did was put a temporary HTML element in between the 2 [code] tags, focus on it, then removed the HTML element completely. Here is my code:

使用@robyates答案的一部分,我所做的是在2 [code]标签之间放置一个临时HTML元素,专注于它,然后完全删除HTML元素。这是我的代码:

setup : function(ed) {
    // Add a custom button
    ed.addButton('codeblock', {
        title : 'Code Block',
        text : '[code/]',
        icon: false,
        onclick : function() {
            // Add you own code to execute something on click
            ed.focus();
            //ed.selection.setContent('[code][/code]');
            ed.execCommand('mceInsertContent', false, '[code]<span id="_cursor" />[/code]');

            ed.selection.select(ed.dom.select('#_cursor')[0]); //select the inserted element
            ed.selection.collapse(0); //collapses the selection to the end of the range, so the cursor is after the inserted element
            ed.dom.remove('_cursor'); //remove the element
        }
    });
}

#8


1  

I've plagiarized this from here.

我从这里抄袭了这个。

function setCaretTo(obj, pos) { 
    if(obj.createTextRange) { 
        /* Create a TextRange, set the internal pointer to
           a specified position and show the cursor at this
           position
        */ 
        var range = obj.createTextRange(); 
        range.move("character", pos); 
        range.select(); 
    } else if(obj.selectionStart) { 
        /* Gecko is a little bit shorter on that. Simply
           focus the element and set the selection to a
           specified position
        */ 
        obj.focus(); 
        obj.setSelectionRange(pos, pos); 
    } 
} 

#9


1  

So, here is solution from the our project. Our objective was to change (+)/(-)/(?) strings to the appropriate images "on the fly" while user is typing.

所以,这是我们项目的解决方案。我们的目标是在用户输入时将“+”/( - )/(?)字符串“动态”更改为适当的图像。

There was a problem: every time after changing string to image, cursor went the beginning of the image, not to the end as was expected.

出现了一个问题:每次将字符串更改为图像后,光标都会出现在图像的开头,而不是预期的结束。

We added bulk of the code which moves cursor to the end of the image, so user can type continuously w/o interrupting on "jumpy" cursor.

我们添加了大量的代码,将光标移动到图像的末尾,因此用户可以连续输入w / o中断“jumpy”光标。

Key part: Instead of using editor.getBody, there is a more elegant way to create the temporary span and furthermore, delete it immediately after the necessary actions.

关键部分:不是使用editor.getBody,而是使用更优雅的方式创建临时跨度,并在必要的操作后立即删除它。

if (value.match(/\([+?-]\)/)) {
        // set current cursor via span
        editor.selection.setContent('<span id="temp-span"/>');

        // refresh Content with new span
        value = editor.getContent();

        // changing (+)/(-)/(?) to the appropriate image "on the fly"
        value = value.replace('(+)', ' <img src="https://url_here/static/task_manager/img/add.png">&nbsp;');
        value = value.replace('(-)', ' <img src="https://url_here/static/task_manager/img/forbidden.png">&nbsp;');
        value = value.replace('(?)', ' <img src="https://url_here/static/task_manager/img/help_16.png">&nbsp;');
        if (this.state.editor) {
            editor.setContent(value);

            // move cursor to the latter span
            var newNode = editor.dom.select('span#temp-span');
            editor.selection.select(newNode[0]);
            editor.selection.setContent('');
        }
        // and refreshing content again w/o span
        value = editor.getContent();
    }

#10


0  

This is the solution that works for me:

这是适合我的解决方案:

// params: 
//   $node: jquery node with tinymce loaded 
//   text: text to set at then before caret
function setTextAndCaretToEnd($node, text) {
     var ed = window.tinyMCE.get($node.attr("id"));
     ed.focus();
     ed.selection.setContent(text);
}