How can I edit a JavaScript variable? - javascript

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).

Related

CSS - returning different values from different browsers

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.

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.

Looking for regular expression that will cover every "file://"

I am try to create a regular expression for a javascript project that covers every hyperlink that starts with "file://"
Thanks :)
Hyperlinks have location properties-
you can read document.links[0].protocol from a link.
var links=document.links, L=links.length, filelinks=[];
while(L){
if(links[--L].protocol=='file:')filelinks.push(links[L].href);
}
//eg:
filelinks.join('\n')
file:///C:/webworks/gallery/gallery.html
file:///C:/webworks/library/shared/dewey.html#holmes
file:///C:/webworks/library/shared/dewey.html#twain
file:///C:/webworks/library/shared/dewey.html
Try this one
/^(file?://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-])/?$/
Enjoy :)
/^file\/\/:/i.test(str)
str.match(/^file\/\/:\S+/i)
I wouldn't check for any more than the protocol, URIs are very complicated.
Here is a very thorough version developed by this guy:
(?i)\b((?:file:(?:\/{2}))(?:www\d{0,3}[.]|[a-z0-9\-]+[.])?(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))
EDIT: Evidently I needed to change a few things to make it more strict. I've updated it. If you want to use the capturing groups, remove the ?: to keep a backreference.
Please use the simpler, /(file:\/{2,3}[!#$&-;=?-\[\]_a-z~]+)/

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;
}

Is there a way to get firefox to not automatically url-decode values assigned to document.location.hash?

I'm using document.location.hash to preserve state on the page, and I'm putting url-encoded key value pairs up there, separated by "&" chars. So far so good.
However I'm running into an annoying problem on Firefox -- Firefox will quietly url-decode the hash value on the way in, so when you get it out later it's been decoded.
I can patch the problem by detecting when I'm running on firefox and calling encodeURIComponent on everything twice on the way in, but obviously that is hideous and I don't really want to do that.
Here's a simple example, where I encode "=" as "%3D", put it in the hash, and when I get it out later it's been turned back into "=" automatically:
// on the way in::
document.location.hash = "foo=" + encodeURIComponent("noisy=input");
//then later.....
// on the way out:
var hash = document.location.hash;
kvPair = hash.split("=");
if (kvPair.length==2) {
console.log("that is correct.")
} else if (kvPair.length==3) {
console.log("oh hai firefox, this is incorrect")
}
I have my fingers crossed that there's maybe some hidden DOM element that firefox creates that represents the actual (un-decoded) hash value?
but bottom line -- has anyone run into this and found a better solution than just doing browser detection and calling encodeURIComponent twice on Firefox?
NOTE: several other questions I think have the same root cause. Most notably this one:
https://stackoverflow.com/questions/4834609/malformed-uri-in-firefox-not-ie-using-encodeuricomponenet-and-setting-hash
I would strongly advise against using the hash value to preserve the state. Hash is supposed to point to object's fragment-id, as explained in RFC 1630
This represents a part of, fragment of, or a sub-function within, an
object. (...) The fragment-id follows the URL of the whole object from which it is
separated by a hash sign (#).
Is there anything stopping you from using cookies to preserve the state? Cookies are simple enough to use in JS, described on Geko DOM Reference pages, and would do the trick quietly, without appending values to the URL which is never pretty.
If you absolutely have to use hash though, you may want to consider replacing '=' with some other character, e.g. ":".
What you could do, is change the "=" to something else using
var string = string2.replace("=", "[$equals]")
You may have to run the line above a couple of times, depending on how many "=" there are.
Then same process you had as above.
NB If you require it for further code, you can replace [$equals] back to "=" after splitting the hash into an array.

Categories