CSS - returning different values from different browsers - javascript

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.

Related

Javascript - How to find specific string using .indexOf instead of just the beginning

I'm trying to run some code if a string is found in the users URL. However I only want it to run if there is nothing else following the string. The string appears at the end of the URL like this.
http://shop.com/?searchTerm=bread
My code:
if (window.location.search.indexOf('searchTerm=bread') > -1) {
do stuff;
}
This works fine but the problem is it will still run if the string is 'searchTerm=bread+rolls' I don't want this to happen. Any ideas?
I should also mention there is a bunch of other parameters in the URL that change, but the one I'm trying to target is always at the end. I'm also unable to use any libraries.
http://shop.com/?p=kjsl&g=sdmjkl&searchTerm=bread
You may use the following example:
var url = window.location.search;
if (/searchTerm=bread$/.test(url)) {
do stuff;
}
else if (/searchTerm=cheese\+slices$/.test(url)) {
do stuff;
}
$ represent end of line.
\ backslash is use to escape the special character like +
Hope this help :)
You want String.prototype.endsWith. See MDN docs. That page also provides a polyfill. For availability, see caniuse.
However, in Chrome 41 this native implementation is 25% slower than the fastest alternative, which uses slice:
function endsWithSlice(string1, string2) {
return string1.slice(-string2.length) === string2;
}
The regexp solution presented in another answer is 50% slower. The MDN polyfill is 38% slower, but still faster than regexp. See jsperf.

JSON.stringify and "\u2028\u2029" check?

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"]".

Isn't the jQuery text() function cross browser?

I want to get the text that contains the element inside a td. Even not knowing what's inside this td using the jQuery mytd.text() returns the text successfully in IE8.
However I noticed that this function text() may be not cross browser since it returns me diferent values in Chrome and FF than in IE8. In both Chrome and FF the string result is much longer than in IE8. It's preceded and appended with empty values " "
As of I have a variable mytd that has the td object how could I retrieve the text that contains in a cross browser manner?
// Does not work
var text = mytd.text()
thank you.
It is cross-browser, but different browsers handle white space in text node differently, and jQuery doesn't abstract that.
It does provide the $.trim method to help you out though.
To strip the white space when you retrieve the text, just do this:
var text = mytd.text().trim();
... this assumes mytd refers to an existing jQuery variable of course. You could do this:
var text = $('.mytd').text().trim();
EDIT:
Sorry, I tested that in Safari which implements the native String.trim() method; to have it work in all browsers you should do this:
var text = $.trim( mytd.text() );
You can use jQuery.trim(str) that removes empty spaces from the start/end of a string.
Eventually, you don't even need jQuery to trim a string, since all strings share a trim method on String.prototype.

XPath queries in IE use zero-based indexes but the W3C spec is one-based. How should I handle the difference?

The Problem
I am converting a relatively large piece of Javascript that currently only works on Internet Explorer in order to make it work on the other browsers as well. Since the code uses XPath extensively we made a little compatibility function to make things easier
function selectNodes(xmlDoc, xpath){
if('selectNodes' in xmlDoc){
//use IE logic
}else{
//use W3C's document.evaluate
}
}
This is mostly working fine but we just came across the limitation that positions in IE are zero-based but in the W3C model used by the other browsers they are one-based. This means that to get the first element we need to do //books[0] in IE and //books[1] in the other browsers.
My proposed solution
The first thought was using a regex to add one to all indexes that appear in the queries if we are using the document.evaluate version:
function addOne(n){ return 1 + parseInt(nStr, 10); }
xpath = xpath.replace(
/\[\s*(\d+)\s*\]/g,
function(_, nStr){ return '[' + addOne(nStr) + ']'; }
);
My question
Is this regex based solution reasonably safe?
Are there any places it will convert something it should not?
Are there any places where it will not convert something it should?
For example, it would fail to replace the index in //books[position()=1] but since IE doesn't appear to support position() and our code is not using that I think this particular case would not be a problem.
Considerations
I downloaded Sarissa to see if they have a way to solve this but after looking at the source code apparently they don't?
I want to add one to the W3C version instead of subtracting one in the IE version to ease my conversion effort.
In the end
We decided to rewrite the code to use proper XPath in IE too by setting the selection language
xmlDoc.setProperty("SelectionLanguage", "XPath");
we just came across the limitation that positions in IE are zero-based
but in the W3C model used by the other browsers they are one-based.
This means that to get the first element we need to do //books[0] in
IE and //books[1] in the other browsers.
Before doing any XPath selection, specify:
xmlDoc.setProperty("SelectionLanguage", "XPath");
MSXML3 uses a dialect of XSLT/XPath that was in use before XSLT and XPath became W3C Recommendations. The default is "XSLPattern" and this is what you see as behavior.
Read more on this topic here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms754679(v=vs.85).aspx
Why not modify the original expressions, so that this:
var expr = "books[1]";
...becomes:
var expr = "books[" + index(1) + "]";
...where index is defined as (pseudocode):
function index(i) {
return isIE ? (i - 1) : i;
}

How can I edit a JavaScript variable?

Say I have a variable
tab_something
I need to drop the tab_ bit.
In php it's easy, using str_replace...
Will
tabSelect = document.location.hash.substr(1,document.location.hash.length);
(which would always be tab_something)
document.write(tabSelect.replace(/tab_/i, ""));
Work the way I would like it to, consistently across all modern browsers (ie6+) ?
Cheers.
Abusing source code rewrite as a substitute for reflection is … possible. I hate to state the obvious, but: maybe take a step back and see if you can reshape the project a bit, such that you can come up with a cleaner solution?
A couple of things:
document.location will be deprecated at some point by document.URL, consider using window.location.
Consider also using String.substring, since it is part of the ECMA-262 Spec.
var tabSelect = window.location.hash.substring(1); // remove "#"
tabSelect = tabSelect.replace(/tab_/i, ""); // remove "tab_"
It will work on old and modern browsers.
If document.location.hash always contains tab_ + some other string that you wish to retrieve, why not take advantage of the prefix always being the same length? You already have call substring() so why not let this function cut of a few more chars?
window.location.hash.substring(5)
Thanks to CMS for pointing out that window.location is preferred to document.location.
Yes it will. And also note that you don't have to use regular expressions in .replace(), .replace('tab_', ''); will do just fine.
Yes that is a standard JavaScript function that's been around long enough to cover all modern browsers ie6 and above. Should work just fine.
You could also use substring if you know it will always be the first 4 characters. tabSelect.substring(4) will give you everything starting the first character after tab_ (it is 0-based).

Categories