eval javascript function IE6 taking long time - javascript

I have the below chunk of code. I've debugged through and located the snippet that is causing a long delay in IE6.
Basically the code loops through a document converting it to XML and sending to a PDF. On Ubuntu and Firefox 4 it takes 3 seconds. On IE it can take up to 40 seconds regularly.
/**
* This function builds up the XML to be saved to the DM.
*/
function getXMLToSave(){
var text="<workbook><sheet><name>Adv4New</name>";
//show_props(document.adv4.row10col1, "document.adv4.row10col1");
for(i=1;i<157;i++){
text = text + "<row number='" + i + "'>";
for(j=1;j<=7;j++){
text = text + "<col ";
//alert(eval('document.adv4.row'+i+'col'+j+'.readonly'));
try{
text = text + "number='" + j + "' label='" + eval('document.adv4.row'+i+'col'+j+'.className')+ "'";
}
catch (e) {
text = text + "number='" + j + "' label=''";
}
try {
if(eval('document.adv4.row'+i+'col'+j).readOnly)
text = text + " type='readonly'";
else
text = text + " type=''";
}
catch (e) {
text = text + " type=''";
}
try {
text = text + " color='" + eval('document.adv4.row'+i+'col'+j+'.style.color') + "'";
}
catch (e) {
text = text + " color=''";
}
text = text + ">";
try {
// don't wrap in a CDATA (like previously), but run cleanNode
// this fixes html entities
var content = eval('document.adv4.row'+i+'col'+j+'.value');
text = text + cleanNode(content);
}
catch (e) {
text = text + "0";
}
text = text + "</col>";
}
text = text + "</row>";
}
text = text + "</sheet></workbook>";
return text;
}
I believe its the eval function causing the delay in IE6. Is there a neat solution to fix this. Thanks very much

Why are you using eval in the firts place?
eval('document.adv4.row'+i+'col'+j+'.style.color')
Use bracket notation!
document.adv4["row"+i+"col"+j].style.color

You don't need eval() at all:
text = text + "number='" + j + "' label='" + document.adv4['row' + i + 'col' + j].className + "'";
Also, in IE6 (but not in newer browsers), building up large strings by repeatedly adding more content is really, really slow. It was way faster in that browser to build up strings by creating an array of substrings and then joining them all together when finished with all the pieces.

Don't use eval EVAL is EVIL. Having said that, you really shouldn't care about IE6: Even MS doesn't support it any longer, why should you bother?
Anyhow, change all eval calls like:
eval('document.adv4.row'+i+'col'+j+'.value');
to
document.adv4['row' + i + 'col' + j].value;
To access the elements directly. Remember that Nodes are objects, so their properties can be accessed either using the dot-notation (foo.bar) or the "associative array" notation: foo['bar'], the latter being very useful when you need the value of a variable to access properties

Don't use eval - period. The eval() should be renamed to evil(). There is almost no situation where you really need to use the eval function.
In this case you can use document.getElementById() to find a DOM node with a specific id.

It's likely that it's all the string concatentation that makes it slow. Each time you add something to the text, it will copy all the previous text into a new string.
Newer browsers have optimised code for this special case, so for them the impact is less.
Instead of concatenating strings like this:
text = text + "something";
use an array instead:
var text = [];
then add items to the array using the push method:
text.push("<workbook><sheet><name>Adv4New</name>");
Finally just join the strings together:
return text.join('');

One solution could be generating a color array (or maybe an object if you need it) and then using it.
But then, ask yourself the question "Should I really support IE6?"

Related

How to fiil paragraph with content?

I want to create a paragraph that contains: name, cost (like "3.66$"). But the problem is that I want to fill the space in dots ("......") and I dont know how.
I take the values (name & cost) from database and each name is diffrent so I can not think about way that makes the space be filled with dots.
For instance, the rows:
"apple 20.58$"
"banana and ice cream 4.99$"
need to be:
"apple ...................... 20.58$"
"banana and ice cream ........ 4.99$"
this is the code:
for (var i = 0; i < data.d.length; i++) {
$(document).ready(function () {
$("#ShowMenu").append(
"<p style='text-align: left;margin: 0px;'>" +
"<span style='font-size: large;font-weight: bold;float:left;'>" + data.d[i].title + "</span>" +
"<span style='float:right;'>" + data.d[i].cost + "</span>" +
"</p>"
);
});
}
If you are replacing a value (and not a regular expression), only the
first instance of the value will be replaced. To replace all
occurrences of a specified value, use the global (g) modifier (see
"More Examples" below).
Souce.
The problem is that replace replaces the first found occurrence. You can do it like this:
function replaceAll(input, what, withWhat) {
while (input.indexOf(what) !== 0) {
input = input.replace(what, withWhat);
}
return input;
}
But this is not performant and not elegant. To improve it, you need to use regular expressions:
function replaceAll(input, what, withWhat) {
return input.replace(new RegExp(what, 'g'), withWhat);
}
and call replaceAll. If you want this to make it more general, you can do something like this:
String.prototype.replaceAll = replaceAll;
EDIT:
The answer above came from the assumption that the text is generated by Javascript. My assumption was wrong as can be seen from the comment section and the question edit. The real situation is that the spaces appear because of CSS styling with float.
A possible solution is to create an image of a dot character and another image with the desired background for the other contents. Set the background image of the paragraph to be the dot image with repeat and the background image of the span to be the colored image.
Another possible solution is not to use float, but to write the dots using javascript until the width is the desired one. This involves tag measuring and is slow.
You can use function like this:
function getReceiptItem(name, cost, maxLength) {
var dotsLength = maxLength - name.length - cost.length - '$'.length;
if (dotsLength < 0) {
name = name.substring(0, name.length + dotsLength);
dotsLength = 0;
}
return name + Array(dotsLength).join('.') + cost + '$';
}
Full example
Don`t forget set monospace font for receipt, like:
* {
font-family: 'monospace';
}

regexp looping and logic in javascript

Not certain if this can be done in regexp under javascript, but thought it would be interesting to see if it is possible.
So thought I would clean up a piece of html to remove most tags, literally just dropping them, so <H1><img><a href ....>. And that would be relatively simple (well, stole the basis from another post, thanks karim79 Remove HTML Tags in Javascript with Regex).
function(inString, maxlength, callback){
console.log("Sting is " + inString)
console.log("Its " + inString.length)
var regex = /(<([^>]+)>)/ig
var outString = inString.replace(regex, "");
console.log("No HTML sting " + outString);
if ( outString.length < maxlength){
callback(outString)
} else {
console.log("Lets cut first bit")
}
}
But then I started thinking, is there a way where I can control regex execution. So lets say that I want to keep certain tabs, like b,br,i and maybe change H1-6 to b. So in pseudo code, something like:
for ( var i in inString.regex.hits ) {
if ( hits[i] == H1 ) {
hits[i] = b;
}
}
The issue is that I want the text thats not HTML tags to stay as it is, and I want it to just cut out by default. One option would of course be to change the ones I want to keep. Say change <b> to [[b]], once that is done to all the ones of interest. Then put them back to <b> once all unknown have been removed. So like this (only for b, and not certain the code below would work):
function(inString, maxlength, callback){
console.log("Sting is " + inString)
console.log("Its " + inString.length)
var regex-remHTML = /(<([^>]+)>)/ig
var regex-hideB = /(<b>)/ig
var regex-showB = /([b])/ig
var outString = inString.replace(regex-hideB, "[b]");
outString = outString.replace(regex-remHTML, "");
outString = outString.replace(regex-showB, "<b>");
console.log("No HTML sting " + outString);
if ( outString.length < maxlength){
callback(outString)
} else {
console.log("Lets cut first bit")
}
}
But would it be possible to be smarter, writing cod ethat says here is a peice of HTML tag, run this code against the match.
As Tim Biegeleisen sai in its comment, maybe a better solution could be using a parser instead of a Regex...
By the way, if you want to control what is going to be changed by the regex you can pass a callback to the String.prototype.replace:
var input = "<div><h1>CIAO Bello</h1></div>";
var output = input.replace(/(<([^>]+)>)/gi, (val) => {
if(val.indexOf("div") > -1) {
return "";
}
return val;
})
;
console.log("output", output);

JQuery get 'id' attribute

So I have the following code that generates a table and applies a click function to each td within the table. It also applies an incremental id starting with 1. When the user clicks on a td element I'm trying to retrieve the id of the <td> they clicked on. However the value of selector is [object Window]. I'm sure it is something simple but I none of the similar questions on here have helped, and I'm not seeing it.
$("#CMGame").click(function() {
$("#TTTContent").hide();
$("#CMContent").show();
var board = $("#CMBoard");
var htmlString = "";
var count = 0;
for (var i = 0; i < 20; i++) {
htmlString += "<tr>";
for (var i2 = 0; i2 < 20; i2++) {
count++;
htmlString += "<td id='" + toString(count) + "'></td>";
}
htmlString += "</tr>";
}
board.html(htmlString);
$("#CMBoard td").click(function() {
var piece = $(this);
var selector = piece.attr('id');
alert(selector);
/*
if (CMBArray[selector] != 1 OR CMBArray[selector] != 2) {
CMBArray[selector] = 1;
piece.addClass('selected');
}
*/
});
});
There are 2 errors in your code, the td id you create can't be just a number, it has to start with a letter and then you can either remove toString(count) and use only count or change it to count.toString(), which is the correct way.
Here is the specs. for a DOM id:
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id
And here for toString():
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString
The toString is wrong in the code. Change
toString(count)
to
count.toLocaleString()
toString(count) is effectively like saying this.toString() which, in your case basically means window.toString(), which results in [object Window].
Instead, use count.toString().
Here's a quick test:
var count = 0;
console.log('second toString: ' + toString(count) );
console.log('second toString: ' + count.toString );
Bear in mind that, whenever you concatonate strings in Javascript, the toString method is called on all objects by default. For example, these two expressions yield the same output:
var number = 5;
console.log( 'The number is ' + number.toString() );
console.log( 'The number is ' + number );
The toString method you are calling is actually window.toString.
By not specifying a parent object for toString, you are invoking the method on the global window object. That is why you see "[object Window]", it is returning a string representation of the invoking object.
You don't need the toString at all. Javascript cast numberics to a string when you add it to a string.
this.id will return the id of the a jQuery element. E.g.:
$("td").click(function(){
alert(this.id);
});
Your problem is in the event $("#CMGame").click(function()
when try to convert to string with toString(count) javascript and jquery don't understand that they do understand count.toString() here is the source javaScript toString function.
Suggestion about some code you have:
first this one var board = $("#CMBoard"); you pass the html element to a javascript variable for you can do this board.html(htmlString); i think you do that so your function can be more faster than using other method to manipulate the DOM but in this case it look that we are not looking for best performances so other option is keep it simple with this $("#CMBoard").append(htmlString)
The id you set to each element is a number that is not a good practice at all and also there is a suggestion for compatibility for HTML5 to HTML4 look;
Note: Using characters except ASCII letters and digits, '_', '-' and '.' may cause compatibility problems, as they weren't allowed in HTML 4. Though this restriction has been lifted in HTML 5, an ID should start with a letter for compatibility. you can find this in global attribute id so is better to set a real id name you can do something like this in your code htmlString += "<td id='item_" + count.toString() + "'></td>";
so the id will come out like id="item_1"

Help on eval() function

I need help on this eval() problem:
var ScoreFuncName = 'scoreCondition_' + criteriaName;
var allCheckBox = $('div#'+SubListId).find("input:image[name^='" + ChkBoxPrefix + "'][value='1']");
eval(ScoreFuncName + '(' + allCheckBox.length + ')');
The eval() function is evaluating which checkbox is ticked and will do other things accordingly, it worked great in Firefox but not in google Chrome and IE.
Scratching my head for 3 days on how to fix this. Thank you.
You should not be using eval for that.
If the function is in global scope. All you need to do is
window[ScoreFuncName](allCheckBox.length);
It would be better to name space it instead of using a global with window
Eval is not needed to do this. Also take notice that I am calling size on the jQuery object rather than length.
var scoreFunc = this['scoreCondition_' + criteriaName];
var allCheckBox =
$('div#'+SubListId).find("input:image[name^='" + ChkBoxPrefix + "'][value='1']");
scoreFunc(allCheckBox.size());
Hm... don't.
There realistically is not a need to use eval in this condition (and I would say that there is no need for a string look-up of the function). Since it looks clear that you have a finite and knowable number of conditions and a finite and knowable number of functions, then you can simply use a switch to actually select a function dynamically:
var toRun; // variable to store the function.
switch(criteriaName)
{
case "criteria1":
// keep the actual function in the variable, not some string.
toRun = function(e){console.log("I is so special! " + e)}
break;
case "criteria2":
toRun = function(e){console.log( e + " is not a squid!" )}
break;
}
var allCheckBox = $('div#'+SubListId).find("input:image[name^='" +
ChkBoxPrefix + "'][value='1']");
// then just call it!
toRun(allCheckBox.length)

How can I get IE to recognize NBSP as NBSP instead of a space?

For the following JavaScript:
function EscapedString(str) {
var obj = document.createElement("span");
obj.innerHTML = str;
return "&#" + (obj.textContent || obj.innerText).charCodeAt(0) + ";";
}
alert(EscapedString(" "));
alert(EscapedString(" "));
alert(EscapedString("\xA0"));
IE returns for each value instead of   like every other browser correctly does. Is .innerText the wrong property for IE?
Here's it running on jsbin.
Ah, I can access the value of the text node created by the innerHTML and that returns the correct value:
function EscapedString(str) {
var obj = document.createElement("div");
obj.innerHTML = str;
return "&#" + (obj.firstChild.nodeValue || obj.textContent).charCodeAt(0) + ";";
}
Here's the latest script running on jsbin
...and here's the gist of the final code I ended up using
Try this out. Split up the '&' character from 'nbsp'
alert('&' + 'nbsp');
That worked for me. are you able to do that?
if not, perhaps you can convert to ascii???
edited
alert(String.fromCharCode(EscapedString(" ")))

Categories

Resources