Forum Moderators: open

Message Too Old, No Replies

Something like URLSearchParams for IE

         

csdude55

5:14 am on Aug 29, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I wrote this nifty bit of code that works great for me to store the name of the URL and remove unwanted query string variables:

// let's say the page is foo/?id=123&h=456&lorem=ipsum&z=789
var saveName = location.pathname;

var params = new URLSearchParams(location.search);

for (let i of ['h', 's', 'z', 'start', 'startview', 'return_here'])
params.delete(i);

if (params.toString())
saveName += '?' + params.toString();

// result
// foo/?id=123&lorem=ipsum


Only problem is that IE doesn't recognize URLSearchParams(). I still have a small amount of IE traffic, so I have to make some sort of allowances for them.

I came up with this alternative, but it's MUCH longer and more complicated:

var saveName = location.pathname,
removeVars = ['h', 's', 'z', 'start', 'startview', 'return_here'],
i;

// Internet Explorer
if (window.document.documentMode) {
var qs = location.search,
pairs = qs.substring(1).split("&"),
params = {},
pair;

for (i in pairs) {
if (pairs[i] === '') continue;

pair = pairs[i].split("=");

params[decodeURIComponent(pair[0])] =
decodeURIComponent(pair[1]);
}

for (i of removeVars)
delete params[i];

if (Object.keys(params).length > 0)
saveName += '?';

for (i in params)
saveName += i + '=' + params[i] + '&';

// remove trailing ? or &
saveName = saveName.replace(/[?&]+$/, '');
}

// everyone else
else {
var params = new URLSearchParams(location.search);

for (i of removeVars)
params.delete(i);

if (params.toString())
saveName += '?' + params.toString();
}


Is there a better way?

robzilla

8:05 am on Aug 29, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



There are a few polyfills available for that function. If you serve one of those to your IE users, then you don't have to change your code at the expense of your non-IE users.

csdude55

4:59 pm on Aug 29, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I'm not familiar with polyfills... I found this on GitHub, but I'm lost on how to install it or use it:

[github.com...]

I'm guessing that I would just rip the min.js and upload it to the server? But after that, I'm not seeing documentation on how to use it.

I'm taking a guess here that I would modify my above script to:

var saveName = location.pathname,
removeVars = ['h', 's', 'z', 'start', 'startview', 'return_here'],
i;

// Internet Explorer
if (window.document.documentMode)
$.getScript("/path/to/min.js"}); // I already use jQuery so it's OK

// everyone else
else {
var params = new URLSearchParams(location.search);

for (i of removeVars)
params.delete(i);

if (params.toString())
saveName += '?' + params.toString();
}


I'm assuming that this wouldn't load min.js unless they're using Internet Explorer, so minimal impact on other users. But after that, I don't know how to use it.

robzilla

6:37 pm on Aug 29, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



A polyfill will test the browser for a particular feature you require, such as the URLSearchParams interface. Then, if the browser doesn't know it, the polyfill contains code to mimick that feature; in your case, it contains code to allow you to use URLSearchParams transparently. Basically, by loading the polyfill you ensure that most every browser can execute your code.

Ideally you'd only serve the polyfill to browsers that you know need it, e.g. through user agent detection. I'd be inclined to do that server-side in this case, since IE is easy to detect and it's best not to burden modern browsers with downloading any polyfills. Your method might work but you'd need to make sure that URLSearchParams is available before you try to use it.

csdude55

4:32 am on Aug 30, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Ahh, I gotcha. So something more like:

<?php

if (strpos($_SERVER['HTTP_USER_AGENT'], 'Trident')) {
echo "<script src='/path/to/min.js'></script>";
}

echo <<<EOF
<script>

var saveName = location.pathname,
removeVars = ['h', 's', 'z', 'start', 'startview', 'return_here'],
i;

var params = new URLSearchParams(location.search);

for (i of removeVars)
params.delete(i);

if (params.toString())
saveName += '?' + params.toString();

</script>


I obviously would have the script in a separate .JS, of course; that's just for the sake of this post.

I found that you can test for URLSearchParams without relying on browser sniffing:

if ('URLSearchParams' in window) { ... }

[developer.chrome.com...]

So maybe it's worth keeping it in JavaScript, anyway? Eg:

var saveName = location.pathname,
removeVars = ['h', 's', 'z', 'start', 'startview', 'return_here'],
i;

// Internet Explorer
if (!window.URLSearchParams)
$.getScript("/path/to/min.js"}); // I already use jQuery so it's OK

var params = new URLSearchParams(location.search);

for (i of removeVars)
params.delete(i);

if (params.toString())
saveName += '?' + params.toString();


In practice, though, I'd probably load min.js in the footer of every page to make sure that it's cached instead of delaying this script.

robzilla

7:27 am on Aug 30, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



You'll probably need a method like done() to avoid firing URLSearchParams() before the script has been downloaded and executed.

But yes I'd just check the user-agent in PHP.

Sidenote: not an issue here because "Trident" will never appear at offset 0 in a valid User Agent string, but keep in mind that when you use if(strpos()) an offset of 0 will be considered false, so generally it's best to use if(strpos() !== false). Or use str_contains() if you're on PHP 8.

csdude55

7:07 pm on Aug 31, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I have a fun new alternative...

This option sets a JavaScript variable server-side for the query string as JSON, and sets it to a JavaScript variable. Then you convert that JSON string to an Object and work with that.

This is in PHP:

<?php

$qs = json_encode($_GET, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);

echo <<<EOF
<script>
// ?id=123&h=456&lorem=ipsum&z=789 becomes
// {"id":123,"h":456,"z":789}
var qs = JSON.parse('$qs');
</script>

// then in the separate JS file
var saveName = location.pathname;

// use "window.qs" in case "qs" is not defined prior, so this is a backup plan
if (!window.qs)
// convert the results of URLSearchParams to a normal Object
var qs = Object.fromEntries(new URLSearchParams(location.search));

// continue if there's a query string
if (Object.values(qs).length > 0) {

// define params to be removed as an Object; values are 1 just because they
// have to be set to something and it's shorter than "true"
var removeObj = {
'h' : 1,
's' : 1,
'z' : 1,
'start' : 1,
'startview' : 1,
'return_here' : 1
}

saveName += '?';

for (let param in qs) {
// add to saveName if param isn't in removeObj
if (!removeObj[param])
saveName += param + '=' + qs[param] + '&';
}
}


Minus the comments, this is only about 100 bytes larger than the original and should work with all browsers :-) The only down side is that there's a potential for a trailing ?, &, or ?&, so I guess I need a regex to clear that out? Unless there's a way to not add them in that last for..in loop.

Fotiman

7:24 pm on Aug 31, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



There may also be potential for executing malicious script injection, as you're directly writing values passed in the search query to your DOM.

csdude55

4:05 am on Sep 1, 2022 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Hmm.

Maybe change the 3rd-from-the-end line to:

saveName += encodeURIComponent(param) + '=' + encodeURIComponent(qs[param]) + '&';

?