2

我正在尝试为 TinyMCE 创建一个插件,以便用户可以为选定区域添加浮动提示。我需要的只是将选定的内容放入跨度中,我这样做:

var formated = 
    '<span id="tooltip_widget_' + id + '">'
    + selectedtext
    + '</span>;
ed.selection.setContent(formated);

它在 Firefox 中运行良好,我可以将文本添加到 span 并继续输入。但是在 Chrome 和 IE 中,以下所有文本都进入了添加的范围。并且继续输入它的唯一方法 - 通过 html 编辑器。

我尝试在插入后包含额外的插入符占位符跨度并在其后折叠,然后删除此占位符以确保插入符将在插入的跨度之后。

但这无济于事。在 chrome 和 IE 中,如果插入符号位于跨度的末尾,它会继续在此跨度内输入。

请建议如何解决这个问题。

4

1 回答 1

1

解决方案可以在这个小提琴中找到或作为代码在这里:

<script type="text/javascript">

function plugin_work(){

        var ed = tinymce.editors[0];
        var innerSpanId = 0;
        var node = ed.selection.getNode();

        // Get the selected contents as text and place it in the input
        if (ed.selection.getNode().className == "tooltipedurl") {

            var innerSpanId = node.id;
            if (innerSpanId != 0) {
                var innerSpanHTML = ed.dom.get('data_' + innerSpanId).innerHTML;
            }
        } else {

           var innerSpanHTML = ed.selection.getContent({format : 'html'});
        }

        var id = new Date().getTime();
        var node = ed.selection.getNode();


        if (node.className == "tooltipedurl") {
            var innerSpanId = node.id;
            if (innerSpanHTML != 0) {
                ed.dom.get('data_' + innerSpanId).innerHTML = innerSpanHTML;
            } else {
                ed.dom.remove(node);
                ed.selection.setContent(node.innerHTML);
                ed.dom.remove(ed.dom.get('data_' + innerSpanId));
                ed.focus();
            }
        } else {
            var formated =
                '<span id=\"tooltip_widget_' + id + '\" class=\"tooltipedurl\" name="tip">'
                + innerSpanHTML
                + '</span><span id="caret_placeholder_' + id + '" name="caret_placeholder">\u200b</span>';

            ed.selection.setContent(formated);

            var rng = tinymce.DOM.createRng();  // the range obj
            var $caret_placeholder = $(ed.getBody()).find ('#caret_placeholder_'+id);    // find the correct selector so that caret_placeholder is the element of your editor text
//            rng.setStart(caret_placeholder.firstChild, f.textFragment.value.length); // 0 is the offset : here it will be at the beginning of the line.
//            rng.setEnd(caret_placeholder.firstChild, f.textFragment.value.length);

//console.log(caret_placeholder);

            rng.setStartAfter($caret_placeholder.get(0));
            rng.setEndAfter($caret_placeholder.get(0));
            ed.selection.setRng(rng);

            //ed.selection.select(caret_placeholder);
            //$(caret_placeholder).html('');

            ed.focus();

            tinyMCE.activeEditor.dom.add(tinyMCE.activeEditor.getBody(), 'span', {id : 'data_tooltip_widget_' + id, style : 'display:none'}, innerSpanHTML);
            ed.onKeyUp.add(function(ed, e) {
                if ($caret_placeholder = $(ed.getBody()).find ('#caret_placeholder_'+id)) {
                    var content = $caret_placeholder.get(0).innerHTML;
                    ed.dom.remove($caret_placeholder.get(0));
                    ed.selection.setContent(content);
                }
            });
        }
}

tinymce.create('tinymce.plugins.floatingtipsPlugin', {
        init : function(ed, url) {
            // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mcefloatingtips');
            ed.addCommand('mcefloatingtips', function() {
                var se = ed.selection;
                // No selection and not in span
                if (se.isCollapsed() && se.getNode().className != "tooltipedurl") {
                    return;
                }

                ed.windowManager.open({
                    file : url + '/dialog.htm',
                    width : 320 + parseInt(ed.getLang('floatingtips.delta_width', 0)),
                    height : 120 + parseInt(ed.getLang('floatingtips.delta_height', 0)),
                    inline : 1
                }, {
                    plugin_url : url, // Plugin absolute URL
                    some_custom_arg : 'custom arg' // Custom argument
                });
            });

            // Register floatingtips button
            ed.addButton('floatingtips', {
                title : 'Add/Edit floating tip',
                cmd : 'mcefloatingtips',
                image : url + '/img/floating_tips.gif'
            });

            // Add a node change handler
            ed.onNodeChange.add(function(ed, cm, n) {
                var se = ed.selection;
                cm.setActive('floatingtips', se.getNode().className == "tooltipedurl");
                cm.setDisabled('floatingtips', se.isCollapsed() && se.getNode().className != "tooltipedurl");
            });

            ed.contentCSS.push(url + '/css/floatingtips.css');
        },

        createControl : function(n, cm) {
            return null;
        },

        getInfo : function() {
            return {
                longname : 'floatingtips plugin',
                author : 'Some author',
                authorurl : 'http://tinymce.moxiecode.com',
                infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/floatingtips',
                version : "1.0"
            };
        }
    });

tinymce.PluginManager.add('floatingtips', tinymce.plugins.floatingtipsPlugin);

/**
 * 
 * Here goes dialog.js
 * What exactly my plugin does
 * 
 *  ================== GOAL =====================
 * Goal - to wrap selected text with span like this: 
 * <span class="tooltipedurl", id="tooltip_widget_" + {someuniueID}> SELECTED TEXT </span>
 * Add to the end of the editor hidden element with tooltip text like this: 
 * <span id="data_tooltip_widget_ + {someuniueID} style="display:none"> TOOLTIP TEXT </span>
 * 
  */

 /**
  * ================= ALGORITHM ==================
  * If some text selected, or if we have caret inside span with class tooltipedurl.
  * We got plugin buton - active.
  * On click we see popup form with two fields.
  * first with selected text, (it is hidden, user shouldn't be able to modify it from popup form)
  * second is the tip input(textarea filed) we load here old tip if the caret inside the span with tip.
  * 
  * if text selected:
  * we got it from the popup form {f.textFragment.value} and replace it with 
  * <span id=\"tooltip_widget_' + id + '\" class=\"tooltipedurl\" name="tip">'+ f.textFragment.value + '</span>
  * also we create hidden span in the end of editor with tip value from the form {f.newTip.value}
  * tinyMCE.activeEditor.dom.add(tinyMCE.activeEditor.getBody(), 'span', {id : 'data_tooltip_widget_' + id, style : 'display:none'}, f.newTip.value);
  * 
  * if caret inside the span which already has tooltip
  * we have in popup form current tooltip message and can edit it and put new value to the corresponding hidden span
  * ed.dom.get('data_' + innerSpanId).innerHTML = f.newTip.value;
  * 
  * if the new tip value = 0, we delete span which contains the text and delete correspondig 
  * hiden element with tooltip text
  * 
  * more detailed comments i added to the script below
  */

var ExampleDialog = {
    init : function() {
        var ed = tinyMCEPopup.editor;

        // f is a form from PopUp 
        var f = document.forms[0];

        // if selection inside the span with class tooltipedurl we will put here the id of this span
        var innerSpanId = 0;

        var node = ed.selection.getNode();

        // Get the selected contents as text and place it in the input fields if we are inside the span with class tooltipedurl
        if (ed.selection.getNode().className == "tooltipedurl") {

            var innerSpanId = node.id;
            //taking all the text to the input from the span even if only part of it was selected
            f.textFragment.value = node.innerText;
            if (innerSpanId != 0) {
                //taking current tooltip text from the corresponding hidden span
                f.newTip.value = ed.dom.get('data_' + innerSpanId).innerHTML;
            }
        } else {
            //if selected text is not in the span with class tooltipedurl we just get as html to apply tooltip later
            f.textFragment.value = ed.selection.getContent({format : 'html'});

        }
    },

    insert : function() {
        var ed = tinyMCEPopup.editor;
        var f = document.forms[0];
        var id = new Date().getTime();
        var node = ed.selection.getNode();

        //if selection is inside the span#tooltipedurl - we gonna edit tooltip text
        if (node.className == "tooltipedurl") {
            var innerSpanId = node.id;
            if (f.newTip.value != 0) {
                //If new tooltip is not 0, we replace inner html of correspondig span in the end of editor
                ed.dom.get('data_' + innerSpanId).innerHTML = f.newTip.value;
            } else {
                //If new tooltip value is 0 - we delete correspondig span in the end of editor and remove <span> tags from text
                ed.dom.remove(node);
                ed.selection.setContent(node.innerHTML);
                ed.dom.remove(ed.dom.get('data_' + innerSpanId));
            }
        } else {
            //if selection doesn't have tooltip, we place it in the tags with unique id and class tooltipedurl
            var formated =
                '<span id=\"tooltip_widget_' + id + '\" class=\"tooltipedurl\" name="tip">'
                + f.textFragment.value
                + '</span>';
            ed.selection.setContent(formated);

            /**
             * THE PROBLEM IS
             * when we add this span and user trying to continue typing.
             * in Chrome and IE all the following text goes in this new span.
             * In firefox it works OK.
             * 
             */

            //Here i am trying to put caret right after added span with dom.range
            var rng = tinymce.DOM.createRng();  // the range obj
            var caret_placeholder = ed.dom.get('tooltip_widget_' + id);   
//            rng.setStart(caret_placeholder.firstChild, f.textFragment.value.length); 
//            rng.setEnd(caret_placeholder.firstChild, f.textFragment.value.length);

            rng.setStartAfter(caret_placeholder);
            rng.setEndAfter(caret_placeholder);
            ed.selection.setRng(rng);
            //But it doesn't help...

            //creating invisible element with tooltip message in the end of the editor
            tinyMCE.activeEditor.dom.add(tinyMCE.activeEditor.getBody(), 'span', {id : 'data_tooltip_widget_' + id, style : 'display:none'}, f.newTip.value);

        }

        tinyMCEPopup.close();

    }
};


/**
 * I don't know how to include popup window from my plugin here
 * But ih has 2 fields 
 * f.textFragment.value ==> it is the selected text  (this field is hidden)
 * f.newTip.value ==> text input with the tip.
 * 
 * so when user selects some text and clicks add floating tip button. he sees the form with 1 text field and can add new tooltip or edit old one
 * 
 */


//tinyMCEPopup.onInit.add(ExampleDialog.init, ExampleDialog);


// Initialize TinyMCE with the new plugin and listbox
tinyMCE.init({
    plugins : '-example, floatingtips', // - tells TinyMCE to skip the loading of the plugin
    mode : "textareas",
    theme : "advanced",
    theme_advanced_buttons1 : "code,mylistbox,mysplitbutton,bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,bullist,numlist,undo,redo,link,unlink, floatingtips",
    theme_advanced_buttons2 : "",
    theme_advanced_buttons3 : "",
    theme_advanced_toolbar_location : "top",
    theme_advanced_toolbar_align : "left",
    theme_advanced_statusbar_location : "bottom"
});


</script>

<form method="post" action="dump.php">
        <textarea name="content">
        test
        </textarea>
</form>
<div onclick="plugin_work();" style="cursor:pointer;background-color:green;width:70px;">Button</div>
于 2012-12-07T08:23:35.147 回答