简体   繁体   English

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

[英]What's the best way to set cursor/caret position?

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 选择的文本区域中,那么设置光标/插入符号位置的最佳方法是什么?

I'm using tinyMCE.execCommand("mceInsertRawHTML", false, content);我正在使用tinyMCE.execCommand("mceInsertRawHTML", false, content); to insert the content, and I'd like set the cursor position to the end of the 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.selectionmyField.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();后来(2):我可以使用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.将选择作为字符串获取,但不是我可以使用getRangeAt(0)的选择对象。 Making progress little by little.一点一点地进步。

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.这是 TinyMCE 开发人员自己在编写 Selection.js 时使用的策略。 Reading the underlying source can be massively helpful for this kind of problem.阅读底层源代码对解决此类问题非常有帮助。

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.在这个问题上花费了超过 15 个小时(我知道是奉献精神)后,我找到了一个在 FF 和 Safari 中有效,但在 IE 中无效的部分解决方案。 For the moment, this is good enough for me although I might continue working on it in the future.目前,这对我来说已经足够了,尽管我将来可能会继续努力。

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.在 Firefox 和 Safari 中,此功能将在 WordPress 用作 TinyMCE 编辑器的 iframe 中的当前插入符号位置插入内容。 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 (ie it completely misses the text editor). IE 7 和 8 的问题是该函数似乎将内容添加到页面顶部,而不是 iframe(即它完全错过了文本编辑器)。 To address this issue, I added a conditional statement based on this code that will use this function instead for IE:为了解决这个问题,我添加了一个基于此代码的条件语句,该语句将在 IE 中使用此函数:

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.随时提出问题以进行澄清。

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. Spocke 先生的回答最初并没有帮助,但最终 API 文档为我提供了答案。 "Select all content and then collapse the selection": “选择所有内容,然后折叠选择”:

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.我希望这对其他人有所帮助,因为该线程是 Google 中最早出现的线程之一。

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 .我发现的最好方法是插入带有临时 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.对于任何试图将 Wordpress 自定义元框中的内容插入 TinyMCE 编辑器的人来说,这是有效的解决方案。 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.我尝试了大量其他脚本,包括此页面上的另一个脚本,上面是 Gary Tan 的答案,在安装自定义 TinyMCE 按钮时对我有用,但在这种情况下不起作用。

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 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.它有效我自己使用它。

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.我们添加了将光标移动到图像末尾的大量代码,因此用户可以连续键入而不会中断“跳跃”光标。

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

I'm inserting html content at current caret position (without staying in that html parent element) like this:我在当前插入符号位置插入 html 内容(不留在该 html 父元素中),如下所示:

editor.insertContent( '<div>My html inserted code here...</div>' + '&nbsp;' , {format: 'html'} );

That blank space at the end will ensure that the further typed text will be placed outside the inserted div element.最后的空格将确保进一步键入的文本将放置在插入的 div 元素之外。

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

在当前选择/插入符号位置插入一个 DOM 节点。

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

Just throwing in my own 2 cents here.只是在这里投入我自己的 2 美分。 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.我没有放入一个 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.使用@robyates 的部分答案,我所做的是在 2 个[code]标签之间放置一个临时 HTML 元素,专注于它,然后完全删除 HTML 元素。 Here is my code:这是我的代码:

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

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

在小版本 5

editor.selection.setCursorLocation(editor.getBody(), editor.getBody().childElementCount);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM