Try this solution:
1. Use a contenteditable
element instead of input
or textarea
.
<div id="txtInput" contenteditable></div>
The reason is we need to display HTML with CSS inside of this input area.
2. Filter the result with highlight text.
// get highlight text from string
const highlighten = (string, highlight) => {
string = stripHtml(string);
// add highlight
if (string.includes(highlight)) {
string = string.replaceAll(highlight, `<span style="color:red">${highlight}</span>`);
}
return string;
};
Use replaceAll
to set the highlight CSS. You can see the stripHTML()
which is for cleaning the string before doing the filter.
3. Handle keyup
event
// on keyup event
$('#txtInput').on('keyup', function(e) {
const $input = $(e.currentTarget);
// you can manage your localStorage data here
// ...
// filter the input
$input.html(highlighten($input.html(), 'h1'));
// set caret
setCaretAtTheEnd($input.get());
});
As we replace the #txtInput
with the new result, we will lose the caret position, that's why we need setCaretAtTheEnd()
to set the caret back to the end of input.
// https://stackoverflow.com/questions/822452/strip-html-from-text-javascript
function stripHtml(html) {
let tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
// https://stackoverflow.com/questions/6249095/how-to-set-the-caret-cursor-position-in-a-contenteditable-element-div
function setCaretAtTheEnd(el) {
var range = document.createRange()
var sel = window.getSelection()
const nodes = el[0].childNodes;
let offset = 0;
nodes.forEach((node, i) => {
offset = node.length || 1;
});
range.setStart(nodes[nodes.length - 1], offset)
range.collapse(true)
sel.removeAllRanges()
sel.addRange(range)
}
// get highlight text from string
const highlighten = (string, highlight) => {
string = stripHtml(string);
// add highlight
if (string.includes(highlight)) {
string = string.replaceAll(highlight, `<span style="color:red">${highlight}</span>`);
}
return string;
};
// on keyup event
$('#txtInput').on('keyup', function(e) {
const $input = $(e.currentTarget);
// you can manage your localStorage data here
// ...
// filter the input
$input.html(highlighten($input.html(), 'h1'));
// set caret
setCaretAtTheEnd($input.get());
});
#txtInput {
width: 400px;
height: 200px;
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="txtInput" contenteditable>
</div>