Sometimes I see in a view source page ( html view source) this code:
if (JSON.stringify(["\u2028\u2029"]) === '["\u2028\u2029"]') JSON.stringify = function (a) {
var b = /\u2028/g,
c = /\u2029/g;
return function (d, e, f) {
var g = a.call(this, d, e, f);
if (g) {
if (-1 < g.indexOf('\u2028')) g = g.replace(b, '\\u2028');
if (-1 < g.indexOf('\u2029')) g = g.replace(c, '\\u2029');
}
return g;
};
}(JSON.stringify);
What is the problem with JSON.stringify(["\u2028\u2029"]) that it needs to be checked ?
Additional info :
JSON.stringify(["\u2028\u2029"]) value is "["
"]"
'["\u2028\u2029"]' value is also "["
"]"
I thought it might be a security feature. FileFormat.info for 2028 and 2029 have a banner stating
Do not use this character in domain names. Browsers are blacklisting it because of the potential for phishing.
But it turns out that the line and paragraph separators \u2028 and \u2029 respectively are treated as a new line in ES5 JavaScript.
From http://www.thespanner.co.uk/2011/07/25/the-json-specification-is-now-wrong/
\u2028 and \u2029 characters that can break entire JSON feeds since the string will contain a new line and the JavaScript parser will bail out
So you are seeing a patch for JSON.stringify. Also see Node.js JavaScript-stringify
Edit: Yes, modern browsers' built-in JSON object should take care of this correctly. I can't find any links to the actual source to back this up though. The Chromium code search doesn't mention any bugs that would warrant adding this workaround manually. It looks like Firefox 3.5 was the first version to have native JSON support, not entirely bug-free though. IE8 supports it too. So it is likely a now unnecessary patch, assuming browsers have implemented the specification correctly.
After reading both answers , here is the Simple visual explanation :
doing this
alert(JSON.stringify({"a":"sddd\u2028sssss"})) // can cause problems
will alert :
While changing the trouble maker to something else ( for example from \u to \1u)
will alert :
Now , let's invoke the function from my original Q ,
Lets try this alert(JSON.stringify({"a":"sddd\u2028sssss"})) again :
result :
and now , everybody's happy.
\u2028 and \u2029 are invisible Unicode line and paragraph separator characters. Natively JSON.stringify method converts these codes to their symbolic representation (as JavaScript automatically does in the strings), resulting in "["
"]". The code you have provided does not let JSON to convert the codes to symbols and preserves their \uXXXX representation in the output string, i.e. returning "["\u2028\u2029"]".
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.
When I am using jQuery to grab CSS values for objects, each of the browsers (IE, Mozilla, Chrome, etc) returns different values.
For example, in Chrome, a background image (.css("background-image")) returns:
url(http://i41.tinypic.com/f01zsy.jpg)
Where in Mozilla, it returns:
url("http://i41.tinypic.com/f01zsy.jpg")
I am having the same problem on other aspects, such as background-size.
In chrome it returns:
50% 50%
But Mozilla returns:
50%+50%
My problem with this is, I have functions that split the CSS (background-size), for example based on a space .split(" "), but this could not work on Mozilla because it uses a + instead.
Is there any way that I can fix this problem and make the browsers to use one standard?
Is there any function that I could write which grabs and splits values, based on the type of browser the user is using?
My problem with this is, I have functions that split the CSS
(background-size), for example based on a space .split(" "), but this
could not work on Mozilla because it uses a + instead.
Try adding \+ to RegExp passed to .split
.split(/\s|\+/)
var res = ["50%+50%", "50% 50%"];
var re = /\s+|\+/;
console.log(res[0].split(re), res[1].split(re));
Different browsers use different CSS standards and you may have to write a full-blown parser to make them one standard.
Workaround is that you should split or use CSS values taking into account the different browsers standards. Like the CSS(background-size) problem can be solved using this:
space.split("\\s|\\+"); //split my string where it either has a space 'or' a plus sign
For CSS(background-image), the solution may be to replace the inverted commas before using it:
space.replace("\"", "");
Try to make the splits generallized for all browsers. Hope that helps.
This probably isn't the cleanest method, but you could run a string parser for the background image source and delete any quotation marks. This would be the most efficient method for parsing the background image URL. It should work without harming the data because URL's typically can't contain quotation marks, as they are encoded as %22
As for the background-size, you could parse the results for + signs and change those to spaces, as + signs typically aren't present as the values for any CSS properties, so you should be relatively safe in taking those out.
In addition, you could check the browser type to see if you'd even have to run these parsings in the first place. As a precaution, you should also see how Opera and Safari return results, and if those are any different, you could create branch statements for the parsers that handle the different types of CSS values returned by the different browsers.
Note: The parsing methods I have described attempt the goal of converting the Firefox results to the Chrome-style results.
Thanks for all the help.
I'll share the code I have ended up using!
cssCommas: function(text)
{
return text.replace(new RegExp("\"", "g"),"");
},
cssPlus: function(text)
{
return text.replace(new RegExp("\\+", "g"),"");
},
cssSplit: function(text,removePercent)
{
var removeParent = removeParent || false;
if(removePercent == true)
{
text = text.replace(new RegExp("%", "g"),"");
}
return text.split(new RegExp("\\s|\\+","g"));
},
css: function(text)
{
return this.cssCommas(this.cssPlus(text));
}
Works perfectly on all browsers now. Thanks a lot.
I am trying to preserve some XML entities when parsing XML files in javascript. The following code snippet illustrates the problem. Is there a way for me to make round-trip parse and retain the XML entities ( is nbsp; html)? This happens in Chrome FF and IE10.
var aaa='<root><div> one two</div></root>'
var doc=new DOMParser().parseFromString(aaa,'application/xml')
new XMLSerializer().serializeToString(doc)
"<root><div> one two</div></root>"
The issue is I am taking some chunks out of html and storing them in xml, and then I want to get the spaces back in XML when I'm done.
Edit:
As Dan and others have pointed out, the parser replaces it with the ascii code 160, which to my eyes looks like an ordinary space but:
var str1=new XMLSerializer().serializeToString(doc)
str1.charCodeAt(15)
160
So where ever my application is losing the spaces, it is not here.
You can use a ranged RegExp to turn the special chars back into xml representations.
as a nice re-usable function:
function escapeExtended(s){
return s.replace(/([\x80-\xff])/g, function (a, b) {
var c = b.charCodeAt();
return "&#" + b.charCodeAt()+";"
});
}
var aaa='<root><div> one two</div></root>'
var doc=new DOMParser().parseFromString(aaa,'application/xml')
var str= new XMLSerializer().serializeToString(doc);
alert(escapeExtended(str)); // shows: "<root><div> one two</div></root>"
Note that HTML entities (ex quot;) will lose their symbol name, and be converted to XML entities (the &#number; kind). you can't get back the names without a huge conversion table.
I want to format number using javascript as below:
10.00=10,00
1,000.00=1.000,00
Every browser supports Number.prototype.toLocaleString(), a method intended to return a localized string from a number. However, the specification defines it as follows:
Produces a string value that represents the value of the Number formatted according to the conventions of the host environment's current locale. This function is implementation-dependent, and it is permissible, but not encouraged, for it to return the same thing as toString.
Implementation-dependant means that it's up to the vendor how the result will look, and results in interoperability issues.
Internet Explorer (IE 5.5 to IE 9) comes closest to what you want and formats the number in a currency style - thousands separator and fixed at 2 decimal places.
Firefox (2+) formats the number with a thousands separator and decimal places but only if applicable.
Opera, Chrome & Safari output the same as toString() -- no thousands separator, decimal place only if required.
Solution
I came up with the following code (based on an old answer of mine) to try and normalize the results to work like Internet Explorer's method:
(function (old) {
var dec = 0.12 .toLocaleString().charAt(1),
tho = dec === "." ? "," : ".";
if (1000 .toLocaleString() !== "1,000.00") {
Number.prototype.toLocaleString = function () {
var neg = this < 0,
f = this.toFixed(2).slice(+neg);
return (neg ? "-" : "")
+ f.slice(0,-3).replace(/(?=(?!^)(?:\d{3})+(?!\d))/g, tho)
+ dec + f.slice(-2);
}
}
})(Number.prototype.toLocaleString);
This will use the browser's built-in localization if it's available, whilst gracefully degrading to the browser's default locale in other cases.
Working demo: http://jsfiddle.net/R4DKn/49/
I know this solution using NumberFormat but it is necessary to convert the values to string.
https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/NumberFormat
// Remove commas
number = "10,000.00".replace(/,/g, '');
// Create a NumberFormat type object
var formatter = new Intl.NumberFormat('de-DE', {
minimumFractionDigits: 2
});
// Apply format
console.log(formatter.format(number));
output:10.000,00
Javascript doesn't provide this functionality itself, but there are a number of third-party functions around which can do what you want.
Note, whichever method you use, you should be careful to only use the resulting string for display purposes -- it won't be a valid number value in Javascript after you've converted the decimal point to a comma.
The quickest solution I can offer is to use the number_format() function written by the phpJS people. They've implemented Javascript versions of a load of commonly-used PHP functions, including number_format(), and this function will do exactly what you want.
See the link here: http://phpjs.org/functions/number_format
I wouldn't bother about taking the whole phpJS library (a lot of it is of questionable value anyway), but just grab the 20-odd line function shown on the page linked above and paste it into your app.
If you want a more flexible solution, there are a number of JS functions around which simulate the printf() function from C. There is already a good question on SO covers this. See here: JavaScript equivalent to printf/string.format
Hope that helps.
I noticed that the jQuery parseJSON basically does a simple regex "check":
parseJSON: function( data ) {
if ( typeof data !== "string" || !data ) {
return null;
}
// Make sure leading/trailing whitespace is removed (IE can't handle it)
data = jQuery.trim( data );
// Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "#")
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
.replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) {
// Try to use the native JSON parser first
return window.JSON && window.JSON.parse ?
window.JSON.parse( data ) :
(new Function("return " + data))();
} else {
jQuery.error( "Invalid JSON: " + data );
}
},
If it passes that "check" and if it's a modern browser a native JSON parser is used. Otherwise, I assume for a browser like IE6 a new function is automatically invoked and returns the object.
Question #1: Since this is just a simple regex test, isn't this prone to some sort of obscure edge-case exploit? Shouldn't we really be using a full blown parser, for the browsers that don't support native JSON parsing at least?
Question #2: How much "safer" is (new Function(" return " + data ))() as opposed to eval("(" + text + ")")?
As mentioned in the comments there jQuery's JSON parser "borrows" the logic that tests to see if the JSON string is valid, right from json2.js. This makes it "as safe" as the most common non-native implementation, which is rather strict anyway:
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '#' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '#').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
What I don't understand is why jQuery runs the regular expression/replaces before checking for a native implementation which would check for correct JSON grammar anyway. It seems like it would speed things up to only do this if a native implementation isn't available.
Question 2 is answered very well by bobince in another question:
It's not really a big difference, but the feeling is that eval is ‘worse’ than new Function. Not in terms of security — they're both equally useless in the face of untrusted input, but then hopefully your webapp is not returning untrusted JSON strings — but in terms of language-level weirdness, and hence resistance to optimisation.
Check out Nick Craver's answer there too for a direct quote from John Resig.
The JSON.parse method is the safest. This is defined when you include json2.js from http://www.json.org/js.html and used automatically by parseJSON/getJSON. It parses instead of executing the JSON markup.