[英]Minimal JavaScript wysiwyg - remove tag from selected text if already exists
我正在做一个最小的JavaScript所见即所得控件。
我不想使用document.execCommand,因为它不允许使用任意HTML,而且在浏览器之间也不一致。
到目前为止,这是我精简到最小工作代码的内容:
<button data-action="strong"><strong>b</strong></button>
<button data-action="em"><em>i</em></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>
$( function(){
$( 'button' ).on( 'click', function(){
var selection = window.getSelection();
var range = selection.getRangeAt( 0 );
var action = $( this ).attr( 'data-action' );
var node = document.createElement( action );
var frag = range.extractContents();
node.appendChild( frag );
range.insertNode( node );
return false;
});
});
</script>
如果某些选择已经包含强标签(或其他内容),我该如何做,以便第二次单击按钮会删除这些标签,而不是用新的强标签包装选择?
写这个问题给了我一个主意。 我现在将尝试使用它,并回答我自己的问题(如果可行)-这样就可以解决其他人遇到的问题。 否则,我将等待着您的帮助:)
编辑:显然,如果其他人发布了可行的解决方案,那么我会接受他们的回答,而不是我的回答是否更好。
编辑(2):所以我的想法没有成功。 事实证明,某些东西(可能是range.insertNode)会为您神奇地平衡标签。 我似乎从选择,范围或碎片中获取的信息不足,无法始终知道选择是否在给定标签内。 有任何想法吗?
编辑:这不是一个好的解决方案。 它比任何一行简单文本都更复杂。 我已经解决了,并将很快发布更好的解决方案。
弄清楚了。
我构建了一个数组,其中包含所见即所得区域中的每个文本节点,以及其父标记的列表。
然后,我将选择内容包装在一个自定义元素中,以便以后可以轻松删除,并避免与任何现有的HTML元素冲突(建议使用x-前缀)。
然后,我从该列表中重建了wysiwyg元素的内容,从选择的所有节点(如果它们都已经拥有)中删除了clicked按钮的标签,这就是大多数wywiwyg编辑器处理该标签的方式。
<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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.