I am writing a messenger and my aim is to add an opportunity to insert code and highlight it as it is done on Stack Overflow. I am using prettify library by Google. Here is html part:
<div id="test" style="margin-left: auto; margin-right: auto; overflow-y: scroll;" contenteditable="true"
placeholder="Type your message" name="message" ng-model="message">
</div>
and js function:
$scope.pasteHtmlAtCaret = function () {
document.getElementById('test').focus();
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
// Range.createContextualFragment() would be useful here but is
// only relatively recently standardized and is not supported in
// some browsers (IE9, for one)
var el = document.createElement("div");
//var el = document.getElementById('test');
/*var text = sel.toString().replace(/</g, "<");
text = text.replace(/>/g, ">");
text = text.replace(/&/g, "&");*/
el.innerHTML = "<pre class=prettyprint linenums><code>" + sel.toString() + '</code></pre></br>';
range.deleteContents();
var frag = document.createDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
var firstNode = frag.firstChild;
range.insertNode(frag);
prettyPrint();
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
range.setStartBefore(firstNode);
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if ((sel = document.selection) && sel.type != "Control") {
var originalRange = sel.createRange();
originalRange.collapse(true);
sel.createRange().pasteHTML(html);
range = sel.createRange();
range.setEndPoint("StartToStart", originalRange);
range.select();
}
}
As you can see, I have already tried to place <
(in comments) and other symbols instead of <, >, & symbols. However, they get displayed as they are in js code, not like symbols. Could you tell me, please, how can I insert prettified html code inside my div block (or, possibly, another container).
Possibly, you could also tell me, how to make prettify show line numbers, because they are not shown right now (they are taken as another class somehow)
Afaict, you're creating a <pre class=prettyprint>
, but the prettify library never actually gets called on it.
I think you can just use PR.prettyPrintOne
and pass in your HTML source code. You're correct that you should escape &
, <
, and >
first since it takes HTML, not plain source code.
PR.prettyPrintOne
is available when you load <script src=".../prettify.js"></script>
but not when you load <script src=".../run_prettify.js"></script>
.
/*var text = sel.toString().replace(/</g, "<"); text = text.replace(/>/g, ">"); text = text.replace(/&/g, "&");*/
There's a bug here. You should do the .replace(/&/g, "&")
first because
"<".replace(/</g, "<").replace(/&/g, "&") === "&lt;"
whereas
"<".replace(/&/g, "&").replace(/</g, "<") === "<"
Replace order matters when some of the substitution strings also match patterns :)
function htmlEscape(s) {
return (String(s).replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">"));
}