How To Wrap With Html Tags A Cross-boundary Dom Selection Range?
is mad
Solution 1:
have you tried the following approach (which is actually the description in the W3C spec of what surroundContents should do):
var wrappingNode = document.createElement("div");
wrappingNode.appendChild(range.extractContents());
range.insertNode(wrappingNode);
Solution 2:
I'm currently working on an inline editor and I've written a function that can properly wrap a cross-element range with any type of element like the execCommand does.
functionsurroundSelection(elementType) {
functiongetAllDescendants (node, callback) {
for (var i = 0; i < node.childNodes.length; i++) {
var child = node.childNodes[i];
getAllDescendants(child, callback);
callback(child);
}
}
functionglueSplitElements (firstEl, secondEl){
var done = false,
result = [];
if(firstEl === undefined || secondEl === undefined){
returnfalse;
}
if(firstEl.nodeName === secondEl.nodeName){
result.push([firstEl, secondEl]);
while(!done){
firstEl = firstEl.childNodes[firstEl.childNodes.length - 1];
secondEl = secondEl.childNodes[0];
if(firstEl === undefined || secondEl === undefined){
break;
}
if(firstEl.nodeName !== secondEl.nodeName){
done = true;
} else {
result.push([firstEl, secondEl]);
}
}
}
for(var i = result.length - 1; i >= 0; i--){
var elements = result[i];
while(elements[1].childNodes.length > 0){
elements[0].appendChild(elements[1].childNodes[0]);
}
elements[1].parentNode.removeChild(elements[1]);
}
}
// abort in case the given elemenType doesn't exist.try {
document.createElement(elementType);
} catch (e){
returnfalse;
}
var selection = getSelection();
if(selection.rangeCount > 0){
var range = selection.getRangeAt(0),
rangeContents = range.extractContents(),
nodesInRange = rangeContents.childNodes,
nodesToWrap = [];
for(var i = 0; i < nodesInRange.length; i++){
if(nodesInRange[i].nodeName.toLowerCase() === "#text"){
nodesToWrap.push(nodesInRange[i]);
} else {
getAllDescendants(nodesInRange[i], function(child){
if(child.nodeName.toLowerCase() === "#text"){
nodesToWrap.push(child);
}
});
}
};
for(var i = 0; i < nodesToWrap.length; i++){
var child = nodesToWrap[i],
wrap = document.createElement(elementType);
if(child.nodeValue.replace(/(\s|\n|\t)/g, "").length !== 0){
child.parentNode.insertBefore(wrap, child);
wrap.appendChild(child);
} else {
wrap = null;
}
}
var firstChild = rangeContents.childNodes[0];
var lastChild = rangeContents.childNodes[rangeContents.childNodes.length - 1];
range.insertNode(rangeContents);
glueSplitElements(firstChild.previousSibling, firstChild);
glueSplitElements(lastChild, lastChild.nextSibling);
rangeContents = null;
}
};
Here's a JSFiddle with some complex HTML as demo: http://jsfiddle.net/mjf9K/1/. Please note that I took this straight out of my application. I use a few helpers to correctly restore the range to the original selection etc. These are not included.
Solution 3:
That is when you add contentEditable=true attribute to the parent of those paragraphs, select any text, even across paragraphs, then make the call
document.execCommand('italic', false, null);
and finally if desired set contentEditable attribute back to false.
Btw, this works on IE too, except that to enter editable mode I think it is called designMode or something, google for it.
Post a Comment for "How To Wrap With Html Tags A Cross-boundary Dom Selection Range?"