Skip to content

Instantly share code, notes, and snippets.

@nanto
Created February 5, 2010 00:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nanto/295297 to your computer and use it in GitHub Desktop.
Save nanto/295297 to your computer and use it in GitHub Desktop.
covertToHTMLString
// Original code by Constellation
// http://d.hatena.ne.jp/Constellation/20100203/1265207970
function convertToHTMLString(source, safe) {
if (!source || (source.getRangeAt && source.isCollapsed)) return '';
var range = source.getRangeAt ? source.getRangeAt(0) : null;
var node = range ? range.cloneContents() : source.cloneNode(true);
if (safe) {
var root = range && range.commonAncestorContainer.cloneNode(false)
if (!root || root.nodeType !== root.ELEMENT_NODE)
root = node.ownerDocument.createElement('div');
root.appendChild(node);
$X('descendant::*[contains(",' +
convertToHTMLString.UNSAFE_ELEMENTS +
',", concat(",", local-name(.), ","))]',
root).forEach(removeElement);
$X('descendant::*/@*[not(contains(",' +
convertToHTMLString.SAFE_ATTRIBUTES +
',", concat(",", local-name(.), ",")))]',
root).forEach(convertToHTMLString.removeAttributeNode);
node = appendChildNodes($DF(), root.childNodes);
}
return new XMLSerializer().serializeToString(node);
}
update(convertToHTMLString, {
UNSAFE_ELEMENTS: 'frame,script,style,frame,iframe',
SAFE_ATTRIBUTES: 'action,cellpadding,cellspacing,checked,cite,clear,' +
'cols,colspan,content,coords,enctype,face,for,href,' +
'label,method,name,nohref,nowrap,rel,rows,rowspan,' +
'shape,span,src,style,title,target,type,usemap,value',
removeAttributeNode: function removeAttributeNode(attr) {
if (attr.ownerElement)
attr.ownerElement.removeAttributeNode(attr);
},
});
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<title>Convert Selction to HTML String</title>
<style type="text/css">
pre {
background-color: #ccc;
padding: 0.3em 0.5em;
white-space: pre-wrap;
}
</style>
<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript" src="convertToHTMLString.js"></script>
</head>
<body>
<p>
<input type="button" value="Convert Selection to HTML String" onclick="$('output').textContent = convertToHTMLString(window.getSelection(), $('safe').checked);" />
<label><input id="safe" type="checkbox" checked="checked"> Remove Unsafe Contents</label>
</p>
<pre id="output"></pre>
<table>
<tr><th>header cell 1</th><th>header cell 2</th></tr>
<tr><td>data cell 1</td><td>data cell 2</td></tr>
</table>
<p>The quick brown <em>fox</em> jumps over the lazy dog.</p>
<ul>
<li><abbr title="Google Chrome">Cr</abbr> uses <a href="http://webkit.org/">WebKit</a>.</li>
<li><abbr title="Mozilla Firefox">Fx</abbr> uses <a href="https://developer.mozilla.org/en/Gecko">Gecko</a>.</li>
</ul>
<p>iframe <iframe></iframe> and input button <input type="button" value="Push me!" onclick="alert('Hi!');" /> with onclick attribute</p>
</body>
</html>
function $(id) {
return document.getElementById(id);
}
function $A(arrayLike) {
return Array.prototype.slice.call(arrayLike);
}
function $DF() {
return document.createDocumentFragment();
}
function $X(xpath, context) {
var doc = context.ownerDocument || context;
var result = doc.evaluate(xpath, context, null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var nodes = [];
for (var i = 0, n = result.snapshotLength; i < n; i++)
nodes.push(result.snapshotItem(i));
return nodes;
}
function update(dest, src) {
for (var i in src)
dest[i] = src[i];
return dest;
}
function appendChildNodes(parent, nodes) {
nodes = (typeof nodes.nodeType === 'number') ? [nodes] : $A(nodes);
nodes.forEach(function (node) { parent.appendChild(node); });
return parent;
}
function removeElement(node) {
if (node.parentNode)
node.parentNode.removeChild(node);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment