最小JavaScript wysiwyg-从选定文本中删除标记(如果已存在)
我正在制作一个最小的JavaScript WYSIWYG控件 我不想使用document.execCommand,因为它不允许任意HTML,它在浏览器之间不一致等等 以下是我迄今为止精简到最低工作代码的内容:最小JavaScript wysiwyg-从选定文本中删除标记(如果已存在),javascript,range,selection,wysiwyg,documentfragment,Javascript,Range,Selection,Wysiwyg,Documentfragment,我正在制作一个最小的JavaScript WYSIWYG控件 我不想使用document.execCommand,因为它不允许任意HTML,它在浏览器之间不一致等等 以下是我迄今为止精简到最低工作代码的内容: b 我 U 敏捷的棕色狐狸跳过了懒狗 $(函数(){ $(“按钮”)。打开(“单击”,函数(){ var selection=window.getSelection(); var range=selection.getRangeAt(0); var action=$(this.attr(
b
我
U
敏捷的棕色狐狸跳过了懒狗
$(函数(){
$(“按钮”)。打开(“单击”,函数(){
var selection=window.getSelection();
var range=selection.getRangeAt(0);
var action=$(this.attr('data action');
var节点=document.createElement(操作);
var frag=range.extractContents();
子节点(frag);
range.insertNode(节点);
返回false;
});
});
如果某些选择已经包含强标记(或其他标记),如何使其再次单击按钮可删除这些标记,而不是使用新的强标记包装选择
写这个问题给了我一个想法。我现在就试试,如果它有效的话,我会回答我自己的问题——这样,这个问题就在这里,以防其他人碰到这个问题。否则我将用诱饵般的呼吸等待你的帮助:)
编辑:显然,如果其他人发布了一个有效的解决方案,我会接受他们的答案,而不是我的答案,如果它更好的话
编辑(2):所以我的想法没有成功。事实证明,某些东西(可能是range.insertNode)会神奇地为您平衡标记。我似乎没有足够的信息从选择,范围或碎片总是知道选择是否在一个给定的标签。有什么想法吗?编辑:这不是一个好的解决方案。它完全被任何比一行简单文本更复杂的东西分解了。我已经解决了问题,不久将发布更好的解决方案。 我明白了 我构建了一个数组,其中包含所见即所得区域中的每个文本节点及其父标记列表 然后,我将所选内容包装在一个自定义元素中,这样以后就可以很容易地删除它,并且不会与任何现有的HTML元素冲突,使用建议的x前缀 然后,我从该列表中重建了wysiwyg元素的内容,从选择中的所有节点(如果它们都已经有)中删除单击按钮的标记,这是大多数WYWIG编辑器处理它的方式
b
我
U
敏捷的棕色狐狸跳过了懒狗
$(函数(){
var-selectionWrapper='X-SELECTION';
函数getTextData(元素){
函数getTextNodesIn(根){
var textNodes=[];
var父项=[];
函数getTextNodes(节点){
如果(node.nodeType==3){
var text=node.textContent;
textNodes.push({
文本:文本,
父对象:父对象。切片(0)
});
}否则{
如果(节点!==根){
parents.push(node.tagName);
}
对于(变量i=0,len=node.childNodes.length;i
我很惊讶你能用这么少的代码制作一个简单的所见即所得编辑器!正是extractContents()
发挥了神奇的作用。要从任意范围生成格式良好的文档片段,并在范围结束时使文档保持格式良好的状态,可能需要在DOM树中完全不同的级别上复制一定数量的节点。您好@TimDown-您编写了Rangy,不是吗?-我似乎看不到任何关于extractContents返回的对象的有用信息-您有什么想法吗?在我脑海中模糊不清的是,我可能不得不担任主播
<button data-action="B"><b>b</b></button>
<button data-action="I"><i>i</i></button>
<button data-action="U"><u>u</u></button>
<p contenteditable>The quick brown fox jumps over the lazy dog.</p>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script>
$( function(){
var selectionWrapper = 'X-SELECTION';
function getTextData( element ) {
function getTextNodesIn( root ) {
var textNodes = [];
var parents = [];
function getTextNodes( node ) {
if( node.nodeType === 3 ){
var text = node.textContent;
textNodes.push({
text: text,
parents: parents.slice( 0 )
});
} else {
if( node !== root ){
parents.push( node.tagName );
}
for( var i = 0, len = node.childNodes.length; i < len; ++i ){
getTextNodes( node.childNodes[ i ] );
}
parents.pop();
}
}
getTextNodes( element );
return textNodes;
}
return getTextNodesIn( element );
}
function handleSelection( container, action ) {
var textData = getTextData( container );
container.innerHTML = '';
//if every textNode in the selection has action as a parent, we want
//to remove it from all of them.
var selection = _( textData ).filter( function( data ){
return _( data.parents ).contains( selectionWrapper );
});
var remove = _( selection ).every( function( data ) {
return _( data.parents ).contains( action ) || data.text.trim() === '';
});
_( selection ).each( function( data ){
if( remove ) {
data.parents = _( data.parents ).without( action );
} else {
data.parents.push( action );
}
});
//rebuild each text node
_( textData ).each( function( data ){
//no need to add empty text nodes
if( data.text === '' ) {
return;
}
//remove duplicates of the same parent tag and remove the selection wrapper
var parents = _( data.parents ).chain().uniq().without( selectionWrapper ).value();
var target = container;
_( parents ).each( function( parent ){
var node = document.createElement( parent );
target.appendChild( node );
target = node;
});
var text = document.createTextNode( data.text );
target.appendChild( text );
});
}
$( 'button' ).on( 'click', function(){
var action = $( this ).attr( 'data-action' );
var selection = window.getSelection();
for( var i = 0; i < selection.rangeCount; i++ ){
var range = selection.getRangeAt( i );
var node = document.createElement( selectionWrapper );
node.appendChild( range.extractContents() );
range.insertNode( node );
handleSelection( $( 'p' )[ 0 ], action );
}
return false;
});
});
</script>