I am working in Classic ASP. The code I'm working with (not my code) was written a very long time ago, perhaps even long before Firefox and Chrome existed.
Anyways, there is the following JavaScript function:
function MM_jumpMenu(targ, selObj, restore) {
eval(targ + ".location ='" + selObj.options[selObj.selectedIndex].getAttribute('value') + "'");
if (restore)
{
selObj.selectedIndex=0;
}
}
That code has all of a sudden stopped working, and I'm trying to figure out why. In Chrome it is giving me the error:
SyntaxError: Unexpected identifier
When I try and run the code, the parameters passed in are as follows:
targ = "parent"
value on selected index of selObj = "edit_details.asp?make=ML&n=&r=DA61CHH&c=Hope Ready Mixed Concrete Ltd - CHY LCV's&cus=HOPEAG02&type=&inc=&id=&fw=&cusid=HOPE03"
restore = 0
Assume code was written solely for IE 6/7 and we're trying to standardise and make it work for all browsers.
eval is evil!! Don't use it!
window[targ].location = selObj.options[selObj.selectedIndex].getAttribute('value');
You have an unescaped single quote in your url.
CHY LCV's&
Espace this:
CHY LCV\'s&
But really, this code is horrible, you should rewrite it if you can.
"value on selected index of selObj " : it has an apostrophe. You'll need to escape that.
Related
I am implementing jQuery chaining - using Mika Tuupola's Chained plugin - in my rails project (using nested form_for partials) and need to dynamically change the chaining attribute:
The code that works without substitution:
$(".employee_title_2").remoteChained({
parents : ".employee_title_1",
url : "titles/employee_title_2",
loading : "Loading...",
clear : true
});
The attributes being substituted are .employee_title_1 and .employee_title_2:
var t2 = new Date().getTime();
var A1 = ".employee_title_1A_" + t2;
var B2 = ".employee_title_2B_" + t2;
In ruby speak, I'm namespacing the variables by adding datetime.
Here's the code I'm using for on-the-fly substitution:
$(`"${B2}"`).remoteChained({
parents : `"${A1}"`,
url : "titles/employee_title_2",
loading : "Loading...",
clear : true
});
Which throws this error:
Uncaught Error: Syntax error, unrecognized expression:
".employee_title_2B_1462463848339"
The issue appears to be the leading '.' How do I escape it, assuming that's the issue? Researching the error message Syntax error, unrecognized expression lead to SO question #14347611 - which suggests "a string is only considered to be HTML if it starts with a less-than ('<) character" Unfortunately, I don't understand how to implement the solution. My javascript skills are weak!
Incidentally, while new Date().getTime(); isn't in date format, it works for my purpose, i.e., it increments as new nested form fields are added to the page
Thanks in advance for your assistance.
$(`"${B2b}"`).remoteChained({
// ^ ^
// These quotes should not be here
As it is evaluated to a string containing something like:
".my_class"
and to tie it together:
$('".my_class"')...
Same goes for the other place you use backtick notation. In your case you could simply use:
$(B2).remoteChained({
parents : A1,
url : "titles/employee_title_2",
loading : "Loading...",
clear : true
});
The back tick (``) syntax is new for Javascript, and provides a templating feature, similar to the way that Ruby provides interpolated strings. For instance, this Javascript code:
var who = "men";
var what = "country";
var famous_quote = `Now is the time for all good ${who} to come to the aid of their #{what}`;
is interpolated in exactly the same way as this Ruby code:
who = "men"
what = "country"
famous_quote = "Now is the time for all good #{who} to come to the aid of their #{what}"
In both cases, the quote ends up reading, "Now is the time for all good men to come to the aid of their country". Similar feature, slightly different syntax.
Moving on to jQuery selectors, you have some flexibility in how you specify them. For instance, this code:
$(".my_class").show();
is functionally equivalent to this code:
var my_class_name = ".my_class";
$(my_class_name).show();
This is a great thing, because that means that you can store the name of jQuery selectors in variables and use them instead of requiring string literals. You can also build them from components, as you will find in this example:
var mine_or_yours = (user_selection == "me") ? "my" : "your";
var my_class_name = "." + mine_or_yours + "_class";
$(my_class_name).show();
This is essentially the behavior that you're trying to get working. Using the two features together (interpolation and dynamic jQuery selectors), you have this:
$(`"${B2}"`).remote_chained(...);
which produces this code through string interpolation:
$("\".employee_title_2B_1462463848339\"").remote_chained(...);
which is not correct. and is actually the cause of the error message from jQuery, because of the embedded double quotes in the value of the string. jQuery is specifically complaining about the extra double quotes surrounding the value that you're passing to the selector.
What you actually want is the equivalent of this:
$(".employee_title_2B_1462463848339").remote_chained(...);
which could either be written this way:
$(`${B2}`).remote_chained(...);
or, much more simply and portably, like so:
$(B2).remote_chained(...);
Try this little sample code to prove the equivalence it to yourself:
if (`${B2}` == B2) {
alert("The world continues to spin on its axis...");
} else if (`"${B2}"` == B2) {
alert("Lucy, you've got some 'splain' to do!");
} else {
alert("Well, back to the drawing board...");
}
So, we've established the equivalency of interpolation to the original strings. We've also established the equivalency of literal jQuery selectors to dynamic selectors. Now, it's time to put the techniques together in the original code context.
Try this instead of the interpolation version:
$(B2).remoteChained({
parents : A1,
url : "titles/employee_title_2",
loading : "Loading...",
clear : true
});
We already know that $(B2) is a perfectly acceptable dynamic jQuery selector, so that works. The value passed to the parents key in the remoteChained hash simply requires a string, and A1 already fits the bill, so there's no need to introduce interpolation in that case, either.
Realistically, nothing about this issue is related to Chained; it just happens to be included in the statement that's failing. So, that means that you can easily isolate the failing code (building and using the jQuery selectors), which makes it far easier to debug.
Note that the Javascript syntax was codified just last year with ECMAScript version 6, so the support for it is still a mixed bag. Check your browser support to make sure that you can use it reliably.
Does anyone know of a way to eval a string so that if it (or a function it defines) generates an error, the line and column numbers shown in the stack trace will be offset by an amount specified in advance?
Alternatively, suppose I want to break up a long source string into chunks and evaluate them separately, but still get stack traces that look as though the entire string was evaluated in one go. Is there any way to achieve this effect, except for using empty lines and columns? (I need a browser-based solution, preferably cross-browser, but I can settle for something that works on at least one of the major browsers.)
I don't think is it possible because the underlying mechanism that is assumed working is actually deprecated. For security reasons browsers don't pass the error object to Javascript anymore.
However, since you are working with a custom programming language that gets compiled into Javascript, you know what the structure of the resulting script will be. You could also introduce statement counters in the resulting Javascript, so you can always know what the last thing executed was. Something like:
function(1); function(2);
function(3);
could be translated as:
var __column=0;
var __line=0;
function(1); __column+=12;
function(2); /*__column+=12;*/ __line++; __column=0;
function(3); /*__column+=12;*/ __line++; __column=0;
Where 12 is "function(n);".length.Of course, the resulting code is ugly, but you could enable this behaviour with a debug flag or something.
The best solution I've found so far is to prepend a sourceURL directive to each string before it's eval'ed, giving it a marker in the form of a unique file name in the stack trace. Stack traces are then parsed (using the parser component stacktracejs) and corrected by looking up the line offsets associated with the markers.
var evalCounter = 0;
var lineCounter = 0;
var lineOffsetTable = {};
function myEval(code) {
lineOffsetTable[evalCounter] = lineCounter;
lineCounter += countLines(code);
return eval("//# sourceURL=" + (evalCounter++) + "\n" + code);
}
window.onerror = function(errorMsg, url, lineNumber, column, e) {
var stackFrames = ErrorStackParser.parse(e);
logStackTrace(stackFrames.map(function(f) {
if(f.fileName in lineOffsetTable)
f.lineNumber += lineOffsetTable[f.fileName];
return f;
}));
};
Unfortunately, this only works in Firefox at the moment. Chrome refuses to pass the error object to the onerror callback (a problem which only happens with eval'ed code, strangely enough) and IE ignores the sourceURL directive.
Over 1 hour on this. This is javascript code inside my index.php file.
function dostuff()
{
var thepath = document.location.search.substring(1);
alert('the path is ' + thepath + " (that's the full path)");
alert(thepath);
// TRIED THESE ALL -- NONE OF THEM WORK.
//var pathLen = String.length("thepath");
//var pathLen = String.length(thepath);
//var pathLen = thepath.length();
var pathLen = String.length(document.location.search.substring(1));
alert('pathLen is ' + pathLen);
}
The symptom: the first 2 alert boxes appear no problem and both show 'thepath' has a valid pathname in it, and it is the correct, expected path too.
But no matter what I try -- see the 4 different attempts, tried one at a time -- the final alert() box NEVER shows up.
Why is alert('pathLen is ' + pathLen) not showing up?
(The other thing is -- I'm using XDEBUG and xampp and Netbeans and the debugger will not let me put a breakpoint in this javascript code, so I can't even step into it to see what's happening, hence the use of the alert()'s in the code. I know the XDEBUG debugger I'm using in Netbeans works -- I've been using it all night to debug PHP code in a different.PHP file. When I set a breakpoint though in any Javascript code, a 'broken breakpoint' icon appears and I cannot find what that means in Netbeans documentation.)
I've never seen that syntax before. You might want to try:
var pathLen = thepath.length;
(You'd be best off debugging with Firebug)
var pathLen = thepath.length;
Length is a property of the string, not a function, so no need for the ().
The length is a property of your string rather than a method.
You should be able to access it via the following:
var pathLen = thepath.length;
When you say the alert box never shows up do you mean it never appears at all? If you're using FF you can open the error console from the Tools menu and clear it then refresh your page. It should highlight any JS errors you have in your code. That's the only reason I know of that the alert wouldn't show at all. (I don't think there is a class method for String.length() which is probably where the error is coming from.)
As for XDebug, as far as I know it's a PHP debugger only I don't think it can debug JS.
pathLen.length
No (). length is a property; if you add the (), it tries to use the value of the property as a function to call, resulting in an exception.
For some reason, I am getting the following Javascript error in Internet Explorer 8 on line 3156 of jquery.js (version 1.4.3, non-compressed version): Object doesn't support this property or method. No error occurs in Firefox and Google Chrome.
This is the line the error occurs on:
if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
Investigation (console.log(Expr.leftMatch[type])) produces the following interesting result: In Google Chrome, it outputs
/(^(?:.|\r|\n)*?):((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\3\))?(?![^\[]*\])(?![^\(]*\))/
However in Internet Explorer this is the output:
function() {
var p = this;
do p = p.previousSibling;
while (p && p.nodeType != 1);
return p;
}
On which exec cannot be called (it is undefined). The quoted function is not present within jquery.js. Does anyone have any clue why this happens, or what I can do to solve it?
I have, unfortunately, not yet been able to create a simple script to reproduce the problem, although I did find this post of someone having the same problem, but it does not offer a solution (the last post suggests the page should be run in Standards Mode, but mine already is).
As it turns out, I managed to figure it out by myself after several painful hours. It appears the Sizzle selector engine breaks in this unexpected way (and only in Internet Explorer), if you have defined Object.prototype.previousObject elsewhere.
Removing that declaration, or renaming previousObject to something else fixes the problem.
The funny thing is, I even put that code there myself (the Object.prototype.previousObject = [the function in my question]), but I did not recognize the code.
Well, that's another day full of development potential wasted.
I have discovered the same behaviour occurs if you attempt to add a method called "inherited" to the Object.prototype, ie Object.prototype.inherited = <some func>
It affects IE6, 7 & 8 but seems to be fixed in IE9 (beta)
May be to late to respond but I had the same problem and solved with selecting elements with plain java script rather then jquery!
var div = document.getElementById("myDiv");
var rect = div.getBoundingClientRect();
This works some how!
I have the following
var id='123';
newDiv.innerHTML = "";
Which renders in my HTML.
The problem I have is that I wish to take the call to the method TestFunction, and use as a string parameter in my function StepTwo(string, boolean), which would ideally end up in live HTML as shown...
notice how the TestFunction is a string here (it is executed within StepTwo using eval).
I have tried to format my JS as by :
newDiv.innerHTML = "";
but while this appears to me correct in my IDE, in the rendered HTML, it as garbelled beyond belief.
Would appreciate if anyone could point me in the right direction. Thanks!
One of the biggest capital failures on the internet is creating html in javascript by gluing strings together.
var mya = document.createElement("a");
mya.href="#";
mya.onclick = function(){
StepTwo(function(){
TestFunction('123', false );
}, true );
};
newDiv.innerHTML = "";
newDiv.appendChild(mya);
This Eliminates the need for any fancy escaping stuff.
( I probably should do 'onclick' differently, but this should work, I'm trying hard not to just use jQuery code to do everything )
Heres how I would do it in jQuery:
jQuery(function($){
var container = $("#container");
var link = document.createElement("a"); /* faster than $("<a></a>"); */
$(link).attr("href", "Something ( or # )" );
$(link).click( function(){
var doStepTwo = function()
{
TestFunction('123', true );
};
StepTwo( doStepTwo, false ); /* StepTwo -> doStepTwo -> TestFunction() */
});
container.append(link);
});
There is no good excuse for gluing strings together in Javascript
All it does is ADD overhead of html parsing back into dom structures, and ADD potential for XSS based broken HTML. Even beloved google get this wrong in some of their advertising scripts and have caused epic failures in many cases I have seen ( and they don't want to know about it )
I don't understand Javascript is the only excuse, and it's NOT a good one.
Try using " instead of \"
newDiv.innerHTML = "<a href="#"...
You should be using " not " or \" inside an HTML string quoted with double-quotes.
NewDiv.innerHTML = "";
There's probably a better way to do this - any time you find yourself using eval() you should stand back and look for a different solution.
You claim that eval is the right thing to do here. I'm not so sure.
Have you considered this approach:
and in your StepTwo function
function StepTwo(func,args,flag){
//do what ever you do with the flag
//instead of eval use the function.apply to call the function.
func.apply(args);
}
You could create the a element and attach to the click event using DOM Methods.
A Javascript Framework (like the ubiquitous jQuery) would make this a lot easier.
Your biggest problem is using eval, it leads to so many potential problems that it's nearly always better to find an alternative solution.
Your immediate problem is that what you really have is
as the next " after the start of the onclick attribute, closes it. Use " as others have suggested. And don't use eval.
You need to alternate your " and '.
Maybe you don't need quotes around the 123, because of Javascripts flexible typing. Pass it without quotes but treat it as a string within TestFunction.
Hey guys, thanks for all the answers. I find that the quot; seems to work best.
I'll give you guys some votes up once I get more reputation!
In regards to eval(), what you see in the question is a very small snapshot of the application being developed. I understand the woes of eval, however, this is one of those one in a million situations where it's the correct choice for the situation at hand.
It would be understood better if you could see what these functions do (have given them very generic names for stackoverflow).
Thanks again!
The best way is to create the element with document.createElement, but if you're not willing to, I guess you could do or use ".
In your code:
newDiv.innerHTML = "";
If it doesn't work, try changing "\'" to "\\'".
Remember that the " character is used to open and close the attribute on HTML tags. If you use it in the attribute's value, the browser will understand it as the close char.
Example:
<input type="text" value="foo"bar"> will end up being <input type="text" value="foo">.
...
I know this is hella' old now, but if anyone has issues with escaped strings when using eval (and you absolutely have to use eval), I've got a way to avoid problems.
var html = '';
eval('(function(div, html){div.innerHTML = html;})')(newDiv, html);
So, what's going on here?
eval creates a function that contains two parameters, div and html and returns it.
The function is immediately run with the parameters to the right of the eval function. This is basically like an IIFE.
In this case
var myNewMethod = eval('(function(div, html){div.innerHTML = html;})');
is basically the same as:
var myNewMethod = function(div, html){div.innerHTML = html;}
and then we're just doing this:
myNewMethod(newDiv, html); //where html had the string containing markup
I would suggest not using eval. If it can't be avoided, or if you control all the inputs and there's no risk of injection then this will help in cases where string escapes are an issue.
I also tend to use Function, but it isn't any more secure.
Here's the snippet I use:
var feval = function(code) {
return (new Function(code))();
}