JS Highlighting Of Text Strings - javascript

Using a small plugin to highlight text strings from an input field within a form.
JavaScript text higlighting jQuery plugin
I have modified the code slightly to allow the user to add multiple strimgs into the input field by splitting them with a comma which will highlight multiple keywords.
This works great in this instance: stack,overflow,js
However if I was to type in stack,overflow,js, (note the , after the last string) it hangs the browser and becomes unresponsive.
The code I am using is:
$(function() {
if ( $("input#searchterm").val().length > 0 ) {
$("input#searchterm").addClass('marked-purple');
var arrayOfKeyWords= $("input#searchterm").val().split(',');
for (var i=0;i<arrayOfKeyWords.length;i++) {
$('.message p.messagecontent').highlight(arrayOfKeyWords[i]);
}
}
});
Does anyone have an idea of how to ignore the last comma if the user has added it?
Thanks in advance

You could do an empty value check before calling highlight(), like this:
if ($("#searchterm").val().length > 0) {
$("#searchterm").addClass('marked-purple');
var arrayOfKeyWords = $("#searchterm").val().split(',');
for (var i = 0; i < arrayOfKeyWords.length; i++) {
if (arrayOfKeyWords[i] !== "") { // ensure there is a value to highlight
$('.message p.messagecontent').highlight(arrayOfKeyWords[i]);
}
}
}
Alternatively you could strip the trailing commas if there are any.
if ($("#searchterm").val().length > 0) {
$("#searchterm").addClass('marked-purple');
var arrayOfKeyWords = $("#searchterm").val().replace(/,+$/, '').split(',');
for (var i = 0; i < arrayOfKeyWords.length; i++) {
$('.message p.messagecontent').highlight(arrayOfKeyWords[i]);
}
}

Thats how you can remove last comma of a string:
var str = "stack,overflow,js,";
if(str.charAt( str.length-1 ) == ",") {
str = str.slice(0, -1);
}

Related

Check for open tag in textarea

I'm making a Ukrainian phonetic keyboard. People type in English, and the letters automatically change to the corresponding Ukrainian characters. However, when I'm using it, I sometimes need to write myself notes in English (they serve the same purpose as comments in code- for other people and for myself).
I'd like to indicate the start of a comment with a tag ("<"). How can I check if there's currently an open tag?
I'm thinking something like this:
if (number of "<" is greater than ">") {//if a tag has been opened and not closed
//disable translation, type in English
}
I understand how to disable the translation- however, I'm unsure about the
"if"
How can I check if
number of "<" is greater than ">"
Thanks!
You can count number of specific characters using .match()
In your case
var string = "<<<>>";
if ((string.match(/</g)||[]).length > (string.match(/>/g)||[]).length) {
console.log("More");
}
else {
console.log("Less or equal");
}
counting each of them is like below
var countGreaterThan = (temp1.match(/</g) || []).length;
var countLessThan = (temp1.match(/</g) || []).length;
and temp is the string value of the textarea
Depending on where your data is, you can do:
var data = document.querySelector('#data-container').innerHTML;
var isOpenTagPresent = getSymbolCount('<') > getSymbolCount('<');
if(isOpenTagPresent) {
//execute your logic
}
function getSymbolCount(symbol) {
var count = 0;
for(var i = 0; i < data.length; ++i) {
if(data[i] === symbol) {
count++;
}
}
return count;
}
Hope this helps, cheers!

jQuery write each character with formatting

let´s say I have a string in JavaScript:
var str = '<span class="color:red;">Hello</span> my name is <span class="color:red;">Julian</span>';
So I would like to print each 300ms one character so that it looks as if it is being entered. Sure I can make a for-loop for each character and print it inside an element, but the problem is the formatting. If I use the for-loop it will even print the span-tag separately, but that will causing problems.
How to print every character after a while with formatting?
This quite an evil trick but you can use a white div on top of your string and move it step by step every 300ms. In this way a letter appears every 300ms. The only problem is to determine how big each step needs to be since the width of each character will vary.
A way to determine the width is to load all the characters separate in a div and measure the width. Of course you first need to strip the html. In order to so you could use How to strip HTML tags with jQuery?
You could split all characters into an array and then loop like this:
var str = '<span class="red">Hello</span> my name is <span class="red">Julian</span>',
AllChars = [],
SetTxt = true,
newstr = '';
for (var i = 0; i < str.length; i++) {
newstr += str.substr(i,1);
if((str.substr(i,1) == '<') || (str.substr(i,1) == '&')){
SetTxt = false;
}else if(SetTxt){
AllChars.push(newstr);
}else if((str.substr(i,1) == '>') || (str.substr(i,1) == ';')){
if(str.length == (i+1)){
AllChars.push(newstr);
}
SetTxt = true;
}
}
for (var i in AllChars){
setTimeout(function(i){
$('#text').html(AllChars[i]);
},300 * i,i);
}
Check the jsfiddle for a working example: http://jsfiddle.net/2R9Dk/1/
You need to parse html tags and text separately. Something like:
var str = '<span class="colored">Hello</span> my name is <span class="colored bold">Julian</span>';
function printTextByLetter(text, selector, speed) {
var html = text.match(/(<[^<>]*>)/gi),
sel = selector || 'body',
arr = text.replace(/(<[^<>]*>)/gi, '{!!}').match(/(\{!!\}|.)/gi),
counter = 0, cursor = jQuery(sel), insideTag,
interval = setInterval(printChar, speed);
function printChar() {
if(arr[0]){
if(arr[0] === '{!!}') {
if(!insideTag) {
insideTag = true;
cursor.append(html[0], html[1]);
html.shift();
html.shift();
cursor = cursor.children().eq(counter);
} else {
insideTag = false;
cursor = cursor.parent();
counter++;
}
} else {
cursor.append(arr[0]);
}
arr.shift();
} else {
clearInterval(interval);
}
}
}
// DOM ready
jQuery(function($){
printTextByLetter(str, '#target', 300);
});
And don't forget to clear intervals - it does affect performance.
Example on JSFiddle: http://jsfiddle.net/36kLf/7/

Search for Special Characters in Text

I have this Javascript code below that searches for any word entered into a textfield. Now, the text that needs to be searched through contains special characters like the apostrophe and dot in this sample text: "And the tribe of Zeb′u·lun."
Now, how can I adopt my JS code to include those special characters? If I type Zebulun with no special characters in my textfield the search function cannot find it.
var SearchResultCount = 0;
var a = new Array();
var oneTime = false;
// helper function, recursively searches in elements and their child nodes
function HighlightAllOccurencesOfStringForElement(element,keyword) {
if (element) {
if (element.nodeType == 3) { // Text node
while (true) {
var value = element.nodeValue; // Search for keyword in text node
var idx = value.toLowerCase().indexOf(keyword;
if (idx < 0) break; // not found, abort
var span = document.createElement("span");
var text = document.createTextNode(value.substr(idx,keyword.length));
span.appendChild(text);
span.setAttribute("class","MyAppHighlight");
text = document.createTextNode(value.substr(idx+keyword.length));
element.deleteData(idx, value.length - idx);
var next = element.nextSibling;
element.parentNode.insertBefore(span, next);
element.parentNode.insertBefore(text, next);
element = text;
span.scrollIntoView();
span.style.background= "-webkit-linear-gradient(top, #FAE309, #FFF7AA)";
span.style.fontWeight = "bold";
span.style.padding = "2px";
span.style.borderRadius = "5px";
span.style.boxShadow = "0px 0px 2px black";
a.push(span); // SET THIS CODE HERE
SearchResultCount++; // update the counter
}
} else if (element.nodeType == 1) { // Element node
if (element.style.display != "none" && element.nodeName.toLowerCase() != 'select') {
for (var i=element.childNodes.length-1; i>=0; i--) {
HighlightAllOccurencesOfStringForElement(element.childNodes[i],keyword);
}
}
}
}
}
// the main entry point to start the search
function HighlightAllOccurencesOfString(keyword) {
RemoveAllHighlights();
HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());
}
First off, there's a closing parenthesis missing in the following line:
var idx = value.toLowerCase().indexOf(keyword;
So I wouldn't be surprised if the function didn't work at all.
To answer your question, one way to do this is to wash out every character except alphabetic characters using the String variable's native replace() function. You'd have to do this with both the search term and the text you're searching, so you'll have to pass both your value and your keyword variables through the function. Something like this:
keyword = cleanUp(keyword);
var value = cleanUp(element.nodeValue);
...
function cleanUp(toClean) {
cleaned = toClean.replace([^a-zA-Z],""); //Deletes non-alphabetic characters (including spaces) by replacing them with nothing. If you want to leave spaces intact, use [^a-zA-Z ] instead.
return cleaned;
}
Once this is done, use the same function you've got going to compare the two strings.

Custom Mask Function does not work when inserting character in the middle Javascript/JQuery

I have a function:
function maskInput(input, location, delimiter, length) {
//Get the delimiter positons
var locs = location.split(',');
//Iterate until all the delimiters are placed in the textbox
for (var delimCount = 0; delimCount <= locs.length; delimCount++) {
for (var inputCharCount = 0; inputCharCount <= input.length; inputCharCount++) {
//Check for the actual position of the delimiter
if (inputCharCount == locs[delimCount]) {
//Confirm that the delimiter is not already present in that position
if (input.substring(inputCharCount, inputCharCount + 1) != delimiter) {
input = input.substring(0, inputCharCount) + delimiter + input.substring(inputCharCount, input.length);
}
}
}
}
input = input.length > length ? input.substring(0, length) : input;
return input;
}
I use this in:
$(document).on('keypress paste drop blur', '#my_phone_number', function() {
//remove any nondigit characters
var myVal = $(this).val().toString().replace(/\D/g,'');
$(this).val(myVal);
var inVal = maskInput(myVal, '3,7', '-', 12);
$(this).val(inVal);
});
This works perfectly but when I try to remove a digit from the middle of string and then add it again it appends it to the end of string, does not stick to the current position.
Example:
Entered String: '1234567890'
After Mask Function Is Called: '123-456-7890'
Number 5 removed and entered Number 8 instead of 5: '123-467-8908'
Note that it appended number 8 at the end of string.
Any help is appreciated, thank you
You should use keyup instead of keypress, since on keypress the value of input is not yet changed and you apply your filter prior to new value is posted to input. That is the reason why new character is appended.
$(document).on('keyup paste drop blur', '#my_phone_number', function() {
...
});
Example of working code here http://jsbin.com/upinux/1/edit

How can I ignore leading and trailing linebreaks within an html "code" block using css, javascript or jquery?

In my HTML source code, I have a code block like the following (I use showdown and highlight.js on this page):
<pre><code class="cpp">
double myNumber = (double)4;
</code></pre>
My problem is that the first linebreak remains part of the "code" block. It's probably because of the enclosing "pre" block, but I need that there because highlight.js expects it (also apparently the HTML5 standard recommends it). The code is rendered like this (note the leading line break):
So my question is, using css, javascript or jquery, how can I remove leading or trailing linebreaks from "code" blocks like this one?
You could use this hack:
pre:first-line {
line-height: 0;
}
Here's another approach using Javascript that also solves the problem:
<script>
window.onload = function (){
// remove leading linebreaks from code blocks.
var pre = document.getElementsByTagName("code");
for (var i = 0, len = pre.length; i < len; i++) {
var text = pre[i].firstChild.nodeValue;
pre[i].firstChild.nodeValue = text.replace(/^\n+|\n+$/g, "");
}
}
</script>
Someone else posted this, then deleted their answer, but I thought it was worth preserving.
That's how pre works by default: it honors line breaks and whitespace. If you don't want the newline to render, then you have to remove it. Either outright remove it from the source or comment it out if you care how the source looks.
http://jsfiddle.net/VL8tG/
<pre><code class="cpp"><!--
-->double myNumber = (double)4;<!--
--></code></pre>
I just remove them manually before the highlighter starts.
const trimLine = node =>
node.firstChild.nodeValue = node.firstChild.nodeValue.replace(/^\n+|\n+$/g, "");
window.onload = function () {
Array.prototype.slice
.call(document.getElementsByTagName("code"), 0)
.map(trimLine);
hljs.initHighlightingOnLoad();
}
Demo: http://jsfiddle.net/WjVVs/4/.
Tested with Chrome and FF on the PC. It does not work in IE 9 when the plugin is applied to a code element (it appears to work fine when applied to a pre element). I can't find a suitable workaround, but feel free to comment/update.
This is a modified version from another answer. This plugin attempts to remove extra indentation caused by the natural flow of the document. I've modified it to be smarter about leading whitespace.
If it works correctly, you should see something like:
Usage
$("code").prettyPre(); // any selector here
HTML with leading whitespace and extra indentation
<div>
<pre><code class="cpp">
double myNumber = (double)4;
// another line
// another line
// this is purposely indented further
for( var i = 0; i < 100; i++ ){
}
</code></pre>
</div>
Plugin
(function( $ ) {
$.fn.prettyPre = function( method ) {
var defaults = {
ignoreExpression: /\s/ // what should be ignored?
};
var methods = {
init: function( options ) {
this.each( function() {
var context = $.extend( {}, defaults, options );
var $obj = $( this );
var usingInnerText = true;
var text = $obj.get( 0 ).innerText;
// some browsers support innerText...some don't...some ONLY work with innerText.
if ( typeof text == "undefined" ) {
text = $obj.html();
usingInnerText = false;
}
// use the first line as a baseline for how many unwanted leading whitespace characters are present
var superfluousSpaceCount = 0;
var pos = 0;
var currentChar = text.substring( 0, 1 );
while ( context.ignoreExpression.test( currentChar ) ) {
if(currentChar !== "\n"){
superfluousSpaceCount++;
}else{
superfluousSpaceCount = 0;
}
currentChar = text.substring( ++pos, pos + 1 );
}
// split
var parts = text.split( "\n" );
var reformattedText = "";
// reconstruct
var length = parts.length;
for ( var i = 0; i < length; i++ ) {
// remove leading whitespace (represented by an empty string)
if(i === 0 && parts[0]=== ""){
continue;
}
// cleanup, and don't append a trailing newline if we are on the last line
reformattedText += parts[i].substring( superfluousSpaceCount ) + ( i == length - 1 ? "" : "\n" );
}
// modify original
if ( usingInnerText ) {
$obj.get( 0 ).innerText = reformattedText;
}
else {
// This does not appear to execute code in any browser but the onus is on the developer to not
// put raw input from a user anywhere on a page, even if it doesn't execute!
$obj.html( reformattedText );
}
} );
}
}
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ) );
}
else if ( typeof method === "object" || !method ) {
return methods.init.apply( this, arguments );
}
else {
$.error( "Method " + method + " does not exist on jQuery.prettyPre." );
}
}
} )( jQuery );
These functions use a class (added to the pre) to remove leading and trailing whitespace
function removeWhitespace(indent) {
// Get a list of all elements that need whitespace removed by indent value (will have class `indent-X`)
// List may be 0 long - loop simply doesn't run
var preElements = document.getElementsByClassName('indent-'+indent);
for (i = 0; i < preElements.length; i++) {
preElements[i].innerHTML = preElements[i].innerHTML.split('\n'+' '.repeat(indent)).join('\n').split('\n'+' '.repeat(indent-2)+'</code>').join('</code>').split("\n").slice(1,-1).join("\n");
//split('\n'+' '.repeat(indent)).join('\n') -- Split at every newline followed by X spaces. Then join together with the newlines.
// .split('\n'+' '.repeat(indent-2)+'</code>').join('</code>') -- The lastline will have 2 less spaces, so remove those, and the newline at the end. Add the tag back in.
//.split("\n").slice(1,-2).join("\n"); -- Remove the first and last lines.
}
}
function removeWhitespaces() {
// Loop over all indents, 2 to 40
for (indent = 2; indent <= 40; indent+=2) {
removeWhitespace(indent);
}
}
Simply add the class indent-X where X is the amount of whitespace you want to remove to the pre.
JSFiddle
function removeWhitespace(indent) {
// Get a list of all elements that need indent removed by indent value (will have class `indent-X`)
// List may be 0 long - loop simply doesn't run
var preElements = document.getElementsByClassName('indent-' + indent);
for (i = 0; i < preElements.length; i++) {
preElements[i].innerHTML = preElements[i].innerHTML.split('\n' + ' '.repeat(indent)).join('\n').split('\n' + ' '.repeat(indent - 2) + '</code>').join('</code>').split("\n").slice(1, -2).join("\n");
//split('\n'+' '.repeat(indent)).join('\n') -- Split at every newline followed by X spaces. Then join together with the newlines.
// .split('\n'+' '.repeat(indent-2)+'</code>').join('</code>') -- The lastline will have 2 less spaces, so remove those, and the newline at the end. Add the tag back in.
//.split("\n").slice(1,-1).join("\n"); -- Remove the first and last lines.
// Remove the clickme element.
document.getElementById('clickme').innerHTML = '';
}
}
function removeWhitespaces() {
// Loop over all indents, 2 to 40
for (indent = 2; indent <= 40; indent += 2) {
removeWhitespace(indent);
}
}
.indent-14 {
background-color: #ccc;
}
<body>
<div id="clickme" onclick="removeWhitespaces()">
Click Me
</div>
<pre class="indent-14">
<code>
function createCORSRequest(method, url) {
var request = new XMLHttpRequest();
if ('withCredentials' in request) {
request.open(method, url, true);
} else if (typeof XDomainRequest != 'undefined') {
request = new XDomainRequest();
request.open(method, url);
} else {
request = null;
}
return request;
}
</code>
</pre>
</body>

Categories

Resources