Making bulk JavaScript replace more efficient - javascript

I have some JavaScript which replaces smiley symbols with their corresponding images in my blog.
So symbols like :) or :( are replaced by proper <img> tags.
Currently there are around 50 smiley symbols that can be used. But in any page only a few of them will be used obviously.
The script has lines of the form element.replace(smileyRegex, <imgTags>) for each smiley.
The problem is that, due to a large number of these regex matching lines, the script causes a slight delay after the page is loaded.
I'm thinking of the following method to make this more efficient: To call replace with a large regex which matches all smiley symbols as first argument, and a function which chooses proper image from an array as the second argument.
Will this usage be more efficient than a number of separate replace calls that may or may not match?

Having one regex match all occurences of smileys would be a lot more efficient. That is because it would only be one iteration through the source, instead of one interation per smiley. Then have an appropriate hashtable / object with smiley -> img src would be an efficient lookup:
var smileyImgMap = {
":)" : "happysmiley.png",
":(" : "sadsmiley.png"
};
Then use it like this:
var smileyImg = smileyImgMap[":)"];
I think you get the idea.

I wrote this jsperf to test the two concepts. It probably needs more representative data put in it for what type of source data you're searching through, how many different things you're looking for and how often you are likely to find a match. You can fill those into the basic framework in the jsperf and then look at it in different browsers.
The regex w/callback option looks basically like this:
var replaceLookup = {aa: "--", bb: "++", cc: "**"};
var result = sourceStr.replace(/aa|bb|cc/g, function(str, p1, p2, offset, s)
{
return(replaceLookup[str]);
});

Almost any "which is more efficient" question is going to get an answer like "it depends". What you're proposing certainly sounds promising but you really should just benchmark on a few different browsers and be sure.
Another solution would be to render the page as is, and then asynchronously go through each of the 50 smileys and run the regexps one at a time. It would certain take more time, but your user wouldn't perceive the delay (since the page is already rendered).

One way to speed it up is to place all smileys in one image and use it as a css sprite.
.smily1 {background:url('/images/allSmilyImage.png') 0px 0px}
.smily2 {background:url('/images/allSmilyImage.png') 0px 50px}
.smily3 {background:url('/images/allSmilyImage.png') 50px 100px}
...
Specify the smileys image position in a css file then use the hash mapping as #jishi suggested for mapping the css styles for the corresponding smily.
var smileyClassMap = {
":)" : "smily1",
":(" : "smily2",
":P" : "smily3"
};
Replace the text smileys with a <span class="smily1" style="display:block" /> tag or similar

Related

Make 1 javascript/function affect several classes at once - how?

I am using the following code on my webpage, in order to format certain numbers (with the ".pricetag" class), as i need to show them as currencies (comma separated at thousands) on my front end:
jQuery(document).ready(function($) {
$.fn.digits = function(text){
$(this).text(text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") + '€' );
};
var tempText = $.trim($(".pricetag").text());
tempText = tempText.substr(0, parseInt(tempText.length) );
$(".pricetag").digits(tempText);
});
So far so good - code works fine, and does what i need it to.
My problem is that i have more classes than just the ".pricetag" class, for which i want to use the function. So right now i have copy pasted the code, and just changed the target class (".pricetag_2" etc.).
How do i tell one version of the javascript/code, to affect several classes (both ".pricetag" and ".pricetag_2") in stead of having to copy paste the same piece of code, let's say 10 times, to target 10 different classes.
It's a bit overkill to have so much code, as the function is exactly the same every time. In CSS it's pretty easy, as you can affect several classes at once, by comma seperating them within a piece of code, but how do i do it in javascript?
Thanks!
If all your classes begin with .pricetag you might try the attribute-starts-with selector.
$("[class^='pricetag']").digits(tempText);

Using grease/tampermonkey (or another extension) to omit certain characters inside web elements

Firstly, I apologize if my terminology here isn't the most accurate; I'm very much a novice when it comes to programming. A forum I frequent has added a bunch of unneccessary, "glitchy" images and text to the page as a part of some promotion, but the result is that the forum is now difficult to use and read. I was able to script out most of it using adblock, but there's one last bit that shows up inside the forum elements themselves, and adblock wants to remove the whole element (which breaks the forum). This is part of the code in question, with the URLs changed:
<td class="windowbg" valign="middle" width="42%">&blk34;&blk34;&blk34;&blk34;&blk34;
Thread title <span class="smalltext"></span><img src="example.com/forumicon.gif"></td>
As you can see, the ▓ character shows up a bunch of times for no reason. Is there a way to make my browser ignore this character when it's inside of an element? If there's a way to do this using AdBlock, I am not smart enough to see it.
Here's one way to do it, using a NodeIterator:
var iter = document.createNodeIterator( document.body, NodeFilter.SHOW_TEXT );
var node;
while (node = iter.nextNode()) {
node.textContent = node.textContent.replace( /[\u2580-\u259f]+/g, '' );
}
This is just plain JavaScript code; you can paste it into the Firefox / Chrome JS console to test it. The regexp /[\u2580-\u259f]+/ matches any sequence of characters in the "Block Elements" Unicode block, including U+2593 Dark Shade (▓). You may want to tweak the regexp to match the characters you want to remove. (Tip: If you don't know what the codes for those characters are, copy and paste them into the "UTF8 String" box on this page.)
Ps. If these characters that you want to remove occur only in a certain part of the document, you can make this code a bit more efficient by replacing the root node (document.body above) with the specific DOM node that you want to remove the characters from. To find the nodes you want, you can use e.g. document.getElementById() or, more generally, document.querySelector() (or even document.querySelectorAll() and loop over the results).

Optimising regex for matching domain name in url

I have a regex that matches iframe urls, and captures various components. The regex is given below
/(<iframe.*?src=['|"])((?:https?:\/\/|\/\/)[^\/]*)(?:.*?)(['|"][^>]*some-token:)([a-zA-Z0-9]+)(.*?>)/igm
To be clear my actual requirement is to transforms in a html string, such strings
<iframe src="http://somehost.com/somepath1/path2" class="some-token:abc123">
to
<iframe src="http://somehost.com/newpath?token=abc123" class="some-token:abc123">
The regex works as it is supposed to be, but for normal length html, it takes around 2 seconds to execute, which i think is very, high.
I would really appreciate if someone could point me how to optimise this regex, i am sure i am doing something terribly wrong, because before i used this regex
/(<iframe.*?src=['|"])(?:.*?)(['|"][^>]*some-token:)([a-zA-Z0-9]+)(.*?>)/igm
to completely replace the source url and just add the paramter, it was taking just 100 ms
You do not need to (and should not) parse the iframe element as a string; you just need to access its attributes, and retrieve information from them and rewrite them.
function fix_iframe_src(iframe) {
var src = iframe.getAttribute('src');
var klass = iframe.getAttribute('class');
var token = get_token(klass);
src = fix_src(src, token);
iframe.setAttribute('src', src);
}
Writing get_token and fix_src are left as an exercise.
If you want to find a bunch of iframes and fix them all up, then
var iframes = document.querySelectorAll('iframe');
for (var i = 0; i < iframes.length; i++) {
fix_iframe_src(iframes[i]);
}
By the way, the value of your class attribute seems to be broken. I doubt if it will match any CSS rules, if that's the intent. Are you using it for something other than to provide the token? In that case, you would be best off using a data attribute such as data-token.
Minor point about regexp flags: the g and m flags are going to do nothing for you. m is about matching anchors like ^ and $ to the beginning and end of lines within the source string, which is not an issue for you. g is about matching multiple times, which is also not an issue.
The reason your regexp is taking so long is most likely that you are throwing the entire DOM at it. Hard to tell unless you show us the code from which you are calling it.

Adapt textarea max word plugin

How would one adapt this jquery plugin so that it counts down from how many words your allowed/you have remaining, instead of counting up to how many your allowed.
www.javascriptkit.com/script/script2/enforceform.shtml
Thanks in advance.
There is also a very simple way to do it without a maxlength attribute. (This example uses 200 as the maximum characters).
$("#YourTextareaId").keyup(function () {
var i = $("#YourTextareaId").val().length;
$('#IdOfCountdownDisplay').val(''+200-i+'');
A nice thing to remember when coding, is that a simple equation can get rid of a whole lot of complicated code.
open the maxlength.js file and put this
$field.data('$statusdiv').css('color', '').html( $field.data('maxsize') - $field.val().length )
instead of this:
$field.data('$statusdiv').css('color', '').html($field.val().length)

How to print pretty xml in javascript?

What's the best way to pretty-print xml in JavaScript? I obtain xml content through ajax call and before displaying this request in textarea i want to format it so it looks nice to the eye :)
This does not take care of any indenting, but helps to encode the XML for use within <pre> or <textarea> tags:
/* hack to encode HTML entities */
var d = document.createElement('div');
var t = document.createTextNode(myXml);
d.appendChild(t);
document.write('<pre>' + d.innerHTML + '</pre>');
And if, instead of a <textarea>, you'd want highlighting and the nodes to be collapsable/expandable, then see Displaying XML in Chrome Browser on Super User.
take a look at the vkBeautify.js plugin
http://www.eslinstructor.net/vkbeautify/
it is exactly what you need.
it's written in plain javascript, less then 1.5K minified and very fast: takes less then 5 msec. to process 50K XML text.
Here is a small self contained prettifier that works for most cases does nice indenting for long lines and colorizes the output if needed.
function formatXml(xml,colorize,indent) {
function esc(s){return s.replace(/[-\/&<> ]/g,function(c){ // Escape special chars
return c==' '?' ':'&#'+c.charCodeAt(0)+';';});}
var sm='<div class="xmt">',se='<div class="xel">',sd='<div class="xdt">',
sa='<div class="xat">',tb='<div class="xtb">',tc='<div class="xtc">',
ind=indent||' ',sz='</div>',tz='</div>',re='',is='',ib,ob,at,i;
if (!colorize) sm=se=sd=sa=sz='';
xml.match(/(?<=<).*(?=>)|$/s)[0].split(/>\s*</).forEach(function(nd){
ob=('<'+nd+'>').match(/^(<[!?\/]?)(.*?)([?\/]?>)$/s); // Split outer brackets
ib=ob[2].match(/^(.*?)>(.*)<\/(.*)$/s)||['',ob[2],'']; // Split inner brackets
at=ib[1].match(/^--.*--$|=|('|").*?\1|[^\t\n\f \/>"'=]+/g)||['']; // Split attributes
if (ob[1]=='</') is=is.substring(ind.length); // Decrease indent
re+=tb+tc+esc(is)+tz+tc+sm+esc(ob[1])+sz+se+esc(at[0])+sz;
for (i=1;i<at.length;i++) re+=(at[i]=="="?sm+"="+sz+sd+esc(at[++i]):sa+' '+at[i])+sz;
re+=ib[2]?sm+esc('>')+sz+sd+esc(ib[2])+sz+sm+esc('</')+sz+se+ib[3]+sz:'';
re+=sm+esc(ob[3])+sz+tz+tz;
if (ob[1]+ob[3]+ib[2]=='<>') is+=ind; // Increase indent
});
return re;
}
for demo see https://jsfiddle.net/dkb0La16/
I agree with Arjan on utilizing the <pre> tags. I was trying to decipher 'ugly' xml code in my html output before I tried this out about 2 days ago. Makes life much easier and keeps you sane.
This is not the best way to do this but you can get the xml as text and use RegExp to find and replace '>' with tabs according to the depth of the node and breaklines but I don't really know RegExp very well, sorry.
You can also use XSLT and transform it using javascript.
Check this link and take a look at this tutorial.
Use prettydiff.com/markup_beauty.js. This is capable of supporting invalid markup, fragments, and JSTL code.
<c:out value="<strong>text</strong>"/>
You can demo that application using a web tool at prettydiff.com. Just choose the "beautify" and "markup" options.
It is important that you use a proper tool to beautify your XML and not arbitrarily rush the job. Otherwise you will add white space tokens where they were not intended and remove them where they were intended. To raw data this may be consequential, but to human consumable content this destroys the integrity of your code, especially with regard to recursion.

Categories

Resources