bililiteRange
to handle some of the subtleties of dealing with contenteditable
elements, a syntax-highlighting editor is relatively easy.
Simplest usage: bililiteRange.fancyText(element, Prism.highlightelement);
.
See the demo.
See the code on github.
There's a fair amount of flakiness; contenteditable
elements are still handled inconsistently. Newlines are changed into actual elements (Firefox adds <br>
s; Chrome adds a whole new <div>
), even though a <pre>
doesn't need that; it would interpret newlines the way we want. So we have to intercept those and just insert the newline. Firefox insists on changing newlines into <br>
's even in pasted text, and Chrome's clipboard implementation includes the carriage return character, so we have to intercept paste events and insert the text appropriately mangled.
Usage
bililiteRange.fancyText(pre-element,[highlighter]);
sets up pre-element
to be an editor; meaning that it listens for input
events and re-highlights the code each time. The element can be any element, though only <pre>
elements are targeted by the Prism CSS, and if you are writing code, whitespace is presumably important. So using <pre>
makes the most sense. In order to allow editing, it should have contenteditable
set, though that is not enforced.
highlighter
is a function highlighter(pre-element)
that does something to the element that leaves its underlying text unchanged; intended to be Prism.highlightelement
. If undefined
, just sets up the keydown
and paste
event listeners as above without doing anything else.
var editor = bililiteRange.fancyText(textarea,[highlighter]);
Replaces textarea
with a <pre>
, calls Prism.editor
on that, and returns it. The original textarea
is deleted.
var editor = bililiteRange.fancyText(pre-element, highlighter, threshold);
Even though Prism is fast, highlighting large texts with every keystroke can be slow. threshold
is the number of milliseconds to "debounce" the input
events; highlighting will only be done after that many milliseconds without any input.
Notes
Originally I had this with the Prism highlighter hard-wired in, as a Prism plugin. I realized that most of the code has nothing to do with Prism per se, so I could use dependency injection to make this a general-purpose highlighting editor; for instance, use
bililiteRange.fancyText(el, function(el){
el.innerHTML = '<span class=line>'+el.innerHTML.split('\n').join('</span>\n<span class=line>')+'</span>';
});
to add line numbers with CSS.
Edited 2013-12-26: Prism requires an editable <pre>
or other element, not a <textarea>
. But that creates problems with progressive enhancement; I'd like my form to work without Javascript and <pre>
's don't get submitted. So ideally, the original HTML should have a <textarea>
and the Javascript should replace it with a <pre contenteditable>
. In that case, clearly the Javascript is working and you can get the text out of the editor to add it to the submitted form.
Prism.editor
now does that. If the input element is a <textarea>
, it replaces it with a <pre contenteditable>
that has the same attributes (including id
) and returns the new element.
Edited 2013-12-17: added threshold
parameter.
Hacking at 0300 : bililiteRange data says:
[…] fancyText does exactly that. See the […]
February 26, 2014, 5:15 pmAntonio says:
Why doesn’t work with CSS or JS?
July 11, 2016, 1:33 pmAntonio says:
Ignore my previous question.
July 11, 2016, 2:02 pmHow can I manage multiple tags?
Danny says:
Antonio:
August 7, 2016, 5:17 pmSorry I haven’t responded earlier.
fancyText
just applies Prism to the range; I would look at the Prism documentation to figure out how to handle multiple tags.–Danny