我正在尝试为TinyMCE创建一个插件,因此用户可以为选定区域添加浮动提示。 我需要的是将选定的内容放入span中,我这样做:
var formated =
'<span id="tooltip_widget_' + id + '">'
+ selectedtext
+ '</span>;
ed.selection.setContent(formated);
它在Firefox中运行良好,我可以添加文本以跨越并继续输入。 但是在Chrome和IE中,以下所有文字都会进入增加的范围。并且继续输入它的唯一方法 - 通过html编辑器。
我尝试在插入后包含额外的插入符占位符范围,然后在它之后折叠,然后删除此占位符以确保插入符号位于插入的范围之后。
但它没有帮助。在chrome和IE中,如果插入符号位于span的末尾,它将继续在此范围内键入。
请建议如何解决这个问题。
答案 0 :(得分:1)
可以找到解决方案in this fiddle或此处的代码:
<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>